blob: 8dfd6bc6b64ba65352d20a3a4cc2998e7c1c026b [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
maruel@chromium.orgca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
maruel@chromium.orgca8d19842009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
14from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
joi@chromium.orgeea609a2011-11-18 13:10:1217
Dirk Prankee3c9c62d2021-05-18 18:35:5918
maruel@chromium.org379e7dd2010-01-28 17:39:2119_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1820 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3121 (r"chrome/android/webapk/shell_apk/src/org/chromium"
22 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0823 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3124 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4725 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3126 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2627 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5228 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3129 r"^media/test/data/.*.ts",
30 r"^native_client_sdksrc/build_tools/make_rules.py",
31 r"^native_client_sdk/src/build_tools/make_simple.py",
32 r"^native_client_sdk/src/tools/.*.mk",
33 r"^net/tools/spdyshark/.*",
34 r"^skia/.*",
35 r"^third_party/blink/.*",
36 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4637 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3138 r"^third_party/sqlite/.*",
39 r"^v8/.*",
maruel@chromium.org3e4eb112011-01-18 03:29:5440 r".*MakeFile$",
gman@chromium.org1084ccc2012-03-14 03:22:5341 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2042 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3143 r".+/pnacl_shim\.c$",
44 r"^gpu/config/.*_list_json\.cc$",
45 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1446 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3147 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5448 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3149 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4550 # Test file compared with generated output.
51 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
maruel@chromium.org4306417642009-06-11 00:33:4052)
maruel@chromium.orgca8d19842009-02-19 16:33:1253
John Abd-El-Malek759fea62021-03-13 03:41:1454_EXCLUDED_SET_NO_PARENT_PATHS = (
55 # It's for historical reasons that blink isn't a top level directory, where
56 # it would be allowed to have "set noparent" to avoid top level owners
57 # accidentally +1ing changes.
58 'third_party/blink/OWNERS',
59)
60
wnwenbdc444e2016-05-25 13:44:1561
joi@chromium.org06e6d0ff2012-12-11 01:36:4462# Fragment of a regular expression that matches C++ and Objective-C++
63# implementation files.
64_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
65
wnwenbdc444e2016-05-25 13:44:1566
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1967# Fragment of a regular expression that matches C++ and Objective-C++
68# header files.
69_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
70
71
Aleksey Khoroshilov9b28c032022-06-03 16:35:3272# Paths with sources that don't use //base.
73_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3174 r"^chrome/browser/browser_switcher/bho/",
75 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3276)
77
78
joi@chromium.org06e6d0ff2012-12-11 01:36:4479# Regular expression that matches code only used for test binaries
80# (best effort).
81_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3182 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
joi@chromium.org06e6d0ff2012-12-11 01:36:4483 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1384 # Test suite files, like:
85 # foo_browsertest.cc
86 # bar_unittest_mac.cc (suffix)
87 # baz_unittests.cc (plural)
88 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
danakj@chromium.orge2d7e6f2013-04-23 12:57:1289 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1890 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2191 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3192 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:4393 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:3194 r'content/shell/.*',
danakj89f47082020-09-02 17:53:4395 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:3196 r'content/web_test/.*',
darin@chromium.org7b054982013-11-27 00:44:4797 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:3198 r'mojo/examples/.*',
lliabraa@chromium.org8176de12014-06-20 19:07:0899 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:31100 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41101 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31102 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17103 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31104 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41105 # Chromium Codelab
Bruce Dawson40fece62022-09-16 19:58:31106 r'codelabs/*'
joi@chromium.org06e6d0ff2012-12-11 01:36:44107)
maruel@chromium.orgca8d19842009-02-19 16:33:12108
Daniel Bratell609102be2019-03-27 20:53:21109_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15110
joi@chromium.orgeea609a2011-11-18 13:10:12111_TEST_ONLY_WARNING = (
112 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55113 'production code. If you are doing this from inside another method\n'
114 'named as *ForTesting(), then consider exposing things to have tests\n'
115 'make that same call directly.\n'
116 'If that is not possible, you may put a comment on the same line with\n'
117 ' // IN-TEST \n'
118 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
119 'method and can be ignored. Do not do this inside production code.\n'
120 'The android-binary-size trybot will block if the method exists in the\n'
121 'release apk.')
joi@chromium.orgeea609a2011-11-18 13:10:12122
123
Daniel Chenga44a1bcd2022-03-15 20:00:15124@dataclass
125class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34126 # String pattern. If the pattern begins with a slash, the pattern will be
127 # treated as a regular expression instead.
128 pattern: str
129 # Explanation as a sequence of strings. Each string in the sequence will be
130 # printed on its own line.
131 explanation: Sequence[str]
132 # Whether or not to treat this ban as a fatal error. If unspecified,
133 # defaults to true.
134 treat_as_error: Optional[bool] = None
135 # Paths that should be excluded from the ban check. Each string is a regular
136 # expression that will be matched against the path of the file being checked
137 # relative to the root of the source tree.
138 excluded_paths: Optional[Sequence[str]] = None
marja@chromium.orgcf9b78f2012-11-14 11:40:28139
Daniel Chenga44a1bcd2022-03-15 20:00:15140
Daniel Cheng917ce542022-03-15 20:46:57141_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15142 BanRule(
143 'import java.net.URI;',
144 (
145 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
146 ),
147 excluded_paths=(
148 (r'net/android/javatests/src/org/chromium/net/'
149 'AndroidProxySelectorTest\.java'),
150 r'components/cronet/',
151 r'third_party/robolectric/local/',
152 ),
Michael Thiessen44457642020-02-06 00:24:15153 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15154 BanRule(
155 'import android.annotation.TargetApi;',
156 (
157 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
158 'RequiresApi ensures that any calls are guarded by the appropriate '
159 'SDK_INT check. See https://crbug.com/1116486.',
160 ),
161 ),
162 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24163 'import androidx.test.rule.UiThreadTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15164 (
165 'Do not use UiThreadTestRule, just use '
166 '@org.chromium.base.test.UiThreadTest on test methods that should run '
167 'on the UI thread. See https://crbug.com/1111893.',
168 ),
169 ),
170 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24171 'import androidx.test.annotation.UiThreadTest;',
172 ('Do not use androidx.test.annotation.UiThreadTest, use '
Daniel Chenga44a1bcd2022-03-15 20:00:15173 'org.chromium.base.test.UiThreadTest instead. See '
174 'https://crbug.com/1111893.',
175 ),
176 ),
177 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24178 'import androidx.test.rule.ActivityTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15179 (
180 'Do not use ActivityTestRule, use '
181 'org.chromium.base.test.BaseActivityTestRule instead.',
182 ),
183 excluded_paths=(
184 'components/cronet/',
185 ),
186 ),
Min Qinbc44383c2023-02-22 17:25:26187 BanRule(
188 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
189 (
190 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
191 'avoid extra indirections. Please also add trace event as the call '
192 'might take more than 20 ms to complete.',
193 ),
194 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15195)
wnwenbdc444e2016-05-25 13:44:15196
Daniel Cheng917ce542022-03-15 20:46:57197_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15198 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41199 'StrictMode.allowThreadDiskReads()',
200 (
201 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
202 'directly.',
203 ),
204 False,
205 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15206 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41207 'StrictMode.allowThreadDiskWrites()',
208 (
209 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
210 'directly.',
211 ),
212 False,
213 ),
Daniel Cheng917ce542022-03-15 20:46:57214 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36215 '.waitForIdleSync()',
216 (
217 'Do not use waitForIdleSync as it masks underlying issues. There is '
218 'almost always something else you should wait on instead.',
219 ),
220 False,
221 ),
Ashley Newson09cbd602022-10-26 11:40:14222 BanRule(
Ashley Newsoneb6f5ced2022-10-26 14:45:42223 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14224 (
225 'Do not call android.content.Context.registerReceiver (or an override) '
226 'directly. Use one of the wrapper methods defined in '
227 'org.chromium.base.ContextUtils, such as '
228 'registerProtectedBroadcastReceiver, '
229 'registerExportedBroadcastReceiver, or '
230 'registerNonExportedBroadcastReceiver. See their documentation for '
231 'which one to use.',
232 ),
233 True,
234 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57235 r'.*Test[^a-z]',
236 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14237 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38238 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14239 ),
240 ),
Ted Chocd5b327b12022-11-05 02:13:22241 BanRule(
242 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
243 (
244 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
245 'IntProperty because it will avoid unnecessary autoboxing of '
246 'primitives.',
247 ),
248 ),
Peilin Wangbba4a8652022-11-10 16:33:57249 BanRule(
250 'requestLayout()',
251 (
252 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
253 'which emits a trace event with additional information to help with '
254 'scroll jank investigations. See http://crbug.com/1354176.',
255 ),
256 False,
257 excluded_paths=(
258 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
259 ),
260 ),
Ted Chocf40ea9152023-02-14 19:02:39261 BanRule(
262 'Profile.getLastUsedRegularProfile()',
263 (
264 'Prefer passing in the Profile reference instead of relying on the '
265 'static getLastUsedRegularProfile() call. Only top level entry points '
266 '(e.g. Activities) should call this method. Otherwise, the Profile '
267 'should either be passed in explicitly or retreived from an existing '
268 'entity with a reference to the Profile (e.g. WebContents).',
269 ),
270 False,
271 excluded_paths=(
272 r'.*Test[A-Z]?.*\.java',
273 ),
274 ),
Min Qinbc44383c2023-02-22 17:25:26275 BanRule(
276 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
277 (
278 'getDrawable() can be expensive. If you have a lot of calls to '
279 'GetDrawable() or your code may introduce janks, please put your calls '
280 'inside a trace().',
281 ),
282 False,
283 excluded_paths=(
284 r'.*Test[A-Z]?.*\.java',
285 ),
286 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39287 BanRule(
288 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
289 (
290 'Raw histogram counts are easy to misuse; for example they don\'t reset '
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',
Chad Duffin06e47de2023-12-14 18:04:13318 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.ts',
Clement Yan9b330cb2022-11-17 05:25:29319 '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',
Ashley Prasad71f9024e2023-09-25 22:33:55324 # TODO(b/301634378): Remove violation exception once Scanning App
325 # migrated off usage of `chrome.send`.
326 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
Clement Yan9b330cb2022-11-17 05:25:29327 ),
328 ),
329)
330
Daniel Cheng917ce542022-03-15 20:46:57331_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15332 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59333 'addTrackingRect:',
avi@chromium.org23e6cbc2012-06-16 18:51:20334 (
335 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
avi@chromium.org127f18ec2012-06-16 05:05:59336 'prohibited. Please use CrTrackingArea instead.',
337 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
338 ),
339 False,
340 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15341 BanRule(
leng@chromium.orgeaae1972014-04-16 04:17:26342 r'/NSTrackingArea\W',
avi@chromium.org23e6cbc2012-06-16 18:51:20343 (
344 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
avi@chromium.org127f18ec2012-06-16 05:05:59345 'instead.',
346 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
347 ),
348 False,
349 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15350 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59351 'convertPointFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20352 (
353 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59354 'Please use |convertPoint:(point) fromView:nil| instead.',
355 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
356 ),
357 True,
358 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15359 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59360 'convertPointToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20361 (
362 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59363 'Please use |convertPoint:(point) toView:nil| instead.',
364 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
365 ),
366 True,
367 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15368 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59369 'convertRectFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20370 (
371 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59372 'Please use |convertRect:(point) fromView:nil| instead.',
373 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
374 ),
375 True,
376 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15377 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59378 'convertRectToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20379 (
380 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59381 'Please use |convertRect:(point) toView:nil| instead.',
382 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
383 ),
384 True,
385 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15386 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59387 'convertSizeFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20388 (
389 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59390 'Please use |convertSize:(point) fromView:nil| instead.',
391 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
392 ),
393 True,
394 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15395 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59396 'convertSizeToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20397 (
398 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59399 'Please use |convertSize:(point) toView:nil| instead.',
400 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
401 ),
402 True,
403 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15404 BanRule(
jif65398702016-10-27 10:19:48405 r"/\s+UTF8String\s*]",
406 (
407 'The use of -[NSString UTF8String] is dangerous as it can return null',
408 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
409 'Please use |SysNSStringToUTF8| instead.',
410 ),
411 True,
Marijn Kruisselbrink1b7c48952023-08-31 16:58:34412 excluded_paths = (
413 '^third_party/ocmock/OCMock/',
414 ),
jif65398702016-10-27 10:19:48415 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15416 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34417 r'__unsafe_unretained',
418 (
419 'The use of __unsafe_unretained is almost certainly wrong, unless',
420 'when interacting with NSFastEnumeration or NSInvocation.',
421 'Please use __weak in files build with ARC, nothing otherwise.',
422 ),
423 False,
424 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15425 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13426 'freeWhenDone:NO',
427 (
428 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
429 'Foundation types is prohibited.',
430 ),
431 True,
432 ),
Avi Drissman3d243a42023-08-01 16:53:59433 BanRule(
434 'This file requires ARC support.',
435 (
436 'ARC compilation is default in Chromium; do not add boilerplate to ',
437 'files that require ARC.',
438 ),
439 True,
440 ),
avi@chromium.org127f18ec2012-06-16 05:05:59441)
442
Sylvain Defresnea8b73d252018-02-28 15:45:54443_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15444 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54445 r'/\bTEST[(]',
446 (
447 'TEST() macro should not be used in Objective-C++ code as it does not ',
448 'drain the autorelease pool at the end of the test. Use TEST_F() ',
449 'macro instead with a fixture inheriting from PlatformTest (or a ',
450 'typedef).'
451 ),
452 True,
453 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15454 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54455 r'/\btesting::Test\b',
456 (
457 'testing::Test should not be used in Objective-C++ code as it does ',
458 'not drain the autorelease pool at the end of the test. Use ',
459 'PlatformTest instead.'
460 ),
461 True,
462 ),
Ewann2ecc8d72022-07-18 07:41:23463 BanRule(
464 ' systemImageNamed:',
465 (
466 '+[UIImage systemImageNamed:] should not be used to create symbols.',
467 'Instead use a wrapper defined in:',
Victor Vianna77a40f62023-01-31 19:04:53468 'ios/chrome/browser/ui/icons/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23469 ),
470 True,
Ewann450a2ef2022-07-19 14:38:23471 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41472 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Gauthier Ambardd36c10b12023-03-16 08:45:03473 'ios/chrome/search_widget_extension/',
Ewann450a2ef2022-07-19 14:38:23474 ),
Ewann2ecc8d72022-07-18 07:41:23475 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54476)
477
Daniel Cheng917ce542022-03-15 20:46:57478_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15479 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05480 r'/\bEXPECT_OCMOCK_VERIFY\b',
481 (
482 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
483 'it is meant for GTests. Use [mock verify] instead.'
484 ),
485 True,
486 ),
487)
488
Daniel Cheng917ce542022-03-15 20:46:57489_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15490 BanRule(
Peter Kasting7c0d98a2023-10-06 15:42:39491 '%#0',
492 (
493 'Zero-padded values that use "#" to add prefixes don\'t exhibit ',
494 'consistent behavior, since the prefix is not prepended for zero ',
495 'values. Use "0x%0..." instead.',
496 ),
497 False,
498 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
499 ),
500 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04501 r'/\busing namespace ',
502 (
503 'Using directives ("using namespace x") are banned by the Google Style',
504 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
505 'Explicitly qualify symbols or use using declarations ("using x::foo").',
506 ),
507 True,
508 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
509 ),
Antonio Gomes07300d02019-03-13 20:59:57510 # Make sure that gtest's FRIEND_TEST() macro is not used; the
511 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
512 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15513 BanRule(
avi@chromium.org23e6cbc2012-06-16 18:51:20514 'FRIEND_TEST(',
515 (
jam@chromium.orge3c945502012-06-26 20:01:49516 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
avi@chromium.org23e6cbc2012-06-16 18:51:20517 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
518 ),
519 False,
Arthur Sonzogni19aa4922023-08-28 17:28:59520 excluded_paths = (
521 "base/gtest_prod_util.h",
Arthur Sonzogni0bcc0232023-10-03 08:48:32522 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
Arthur Sonzogni19aa4922023-08-28 17:28:59523 ),
avi@chromium.org23e6cbc2012-06-16 18:51:20524 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15525 BanRule(
tomhudsone2c14d552016-05-26 17:07:46526 'setMatrixClip',
527 (
528 'Overriding setMatrixClip() is prohibited; ',
529 'the base function is deprecated. ',
530 ),
531 True,
532 (),
533 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15534 BanRule(
enne@chromium.org52657f62013-05-20 05:30:31535 'SkRefPtr',
536 (
537 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22538 'Please use sk_sp<> instead.'
enne@chromium.org52657f62013-05-20 05:30:31539 ),
540 True,
541 (),
542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15543 BanRule(
enne@chromium.org52657f62013-05-20 05:30:31544 'SkAutoRef',
545 (
546 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22547 'Please use sk_sp<> instead.'
enne@chromium.org52657f62013-05-20 05:30:31548 ),
549 True,
550 (),
551 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15552 BanRule(
enne@chromium.org52657f62013-05-20 05:30:31553 'SkAutoTUnref',
554 (
555 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22556 'converts to a raw pointer. Please use sk_sp<> instead.'
enne@chromium.org52657f62013-05-20 05:30:31557 ),
558 True,
559 (),
560 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15561 BanRule(
enne@chromium.org52657f62013-05-20 05:30:31562 'SkAutoUnref',
563 (
564 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
565 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22566 'Please use sk_sp<> instead.'
enne@chromium.org52657f62013-05-20 05:30:31567 ),
568 True,
569 (),
570 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15571 BanRule(
mark@chromium.orgd89eec82013-12-03 14:10:59572 r'/HANDLE_EINTR\(.*close',
573 (
574 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
575 'descriptor will be closed, and it is incorrect to retry the close.',
576 'Either call close directly and ignore its return value, or wrap close',
577 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
578 ),
579 True,
580 (),
581 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15582 BanRule(
mark@chromium.orgd89eec82013-12-03 14:10:59583 r'/IGNORE_EINTR\((?!.*close)',
584 (
585 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
586 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
587 ),
588 True,
589 (
590 # Files that #define IGNORE_EINTR.
Bruce Dawson40fece62022-09-16 19:58:31591 r'^base/posix/eintr_wrapper\.h$',
592 r'^ppapi/tests/test_broker\.cc$',
mark@chromium.orgd89eec82013-12-03 14:10:59593 ),
594 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15595 BanRule(
jochen@chromium.orgec5b3f02014-04-04 18:43:43596 r'/v8::Extension\(',
597 (
598 'Do not introduce new v8::Extensions into the code base, use',
599 'gin::Wrappable instead. See http://crbug.com/334679',
600 ),
601 True,
rockot@chromium.orgf55c90ee62014-04-12 00:50:03602 (
Bruce Dawson40fece62022-09-16 19:58:31603 r'extensions/renderer/safe_builtins\.*',
rockot@chromium.orgf55c90ee62014-04-12 00:50:03604 ),
jochen@chromium.orgec5b3f02014-04-04 18:43:43605 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15606 BanRule(
jame2d1a952016-04-02 00:27:10607 '#pragma comment(lib,',
608 (
609 'Specify libraries to link with in build files and not in the source.',
610 ),
611 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41612 (
Bruce Dawson40fece62022-09-16 19:58:31613 r'^base/third_party/symbolize/.*',
614 r'^third_party/abseil-cpp/.*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41615 ),
jame2d1a952016-04-02 00:27:10616 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15617 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02618 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59619 (
620 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
621 ),
622 False,
623 (),
624 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15625 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02626 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59627 (
628 'Consider using THREAD_CHECKER macros instead of the class directly.',
629 ),
630 False,
631 (),
632 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15633 BanRule(
Sean Maher03efef12022-09-23 22:43:13634 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
635 (
636 'It is not allowed to call these methods from the subclasses ',
637 'of Sequenced or SingleThread task runners.',
638 ),
639 True,
640 (),
641 ),
642 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06643 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
644 (
645 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
646 'deprecated (http://crbug.com/634507). Please avoid converting away',
647 'from the Time types in Chromium code, especially if any math is',
648 'being done on time values. For interfacing with platform/library',
Peter Kasting8a2605652023-09-14 03:57:15649 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
650 'base::{TimeDelta::In}Microseconds(), or one of the other type',
651 'converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48652 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06653 'other use cases, please contact base/time/OWNERS.',
654 ),
655 False,
Arthur Sonzogni19aa4922023-08-28 17:28:59656 excluded_paths = (
657 "base/time/time.h",
Arthur Sonzogni0bcc0232023-10-03 08:48:32658 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
Arthur Sonzogni19aa4922023-08-28 17:28:59659 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06660 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15661 BanRule(
dbeamb6f4fde2017-06-15 04:03:06662 'CallJavascriptFunctionUnsafe',
663 (
664 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
665 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
666 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
667 ),
668 False,
669 (
Bruce Dawson40fece62022-09-16 19:58:31670 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
671 r'^content/public/browser/web_ui\.h$',
672 r'^content/public/test/test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06673 ),
674 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15675 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24676 'leveldb::DB::Open',
677 (
678 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
679 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
680 "Chrome's tracing, making their memory usage visible.",
681 ),
682 True,
683 (
684 r'^third_party/leveldatabase/.*\.(cc|h)$',
685 ),
Gabriel Charette0592c3a2017-07-26 12:02:04686 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15687 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08688 'leveldb::NewMemEnv',
689 (
690 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58691 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
692 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08693 ),
694 True,
695 (
696 r'^third_party/leveldatabase/.*\.(cc|h)$',
697 ),
698 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15699 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47700 'RunLoop::QuitCurrent',
701 (
Robert Liao64b7ab22017-08-04 23:03:43702 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
703 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47704 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41705 False,
Gabriel Charetted9839bc2017-07-29 14:17:47706 (),
Gabriel Charettea44975052017-08-21 23:14:04707 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15708 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04709 'base::ScopedMockTimeMessageLoopTaskRunner',
710 (
Gabriel Charette87cc1af2018-04-25 20:52:51711 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11712 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51713 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
714 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
715 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04716 ),
Gabriel Charette87cc1af2018-04-25 20:52:51717 False,
Gabriel Charettea44975052017-08-21 23:14:04718 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57719 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15720 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44721 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57722 (
723 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02724 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57725 ),
726 True,
Robert Ogden4c43a712023-06-28 22:03:19727 [
728 # Abseil's benchmarks never linked into chrome.
729 'third_party/abseil-cpp/.*_benchmark.cc',
Robert Ogden4c43a712023-06-28 22:03:19730 ],
Francois Doray43670e32017-09-27 12:40:38731 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15732 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08733 r'/\bstd::sto(i|l|ul|ll|ull)\b',
Peter Kasting991618a62019-06-17 22:00:09734 (
Peter Kastinge2c5ee82023-02-15 17:23:08735 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
736 'Use base::StringTo[U]Int[64]() instead.',
Peter Kasting991618a62019-06-17 22:00:09737 ),
738 True,
739 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
740 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15741 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08742 r'/\bstd::sto(f|d|ld)\b',
Peter Kasting991618a62019-06-17 22:00:09743 (
Peter Kastinge2c5ee82023-02-15 17:23:08744 'std::sto{f,d,ld}() use exceptions to communicate results. ',
Peter Kasting991618a62019-06-17 22:00:09745 'For locale-independent values, e.g. reading numbers from disk',
746 'profiles, use base::StringToDouble().',
747 'For user-visible values, parse using ICU.',
748 ),
749 True,
750 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
751 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15752 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45753 r'/\bstd::to_string\b',
754 (
Peter Kastinge2c5ee82023-02-15 17:23:08755 'std::to_string() is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09756 'For locale-independent strings, e.g. writing numbers to disk',
757 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45758 'For user-visible strings, use base::FormatNumber() and',
759 'the related functions in base/i18n/number_formatting.h.',
760 ),
Peter Kasting991618a62019-06-17 22:00:09761 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21762 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45763 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15764 BanRule(
Peter Kasting6f79b202023-08-09 21:25:41765 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
766 (
767 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
768 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
769 ),
770 True,
771 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
772 ),
773 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45774 r'/\bstd::shared_ptr\b',
775 (
Peter Kastinge2c5ee82023-02-15 17:23:08776 'std::shared_ptr is banned. Use scoped_refptr instead.',
Daniel Bratell69334cc2019-03-26 11:07:45777 ),
778 True,
Ulan Degenbaev947043882021-02-10 14:02:31779 [
780 # Needed for interop with third-party library.
781 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57782 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58783 '^third_party/blink/renderer/bindings/core/v8/' +
784 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58785 '^gin/array_buffer\.(cc|h)',
Jiahe Zhange97ba772023-07-27 02:46:41786 '^gin/per_isolate_data\.(cc|h)',
Wez5f56be52021-05-04 09:30:58787 '^chrome/services/sharing/nearby/',
Stephen Nuskoe09c8ef22022-09-29 00:47:28788 # Needed for interop with third-party library libunwindstack.
Stephen Nuskoe51c1382022-09-26 15:49:03789 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
Thiabaud Engelbrecht42e09812023-08-29 21:19:30790 '^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
Bob Beck03509d282022-12-07 21:49:05791 # Needed for interop with third-party boringssl cert verifier
792 '^third_party/boringssl/',
793 '^net/cert/',
794 '^net/tools/cert_verify_tool/',
795 '^services/cert_verifier/',
796 '^components/certificate_transparency/',
797 '^components/media_router/common/providers/cast/certificate/',
Meilin Wang00efc7c2021-05-13 01:12:42798 # gRPC provides some C++ libraries that use std::shared_ptr<>.
Yeunjoo Choi1b644402022-08-25 02:36:10799 '^chromeos/ash/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59800 '^chromecast/cast_core/grpc',
801 '^chromecast/cast_core/runtime/browser',
Yue Shef83d95202022-09-26 20:23:45802 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Wez5f56be52021-05-04 09:30:58803 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Wez6da2e412022-11-23 11:28:48804 '^base/fuchsia/.*\.(cc|h)',
Wez5f56be52021-05-04 09:30:58805 '.*fuchsia.*test\.(cc|h)',
miktb599ed12023-05-26 07:03:56806 # Clang plugins have different build config.
807 '^tools/clang/plugins/',
Alex Chau9eb03cdd52020-07-13 21:04:57808 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21809 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15810 BanRule(
Peter Kasting991618a62019-06-17 22:00:09811 r'/\bstd::weak_ptr\b',
812 (
Peter Kastinge2c5ee82023-02-15 17:23:08813 'std::weak_ptr is banned. Use base::WeakPtr instead.',
Peter Kasting991618a62019-06-17 22:00:09814 ),
815 True,
816 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
817 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15818 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21819 r'/\blong long\b',
820 (
Peter Kastinge2c5ee82023-02-15 17:23:08821 'long long is banned. Use [u]int64_t instead.',
Daniel Bratell609102be2019-03-27 20:53:21822 ),
823 False, # Only a warning since it is already used.
824 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
825 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15826 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44827 r'/\b(absl|std)::any\b',
Daniel Chengc05fcc62022-01-12 16:54:29828 (
Peter Kastinge2c5ee82023-02-15 17:23:08829 '{absl,std}::any are banned due to incompatibility with the component ',
830 'build.',
Daniel Chengc05fcc62022-01-12 16:54:29831 ),
832 True,
833 # Not an error in third party folders, though it probably should be :)
834 [_THIRD_PARTY_EXCEPT_BLINK],
835 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15836 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21837 r'/\bstd::bind\b',
838 (
Peter Kastinge2c5ee82023-02-15 17:23:08839 'std::bind() is banned because of lifetime risks. Use ',
840 'base::Bind{Once,Repeating}() instead.',
Daniel Bratell609102be2019-03-27 20:53:21841 ),
842 True,
843 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
844 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15845 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44846 (
Peter Kastingc7460d982023-03-14 21:01:42847 r'/\bstd::(?:'
848 r'linear_congruential_engine|mersenne_twister_engine|'
849 r'subtract_with_carry_engine|discard_block_engine|'
850 r'independent_bits_engine|shuffle_order_engine|'
851 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
852 r'default_random_engine|'
853 r'random_device|'
854 r'seed_seq'
Daniel Cheng192683f2022-11-01 20:52:44855 r')\b'
856 ),
857 (
858 'STL random number engines and generators are banned. Use the ',
859 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
860 'base::RandomBitGenerator.'
Daniel Cheng57d967762023-10-10 19:03:06861 '',
862 'Please reach out to cxx@chromium.org if the base APIs are ',
863 'insufficient for your needs.',
Daniel Cheng192683f2022-11-01 20:52:44864 ),
865 True,
866 [
867 # Not an error in third_party folders.
868 _THIRD_PARTY_EXCEPT_BLINK,
869 # Various tools which build outside of Chrome.
870 r'testing/libfuzzer',
871 r'tools/android/io_benchmark/',
872 # Fuzzers are allowed to use standard library random number generators
873 # since fuzzing speed + reproducibility is important.
874 r'tools/ipc_fuzzer/',
875 r'.+_fuzzer\.cc$',
876 r'.+_fuzzertest\.cc$',
877 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
878 # the standard library's random number generators, and should be
879 # migrated to the //base equivalent.
880 r'ash/ambient/model/ambient_topic_queue\.cc',
Arthur Sonzogni0bcc0232023-10-03 08:48:32881 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
Daniel Cheng192683f2022-11-01 20:52:44882 r'base/ranges/algorithm_unittest\.cc',
883 r'base/test/launcher/test_launcher\.cc',
884 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
885 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
886 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
887 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
888 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
889 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
890 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
891 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
892 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
893 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
Daniel Cheng192683f2022-11-01 20:52:44894 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
895 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
896 r'components/metrics/metrics_state_manager\.cc',
897 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
898 r'components/zucchini/disassembler_elf_unittest\.cc',
899 r'content/browser/webid/federated_auth_request_impl\.cc',
900 r'content/browser/webid/federated_auth_request_impl\.cc',
901 r'media/cast/test/utility/udp_proxy\.h',
902 r'sql/recover_module/module_unittest\.cc',
Samarc64873a72023-10-10 09:19:12903 r'components/search_engines/template_url_prepopulate_data.cc',
Daniel Cheng57d967762023-10-10 19:03:06904 # Do not add new entries to this list. If you have a use case which is
905 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
906 # sequence, or stability of some sort is required), please contact
907 # cxx@chromium.org.
Daniel Cheng192683f2022-11-01 20:52:44908 ],
909 ),
910 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08911 r'/\b(absl,std)::bind_front\b',
Peter Kasting4f35bfc2022-10-18 18:39:12912 (
Peter Kastinge2c5ee82023-02-15 17:23:08913 '{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
914 'instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12915 ),
916 True,
917 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
918 ),
919 BanRule(
920 r'/\bABSL_FLAG\b',
921 (
922 'ABSL_FLAG is banned. Use base::CommandLine instead.',
923 ),
924 True,
925 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
926 ),
927 BanRule(
928 r'/\babsl::c_',
929 (
Peter Kastinge2c5ee82023-02-15 17:23:08930 'Abseil container utilities are banned. Use base/ranges/algorithm.h ',
Peter Kasting4f35bfc2022-10-18 18:39:12931 'instead.',
932 ),
933 True,
934 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
935 ),
936 BanRule(
Peter Kasting431239a2023-09-29 03:11:44937 r'/\babsl::FixedArray\b',
938 (
939 'absl::FixedArray is banned. Use base::FixedArray instead.',
940 ),
941 True,
942 [
943 # base::FixedArray provides canonical access.
944 r'^base/types/fixed_array.h',
945 # Not an error in third_party folders.
946 _THIRD_PARTY_EXCEPT_BLINK,
947 ],
948 ),
949 BanRule(
Peter Kasting4f35bfc2022-10-18 18:39:12950 r'/\babsl::FunctionRef\b',
951 (
952 'absl::FunctionRef is banned. Use base::FunctionRef instead.',
953 ),
954 True,
955 [
956 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
957 # interoperability.
958 r'^base/functional/bind_internal\.h',
959 # base::FunctionRef is implemented on top of absl::FunctionRef.
960 r'^base/functional/function_ref.*\..+',
961 # Not an error in third_party folders.
962 _THIRD_PARTY_EXCEPT_BLINK,
963 ],
964 ),
965 BanRule(
966 r'/\babsl::(Insecure)?BitGen\b',
967 (
Daniel Cheng192683f2022-11-01 20:52:44968 'absl random number generators are banned. Use the helpers in '
969 'base/rand_util.h instead, e.g. base::RandBytes() or ',
970 'base::RandomBitGenerator.'
Peter Kasting4f35bfc2022-10-18 18:39:12971 ),
972 True,
973 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
974 ),
975 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08976 r'/(\babsl::Span\b|#include <span>)',
Peter Kasting4f35bfc2022-10-18 18:39:12977 (
Peter Kastinge2c5ee82023-02-15 17:23:08978 'absl::Span is banned and <span> is not allowed yet ',
979 '(https://crbug.com/1414652). Use base::span instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12980 ),
981 True,
Victor Vasiliev23b9ea6a2023-01-05 19:42:29982 [
983 # Needed to use QUICHE API.
984 r'services/network/web_transport\.cc',
Brianna Goldstein846d8002023-05-16 19:24:30985 r'chrome/browser/ip_protection/.*',
Victor Vasiliev23b9ea6a2023-01-05 19:42:29986 # Not an error in third_party folders.
987 _THIRD_PARTY_EXCEPT_BLINK
988 ],
Peter Kasting4f35bfc2022-10-18 18:39:12989 ),
990 BanRule(
991 r'/\babsl::StatusOr\b',
992 (
993 'absl::StatusOr is banned. Use base::expected instead.',
994 ),
995 True,
Adithya Srinivasanb2041882022-10-21 19:34:20996 [
997 # Needed to use liburlpattern API.
998 r'third_party/blink/renderer/core/url_pattern/.*',
Louise Brettc6d23872023-04-11 02:48:32999 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Brianna Goldstein846d8002023-05-16 19:24:301000 # Needed to use QUICHE API.
1001 r'chrome/browser/ip_protection/.*',
Piotr Bialecki7f2549fd2023-10-17 17:49:461002 # Needed to use MediaPipe API.
1003 r'components/media_effects/.*\.cc',
Adithya Srinivasanb2041882022-10-21 19:34:201004 # Not an error in third_party folders.
1005 _THIRD_PARTY_EXCEPT_BLINK
1006 ],
Peter Kasting4f35bfc2022-10-18 18:39:121007 ),
1008 BanRule(
1009 r'/\babsl::StrFormat\b',
1010 (
Peter Kastinge2c5ee82023-02-15 17:23:081011 'absl::StrFormat() is not allowed yet (https://crbug.com/1371963). ',
1012 'Use base::StringPrintf() instead.',
Peter Kasting4f35bfc2022-10-18 18:39:121013 ),
1014 True,
1015 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1016 ),
1017 BanRule(
Peter Kasting4f35bfc2022-10-18 18:39:121018 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
1019 (
1020 'Abseil string utilities are banned. Use base/strings instead.',
1021 ),
1022 True,
1023 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1024 ),
1025 BanRule(
1026 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1027 (
1028 'Abseil synchronization primitives are banned. Use',
1029 'base/synchronization instead.',
1030 ),
1031 True,
1032 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1033 ),
1034 BanRule(
1035 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1036 (
1037 'Abseil\'s time library is banned. Use base/time instead.',
1038 ),
1039 True,
Dustin J. Mitchell626a6d322023-06-26 15:02:481040 [
1041 # Needed to use QUICHE API.
1042 r'chrome/browser/ip_protection/.*',
Victor Vasilieva8638882023-09-25 16:41:041043 r'services/network/web_transport.*',
Dustin J. Mitchell626a6d322023-06-26 15:02:481044 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1045 ],
Peter Kasting4f35bfc2022-10-18 18:39:121046 ),
1047 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081048 r'/#include <chrono>',
Daniel Bratell609102be2019-03-27 20:53:211049 (
Peter Kastinge2c5ee82023-02-15 17:23:081050 '<chrono> is banned. Use base/time instead.',
Daniel Bratell609102be2019-03-27 20:53:211051 ),
1052 True,
Arthur Sonzogni2ee5e382023-09-11 09:13:031053 [
1054 # Not an error in third_party folders:
1055 _THIRD_PARTY_EXCEPT_BLINK,
1056 # PartitionAlloc's starscan, doesn't depend on base/. It can't use
1057 # base::ConditionalVariable::TimedWait(..).
Arthur Sonzogni0bcc0232023-10-03 08:48:321058 "base/allocator/partition_allocator/src/partition_alloc/starscan/pcscan_internal.cc",
Arthur Sonzogni2ee5e382023-09-11 09:13:031059 ]
Daniel Bratell609102be2019-03-27 20:53:211060 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151061 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081062 r'/#include <exception>',
Daniel Bratell609102be2019-03-27 20:53:211063 (
1064 'Exceptions are banned and disabled in Chromium.',
1065 ),
1066 True,
1067 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1068 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151069 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211070 r'/\bstd::function\b',
1071 (
Peter Kastinge2c5ee82023-02-15 17:23:081072 'std::function is banned. Use base::{Once,Repeating}Callback instead.',
Daniel Bratell609102be2019-03-27 20:53:211073 ),
Daniel Chenge5583e3c2022-09-22 00:19:411074 True,
Daniel Chengcd23b8b2022-09-16 17:16:241075 [
1076 # Has tests that template trait helpers don't unintentionally match
1077 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:411078 r'base/functional/callback_helpers_unittest\.cc',
1079 # Required to implement interfaces from the third-party perfetto
1080 # library.
1081 r'base/tracing/perfetto_task_runner\.cc',
1082 r'base/tracing/perfetto_task_runner\.h',
1083 # Needed for interop with the third-party nearby library type
1084 # location::nearby::connections::ResultCallback.
1085 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1086 # Needed for interop with the internal libassistant library.
1087 'chromeos/ash/services/libassistant/callback_utils\.h',
1088 # Needed for interop with Fuchsia fidl APIs.
1089 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1090 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1091 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
Ken Rockot2af0d1742023-11-22 17:03:471092 # Required to interop with interfaces from the third-party ChromeML
1093 # library API.
1094 'services/on_device_model/ml/chrome_ml_api\.h',
1095 'services/on_device_model/ml/on_device_model_executor\.cc',
1096 'services/on_device_model/ml/on_device_model_executor\.h',
Daniel Chenge5583e3c2022-09-22 00:19:411097 # Required to interop with interfaces from the third-party perfetto
1098 # library.
1099 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1100 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1101 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1102 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1103 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1104 'services/tracing/public/cpp/perfetto/producer_client\.h',
1105 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1106 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1107 # Required for interop with the third-party webrtc library.
1108 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1109 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Daniel Chenge5583e3c2022-09-22 00:19:411110 # TODO(https://crbug.com/1364577): Various uses that should be
1111 # migrated to something else.
1112 # Should use base::OnceCallback or base::RepeatingCallback.
1113 'base/allocator/dispatcher/initializer_unittest\.cc',
1114 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1115 'chrome/browser/ash/accessibility/speech_monitor\.h',
1116 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1117 'chromecast/base/observer_unittest\.cc',
1118 'chromecast/browser/cast_web_view\.h',
1119 'chromecast/public/cast_media_shlib\.h',
1120 'device/bluetooth/floss/exported_callback_manager\.h',
1121 'device/bluetooth/floss/floss_dbus_client\.h',
1122 'device/fido/cable/v2_handshake_unittest\.cc',
1123 'device/fido/pin\.cc',
1124 'services/tracing/perfetto/test_utils\.h',
1125 # Should use base::FunctionRef.
1126 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1127 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1128 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1129 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1130 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1131 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1132 # Does not need std::function at all.
1133 'components/omnibox/browser/autocomplete_result\.cc',
1134 'device/fido/win/webauthn_api\.cc',
1135 'media/audio/alsa/alsa_util\.cc',
1136 'media/remoting/stream_provider\.h',
1137 'sql/vfs_wrapper\.cc',
1138 # TODO(https://crbug.com/1364585): Remove usage and exception list
1139 # entries.
1140 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1141 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1142 # TODO(https://crbug.com/1364579): Remove usage and exception list
1143 # entry.
1144 'ui/views/controls/focus_ring\.h',
1145
1146 # Various pre-existing uses in //tools that is low-priority to fix.
1147 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1148 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1149 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1150 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1151 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
1152
Daniel Chengcd23b8b2022-09-16 17:16:241153 # Not an error in third_party folders.
1154 _THIRD_PARTY_EXCEPT_BLINK
1155 ],
Daniel Bratell609102be2019-03-27 20:53:211156 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151157 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081158 r'/#include <X11/',
Tom Andersona95e12042020-09-09 23:08:001159 (
1160 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
1161 ),
1162 True,
1163 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1164 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151165 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211166 r'/\bstd::ratio\b',
1167 (
1168 'std::ratio is banned by the Google Style Guide.',
1169 ),
1170 True,
1171 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451172 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151173 BanRule(
Peter Kasting6d77e9d2023-02-09 21:58:181174 r'/\bstd::aligned_alloc\b',
1175 (
Peter Kastinge2c5ee82023-02-15 17:23:081176 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1177 'base::AlignedAlloc() instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181178 ),
1179 True,
1180 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1181 ),
1182 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081183 r'/#include <(barrier|latch|semaphore|stop_token)>',
Peter Kasting6d77e9d2023-02-09 21:58:181184 (
Peter Kastinge2c5ee82023-02-15 17:23:081185 'The thread support library is banned. Use base/synchronization '
1186 'instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181187 ),
1188 True,
1189 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1190 ),
1191 BanRule(
Avi Drissman70cb7f72023-12-12 17:44:371192 r'/\bstd::bit_cast\b',
1193 (
1194 'std::bit_cast is banned; use base::bit_cast instead for values and '
1195 'standard C++ casting when pointers are involved.',
1196 ),
1197 True,
1198 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1199 ),
1200 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081201 r'/\bstd::(c8rtomb|mbrtoc8)\b',
Peter Kasting6d77e9d2023-02-09 21:58:181202 (
Peter Kastinge2c5ee82023-02-15 17:23:081203 'std::c8rtomb() and std::mbrtoc8() are banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181204 ),
1205 True,
1206 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1207 ),
1208 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081209 r'/\bchar8_t|std::u8string\b',
Peter Kasting6d77e9d2023-02-09 21:58:181210 (
Peter Kastinge2c5ee82023-02-15 17:23:081211 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1212 ' char and std::string instead?',
1213 ),
1214 True,
Daniel Cheng893c563f2023-04-21 09:54:521215 [
1216 # The demangler does not use this type but needs to know about it.
1217 'base/third_party/symbolize/demangle\.cc',
1218 # Don't warn in third_party folders.
1219 _THIRD_PARTY_EXCEPT_BLINK
1220 ],
Peter Kastinge2c5ee82023-02-15 17:23:081221 ),
1222 BanRule(
1223 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1224 (
1225 'Coroutines are not yet allowed (https://crbug.com/1403840).',
1226 ),
1227 True,
1228 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1229 ),
1230 BanRule(
Peter Kastingcc152522023-03-22 20:17:371231 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
Peter Kasting69357dc2023-03-14 01:34:291232 (
1233 'Modules are disallowed for now due to lack of toolchain support.',
1234 ),
1235 True,
1236 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1237 ),
1238 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081239 r'/\[\[(un)?likely\]\]',
1240 (
1241 '[[likely]] and [[unlikely]] are not yet allowed ',
1242 '(https://crbug.com/1414620). Use [UN]LIKELY instead.',
1243 ),
1244 True,
1245 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1246 ),
1247 BanRule(
Peter Kasting8bc046d22023-11-14 00:38:031248 r'/\[\[(\w*::)?no_unique_address\]\]',
1249 (
1250 '[[no_unique_address]] does not work as expected on Windows ',
1251 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1252 ),
1253 True,
1254 [
Daniel Chenga04e0d22024-01-16 18:27:251255 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1256 r'^base/compiler_specific\.h',
1257 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
Peter Kasting8bc046d22023-11-14 00:38:031258 # Not an error in third_party folders.
1259 _THIRD_PARTY_EXCEPT_BLINK,
1260 ],
1261 ),
1262 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081263 r'/#include <format>',
1264 (
1265 '<format> is not yet allowed. Use base::StringPrintf() instead.',
1266 ),
1267 True,
1268 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1269 ),
1270 BanRule(
1271 r'/#include <ranges>',
1272 (
1273 '<ranges> is not yet allowed. Use base/ranges/algorithm.h instead.',
1274 ),
1275 True,
1276 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1277 ),
1278 BanRule(
1279 r'/#include <source_location>',
1280 (
1281 '<source_location> is not yet allowed. Use base/location.h instead.',
1282 ),
1283 True,
1284 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1285 ),
1286 BanRule(
1287 r'/#include <syncstream>',
1288 (
1289 '<syncstream> is banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181290 ),
1291 True,
1292 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1293 ),
1294 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:581295 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:191296 (
1297 'RunMessageLoop is deprecated, use RunLoop instead.',
1298 ),
1299 False,
1300 (),
1301 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151302 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441303 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191304 (
1305 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1306 "if you're convinced you need this.",
1307 ),
1308 False,
1309 (),
1310 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151311 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441312 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191313 (
1314 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041315 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191316 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1317 'async events instead of flushing threads.',
1318 ),
1319 False,
1320 (),
1321 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151322 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191323 r'MessageLoopRunner',
1324 (
1325 'MessageLoopRunner is deprecated, use RunLoop instead.',
1326 ),
1327 False,
1328 (),
1329 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151330 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441331 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191332 (
1333 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1334 "gab@ if you found a use case where this is the only solution.",
1335 ),
1336 False,
1337 (),
1338 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151339 BanRule(
Victor Costane48a2e82019-03-15 22:02:341340 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161341 (
Victor Costane48a2e82019-03-15 22:02:341342 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161343 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1344 ),
1345 True,
1346 (
1347 r'^sql/initialization\.(cc|h)$',
1348 r'^third_party/sqlite/.*\.(c|cc|h)$',
1349 ),
1350 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151351 BanRule(
Austin Sullivand661ab52022-11-16 08:55:151352 'CREATE VIEW',
1353 (
1354 'SQL views are disabled in Chromium feature code',
1355 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1356 ),
1357 True,
1358 (
1359 _THIRD_PARTY_EXCEPT_BLINK,
1360 # sql/ itself uses views when using memory-mapped IO.
1361 r'^sql/.*',
1362 # Various performance tools that do not build as part of Chrome.
1363 r'^infra/.*',
1364 r'^tools/perf.*',
1365 r'.*perfetto.*',
1366 ),
1367 ),
1368 BanRule(
1369 'CREATE VIRTUAL TABLE',
1370 (
1371 'SQL virtual tables are disabled in Chromium feature code',
1372 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1373 ),
1374 True,
1375 (
1376 _THIRD_PARTY_EXCEPT_BLINK,
1377 # sql/ itself uses virtual tables in the recovery module and tests.
1378 r'^sql/.*',
1379 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1380 r'third_party/blink/web_tests/storage/websql/.*'
1381 # Various performance tools that do not build as part of Chrome.
1382 r'^tools/perf.*',
1383 r'.*perfetto.*',
1384 ),
1385 ),
1386 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441387 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471388 (
1389 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1390 'base::RandomShuffle instead.'
1391 ),
1392 True,
1393 (),
1394 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151395 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241396 'ios/web/public/test/http_server',
1397 (
1398 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1399 ),
1400 False,
1401 (),
1402 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151403 BanRule(
Robert Liao764c9492019-01-24 18:46:281404 'GetAddressOf',
1405 (
1406 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531407 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111408 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531409 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281410 ),
1411 True,
1412 (),
1413 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151414 BanRule(
Ben Lewisa9514602019-04-29 17:53:051415 'SHFileOperation',
1416 (
1417 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1418 'complex functions to achieve the same goals. Use IFileOperation for ',
1419 'any esoteric actions instead.'
1420 ),
1421 True,
1422 (),
1423 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151424 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511425 'StringFromGUID2',
1426 (
1427 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241428 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511429 ),
1430 True,
1431 (
Daniel Chenga44a1bcd2022-03-15 20:00:151432 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511433 ),
1434 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151435 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511436 'StringFromCLSID',
1437 (
1438 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241439 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511440 ),
1441 True,
1442 (
Daniel Chenga44a1bcd2022-03-15 20:00:151443 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511444 ),
1445 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151446 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131447 'kCFAllocatorNull',
1448 (
1449 'The use of kCFAllocatorNull with the NoCopy creation of ',
1450 'CoreFoundation types is prohibited.',
1451 ),
1452 True,
1453 (),
1454 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151455 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291456 'mojo::ConvertTo',
1457 (
1458 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1459 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1460 'StringTraits if you would like to convert between custom types and',
1461 'the wire format of mojom types.'
1462 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221463 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291464 (
David Dorwin13dc48b2022-06-03 21:18:421465 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1466 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291467 r'^third_party/blink/.*\.(cc|h)$',
1468 r'^content/renderer/.*\.(cc|h)$',
1469 ),
1470 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151471 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161472 'GetInterfaceProvider',
1473 (
1474 'InterfaceProvider is deprecated.',
1475 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1476 'or Platform::GetBrowserInterfaceBroker.'
1477 ),
1478 False,
1479 (),
1480 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151481 BanRule(
Robert Liao1d78df52019-11-11 20:02:011482 'CComPtr',
1483 (
1484 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1485 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1486 'details.'
1487 ),
1488 False,
1489 (),
1490 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151491 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201492 r'/\b(IFACE|STD)METHOD_?\(',
1493 (
1494 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1495 'Instead, always use IFACEMETHODIMP in the declaration.'
1496 ),
1497 False,
1498 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1499 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151500 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471501 'set_owned_by_client',
1502 (
1503 'set_owned_by_client is deprecated.',
1504 'views::View already owns the child views by default. This introduces ',
1505 'a competing ownership model which makes the code difficult to reason ',
1506 'about. See http://crbug.com/1044687 for more details.'
1507 ),
1508 False,
1509 (),
1510 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151511 BanRule(
Peter Boström7ff41522021-07-29 03:43:271512 'RemoveAllChildViewsWithoutDeleting',
1513 (
1514 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1515 'This method is deemed dangerous as, unless raw pointers are re-added,',
1516 'calls to this method introduce memory leaks.'
1517 ),
1518 False,
1519 (),
1520 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151521 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121522 r'/\bTRACE_EVENT_ASYNC_',
1523 (
1524 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1525 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1526 ),
1527 False,
1528 (
1529 r'^base/trace_event/.*',
1530 r'^base/tracing/.*',
1531 ),
1532 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151533 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431534 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1535 (
1536 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1537 'dumps and may spam crash reports. Consider if the throttled',
1538 'variants suffice instead.',
1539 ),
1540 False,
1541 (),
1542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151543 BanRule(
Robert Liao22f66a52021-04-10 00:57:521544 'RoInitialize',
1545 (
Robert Liao48018922021-04-16 23:03:021546 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521547 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1548 'instead. See http://crbug.com/1197722 for more information.'
1549 ),
1550 True,
Robert Liao48018922021-04-16 23:03:021551 (
Bruce Dawson40fece62022-09-16 19:58:311552 r'^base/win/scoped_winrt_initializer\.cc$',
Danil Chapovalov07694382023-05-24 17:55:211553 r'^third_party/abseil-cpp/absl/.*',
Robert Liao48018922021-04-16 23:03:021554 ),
Robert Liao22f66a52021-04-10 00:57:521555 ),
Patrick Monettec343bb982022-06-01 17:18:451556 BanRule(
1557 r'base::Watchdog',
1558 (
1559 'base::Watchdog is deprecated because it creates its own thread.',
1560 'Instead, manually start a timer on a SequencedTaskRunner.',
1561 ),
1562 False,
1563 (),
1564 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091565 BanRule(
1566 'base::Passed',
1567 (
1568 'Do not use base::Passed. It is a legacy helper for capturing ',
1569 'move-only types with base::BindRepeating, but invoking the ',
1570 'resulting RepeatingCallback moves the captured value out of ',
1571 'the callback storage, and subsequent invocations may pass the ',
1572 'value in a valid but undefined state. Prefer base::BindOnce().',
1573 'See http://crbug.com/1326449 for context.'
1574 ),
1575 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481576 (
1577 # False positive, but it is also fine to let bind internals reference
1578 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241579 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481580 r'^base[\\/]functional[\\/]bind_internal\.h',
1581 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091582 ),
Daniel Cheng2248b332022-07-27 06:16:591583 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431584 r'base::Feature k',
1585 (
1586 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1587 'directly declaring/defining features.'
1588 ),
1589 True,
1590 [
Daniel Chengb000a8c2023-12-08 04:37:281591 # Implements BASE_DECLARE_FEATURE().
1592 r'^base/feature_list\.h',
Daniel Chengba3bc2e2022-10-03 02:45:431593 ],
1594 ),
Robert Ogden92101dcb2022-10-19 23:49:361595 BanRule(
Arthur Sonzogni1da65fa2023-03-27 16:01:521596 r'/\bchartorune\b',
Robert Ogden92101dcb2022-10-19 23:49:361597 (
1598 'chartorune is not memory-safe, unless you can guarantee the input ',
1599 'string is always null-terminated. Otherwise, please use charntorune ',
1600 'from libphonenumber instead.'
1601 ),
1602 True,
1603 [
1604 _THIRD_PARTY_EXCEPT_BLINK,
1605 # Exceptions to this rule should have a fuzzer.
1606 ],
1607 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521608 BanRule(
1609 r'/\b#include "base/atomicops\.h"\b',
1610 (
1611 'Do not use base::subtle atomics, but std::atomic, which are simpler '
1612 'to use, have better understood, clearer and richer semantics, and are '
1613 'harder to mis-use. See details in base/atomicops.h.',
1614 ),
1615 False,
1616 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571617 ),
Arthur Sonzogni60348572e2023-04-07 10:22:521618 BanRule(
1619 r'CrossThreadPersistent<',
1620 (
1621 'Do not use blink::CrossThreadPersistent, but '
1622 'blink::CrossThreadHandle. It is harder to mis-use.',
1623 'More info: '
1624 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1625 'Please contact platform-architecture-dev@ before adding new instances.'
1626 ),
1627 False,
1628 []
1629 ),
1630 BanRule(
1631 r'CrossThreadWeakPersistent<',
1632 (
1633 'Do not use blink::CrossThreadWeakPersistent, but '
1634 'blink::CrossThreadWeakHandle. It is harder to mis-use.',
1635 'More info: '
1636 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1637 'Please contact platform-architecture-dev@ before adding new instances.'
1638 ),
1639 False,
1640 []
1641 ),
Avi Drissman491617c2023-04-13 17:33:151642 BanRule(
1643 r'objc/objc.h',
1644 (
1645 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1646 'annotations, and is thus dangerous.',
1647 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1648 'For further reading on how to safely mix C++ and Obj-C, see',
1649 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
1650 ),
1651 True,
1652 []
1653 ),
Grace Park8d59b54b2023-04-26 17:53:351654 BanRule(
1655 r'/#include <filesystem>',
1656 (
1657 'libc++ <filesystem> is banned per the Google C++ styleguide.',
1658 ),
1659 True,
1660 # This fuzzing framework is a standalone open source project and
1661 # cannot rely on Chromium base.
1662 (r'third_party/centipede'),
1663 ),
Daniel Cheng72153e02023-05-18 21:18:141664 BanRule(
1665 r'TopDocument()',
1666 (
1667 'TopDocument() does not work correctly with out-of-process iframes. '
1668 'Please do not introduce new uses.',
1669 ),
1670 True,
1671 (
1672 # TODO(crbug.com/617677): Remove all remaining uses.
1673 r'^third_party/blink/renderer/core/dom/document\.cc',
1674 r'^third_party/blink/renderer/core/dom/document\.h',
1675 r'^third_party/blink/renderer/core/dom/element\.cc',
1676 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1677 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
Daniel Cheng72153e02023-05-18 21:18:141678 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1679 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1680 r'^third_party/blink/renderer/core/html/html_element\.cc',
1681 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1682 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1683 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1684 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1685 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1686 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1687 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1688 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1689 ),
1690 ),
Arthur Sonzognif0eea302023-08-18 19:20:311691 BanRule(
1692 pattern = r'base::raw_ptr<',
1693 explanation = (
1694 'Do not use base::raw_ptr, use raw_ptr.',
1695 ),
1696 treat_as_error = True,
1697 excluded_paths = (
1698 '^base/',
1699 '^tools/',
1700 ),
1701 ),
1702 BanRule(
1703 pattern = r'base:raw_ref<',
1704 explanation = (
1705 'Do not use base::raw_ref, use raw_ref.',
1706 ),
1707 treat_as_error = True,
1708 excluded_paths = (
1709 '^base/',
1710 '^tools/',
1711 ),
1712 ),
Anton Maliev66751812023-08-24 16:28:131713 BanRule(
Tom Sepez41eb158d2023-09-12 16:16:221714 pattern = r'/raw_ptr<[^;}]*\w{};',
1715 explanation = (
1716 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1717 ),
1718 treat_as_error = True,
1719 excluded_paths = (
1720 '^base/',
1721 '^tools/',
1722 ),
1723 ),
1724 BanRule(
Arthur Sonzogni48c6aea22023-09-04 22:25:201725 pattern = r'/#include "base/allocator/.*/raw_'
1726 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1727 explanation = (
1728 'Please include the corresponding facade headers:',
1729 '- #include "base/memory/raw_ptr.h"',
1730 '- #include "base/memory/raw_ptr_cast.h"',
1731 '- #include "base/memory/raw_ptr_exclusion.h"',
1732 '- #include "base/memory/raw_ref.h"',
1733 ),
1734 treat_as_error = True,
1735 excluded_paths = (
1736 '^base/',
1737 '^tools/',
1738 ),
1739 ),
1740 BanRule(
Anton Maliev66751812023-08-24 16:28:131741 pattern = r'ContentSettingsType::COOKIES',
1742 explanation = (
1743 'Do not use ContentSettingsType::COOKIES to check whether cookies are '
1744 'supported in the provided context. Instead rely on the '
1745 'content_settings::CookieSettings API. If you are using '
1746 'ContentSettingsType::COOKIES to check the user preference setting '
1747 'specifically, disregard this warning.',
1748 ),
1749 treat_as_error = False,
1750 excluded_paths = (
1751 '^chrome/browser/ui/content_settings/',
1752 '^components/content_settings/',
Christian Dullweber61416642023-10-05 11:46:431753 '^services/network/cookie_settings.cc',
1754 '.*test.cc',
Anton Maliev66751812023-08-24 16:28:131755 ),
1756 ),
Tom Andersoncd522072023-10-03 00:52:351757 BanRule(
1758 pattern = r'\bg_signal_connect',
1759 explanation = (
1760 'Use ScopedGSignal instead of g_signal_connect*()',
1761 ),
1762 treat_as_error = True,
1763 excluded_paths = (
1764 '^ui/base/glib/scoped_gsignal.h',
1765 ),
1766 ),
Christian Flach8da3bf82023-10-12 09:42:531767 BanRule(
1768 pattern = r'features::kIsolatedWebApps',
1769 explanation = (
1770 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1771 'Web App code. ',
1772 'Use `content::IsolatedWebAppsPolicy::AreIsolatedWebAppsEnabled()` in ',
1773 'the browser process or check the `kEnableIsolatedWebAppsInRenderer` ',
1774 'command line flag in the renderer process.',
1775 ),
1776 treat_as_error = True,
1777 excluded_paths = _TEST_CODE_EXCLUDED_PATHS + (
1778 '^chrome/browser/about_flags.cc',
1779 '^chrome/browser/chrome_content_browser_client.cc',
1780 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1781 '^content/shell/browser/shell_content_browser_client.cc'
1782 )
1783 ),
avi@chromium.org127f18ec2012-06-16 05:05:591784)
1785
Daniel Cheng92c15e32022-03-16 17:48:221786_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1787 BanRule(
1788 'handle<shared_buffer>',
1789 (
1790 'Please use one of the more specific shared memory types instead:',
1791 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1792 ' mojo_base.mojom.WritableSharedMemoryRegion',
1793 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1794 ),
1795 True,
1796 ),
1797)
1798
mlamouria82272622014-09-16 18:45:041799_IPC_ENUM_TRAITS_DEPRECATED = (
1800 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501801 'See http://www.chromium.org/Home/chromium-security/education/'
1802 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041803
Stephen Martinis97a394142018-06-07 23:06:051804_LONG_PATH_ERROR = (
1805 'Some files included in this CL have file names that are too long (> 200'
1806 ' characters). If committed, these files will cause issues on Windows. See'
1807 ' https://crbug.com/612667 for more details.'
1808)
1809
Shenghua Zhangbfaa38b82017-11-16 21:58:021810_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:311811 r".*/AppHooksImpl\.java",
1812 r".*/BuildHooksAndroidImpl\.java",
1813 r".*/LicenseContentProvider\.java",
1814 r".*/PlatformServiceBridgeImpl.java",
1815 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021816]
avi@chromium.org127f18ec2012-06-16 05:05:591817
Mohamed Heikald048240a2019-11-12 16:57:371818# List of image extensions that are used as resources in chromium.
1819_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1820
Sean Kau46e29bc2017-08-28 16:31:161821# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401822_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:311823 r'test/data/',
1824 r'testing/buildbot/',
1825 r'^components/policy/resources/policy_templates\.json$',
1826 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:031827 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:311828 r'^third_party/blink/renderer/devtools/protocol\.json$',
1829 r'^third_party/blink/web_tests/external/wpt/',
1830 r'^tools/perf/',
1831 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311832 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:311833 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:161834]
1835
Andrew Grieveb773bad2020-06-05 18:00:381836# These are not checked on the public chromium-presubmit trybot.
1837# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041838# checkouts.
agrievef32bcc72016-04-04 14:57:401839_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381840 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381841]
1842
1843
1844_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101845 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041846 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361847 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041848 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361849 'build/android/gyp/aar.pydeps',
1850 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271851 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361852 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381853 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:371854 'build/android/gyp/binary_baseline_profile.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361855 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021856 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221857 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111858 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:301859 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361860 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361861 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361862 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111863 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041864 'build/android/gyp/create_app_bundle_apks.pydeps',
1865 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361866 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121867 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091868 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221869 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401870 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001871 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361872 'build/android/gyp/dex.pydeps',
1873 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361874 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211875 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361876 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361877 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361878 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581879 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361880 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141881 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261882 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471883 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041884 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361885 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361886 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101887 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361888 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221889 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361890 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221891 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101892 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461893 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301894 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241895 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361896 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461897 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561898 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361899 'build/android/incremental_install/generate_android_manifest.pydeps',
1900 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321901 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041902 'build/android/resource_sizes.pydeps',
1903 'build/android/test_runner.pydeps',
1904 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361905 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361906 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321907 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271908 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1909 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041910 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:301911 'components/cronet/tools/check_combined_proguard_file.pydeps',
1912 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001913 'components/cronet/tools/generate_javadoc.pydeps',
1914 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381915 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001916 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381917 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181918 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411919 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1920 'testing/merge_scripts/standard_gtest_merge.pydeps',
1921 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1922 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041923 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421924 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251925 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421926 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131927 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:341928 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501929 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411930 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1931 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061932 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221933 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451934 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401935]
1936
wnwenbdc444e2016-05-25 13:44:151937
agrievef32bcc72016-04-04 14:57:401938_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1939
1940
Eric Boren6fd2b932018-01-25 15:05:081941# Bypass the AUTHORS check for these accounts.
1942_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591943 ) | set('%s@appspot.gserviceaccount.com' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451944 ) | set('%s@developer.gserviceaccount.com' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591945 ) | set('%s@chops-service-accounts.iam.gserviceaccount.com' % s
smutde797052019-12-04 02:03:521946 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231947 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471948 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461949 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:181950 'lacros-sdk-version-roller', 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:041951 'chromium-automated-expectation', 'chrome-branch-day',
1952 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:041953 ) | set('%s@skia-public.iam.gserviceaccount.com' % s
Eric Boren66150e52020-01-08 11:20:271954 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041955 ) | set('%s@skia-corp.google.com.iam.gserviceaccount.com' % s
Yulan Lineb0cfba2021-04-09 18:43:161956 for s in ('chromium-internal-autoroll',)
1957 ) | set('%s@owners-cleanup-prod.google.com.iam.gserviceaccount.com' % s
Chong Gub277e342022-10-15 03:30:551958 for s in ('swarming-tasks',)
1959 ) | set('%s@fuchsia-infra.iam.gserviceaccount.com' % s
1960 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:551961 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:541962 ) | set('%s@prod.google.com' % s
1963 for s in ('chops-security-borg',
1964 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:081965
Matt Stark6ef08872021-07-29 01:21:461966_INVALID_GRD_FILE_LINE = [
1967 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1968]
Eric Boren6fd2b932018-01-25 15:05:081969
Daniel Bratell65b033262019-04-23 08:17:061970def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501971 """Returns True if this file contains C++-like code (and not Python,
1972 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061973
Sam Maiera6e76d72022-02-11 21:43:501974 ext = input_api.os_path.splitext(file_path)[1]
1975 # This list is compatible with CppChecker.IsCppFile but we should
1976 # consider adding ".c" to it. If we do that we can use this function
1977 # at more places in the code.
1978 return ext in (
1979 '.h',
1980 '.cc',
1981 '.cpp',
1982 '.m',
1983 '.mm',
1984 )
1985
Daniel Bratell65b033262019-04-23 08:17:061986
1987def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501988 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061989
1990
1991def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501992 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061993
1994
1995def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501996 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061997
Mohamed Heikal5e5b7922020-10-29 18:57:591998
Erik Staabc734cd7a2021-11-23 03:11:521999def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502000 ext = input_api.os_path.splitext(file_path)[1]
2001 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522002
2003
Sven Zheng76a79ea2022-12-21 21:25:242004def _IsMojomFile(input_api, file_path):
2005 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2006
2007
Mohamed Heikal5e5b7922020-10-29 18:57:592008def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502009 """Prevent additions of dependencies from the upstream repo on //clank."""
2010 # clank can depend on clank
2011 if input_api.change.RepositoryRoot().endswith('clank'):
2012 return []
2013 build_file_patterns = [
2014 r'(.+/)?BUILD\.gn',
2015 r'.+\.gni',
2016 ]
2017 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2018 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592019
Sam Maiera6e76d72022-02-11 21:43:502020 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592021
Sam Maiera6e76d72022-02-11 21:43:502022 def FilterFile(affected_file):
2023 return input_api.FilterSourceFile(affected_file,
2024 files_to_check=build_file_patterns,
2025 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592026
Sam Maiera6e76d72022-02-11 21:43:502027 problems = []
2028 for f in input_api.AffectedSourceFiles(FilterFile):
2029 local_path = f.LocalPath()
2030 for line_number, line in f.ChangedContents():
2031 if (bad_pattern.search(line)):
2032 problems.append('%s:%d\n %s' %
2033 (local_path, line_number, line.strip()))
2034 if problems:
2035 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2036 else:
2037 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592038
2039
Saagar Sanghavifceeaae2020-08-12 16:40:362040def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502041 """Attempts to prevent use of functions intended only for testing in
2042 non-testing code. For now this is just a best-effort implementation
2043 that ignores header files and may have some false positives. A
2044 better implementation would probably need a proper C++ parser.
2045 """
2046 # We only scan .cc files and the like, as the declaration of
2047 # for-testing functions in header files are hard to distinguish from
2048 # calls to such functions without a proper C++ parser.
2049 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
joi@chromium.org55459852011-08-10 15:17:192050
Sam Maiera6e76d72022-02-11 21:43:502051 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2052 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2053 base_function_pattern)
2054 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2055 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2056 exclusion_pattern = input_api.re.compile(
2057 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2058 (base_function_pattern, base_function_pattern))
2059 # Avoid a false positive in this case, where the method name, the ::, and
2060 # the closing { are all on different lines due to line wrapping.
2061 # HelperClassForTesting::
2062 # HelperClassForTesting(
2063 # args)
2064 # : member(0) {}
2065 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
joi@chromium.org55459852011-08-10 15:17:192066
Sam Maiera6e76d72022-02-11 21:43:502067 def FilterFile(affected_file):
2068 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2069 input_api.DEFAULT_FILES_TO_SKIP)
2070 return input_api.FilterSourceFile(
2071 affected_file,
2072 files_to_check=file_inclusion_pattern,
2073 files_to_skip=files_to_skip)
joi@chromium.org55459852011-08-10 15:17:192074
Sam Maiera6e76d72022-02-11 21:43:502075 problems = []
2076 for f in input_api.AffectedSourceFiles(FilterFile):
2077 local_path = f.LocalPath()
2078 in_method_defn = False
2079 for line_number, line in f.ChangedContents():
2080 if (inclusion_pattern.search(line)
2081 and not comment_pattern.search(line)
2082 and not exclusion_pattern.search(line)
2083 and not allowlist_pattern.search(line)
2084 and not in_method_defn):
2085 problems.append('%s:%d\n %s' %
2086 (local_path, line_number, line.strip()))
2087 in_method_defn = method_defn_pattern.search(line)
joi@chromium.org55459852011-08-10 15:17:192088
Sam Maiera6e76d72022-02-11 21:43:502089 if problems:
2090 return [
2091 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2092 ]
2093 else:
2094 return []
joi@chromium.org55459852011-08-10 15:17:192095
2096
Saagar Sanghavifceeaae2020-08-12 16:40:362097def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502098 """This is a simplified version of
2099 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2100 """
2101 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2102 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2103 name_pattern = r'ForTest(s|ing)?'
2104 # Describes an occurrence of "ForTest*" inside a // comment.
2105 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2106 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2107 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2108 # Catch calls.
2109 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2110 # Ignore definitions. (Comments are ignored separately.)
2111 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512112 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232113
Sam Maiera6e76d72022-02-11 21:43:502114 problems = []
2115 sources = lambda x: input_api.FilterSourceFile(
2116 x,
2117 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2118 DEFAULT_FILES_TO_SKIP),
2119 files_to_check=[r'.*\.java$'])
2120 for f in input_api.AffectedFiles(include_deletes=False,
2121 file_filter=sources):
2122 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232123 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502124 for line_number, line in f.ChangedContents():
2125 if is_inside_javadoc and javadoc_end_re.search(line):
2126 is_inside_javadoc = False
2127 if not is_inside_javadoc and javadoc_start_re.search(line):
2128 is_inside_javadoc = True
2129 if is_inside_javadoc:
2130 continue
2131 if (inclusion_re.search(line) and not comment_re.search(line)
2132 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512133 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502134 and not exclusion_re.search(line)):
2135 problems.append('%s:%d\n %s' %
2136 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232137
Sam Maiera6e76d72022-02-11 21:43:502138 if problems:
2139 return [
2140 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2141 ]
2142 else:
2143 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232144
2145
Saagar Sanghavifceeaae2020-08-12 16:40:362146def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502147 """Checks to make sure no .h files include <iostream>."""
2148 files = []
2149 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2150 input_api.re.MULTILINE)
2151 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2152 if not f.LocalPath().endswith('.h'):
2153 continue
2154 contents = input_api.ReadFile(f)
2155 if pattern.search(contents):
2156 files.append(f)
thakis@chromium.org10689ca2011-09-02 02:31:542157
Sam Maiera6e76d72022-02-11 21:43:502158 if len(files):
2159 return [
2160 output_api.PresubmitError(
2161 'Do not #include <iostream> in header files, since it inserts static '
2162 'initialization into every file including the header. Instead, '
2163 '#include <ostream>. See http://crbug.com/94794', files)
2164 ]
2165 return []
2166
thakis@chromium.org10689ca2011-09-02 02:31:542167
Aleksey Khoroshilov9b28c032022-06-03 16:35:322168def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502169 """Checks no windows headers with StrCat redefined are included directly."""
2170 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322171 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2172 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2173 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2174 _NON_BASE_DEPENDENT_PATHS)
2175 sources_filter = lambda f: input_api.FilterSourceFile(
2176 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2177
Sam Maiera6e76d72022-02-11 21:43:502178 pattern_deny = input_api.re.compile(
2179 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2180 input_api.re.MULTILINE)
2181 pattern_allow = input_api.re.compile(
2182 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322183 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502184 contents = input_api.ReadFile(f)
2185 if pattern_deny.search(
2186 contents) and not pattern_allow.search(contents):
2187 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432188
Sam Maiera6e76d72022-02-11 21:43:502189 if len(files):
2190 return [
2191 output_api.PresubmitError(
2192 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2193 'directly since they pollute code with StrCat macro. Instead, '
2194 'include matching header from base/win. See http://crbug.com/856536',
2195 files)
2196 ]
2197 return []
Danil Chapovalov3518f362018-08-11 16:13:432198
thakis@chromium.org10689ca2011-09-02 02:31:542199
Andrew Williamsc9f69b482023-07-10 16:07:362200def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2201 problems = []
2202
2203 unit_test_macro = input_api.re.compile(
2204 '^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
2205 for line_num, line in f.ChangedContents():
2206 if unit_test_macro.match(line):
2207 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2208
2209 return problems
2210
2211
Saagar Sanghavifceeaae2020-08-12 16:40:362212def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502213 """Checks to make sure no source files use UNIT_TEST."""
2214 problems = []
2215 for f in input_api.AffectedFiles():
2216 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2217 continue
Andrew Williamsc9f69b482023-07-10 16:07:362218 problems.extend(
2219 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
jam@chromium.org72df4e782012-06-21 16:28:182220
Sam Maiera6e76d72022-02-11 21:43:502221 if not problems:
2222 return []
2223 return [
2224 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2225 '\n'.join(problems))
2226 ]
2227
jam@chromium.org72df4e782012-06-21 16:28:182228
Saagar Sanghavifceeaae2020-08-12 16:40:362229def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502230 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342231
Sam Maiera6e76d72022-02-11 21:43:502232 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2233 instead of DISABLED_. To filter false positives, reports are only generated
2234 if a corresponding MAYBE_ line exists.
2235 """
2236 problems = []
Dominic Battre033531052018-09-24 15:45:342237
Sam Maiera6e76d72022-02-11 21:43:502238 # The following two patterns are looked for in tandem - is a test labeled
2239 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2240 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2241 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342242
Sam Maiera6e76d72022-02-11 21:43:502243 # This is for the case that a test is disabled on all platforms.
2244 full_disable_pattern = input_api.re.compile(
2245 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2246 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342247
Sam Maiera6e76d72022-02-11 21:43:502248 for f in input_api.AffectedFiles(False):
2249 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2250 continue
Dominic Battre033531052018-09-24 15:45:342251
Sam Maiera6e76d72022-02-11 21:43:502252 # Search for MABYE_, DISABLE_ pairs.
2253 disable_lines = {} # Maps of test name to line number.
2254 maybe_lines = {}
2255 for line_num, line in f.ChangedContents():
2256 disable_match = disable_pattern.search(line)
2257 if disable_match:
2258 disable_lines[disable_match.group(1)] = line_num
2259 maybe_match = maybe_pattern.search(line)
2260 if maybe_match:
2261 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342262
Sam Maiera6e76d72022-02-11 21:43:502263 # Search for DISABLE_ occurrences within a TEST() macro.
2264 disable_tests = set(disable_lines.keys())
2265 maybe_tests = set(maybe_lines.keys())
2266 for test in disable_tests.intersection(maybe_tests):
2267 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342268
Sam Maiera6e76d72022-02-11 21:43:502269 contents = input_api.ReadFile(f)
2270 full_disable_match = full_disable_pattern.search(contents)
2271 if full_disable_match:
2272 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342273
Sam Maiera6e76d72022-02-11 21:43:502274 if not problems:
2275 return []
2276 return [
2277 output_api.PresubmitPromptWarning(
2278 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2279 '\n'.join(problems))
2280 ]
2281
Dominic Battre033531052018-09-24 15:45:342282
Nina Satragnof7660532021-09-20 18:03:352283def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502284 """Checks to make sure tests disabled conditionally are not missing a
2285 corresponding MAYBE_ prefix.
2286 """
2287 # Expect at least a lowercase character in the test name. This helps rule out
2288 # false positives with macros wrapping the actual tests name.
2289 define_maybe_pattern = input_api.re.compile(
2290 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192291 # The test_maybe_pattern needs to handle all of these forms. The standard:
2292 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2293 # With a wrapper macro around the test name:
2294 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2295 # And the odd-ball NACL_BROWSER_TEST_f format:
2296 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2297 # The optional E2E_ENABLED-style is handled with (\w*\()?
2298 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2299 # trailing ')'.
2300 test_maybe_pattern = (
2301 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502302 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2303 warnings = []
Nina Satragnof7660532021-09-20 18:03:352304
Sam Maiera6e76d72022-02-11 21:43:502305 # Read the entire files. We can't just read the affected lines, forgetting to
2306 # add MAYBE_ on a change would not show up otherwise.
2307 for f in input_api.AffectedFiles(False):
2308 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2309 continue
2310 contents = input_api.ReadFile(f)
2311 lines = contents.splitlines(True)
2312 current_position = 0
2313 warning_test_names = set()
2314 for line_num, line in enumerate(lines, start=1):
2315 current_position += len(line)
2316 maybe_match = define_maybe_pattern.search(line)
2317 if maybe_match:
2318 test_name = maybe_match.group('test_name')
2319 # Do not warn twice for the same test.
2320 if (test_name in warning_test_names):
2321 continue
2322 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352323
Sam Maiera6e76d72022-02-11 21:43:502324 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2325 # the current position.
2326 test_match = input_api.re.compile(
2327 test_maybe_pattern.format(test_name=test_name),
2328 input_api.re.MULTILINE).search(contents, current_position)
2329 suite_match = input_api.re.compile(
2330 suite_maybe_pattern.format(test_name=test_name),
2331 input_api.re.MULTILINE).search(contents, current_position)
2332 if not test_match and not suite_match:
2333 warnings.append(
2334 output_api.PresubmitPromptWarning(
2335 '%s:%d found MAYBE_ defined without corresponding test %s'
2336 % (f.LocalPath(), line_num, test_name)))
2337 return warnings
2338
jam@chromium.org72df4e782012-06-21 16:28:182339
Saagar Sanghavifceeaae2020-08-12 16:40:362340def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502341 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2342 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162343 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502344 input_api.re.MULTILINE)
2345 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2346 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2347 continue
2348 for lnum, line in f.ChangedContents():
2349 if input_api.re.search(pattern, line):
2350 errors.append(
2351 output_api.PresubmitError((
2352 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2353 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2354 (f.LocalPath(), lnum)))
2355 return errors
danakj61c1aa22015-10-26 19:55:522356
2357
Weilun Shia487fad2020-10-28 00:10:342358# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2359# more reliable way. See
2360# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192361
wnwenbdc444e2016-05-25 13:44:152362
Saagar Sanghavifceeaae2020-08-12 16:40:362363def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502364 """Check that FlakyTest annotation is our own instead of the android one"""
2365 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2366 files = []
2367 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2368 if f.LocalPath().endswith('Test.java'):
2369 if pattern.search(input_api.ReadFile(f)):
2370 files.append(f)
2371 if len(files):
2372 return [
2373 output_api.PresubmitError(
2374 'Use org.chromium.base.test.util.FlakyTest instead of '
2375 'android.test.FlakyTest', files)
2376 ]
2377 return []
mcasasb7440c282015-02-04 14:52:192378
wnwenbdc444e2016-05-25 13:44:152379
Saagar Sanghavifceeaae2020-08-12 16:40:362380def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502381 """Make sure .DEPS.git is never modified manually."""
2382 if any(f.LocalPath().endswith('.DEPS.git')
2383 for f in input_api.AffectedFiles()):
2384 return [
2385 output_api.PresubmitError(
2386 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2387 'automated system based on what\'s in DEPS and your changes will be\n'
2388 'overwritten.\n'
2389 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2390 'get-the-code#Rolling_DEPS\n'
2391 'for more information')
2392 ]
2393 return []
maruel@chromium.org2a8ac9c2011-10-19 17:20:442394
2395
Sven Zheng76a79ea2022-12-21 21:25:242396def CheckCrosApiNeedBrowserTest(input_api, output_api):
2397 """Check new crosapi should add browser test."""
2398 has_new_crosapi = False
2399 has_browser_test = False
2400 for f in input_api.AffectedFiles():
2401 path = f.LocalPath()
2402 if (path.startswith('chromeos/crosapi/mojom') and
2403 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2404 has_new_crosapi = True
2405 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2406 has_browser_test = True
2407 if has_new_crosapi and not has_browser_test:
2408 return [
2409 output_api.PresubmitPromptWarning(
2410 'You are adding a new crosapi, but there is no file ends with '
2411 'browsertest.cc file being added or modified. It is important '
2412 'to add crosapi browser test coverage to avoid version '
2413 ' skew issues.\n'
2414 'Check //docs/lacros/test_instructions.md for more information.'
2415 )
2416 ]
2417 return []
2418
2419
Saagar Sanghavifceeaae2020-08-12 16:40:362420def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502421 """Checks that DEPS file deps are from allowed_hosts."""
2422 # Run only if DEPS file has been modified to annoy fewer bystanders.
2423 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2424 return []
2425 # Outsource work to gclient verify
2426 try:
2427 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2428 'third_party', 'depot_tools',
2429 'gclient.py')
2430 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322431 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502432 stderr=input_api.subprocess.STDOUT)
2433 return []
2434 except input_api.subprocess.CalledProcessError as error:
2435 return [
2436 output_api.PresubmitError(
2437 'DEPS file must have only git dependencies.',
2438 long_text=error.output)
2439 ]
tandriief664692014-09-23 14:51:472440
2441
Mario Sanchez Prada2472cab2019-09-18 10:58:312442def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152443 ban_rule):
Allen Bauer84778682022-09-22 16:28:562444 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312445
Sam Maiera6e76d72022-02-11 21:43:502446 Returns an string composed of the name of the file, the line number where the
2447 match has been found and the additional text passed as |message| in case the
2448 target type name matches the text inside the line passed as parameter.
2449 """
2450 result = []
Peng Huang9c5949a02020-06-11 19:20:542451
Daniel Chenga44a1bcd2022-03-15 20:00:152452 # Ignore comments about banned types.
2453 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502454 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152455 # A // nocheck comment will bypass this error.
2456 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502457 return result
2458
2459 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152460 if ban_rule.pattern[0:1] == '/':
2461 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502462 if input_api.re.search(regex, line):
2463 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152464 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502465 matched = True
2466
2467 if matched:
2468 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152469 for line in ban_rule.explanation:
2470 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502471
danakjd18e8892020-12-17 17:42:012472 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312473
2474
Saagar Sanghavifceeaae2020-08-12 16:40:362475def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502476 """Make sure that banned functions are not used."""
2477 warnings = []
2478 errors = []
avi@chromium.org127f18ec2012-06-16 05:05:592479
Sam Maiera6e76d72022-02-11 21:43:502480 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152481 if not excluded_paths:
2482 return False
2483
Sam Maiera6e76d72022-02-11 21:43:502484 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312485 # Consistently use / as path separator to simplify the writing of regex
2486 # expressions.
2487 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502488 for item in excluded_paths:
2489 if input_api.re.match(item, local_path):
2490 return True
2491 return False
wnwenbdc444e2016-05-25 13:44:152492
Sam Maiera6e76d72022-02-11 21:43:502493 def IsIosObjcFile(affected_file):
2494 local_path = affected_file.LocalPath()
2495 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2496 '.h'):
2497 return False
2498 basename = input_api.os_path.basename(local_path)
2499 if 'ios' in basename.split('_'):
2500 return True
2501 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2502 if sep and 'ios' in local_path.split(sep):
2503 return True
2504 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542505
Daniel Chenga44a1bcd2022-03-15 20:00:152506 def CheckForMatch(affected_file, line_num: int, line: str,
2507 ban_rule: BanRule):
2508 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2509 return
2510
Sam Maiera6e76d72022-02-11 21:43:502511 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152512 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502513 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152514 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502515 errors.extend(problems)
2516 else:
2517 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152518
Sam Maiera6e76d72022-02-11 21:43:502519 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2520 for f in input_api.AffectedFiles(file_filter=file_filter):
2521 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152522 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2523 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412524
Clement Yan9b330cb2022-11-17 05:25:292525 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2526 for f in input_api.AffectedFiles(file_filter=file_filter):
2527 for line_num, line in f.ChangedContents():
2528 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2529 CheckForMatch(f, line_num, line, ban_rule)
2530
Sam Maiera6e76d72022-02-11 21:43:502531 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2532 for f in input_api.AffectedFiles(file_filter=file_filter):
2533 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152534 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2535 CheckForMatch(f, line_num, line, ban_rule)
avi@chromium.org127f18ec2012-06-16 05:05:592536
Sam Maiera6e76d72022-02-11 21:43:502537 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2538 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152539 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2540 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542541
Sam Maiera6e76d72022-02-11 21:43:502542 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2543 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2544 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152545 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2546 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052547
Sam Maiera6e76d72022-02-11 21:43:502548 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2549 for f in input_api.AffectedFiles(file_filter=file_filter):
2550 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152551 for ban_rule in _BANNED_CPP_FUNCTIONS:
2552 CheckForMatch(f, line_num, line, ban_rule)
avi@chromium.org127f18ec2012-06-16 05:05:592553
Daniel Cheng92c15e32022-03-16 17:48:222554 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2555 for f in input_api.AffectedFiles(file_filter=file_filter):
2556 for line_num, line in f.ChangedContents():
2557 for ban_rule in _BANNED_MOJOM_PATTERNS:
2558 CheckForMatch(f, line_num, line, ban_rule)
2559
2560
Sam Maiera6e76d72022-02-11 21:43:502561 result = []
2562 if (warnings):
2563 result.append(
2564 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2565 '\n'.join(warnings)))
2566 if (errors):
2567 result.append(
2568 output_api.PresubmitError('Banned functions were used.\n' +
2569 '\n'.join(errors)))
2570 return result
avi@chromium.org127f18ec2012-06-16 05:05:592571
Allen Bauer84778682022-09-22 16:28:562572def CheckNoLayoutCallsInTests(input_api, output_api):
2573 """Make sure there are no explicit calls to View::Layout() in tests"""
2574 warnings = []
2575 ban_rule = BanRule(
2576 r'/(\.|->)Layout\(\);',
2577 (
2578 'Direct calls to View::Layout() are not allowed in tests. '
2579 'If the view must be laid out here, use RunScheduledLayout(view). It '
2580 'is found in //ui/views/test/views_test_utils.h. '
2581 'See http://crbug.com/1350521 for more details.',
2582 ),
2583 False,
2584 )
2585 file_filter = lambda f: input_api.re.search(
2586 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2587 for f in input_api.AffectedFiles(file_filter = file_filter):
2588 for line_num, line in f.ChangedContents():
2589 problems = _GetMessageForMatchingType(input_api, f,
2590 line_num, line,
2591 ban_rule)
2592 if problems:
2593 warnings.extend(problems)
2594 result = []
2595 if (warnings):
2596 result.append(
2597 output_api.PresubmitPromptWarning(
2598 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2599 return result
avi@chromium.org127f18ec2012-06-16 05:05:592600
Michael Thiessen44457642020-02-06 00:24:152601def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502602 """Make sure that banned java imports are not used."""
2603 errors = []
Michael Thiessen44457642020-02-06 00:24:152604
Sam Maiera6e76d72022-02-11 21:43:502605 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2606 for f in input_api.AffectedFiles(file_filter=file_filter):
2607 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152608 for ban_rule in _BANNED_JAVA_IMPORTS:
2609 # Consider merging this into the above function. There is no
2610 # real difference anymore other than helping with a little
2611 # bit of boilerplate text. Doing so means things like
2612 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502613 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152614 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502615 if problems:
2616 errors.extend(problems)
2617 result = []
2618 if (errors):
2619 result.append(
2620 output_api.PresubmitError('Banned imports were used.\n' +
2621 '\n'.join(errors)))
2622 return result
Michael Thiessen44457642020-02-06 00:24:152623
2624
Saagar Sanghavifceeaae2020-08-12 16:40:362625def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502626 """Make sure that banned functions are not used."""
2627 files = []
2628 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2629 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2630 if not f.LocalPath().endswith('.h'):
2631 continue
Bruce Dawson4c4c2922022-05-02 18:07:332632 if f.LocalPath().endswith('com_imported_mstscax.h'):
2633 continue
Sam Maiera6e76d72022-02-11 21:43:502634 contents = input_api.ReadFile(f)
2635 if pattern.search(contents):
2636 files.append(f)
dcheng@chromium.org6c063c62012-07-11 19:11:062637
Sam Maiera6e76d72022-02-11 21:43:502638 if files:
2639 return [
2640 output_api.PresubmitError(
2641 'Do not use #pragma once in header files.\n'
2642 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2643 files)
2644 ]
2645 return []
dcheng@chromium.org6c063c62012-07-11 19:11:062646
avi@chromium.org127f18ec2012-06-16 05:05:592647
Saagar Sanghavifceeaae2020-08-12 16:40:362648def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502649 """Checks to make sure we don't introduce use of foo ? true : false."""
2650 problems = []
2651 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2652 for f in input_api.AffectedFiles():
2653 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2654 continue
thestig@chromium.orge7479052012-09-19 00:26:122655
Sam Maiera6e76d72022-02-11 21:43:502656 for line_num, line in f.ChangedContents():
2657 if pattern.match(line):
2658 problems.append(' %s:%d' % (f.LocalPath(), line_num))
thestig@chromium.orge7479052012-09-19 00:26:122659
Sam Maiera6e76d72022-02-11 21:43:502660 if not problems:
2661 return []
2662 return [
2663 output_api.PresubmitPromptWarning(
2664 'Please consider avoiding the "? true : false" pattern if possible.\n'
2665 + '\n'.join(problems))
2666 ]
thestig@chromium.orge7479052012-09-19 00:26:122667
2668
Saagar Sanghavifceeaae2020-08-12 16:40:362669def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502670 """Runs checkdeps on #include and import statements added in this
2671 change. Breaking - rules is an error, breaking ! rules is a
2672 warning.
2673 """
2674 # Return early if no relevant file types were modified.
2675 for f in input_api.AffectedFiles():
2676 path = f.LocalPath()
2677 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2678 or _IsJavaFile(input_api, path)):
2679 break
joi@chromium.org55f9f382012-07-31 11:02:182680 else:
Sam Maiera6e76d72022-02-11 21:43:502681 return []
rhalavati08acd232017-04-03 07:23:282682
Sam Maiera6e76d72022-02-11 21:43:502683 import sys
2684 # We need to wait until we have an input_api object and use this
2685 # roundabout construct to import checkdeps because this file is
2686 # eval-ed and thus doesn't have __file__.
2687 original_sys_path = sys.path
2688 try:
2689 sys.path = sys.path + [
2690 input_api.os_path.join(input_api.PresubmitLocalPath(),
2691 'buildtools', 'checkdeps')
2692 ]
2693 import checkdeps
2694 from rules import Rule
2695 finally:
2696 # Restore sys.path to what it was before.
2697 sys.path = original_sys_path
joi@chromium.org55f9f382012-07-31 11:02:182698
Sam Maiera6e76d72022-02-11 21:43:502699 added_includes = []
2700 added_imports = []
2701 added_java_imports = []
2702 for f in input_api.AffectedFiles():
2703 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2704 changed_lines = [line for _, line in f.ChangedContents()]
2705 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2706 elif _IsProtoFile(input_api, f.LocalPath()):
2707 changed_lines = [line for _, line in f.ChangedContents()]
2708 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2709 elif _IsJavaFile(input_api, f.LocalPath()):
2710 changed_lines = [line for _, line in f.ChangedContents()]
2711 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242712
Sam Maiera6e76d72022-02-11 21:43:502713 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2714
2715 error_descriptions = []
2716 warning_descriptions = []
2717 error_subjects = set()
2718 warning_subjects = set()
2719
2720 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2721 added_includes):
2722 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2723 description_with_path = '%s\n %s' % (path, rule_description)
2724 if rule_type == Rule.DISALLOW:
2725 error_descriptions.append(description_with_path)
2726 error_subjects.add("#includes")
2727 else:
2728 warning_descriptions.append(description_with_path)
2729 warning_subjects.add("#includes")
2730
2731 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2732 added_imports):
2733 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2734 description_with_path = '%s\n %s' % (path, rule_description)
2735 if rule_type == Rule.DISALLOW:
2736 error_descriptions.append(description_with_path)
2737 error_subjects.add("imports")
2738 else:
2739 warning_descriptions.append(description_with_path)
2740 warning_subjects.add("imports")
2741
2742 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2743 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2744 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2745 description_with_path = '%s\n %s' % (path, rule_description)
2746 if rule_type == Rule.DISALLOW:
2747 error_descriptions.append(description_with_path)
2748 error_subjects.add("imports")
2749 else:
2750 warning_descriptions.append(description_with_path)
2751 warning_subjects.add("imports")
2752
2753 results = []
2754 if error_descriptions:
2755 results.append(
2756 output_api.PresubmitError(
2757 'You added one or more %s that violate checkdeps rules.' %
2758 " and ".join(error_subjects), error_descriptions))
2759 if warning_descriptions:
2760 results.append(
2761 output_api.PresubmitPromptOrNotify(
2762 'You added one or more %s of files that are temporarily\n'
2763 'allowed but being removed. Can you avoid introducing the\n'
2764 '%s? See relevant DEPS file(s) for details and contacts.' %
2765 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2766 warning_descriptions))
2767 return results
joi@chromium.org55f9f382012-07-31 11:02:182768
2769
Saagar Sanghavifceeaae2020-08-12 16:40:362770def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502771 """Check that all files have their permissions properly set."""
2772 if input_api.platform == 'win32':
2773 return []
2774 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2775 'tools', 'checkperms',
2776 'checkperms.py')
2777 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322778 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502779 input_api.change.RepositoryRoot()
2780 ]
2781 with input_api.CreateTemporaryFile() as file_list:
2782 for f in input_api.AffectedFiles():
2783 # checkperms.py file/directory arguments must be relative to the
2784 # repository.
2785 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2786 file_list.close()
2787 args += ['--file-list', file_list.name]
2788 try:
2789 input_api.subprocess.check_output(args)
2790 return []
2791 except input_api.subprocess.CalledProcessError as error:
2792 return [
2793 output_api.PresubmitError('checkperms.py failed:',
2794 long_text=error.output.decode(
2795 'utf-8', 'ignore'))
2796 ]
csharp@chromium.orgfbcafe5a2012-08-08 15:31:222797
2798
Saagar Sanghavifceeaae2020-08-12 16:40:362799def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502800 """Makes sure we don't include ui/aura/window_property.h
2801 in header files.
2802 """
2803 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2804 errors = []
2805 for f in input_api.AffectedFiles():
2806 if not f.LocalPath().endswith('.h'):
2807 continue
2808 for line_num, line in f.ChangedContents():
2809 if pattern.match(line):
2810 errors.append(' %s:%d' % (f.LocalPath(), line_num))
oshima@chromium.orgc8278b32012-10-30 20:35:492811
Sam Maiera6e76d72022-02-11 21:43:502812 results = []
2813 if errors:
2814 results.append(
2815 output_api.PresubmitError(
2816 'Header files should not include ui/aura/window_property.h',
2817 errors))
2818 return results
oshima@chromium.orgc8278b32012-10-30 20:35:492819
2820
Omer Katzcc77ea92021-04-26 10:23:282821def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502822 """Makes sure we don't include any headers from
2823 third_party/blink/renderer/platform/heap/impl or
2824 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2825 third_party/blink/renderer/platform/heap
2826 """
2827 impl_pattern = input_api.re.compile(
2828 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2829 v8_wrapper_pattern = input_api.re.compile(
2830 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2831 )
Bruce Dawson40fece62022-09-16 19:58:312832 # Consistently use / as path separator to simplify the writing of regex
2833 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502834 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312835 r"^third_party/blink/renderer/platform/heap/.*",
2836 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502837 errors = []
Omer Katzcc77ea92021-04-26 10:23:282838
Sam Maiera6e76d72022-02-11 21:43:502839 for f in input_api.AffectedFiles(file_filter=file_filter):
2840 for line_num, line in f.ChangedContents():
2841 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2842 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282843
Sam Maiera6e76d72022-02-11 21:43:502844 results = []
2845 if errors:
2846 results.append(
2847 output_api.PresubmitError(
2848 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2849 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2850 'relevant counterparts from third_party/blink/renderer/platform/heap',
2851 errors))
2852 return results
Omer Katzcc77ea92021-04-26 10:23:282853
2854
dbeam@chromium.org70ca77752012-11-20 03:45:032855def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502856 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2857 errors = []
2858 for line_num, line in f.ChangedContents():
2859 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2860 # First-level headers in markdown look a lot like version control
2861 # conflict markers. http://daringfireball.net/projects/markdown/basics
2862 continue
2863 if pattern.match(line):
2864 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2865 return errors
dbeam@chromium.org70ca77752012-11-20 03:45:032866
2867
Saagar Sanghavifceeaae2020-08-12 16:40:362868def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502869 """Usually this is not intentional and will cause a compile failure."""
2870 errors = []
2871 for f in input_api.AffectedFiles():
2872 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
dbeam@chromium.org70ca77752012-11-20 03:45:032873
Sam Maiera6e76d72022-02-11 21:43:502874 results = []
2875 if errors:
2876 results.append(
2877 output_api.PresubmitError(
2878 'Version control conflict markers found, please resolve.',
2879 errors))
2880 return results
dbeam@chromium.org70ca77752012-11-20 03:45:032881
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202882
Saagar Sanghavifceeaae2020-08-12 16:40:362883def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502884 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2885 errors = []
2886 for f in input_api.AffectedFiles():
2887 for line_num, line in f.ChangedContents():
2888 if pattern.search(line):
2889 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162890
Sam Maiera6e76d72022-02-11 21:43:502891 results = []
2892 if errors:
2893 results.append(
2894 output_api.PresubmitPromptWarning(
2895 'Found Google support URL addressed by answer number. Please replace '
2896 'with a p= identifier instead. See crbug.com/679462\n',
2897 errors))
2898 return results
estadee17314a02017-01-12 16:22:162899
dbeam@chromium.org70ca77752012-11-20 03:45:032900
Saagar Sanghavifceeaae2020-08-12 16:40:362901def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502902 def FilterFile(affected_file):
2903 """Filter function for use with input_api.AffectedSourceFiles,
2904 below. This filters out everything except non-test files from
2905 top-level directories that generally speaking should not hard-code
2906 service URLs (e.g. src/android_webview/, src/content/ and others).
2907 """
2908 return input_api.FilterSourceFile(
2909 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312910 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502911 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2912 input_api.DEFAULT_FILES_TO_SKIP))
joi@chromium.org06e6d0ff2012-12-11 01:36:442913
Sam Maiera6e76d72022-02-11 21:43:502914 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2915 '\.(com|net)[^"]*"')
2916 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2917 pattern = input_api.re.compile(base_pattern)
2918 problems = [] # items are (filename, line_number, line)
2919 for f in input_api.AffectedSourceFiles(FilterFile):
2920 for line_num, line in f.ChangedContents():
2921 if not comment_pattern.search(line) and pattern.search(line):
2922 problems.append((f.LocalPath(), line_num, line))
joi@chromium.org06e6d0ff2012-12-11 01:36:442923
Sam Maiera6e76d72022-02-11 21:43:502924 if problems:
2925 return [
2926 output_api.PresubmitPromptOrNotify(
2927 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2928 'Are you sure this is correct?', [
2929 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2930 for problem in problems
2931 ])
2932 ]
2933 else:
2934 return []
joi@chromium.org06e6d0ff2012-12-11 01:36:442935
2936
Saagar Sanghavifceeaae2020-08-12 16:40:362937def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502938 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292939
Sam Maiera6e76d72022-02-11 21:43:502940 def FileFilter(affected_file):
2941 """Includes directories known to be Chrome OS only."""
2942 return input_api.FilterSourceFile(
2943 affected_file,
2944 files_to_check=(
2945 '^ash/',
2946 '^chromeos/', # Top-level src/chromeos.
2947 '.*/chromeos/', # Any path component.
2948 '^components/arc',
2949 '^components/exo'),
2950 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292951
Sam Maiera6e76d72022-02-11 21:43:502952 prefs = []
2953 priority_prefs = []
2954 for f in input_api.AffectedFiles(file_filter=FileFilter):
2955 for line_num, line in f.ChangedContents():
2956 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2957 line):
2958 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2959 prefs.append(' %s' % line)
2960 if input_api.re.search(
2961 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2962 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2963 priority_prefs.append(' %s' % line)
2964
2965 results = []
2966 if (prefs):
2967 results.append(
2968 output_api.PresubmitPromptWarning(
2969 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2970 'by browser sync settings. If these prefs should be controlled by OS '
2971 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2972 '\n'.join(prefs)))
2973 if (priority_prefs):
2974 results.append(
2975 output_api.PresubmitPromptWarning(
2976 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2977 'controlled by browser sync settings. If these prefs should be '
2978 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2979 'instead.\n' + '\n'.join(prefs)))
2980 return results
James Cook6b6597c2019-11-06 22:05:292981
2982
Saagar Sanghavifceeaae2020-08-12 16:40:362983def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502984 """Makes sure there are no abbreviations in the name of PNG files.
2985 The native_client_sdk directory is excluded because it has auto-generated PNG
2986 files for documentation.
2987 """
2988 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:172989 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:312990 files_to_skip = [r'^native_client_sdk/',
2991 r'^services/test/',
2992 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182993 ]
Sam Maiera6e76d72022-02-11 21:43:502994 file_filter = lambda f: input_api.FilterSourceFile(
2995 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:172996 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:502997 for f in input_api.AffectedFiles(include_deletes=False,
2998 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:172999 file_name = input_api.os_path.split(f.LocalPath())[1]
3000 if abbreviation.search(file_name):
3001 errors.append(' %s' % f.LocalPath())
oshima@chromium.orgd2530012013-01-25 16:39:273002
Sam Maiera6e76d72022-02-11 21:43:503003 results = []
3004 if errors:
3005 results.append(
3006 output_api.PresubmitError(
3007 'The name of PNG files should not have abbreviations. \n'
3008 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3009 'Contact oshima@chromium.org if you have questions.', errors))
3010 return results
oshima@chromium.orgd2530012013-01-25 16:39:273011
Evan Stade7cd4a2c2022-08-04 23:37:253012def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3013 """Heuristically identifies product icons based on their file name and reminds
3014 contributors not to add them to the Chromium repository.
3015 """
3016 errors = []
3017 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3018 file_filter = lambda f: input_api.FilterSourceFile(
3019 f, files_to_check=files_to_check)
3020 for f in input_api.AffectedFiles(include_deletes=False,
3021 file_filter=file_filter):
3022 errors.append(' %s' % f.LocalPath())
3023
3024 results = []
3025 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083026 # Give warnings instead of errors on presubmit --all and presubmit
3027 # --files.
3028 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
3029 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253030 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083031 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253032 'Trademarked images should not be added to the public repo. '
3033 'See crbug.com/944754', errors))
3034 return results
3035
oshima@chromium.orgd2530012013-01-25 16:39:273036
Daniel Cheng4dcdb6b2017-04-13 08:30:173037def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503038 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173039
Sam Maiera6e76d72022-02-11 21:43:503040 Args:
3041 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3042 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173043 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503044 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173045 if rule.startswith('+') or rule.startswith('!')
3046 ])
Sam Maiera6e76d72022-02-11 21:43:503047 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3048 add_rules.update([
3049 rule[1:] for rule in rules
3050 if rule.startswith('+') or rule.startswith('!')
3051 ])
3052 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173053
3054
3055def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503056 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173057
Sam Maiera6e76d72022-02-11 21:43:503058 # Stubs for handling special syntax in the root DEPS file.
3059 class _VarImpl:
3060 def __init__(self, local_scope):
3061 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173062
Sam Maiera6e76d72022-02-11 21:43:503063 def Lookup(self, var_name):
3064 """Implements the Var syntax."""
3065 try:
3066 return self._local_scope['vars'][var_name]
3067 except KeyError:
3068 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173069
Sam Maiera6e76d72022-02-11 21:43:503070 local_scope = {}
3071 global_scope = {
3072 'Var': _VarImpl(local_scope).Lookup,
3073 'Str': str,
3074 }
Dirk Pranke1b9e06382021-05-14 01:16:223075
Sam Maiera6e76d72022-02-11 21:43:503076 exec(contents, global_scope, local_scope)
3077 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173078
3079
3080def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503081 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3082 a set of DEPS entries that we should look up.
joi@chromium.org14a6131c2014-01-08 01:15:413083
Sam Maiera6e76d72022-02-11 21:43:503084 For a directory (rather than a specific filename) we fake a path to
3085 a specific filename by adding /DEPS. This is chosen as a file that
3086 will seldom or never be subject to per-file include_rules.
3087 """
3088 # We ignore deps entries on auto-generated directories.
3089 AUTO_GENERATED_DIRS = ['grit', 'jni']
tony@chromium.orgf32e2d1e2013-07-26 21:39:083090
Sam Maiera6e76d72022-02-11 21:43:503091 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3092 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173093
Sam Maiera6e76d72022-02-11 21:43:503094 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173095
Sam Maiera6e76d72022-02-11 21:43:503096 results = set()
3097 for added_dep in added_deps:
3098 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3099 continue
3100 # Assume that a rule that ends in .h is a rule for a specific file.
3101 if added_dep.endswith('.h'):
3102 results.add(added_dep)
3103 else:
3104 results.add(os_path.join(added_dep, 'DEPS'))
3105 return results
tony@chromium.orgf32e2d1e2013-07-26 21:39:083106
3107
Saagar Sanghavifceeaae2020-08-12 16:40:363108def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503109 """When a dependency prefixed with + is added to a DEPS file, we
3110 want to make sure that the change is reviewed by an OWNER of the
3111 target file or directory, to avoid layering violations from being
3112 introduced. This check verifies that this happens.
3113 """
3114 # We rely on Gerrit's code-owners to check approvals.
3115 # input_api.gerrit is always set for Chromium, but other projects
3116 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103117 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503118 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303119 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503120 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303121 try:
3122 if (input_api.change.issue and
3123 input_api.gerrit.IsOwnersOverrideApproved(
3124 input_api.change.issue)):
3125 # Skip OWNERS check when Owners-Override label is approved. This is
3126 # intended for global owners, trusted bots, and on-call sheriffs.
3127 # Review is still required for these changes.
3128 return []
3129 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243130 return [output_api.PresubmitPromptWarning(
3131 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233132
Sam Maiera6e76d72022-02-11 21:43:503133 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:243134
Bruce Dawson40fece62022-09-16 19:58:313135 # Consistently use / as path separator to simplify the writing of regex
3136 # expressions.
Sam Maiera6e76d72022-02-11 21:43:503137 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313138 r"^third_party/blink/.*",
3139 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:503140 for f in input_api.AffectedFiles(include_deletes=False,
3141 file_filter=file_filter):
3142 filename = input_api.os_path.basename(f.LocalPath())
3143 if filename == 'DEPS':
3144 virtual_depended_on_files.update(
3145 _CalculateAddedDeps(input_api.os_path,
3146 '\n'.join(f.OldContents()),
3147 '\n'.join(f.NewContents())))
joi@chromium.orge871964c2013-05-13 14:14:553148
Sam Maiera6e76d72022-02-11 21:43:503149 if not virtual_depended_on_files:
3150 return []
joi@chromium.orge871964c2013-05-13 14:14:553151
Sam Maiera6e76d72022-02-11 21:43:503152 if input_api.is_committing:
3153 if input_api.tbr:
3154 return [
3155 output_api.PresubmitNotifyResult(
3156 '--tbr was specified, skipping OWNERS check for DEPS additions'
3157 )
3158 ]
Daniel Cheng3008dc12022-05-13 04:02:113159 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3160 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503161 if input_api.dry_run:
3162 return [
3163 output_api.PresubmitNotifyResult(
3164 'This is a dry run, skipping OWNERS check for DEPS additions'
3165 )
3166 ]
3167 if not input_api.change.issue:
3168 return [
3169 output_api.PresubmitError(
3170 "DEPS approval by OWNERS check failed: this change has "
3171 "no change number, so we can't check it for approvals.")
3172 ]
3173 output = output_api.PresubmitError
joi@chromium.org14a6131c2014-01-08 01:15:413174 else:
Sam Maiera6e76d72022-02-11 21:43:503175 output = output_api.PresubmitNotifyResult
joi@chromium.orge871964c2013-05-13 14:14:553176
Sam Maiera6e76d72022-02-11 21:43:503177 owner_email, reviewers = (
3178 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3179 input_api, None, approval_needed=input_api.is_committing))
joi@chromium.orge871964c2013-05-13 14:14:553180
Sam Maiera6e76d72022-02-11 21:43:503181 owner_email = owner_email or input_api.change.author_email
3182
3183 approval_status = input_api.owners_client.GetFilesApprovalStatus(
3184 virtual_depended_on_files, reviewers.union([owner_email]), [])
3185 missing_files = [
3186 f for f in virtual_depended_on_files
3187 if approval_status[f] != input_api.owners_client.APPROVED
3188 ]
3189
3190 # We strip the /DEPS part that was added by
3191 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3192 # directory.
3193 def StripDeps(path):
3194 start_deps = path.rfind('/DEPS')
3195 if start_deps != -1:
3196 return path[:start_deps]
3197 else:
3198 return path
3199
3200 unapproved_dependencies = [
3201 "'+%s'," % StripDeps(path) for path in missing_files
3202 ]
3203
3204 if unapproved_dependencies:
3205 output_list = [
3206 output(
3207 'You need LGTM from owners of depends-on paths in DEPS that were '
3208 'modified in this CL:\n %s' %
3209 '\n '.join(sorted(unapproved_dependencies)))
3210 ]
3211 suggested_owners = input_api.owners_client.SuggestOwners(
3212 missing_files, exclude=[owner_email])
3213 output_list.append(
3214 output('Suggested missing target path OWNERS:\n %s' %
3215 '\n '.join(suggested_owners or [])))
3216 return output_list
3217
3218 return []
joi@chromium.orge871964c2013-05-13 14:14:553219
3220
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493221# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363222def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503223 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3224 files_to_skip = (
3225 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3226 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013227 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313228 r"^base/logging\.h$",
3229 r"^base/logging\.cc$",
3230 r"^base/task/thread_pool/task_tracker\.cc$",
3231 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033232 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3233 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313234 r"^chrome/browser/chrome_browser_main\.cc$",
3235 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3236 r"^chrome/browser/browser_switcher/bho/.*",
3237 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313238 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3239 r"^chrome/installer/setup/.*",
3240 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203241 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313242 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493243 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313244 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503245 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313246 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503247 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313248 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503249 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313250 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3251 r"^courgette/courgette_minimal_tool\.cc$",
3252 r"^courgette/courgette_tool\.cc$",
3253 r"^extensions/renderer/logging_native_handler\.cc$",
3254 r"^fuchsia_web/common/init_logging\.cc$",
3255 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153256 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313257 r"^headless/app/headless_shell\.cc$",
3258 r"^ipc/ipc_logging\.cc$",
3259 r"^native_client_sdk/",
3260 r"^remoting/base/logging\.h$",
3261 r"^remoting/host/.*",
3262 r"^sandbox/linux/.*",
3263 r"^storage/browser/file_system/dump_file_system\.cc$",
3264 r"^tools/",
3265 r"^ui/base/resource/data_pack\.cc$",
3266 r"^ui/aura/bench/bench_main\.cc$",
3267 r"^ui/ozone/platform/cast/",
3268 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503269 r"xwmstartupcheck\.cc$"))
3270 source_file_filter = lambda x: input_api.FilterSourceFile(
3271 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
thakis@chromium.org85218562013-11-22 07:41:403272
Sam Maiera6e76d72022-02-11 21:43:503273 log_info = set([])
3274 printf = set([])
thakis@chromium.org85218562013-11-22 07:41:403275
Sam Maiera6e76d72022-02-11 21:43:503276 for f in input_api.AffectedSourceFiles(source_file_filter):
3277 for _, line in f.ChangedContents():
3278 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3279 log_info.add(f.LocalPath())
3280 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3281 log_info.add(f.LocalPath())
jln@chromium.org18b466b2013-12-02 22:01:373282
Sam Maiera6e76d72022-02-11 21:43:503283 if input_api.re.search(r"\bprintf\(", line):
3284 printf.add(f.LocalPath())
3285 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3286 printf.add(f.LocalPath())
thakis@chromium.org85218562013-11-22 07:41:403287
Sam Maiera6e76d72022-02-11 21:43:503288 if log_info:
3289 return [
3290 output_api.PresubmitError(
3291 'These files spam the console log with LOG(INFO):',
3292 items=log_info)
3293 ]
3294 if printf:
3295 return [
3296 output_api.PresubmitError(
3297 'These files spam the console log with printf/fprintf:',
3298 items=printf)
3299 ]
3300 return []
thakis@chromium.org85218562013-11-22 07:41:403301
3302
Saagar Sanghavifceeaae2020-08-12 16:40:363303def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503304 """These types are all expected to hold locks while in scope and
3305 so should never be anonymous (which causes them to be immediately
3306 destroyed)."""
3307 they_who_must_be_named = [
3308 'base::AutoLock',
3309 'base::AutoReset',
3310 'base::AutoUnlock',
3311 'SkAutoAlphaRestore',
3312 'SkAutoBitmapShaderInstall',
3313 'SkAutoBlitterChoose',
3314 'SkAutoBounderCommit',
3315 'SkAutoCallProc',
3316 'SkAutoCanvasRestore',
3317 'SkAutoCommentBlock',
3318 'SkAutoDescriptor',
3319 'SkAutoDisableDirectionCheck',
3320 'SkAutoDisableOvalCheck',
3321 'SkAutoFree',
3322 'SkAutoGlyphCache',
3323 'SkAutoHDC',
3324 'SkAutoLockColors',
3325 'SkAutoLockPixels',
3326 'SkAutoMalloc',
3327 'SkAutoMaskFreeImage',
3328 'SkAutoMutexAcquire',
3329 'SkAutoPathBoundsUpdate',
3330 'SkAutoPDFRelease',
3331 'SkAutoRasterClipValidate',
3332 'SkAutoRef',
3333 'SkAutoTime',
3334 'SkAutoTrace',
3335 'SkAutoUnref',
3336 ]
3337 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3338 # bad: base::AutoLock(lock.get());
3339 # not bad: base::AutoLock lock(lock.get());
3340 bad_pattern = input_api.re.compile(anonymous)
3341 # good: new base::AutoLock(lock.get())
3342 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3343 errors = []
enne@chromium.org49aa76a2013-12-04 06:59:163344
Sam Maiera6e76d72022-02-11 21:43:503345 for f in input_api.AffectedFiles():
3346 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3347 continue
3348 for linenum, line in f.ChangedContents():
3349 if bad_pattern.search(line) and not good_pattern.search(line):
3350 errors.append('%s:%d' % (f.LocalPath(), linenum))
enne@chromium.org49aa76a2013-12-04 06:59:163351
Sam Maiera6e76d72022-02-11 21:43:503352 if errors:
3353 return [
3354 output_api.PresubmitError(
3355 'These lines create anonymous variables that need to be named:',
3356 items=errors)
3357 ]
3358 return []
enne@chromium.org49aa76a2013-12-04 06:59:163359
3360
Saagar Sanghavifceeaae2020-08-12 16:40:363361def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503362 # Returns whether |template_str| is of the form <T, U...> for some types T
3363 # and U. Assumes that |template_str| is already in the form <...>.
3364 def HasMoreThanOneArg(template_str):
3365 # Level of <...> nesting.
3366 nesting = 0
3367 for c in template_str:
3368 if c == '<':
3369 nesting += 1
3370 elif c == '>':
3371 nesting -= 1
3372 elif c == ',' and nesting == 1:
3373 return True
3374 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533375
Sam Maiera6e76d72022-02-11 21:43:503376 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3377 sources = lambda affected_file: input_api.FilterSourceFile(
3378 affected_file,
3379 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3380 DEFAULT_FILES_TO_SKIP),
3381 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553382
Sam Maiera6e76d72022-02-11 21:43:503383 # Pattern to capture a single "<...>" block of template arguments. It can
3384 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3385 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3386 # latter would likely require counting that < and > match, which is not
3387 # expressible in regular languages. Should the need arise, one can introduce
3388 # limited counting (matching up to a total number of nesting depth), which
3389 # should cover all practical cases for already a low nesting limit.
3390 template_arg_pattern = (
3391 r'<[^>]*' # Opening block of <.
3392 r'>([^<]*>)?') # Closing block of >.
3393 # Prefix expressing that whatever follows is not already inside a <...>
3394 # block.
3395 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3396 null_construct_pattern = input_api.re.compile(
3397 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3398 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553399
Sam Maiera6e76d72022-02-11 21:43:503400 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3401 template_arg_no_array_pattern = (
3402 r'<[^>]*[^]]' # Opening block of <.
3403 r'>([^(<]*[^]]>)?') # Closing block of >.
3404 # Prefix saying that what follows is the start of an expression.
3405 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3406 # Suffix saying that what follows are call parentheses with a non-empty list
3407 # of arguments.
3408 nonempty_arg_list_pattern = r'\(([^)]|$)'
3409 # Put the template argument into a capture group for deeper examination later.
3410 return_construct_pattern = input_api.re.compile(
3411 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3412 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553413
Sam Maiera6e76d72022-02-11 21:43:503414 problems_constructor = []
3415 problems_nullptr = []
3416 for f in input_api.AffectedSourceFiles(sources):
3417 for line_number, line in f.ChangedContents():
3418 # Disallow:
3419 # return std::unique_ptr<T>(foo);
3420 # bar = std::unique_ptr<T>(foo);
3421 # But allow:
3422 # return std::unique_ptr<T[]>(foo);
3423 # bar = std::unique_ptr<T[]>(foo);
3424 # And also allow cases when the second template argument is present. Those
3425 # cases cannot be handled by std::make_unique:
3426 # return std::unique_ptr<T, U>(foo);
3427 # bar = std::unique_ptr<T, U>(foo);
3428 local_path = f.LocalPath()
3429 return_construct_result = return_construct_pattern.search(line)
3430 if return_construct_result and not HasMoreThanOneArg(
3431 return_construct_result.group('template_arg')):
3432 problems_constructor.append(
3433 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3434 # Disallow:
3435 # std::unique_ptr<T>()
3436 if null_construct_pattern.search(line):
3437 problems_nullptr.append(
3438 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053439
Sam Maiera6e76d72022-02-11 21:43:503440 errors = []
3441 if problems_nullptr:
3442 errors.append(
3443 output_api.PresubmitPromptWarning(
3444 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3445 problems_nullptr))
3446 if problems_constructor:
3447 errors.append(
3448 output_api.PresubmitError(
3449 'The following files use explicit std::unique_ptr constructor. '
3450 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3451 'std::make_unique is not an option.', problems_constructor))
3452 return errors
Peter Kasting4844e46e2018-02-23 07:27:103453
3454
Saagar Sanghavifceeaae2020-08-12 16:40:363455def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503456 """Checks if any new user action has been added."""
3457 if any('actions.xml' == input_api.os_path.basename(f)
3458 for f in input_api.LocalPaths()):
3459 # If actions.xml is already included in the changelist, the PRESUBMIT
3460 # for actions.xml will do a more complete presubmit check.
3461 return []
3462
3463 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3464 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3465 input_api.DEFAULT_FILES_TO_SKIP)
3466 file_filter = lambda f: input_api.FilterSourceFile(
3467 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3468
3469 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3470 current_actions = None
3471 for f in input_api.AffectedFiles(file_filter=file_filter):
3472 for line_num, line in f.ChangedContents():
3473 match = input_api.re.search(action_re, line)
3474 if match:
3475 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3476 # loaded only once.
3477 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:093478 with open('tools/metrics/actions/actions.xml',
3479 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:503480 current_actions = actions_f.read()
3481 # Search for the matched user action name in |current_actions|.
3482 for action_name in match.groups():
3483 action = 'name="{0}"'.format(action_name)
3484 if action not in current_actions:
3485 return [
3486 output_api.PresubmitPromptWarning(
3487 'File %s line %d: %s is missing in '
3488 'tools/metrics/actions/actions.xml. Please run '
3489 'tools/metrics/actions/extract_actions.py to update.'
3490 % (f.LocalPath(), line_num, action_name))
3491 ]
yiyaoliu@chromium.org999261d2014-03-03 20:08:083492 return []
3493
yiyaoliu@chromium.org999261d2014-03-03 20:08:083494
Daniel Cheng13ca61a882017-08-25 15:11:253495def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503496 import sys
3497 sys.path = sys.path + [
3498 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3499 'json_comment_eater')
3500 ]
3501 import json_comment_eater
3502 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:253503
3504
yoz@chromium.org99171a92014-06-03 08:44:473505def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:173506 try:
Sam Maiera6e76d72022-02-11 21:43:503507 contents = input_api.ReadFile(filename)
3508 if eat_comments:
3509 json_comment_eater = _ImportJSONCommentEater(input_api)
3510 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:173511
Sam Maiera6e76d72022-02-11 21:43:503512 input_api.json.loads(contents)
3513 except ValueError as e:
3514 return e
Andrew Grieve4deedb12022-02-03 21:34:503515 return None
3516
3517
Sam Maiera6e76d72022-02-11 21:43:503518def _GetIDLParseError(input_api, filename):
3519 try:
3520 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:283521 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:343522 if not char.isascii():
3523 return (
3524 'Non-ascii character "%s" (ord %d) found at offset %d.' %
3525 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:503526 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
3527 'tools', 'json_schema_compiler',
3528 'idl_schema.py')
3529 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:283530 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:503531 stdin=input_api.subprocess.PIPE,
3532 stdout=input_api.subprocess.PIPE,
3533 stderr=input_api.subprocess.PIPE,
3534 universal_newlines=True)
3535 (_, error) = process.communicate(input=contents)
3536 return error or None
3537 except ValueError as e:
3538 return e
agrievef32bcc72016-04-04 14:57:403539
agrievef32bcc72016-04-04 14:57:403540
Sam Maiera6e76d72022-02-11 21:43:503541def CheckParseErrors(input_api, output_api):
3542 """Check that IDL and JSON files do not contain syntax errors."""
3543 actions = {
3544 '.idl': _GetIDLParseError,
3545 '.json': _GetJSONParseError,
3546 }
3547 # Most JSON files are preprocessed and support comments, but these do not.
3548 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313549 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:503550 ]
3551 # Only run IDL checker on files in these directories.
3552 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313553 r'^chrome/common/extensions/api/',
3554 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:503555 ]
agrievef32bcc72016-04-04 14:57:403556
Sam Maiera6e76d72022-02-11 21:43:503557 def get_action(affected_file):
3558 filename = affected_file.LocalPath()
3559 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:403560
Sam Maiera6e76d72022-02-11 21:43:503561 def FilterFile(affected_file):
3562 action = get_action(affected_file)
3563 if not action:
3564 return False
3565 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403566
Sam Maiera6e76d72022-02-11 21:43:503567 if _MatchesFile(input_api,
3568 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3569 return False
3570
3571 if (action == _GetIDLParseError
3572 and not _MatchesFile(input_api, idl_included_patterns, path)):
3573 return False
3574 return True
3575
3576 results = []
3577 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3578 include_deletes=False):
3579 action = get_action(affected_file)
3580 kwargs = {}
3581 if (action == _GetJSONParseError
3582 and _MatchesFile(input_api, json_no_comments_patterns,
3583 affected_file.LocalPath())):
3584 kwargs['eat_comments'] = False
3585 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3586 **kwargs)
3587 if parse_error:
3588 results.append(
3589 output_api.PresubmitError(
3590 '%s could not be parsed: %s' %
3591 (affected_file.LocalPath(), parse_error)))
3592 return results
3593
3594
3595def CheckJavaStyle(input_api, output_api):
3596 """Runs checkstyle on changed java files and returns errors if any exist."""
3597
3598 # Return early if no java files were modified.
3599 if not any(
3600 _IsJavaFile(input_api, f.LocalPath())
3601 for f in input_api.AffectedFiles()):
3602 return []
3603
3604 import sys
3605 original_sys_path = sys.path
3606 try:
3607 sys.path = sys.path + [
3608 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3609 'android', 'checkstyle')
3610 ]
3611 import checkstyle
3612 finally:
3613 # Restore sys.path to what it was before.
3614 sys.path = original_sys_path
3615
Andrew Grieve4f88e3ca2022-11-22 19:09:203616 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:503617 input_api,
3618 output_api,
Sam Maiera6e76d72022-02-11 21:43:503619 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3620
3621
3622def CheckPythonDevilInit(input_api, output_api):
3623 """Checks to make sure devil is initialized correctly in python scripts."""
3624 script_common_initialize_pattern = input_api.re.compile(
3625 r'script_common\.InitializeEnvironment\(')
3626 devil_env_config_initialize = input_api.re.compile(
3627 r'devil_env\.config\.Initialize\(')
3628
3629 errors = []
3630
3631 sources = lambda affected_file: input_api.FilterSourceFile(
3632 affected_file,
3633 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313634 r'^build/android/devil_chromium\.py',
3635 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503636 )),
3637 files_to_check=[r'.*\.py$'])
3638
3639 for f in input_api.AffectedSourceFiles(sources):
3640 for line_num, line in f.ChangedContents():
3641 if (script_common_initialize_pattern.search(line)
3642 or devil_env_config_initialize.search(line)):
3643 errors.append("%s:%d" % (f.LocalPath(), line_num))
3644
3645 results = []
3646
3647 if errors:
3648 results.append(
3649 output_api.PresubmitError(
3650 'Devil initialization should always be done using '
3651 'devil_chromium.Initialize() in the chromium project, to use better '
3652 'defaults for dependencies (ex. up-to-date version of adb).',
3653 errors))
3654
3655 return results
3656
3657
3658def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313659 # Consistently use / as path separator to simplify the writing of regex
3660 # expressions.
3661 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503662 for pattern in patterns:
3663 if input_api.re.search(pattern, path):
3664 return True
3665 return False
3666
3667
Daniel Chenga37c03db2022-05-12 17:20:343668def _ChangeHasSecurityReviewer(input_api, owners_file):
3669 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503670
Daniel Chenga37c03db2022-05-12 17:20:343671 Args:
3672 input_api: The presubmit input API.
3673 owners_file: OWNERS file with required reviewers. Typically, this is
3674 something like ipc/SECURITY_OWNERS.
3675
3676 Note: if the presubmit is running for commit rather than for upload, this
3677 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503678 """
Daniel Chengd88244472022-05-16 09:08:473679 # Owners-Override should bypass all additional OWNERS enforcement checks.
3680 # A CR+1 vote will still be required to land this change.
3681 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3682 input_api.change.issue)):
3683 return True
3684
Daniel Chenga37c03db2022-05-12 17:20:343685 owner_email, reviewers = (
3686 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113687 input_api,
3688 None,
3689 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503690
Daniel Chenga37c03db2022-05-12 17:20:343691 security_owners = input_api.owners_client.ListOwners(owners_file)
3692 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503693
Daniel Chenga37c03db2022-05-12 17:20:343694
3695@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253696class _SecurityProblemWithItems:
3697 problem: str
3698 items: Sequence[str]
3699
3700
3701@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343702class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253703 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343704 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253705 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343706
3707
3708def _FindMissingSecurityOwners(input_api,
3709 output_api,
3710 file_patterns: Sequence[str],
3711 excluded_patterns: Sequence[str],
3712 required_owners_file: str,
3713 custom_rule_function: Optional[Callable] = None
3714 ) -> _MissingSecurityOwnersResult:
3715 """Find OWNERS files missing per-file rules for security-sensitive files.
3716
3717 Args:
3718 input_api: the PRESUBMIT input API object.
3719 output_api: the PRESUBMIT output API object.
3720 file_patterns: basename patterns that require a corresponding per-file
3721 security restriction.
3722 excluded_patterns: path patterns that should be exempted from
3723 requiring a security restriction.
3724 required_owners_file: path to the required OWNERS file, e.g.
3725 ipc/SECURITY_OWNERS
3726 cc_alias: If not None, email that will be CCed automatically if the
3727 change contains security-sensitive files, as determined by
3728 `file_patterns` and `excluded_patterns`.
3729 custom_rule_function: If not None, will be called with `input_api` and
3730 the current file under consideration. Returning True will add an
3731 exact match per-file rule check for the current file.
3732 """
3733
3734 # `to_check` is a mapping of an OWNERS file path to Patterns.
3735 #
3736 # Patterns is a dictionary mapping glob patterns (suitable for use in
3737 # per-file rules) to a PatternEntry.
3738 #
Sam Maiera6e76d72022-02-11 21:43:503739 # PatternEntry is a dictionary with two keys:
3740 # - 'files': the files that are matched by this pattern
3741 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343742 #
Sam Maiera6e76d72022-02-11 21:43:503743 # For example, if we expect OWNERS file to contain rules for *.mojom and
3744 # *_struct_traits*.*, Patterns might look like this:
3745 # {
3746 # '*.mojom': {
3747 # 'files': ...,
3748 # 'rules': [
3749 # 'per-file *.mojom=set noparent',
3750 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3751 # ],
3752 # },
3753 # '*_struct_traits*.*': {
3754 # 'files': ...,
3755 # 'rules': [
3756 # 'per-file *_struct_traits*.*=set noparent',
3757 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3758 # ],
3759 # },
3760 # }
3761 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343762 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503763
Daniel Chenga37c03db2022-05-12 17:20:343764 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503765 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473766 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503767 if owners_file not in to_check:
3768 to_check[owners_file] = {}
3769 if pattern not in to_check[owners_file]:
3770 to_check[owners_file][pattern] = {
3771 'files': [],
3772 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343773 f'per-file {pattern}=set noparent',
3774 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503775 ]
3776 }
Daniel Chenged57a162022-05-25 02:56:343777 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343778 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503779
Daniel Chenga37c03db2022-05-12 17:20:343780 # Only enforce security OWNERS rules for a directory if that directory has a
3781 # file that matches `file_patterns`. For example, if a directory only
3782 # contains *.mojom files and no *_messages*.h files, the check should only
3783 # ensure that rules for *.mojom files are present.
3784 for file in input_api.AffectedFiles(include_deletes=False):
3785 file_basename = input_api.os_path.basename(file.LocalPath())
3786 if custom_rule_function is not None and custom_rule_function(
3787 input_api, file):
3788 AddPatternToCheck(file, file_basename)
3789 continue
Sam Maiera6e76d72022-02-11 21:43:503790
Daniel Chenga37c03db2022-05-12 17:20:343791 if any(
3792 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3793 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503794 continue
3795
3796 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343797 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3798 # file's basename.
3799 if input_api.fnmatch.fnmatch(file_basename, pattern):
3800 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503801 break
3802
Daniel Chenga37c03db2022-05-12 17:20:343803 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253804
3805 # Check if any newly added lines in OWNERS files intersect with required
3806 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3807 # This is a hack, but is needed because the OWNERS check (by design) ignores
3808 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3809 # OWNER and have that newly-added OWNER self-approve their own addition.
3810 newly_covered_files = []
3811 for file in input_api.AffectedFiles(include_deletes=False):
3812 if not file.LocalPath() in to_check:
3813 continue
3814 for _, line in file.ChangedContents():
3815 for _, entry in to_check[file.LocalPath()].items():
3816 if line in entry['rules']:
3817 newly_covered_files.extend(entry['files'])
3818
3819 missing_reviewer_problems = None
3820 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343821 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253822 missing_reviewer_problems = _SecurityProblemWithItems(
3823 f'Review from an owner in {required_owners_file} is required for '
3824 'the following newly-added files:',
3825 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503826
3827 # Go through the OWNERS files to check, filtering out rules that are already
3828 # present in that OWNERS file.
3829 for owners_file, patterns in to_check.items():
3830 try:
Daniel Cheng171dad8d2022-05-21 00:40:253831 lines = set(
3832 input_api.ReadFile(
3833 input_api.os_path.join(input_api.change.RepositoryRoot(),
3834 owners_file)).splitlines())
3835 for entry in patterns.values():
3836 entry['rules'] = [
3837 rule for rule in entry['rules'] if rule not in lines
3838 ]
Sam Maiera6e76d72022-02-11 21:43:503839 except IOError:
3840 # No OWNERS file, so all the rules are definitely missing.
3841 continue
3842
3843 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253844 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343845
Sam Maiera6e76d72022-02-11 21:43:503846 for owners_file, patterns in to_check.items():
3847 missing_lines = []
3848 files = []
3849 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343850 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503851 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503852 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253853 joined_missing_lines = '\n'.join(line for line in missing_lines)
3854 owners_file_problems.append(
3855 _SecurityProblemWithItems(
3856 'Found missing OWNERS lines for security-sensitive files. '
3857 f'Please add the following lines to {owners_file}:\n'
3858 f'{joined_missing_lines}\n\nTo ensure security review for:',
3859 files))
Daniel Chenga37c03db2022-05-12 17:20:343860
Daniel Cheng171dad8d2022-05-21 00:40:253861 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343862 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253863 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343864
3865
3866def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3867 # Whether or not a file affects IPC is (mostly) determined by a simple list
3868 # of filename patterns.
3869 file_patterns = [
3870 # Legacy IPC:
3871 '*_messages.cc',
3872 '*_messages*.h',
3873 '*_param_traits*.*',
3874 # Mojo IPC:
3875 '*.mojom',
3876 '*_mojom_traits*.*',
3877 '*_type_converter*.*',
3878 # Android native IPC:
3879 '*.aidl',
3880 ]
3881
Daniel Chenga37c03db2022-05-12 17:20:343882 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463883 # These third_party directories do not contain IPCs, but contain files
3884 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343885 'third_party/crashpad/*',
3886 'third_party/blink/renderer/platform/bindings/*',
3887 'third_party/protobuf/benchmarks/python/*',
3888 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473889 # Enum-only mojoms used for web metrics, so no security review needed.
3890 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343891 # These files are just used to communicate between class loaders running
3892 # in the same process.
3893 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3894 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3895 ]
3896
3897 def IsMojoServiceManifestFile(input_api, file):
3898 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3899 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3900 if not manifest_pattern.search(file.LocalPath()):
3901 return False
3902
3903 if test_manifest_pattern.search(file.LocalPath()):
3904 return False
3905
3906 # All actual service manifest files should contain at least one
3907 # qualified reference to service_manager::Manifest.
3908 return any('service_manager::Manifest' in line
3909 for line in file.NewContents())
3910
3911 return _FindMissingSecurityOwners(
3912 input_api,
3913 output_api,
3914 file_patterns,
3915 excluded_patterns,
3916 'ipc/SECURITY_OWNERS',
3917 custom_rule_function=IsMojoServiceManifestFile)
3918
3919
3920def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3921 file_patterns = [
3922 # Component specifications.
3923 '*.cml', # Component Framework v2.
3924 '*.cmx', # Component Framework v1.
3925
3926 # Fuchsia IDL protocol specifications.
3927 '*.fidl',
3928 ]
3929
3930 # Don't check for owners files for changes in these directories.
3931 excluded_patterns = [
3932 'third_party/crashpad/*',
3933 ]
3934
3935 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3936 excluded_patterns,
3937 'build/fuchsia/SECURITY_OWNERS')
3938
3939
3940def CheckSecurityOwners(input_api, output_api):
3941 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3942 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3943 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3944 input_api, output_api)
3945
3946 if ipc_results.has_security_sensitive_files:
3947 output_api.AppendCC('ipc-security-reviews@chromium.org')
Sam Maiera6e76d72022-02-11 21:43:503948
3949 results = []
Daniel Chenga37c03db2022-05-12 17:20:343950
Daniel Cheng171dad8d2022-05-21 00:40:253951 missing_reviewer_problems = []
3952 if ipc_results.missing_reviewer_problem:
3953 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3954 if fuchsia_results.missing_reviewer_problem:
3955 missing_reviewer_problems.append(
3956 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343957
Daniel Cheng171dad8d2022-05-21 00:40:253958 # Missing reviewers are an error unless there's no issue number
3959 # associated with this branch; in that case, the presubmit is being run
3960 # with --all or --files.
3961 #
3962 # Note that upload should never be an error; otherwise, it would be
3963 # impossible to upload changes at all.
3964 if input_api.is_committing and input_api.change.issue:
3965 make_presubmit_message = output_api.PresubmitError
3966 else:
3967 make_presubmit_message = output_api.PresubmitNotifyResult
3968 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503969 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253970 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343971
Daniel Cheng171dad8d2022-05-21 00:40:253972 owners_file_problems = []
3973 owners_file_problems.extend(ipc_results.owners_file_problems)
3974 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343975
Daniel Cheng171dad8d2022-05-21 00:40:253976 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113977 # Missing per-file rules are always an error. While swarming and caching
3978 # means that uploading a patchset with updated OWNERS files and sending
3979 # it to the CQ again should not have a large incremental cost, it is
3980 # still frustrating to discover the error only after the change has
3981 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343982 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253983 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503984
3985 return results
3986
3987
3988def _GetFilesUsingSecurityCriticalFunctions(input_api):
3989 """Checks affected files for changes to security-critical calls. This
3990 function checks the full change diff, to catch both additions/changes
3991 and removals.
3992
3993 Returns a dict keyed by file name, and the value is a set of detected
3994 functions.
3995 """
3996 # Map of function pretty name (displayed in an error) to the pattern to
3997 # match it with.
3998 _PATTERNS_TO_CHECK = {
3999 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4000 }
4001 _PATTERNS_TO_CHECK = {
4002 k: input_api.re.compile(v)
4003 for k, v in _PATTERNS_TO_CHECK.items()
4004 }
4005
Sam Maiera6e76d72022-02-11 21:43:504006 # We don't want to trigger on strings within this file.
4007 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344008 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504009
4010 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4011 files_to_functions = {}
4012 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4013 diff = f.GenerateScmDiff()
4014 for line in diff.split('\n'):
4015 # Not using just RightHandSideLines() because removing a
4016 # call to a security-critical function can be just as important
4017 # as adding or changing the arguments.
4018 if line.startswith('-') or (line.startswith('+')
4019 and not line.startswith('++')):
4020 for name, pattern in _PATTERNS_TO_CHECK.items():
4021 if pattern.search(line):
4022 path = f.LocalPath()
4023 if not path in files_to_functions:
4024 files_to_functions[path] = set()
4025 files_to_functions[path].add(name)
4026 return files_to_functions
4027
4028
4029def CheckSecurityChanges(input_api, output_api):
4030 """Checks that changes involving security-critical functions are reviewed
4031 by the security team.
4032 """
4033 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4034 if not len(files_to_functions):
4035 return []
4036
Sam Maiera6e76d72022-02-11 21:43:504037 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344038 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504039 return []
4040
Daniel Chenga37c03db2022-05-12 17:20:344041 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504042 'that need to be reviewed by {}.\n'.format(owners_file)
4043 for path, names in files_to_functions.items():
4044 msg += ' {}\n'.format(path)
4045 for name in names:
4046 msg += ' {}\n'.format(name)
4047 msg += '\n'
4048
4049 if input_api.is_committing:
4050 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034051 else:
Sam Maiera6e76d72022-02-11 21:43:504052 output = output_api.PresubmitNotifyResult
4053 return [output(msg)]
4054
4055
4056def CheckSetNoParent(input_api, output_api):
4057 """Checks that set noparent is only used together with an OWNERS file in
4058 //build/OWNERS.setnoparent (see also
4059 //docs/code_reviews.md#owners-files-details)
4060 """
4061 # Return early if no OWNERS files were modified.
4062 if not any(f.LocalPath().endswith('OWNERS')
4063 for f in input_api.AffectedFiles(include_deletes=False)):
4064 return []
4065
4066 errors = []
4067
4068 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4069 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164070 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504071 for line in f:
4072 line = line.strip()
4073 if not line or line.startswith('#'):
4074 continue
4075 allowed_owners_files.add(line)
4076
4077 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4078
4079 for f in input_api.AffectedFiles(include_deletes=False):
4080 if not f.LocalPath().endswith('OWNERS'):
4081 continue
4082
4083 found_owners_files = set()
4084 found_set_noparent_lines = dict()
4085
4086 # Parse the OWNERS file.
4087 for lineno, line in enumerate(f.NewContents(), 1):
4088 line = line.strip()
4089 if line.startswith('set noparent'):
4090 found_set_noparent_lines[''] = lineno
4091 if line.startswith('file://'):
4092 if line in allowed_owners_files:
4093 found_owners_files.add('')
4094 if line.startswith('per-file'):
4095 match = per_file_pattern.match(line)
4096 if match:
4097 glob = match.group(1).strip()
4098 directive = match.group(2).strip()
4099 if directive == 'set noparent':
4100 found_set_noparent_lines[glob] = lineno
4101 if directive.startswith('file://'):
4102 if directive in allowed_owners_files:
4103 found_owners_files.add(glob)
4104
4105 # Check that every set noparent line has a corresponding file:// line
4106 # listed in build/OWNERS.setnoparent. An exception is made for top level
4107 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:494108 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
4109 if (linux_path.count('/') != 1
4110 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504111 for set_noparent_line in found_set_noparent_lines:
4112 if set_noparent_line in found_owners_files:
4113 continue
4114 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494115 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504116 found_set_noparent_lines[set_noparent_line]))
4117
4118 results = []
4119 if errors:
4120 if input_api.is_committing:
4121 output = output_api.PresubmitError
4122 else:
4123 output = output_api.PresubmitPromptWarning
4124 results.append(
4125 output(
4126 'Found the following "set noparent" restrictions in OWNERS files that '
4127 'do not include owners from build/OWNERS.setnoparent:',
4128 long_text='\n\n'.join(errors)))
4129 return results
4130
4131
4132def CheckUselessForwardDeclarations(input_api, output_api):
4133 """Checks that added or removed lines in non third party affected
4134 header files do not lead to new useless class or struct forward
4135 declaration.
4136 """
4137 results = []
4138 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4139 input_api.re.MULTILINE)
4140 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4141 input_api.re.MULTILINE)
4142 for f in input_api.AffectedFiles(include_deletes=False):
4143 if (f.LocalPath().startswith('third_party')
4144 and not f.LocalPath().startswith('third_party/blink')
4145 and not f.LocalPath().startswith('third_party\\blink')):
4146 continue
4147
4148 if not f.LocalPath().endswith('.h'):
4149 continue
4150
4151 contents = input_api.ReadFile(f)
4152 fwd_decls = input_api.re.findall(class_pattern, contents)
4153 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4154
4155 useless_fwd_decls = []
4156 for decl in fwd_decls:
4157 count = sum(1 for _ in input_api.re.finditer(
4158 r'\b%s\b' % input_api.re.escape(decl), contents))
4159 if count == 1:
4160 useless_fwd_decls.append(decl)
4161
4162 if not useless_fwd_decls:
4163 continue
4164
4165 for line in f.GenerateScmDiff().splitlines():
4166 if (line.startswith('-') and not line.startswith('--')
4167 or line.startswith('+') and not line.startswith('++')):
4168 for decl in useless_fwd_decls:
4169 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4170 results.append(
4171 output_api.PresubmitPromptWarning(
4172 '%s: %s forward declaration is no longer needed'
4173 % (f.LocalPath(), decl)))
4174 useless_fwd_decls.remove(decl)
4175
4176 return results
4177
4178
4179def _CheckAndroidDebuggableBuild(input_api, output_api):
4180 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4181 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4182 this is a debuggable build of Android.
4183 """
4184 build_type_check_pattern = input_api.re.compile(
4185 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4186
4187 errors = []
4188
4189 sources = lambda affected_file: input_api.FilterSourceFile(
4190 affected_file,
4191 files_to_skip=(
4192 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4193 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314194 r"^android_webview/support_library/boundary_interfaces/",
4195 r"^chrome/android/webapk/.*",
4196 r'^third_party/.*',
4197 r"tools/android/customtabs_benchmark/.*",
4198 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504199 )),
4200 files_to_check=[r'.*\.java$'])
4201
4202 for f in input_api.AffectedSourceFiles(sources):
4203 for line_num, line in f.ChangedContents():
4204 if build_type_check_pattern.search(line):
4205 errors.append("%s:%d" % (f.LocalPath(), line_num))
4206
4207 results = []
4208
4209 if errors:
4210 results.append(
4211 output_api.PresubmitPromptWarning(
4212 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4213 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4214
4215 return results
4216
4217# TODO: add unit tests
4218def _CheckAndroidToastUsage(input_api, output_api):
4219 """Checks that code uses org.chromium.ui.widget.Toast instead of
4220 android.widget.Toast (Chromium Toast doesn't force hardware
4221 acceleration on low-end devices, saving memory).
4222 """
4223 toast_import_pattern = input_api.re.compile(
4224 r'^import android\.widget\.Toast;$')
4225
4226 errors = []
4227
4228 sources = lambda affected_file: input_api.FilterSourceFile(
4229 affected_file,
4230 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314231 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4232 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504233 files_to_check=[r'.*\.java$'])
4234
4235 for f in input_api.AffectedSourceFiles(sources):
4236 for line_num, line in f.ChangedContents():
4237 if toast_import_pattern.search(line):
4238 errors.append("%s:%d" % (f.LocalPath(), line_num))
4239
4240 results = []
4241
4242 if errors:
4243 results.append(
4244 output_api.PresubmitError(
4245 'android.widget.Toast usage is detected. Android toasts use hardware'
4246 ' acceleration, and can be\ncostly on low-end devices. Please use'
4247 ' org.chromium.ui.widget.Toast instead.\n'
4248 'Contact dskiba@chromium.org if you have any questions.',
4249 errors))
4250
4251 return results
4252
4253
4254def _CheckAndroidCrLogUsage(input_api, output_api):
4255 """Checks that new logs using org.chromium.base.Log:
4256 - Are using 'TAG' as variable name for the tags (warn)
4257 - Are using a tag that is shorter than 20 characters (error)
4258 """
4259
4260 # Do not check format of logs in the given files
4261 cr_log_check_excluded_paths = [
4262 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314263 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504264 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314265 r"^android_webview/glue/java/src/com/android/"
4266 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504267 # The customtabs_benchmark is a small app that does not depend on Chromium
4268 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314269 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504270 ]
4271
4272 cr_log_import_pattern = input_api.re.compile(
4273 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4274 class_in_base_pattern = input_api.re.compile(
4275 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4276 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4277 input_api.re.MULTILINE)
4278 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4279 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4280 log_decl_pattern = input_api.re.compile(
4281 r'static final String TAG = "(?P<name>(.*))"')
4282 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4283
4284 REF_MSG = ('See docs/android_logging.md for more info.')
4285 sources = lambda x: input_api.FilterSourceFile(
4286 x,
4287 files_to_check=[r'.*\.java$'],
4288 files_to_skip=cr_log_check_excluded_paths)
4289
4290 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384291 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504292 tag_errors = []
4293 tag_with_dot_errors = []
4294 util_log_errors = []
4295
4296 for f in input_api.AffectedSourceFiles(sources):
4297 file_content = input_api.ReadFile(f)
4298 has_modified_logs = False
4299 # Per line checks
4300 if (cr_log_import_pattern.search(file_content)
4301 or (class_in_base_pattern.search(file_content)
4302 and not has_some_log_import_pattern.search(file_content))):
4303 # Checks to run for files using cr log
4304 for line_num, line in f.ChangedContents():
4305 if rough_log_decl_pattern.search(line):
4306 has_modified_logs = True
4307
4308 # Check if the new line is doing some logging
4309 match = log_call_pattern.search(line)
4310 if match:
4311 has_modified_logs = True
4312
4313 # Make sure it uses "TAG"
4314 if not match.group('tag') == 'TAG':
4315 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4316 else:
4317 # Report non cr Log function calls in changed lines
4318 for line_num, line in f.ChangedContents():
4319 if log_call_pattern.search(line):
4320 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4321
4322 # Per file checks
4323 if has_modified_logs:
4324 # Make sure the tag is using the "cr" prefix and is not too long
4325 match = log_decl_pattern.search(file_content)
4326 tag_name = match.group('name') if match else None
4327 if not tag_name:
4328 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384329 elif len(tag_name) > 20:
4330 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504331 elif '.' in tag_name:
4332 tag_with_dot_errors.append(f.LocalPath())
4333
4334 results = []
4335 if tag_decl_errors:
4336 results.append(
4337 output_api.PresubmitPromptWarning(
4338 'Please define your tags using the suggested format: .\n'
4339 '"private static final String TAG = "<package tag>".\n'
4340 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4341 tag_decl_errors))
4342
Andrew Grieved3a35d82024-01-02 21:24:384343 if tag_length_errors:
4344 results.append(
4345 output_api.PresubmitError(
4346 'The tag length is restricted by the system to be at most '
4347 '20 characters.\n' + REF_MSG, tag_length_errors))
4348
Sam Maiera6e76d72022-02-11 21:43:504349 if tag_errors:
4350 results.append(
4351 output_api.PresubmitPromptWarning(
4352 'Please use a variable named "TAG" for your log tags.\n' +
4353 REF_MSG, tag_errors))
4354
4355 if util_log_errors:
4356 results.append(
4357 output_api.PresubmitPromptWarning(
4358 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4359 util_log_errors))
4360
4361 if tag_with_dot_errors:
4362 results.append(
4363 output_api.PresubmitPromptWarning(
4364 'Dot in log tags cause them to be elided in crash reports.\n' +
4365 REF_MSG, tag_with_dot_errors))
4366
4367 return results
4368
4369
4370def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
4371 """Checks that junit.framework.* is no longer used."""
4372 deprecated_junit_framework_pattern = input_api.re.compile(
4373 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
4374 sources = lambda x: input_api.FilterSourceFile(
4375 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4376 errors = []
4377 for f in input_api.AffectedFiles(file_filter=sources):
4378 for line_num, line in f.ChangedContents():
4379 if deprecated_junit_framework_pattern.search(line):
4380 errors.append("%s:%d" % (f.LocalPath(), line_num))
4381
4382 results = []
4383 if errors:
4384 results.append(
4385 output_api.PresubmitError(
4386 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
4387 '(org.junit.*) from //third_party/junit. Contact yolandyan@chromium.org'
4388 ' if you have any question.', errors))
4389 return results
4390
4391
4392def _CheckAndroidTestJUnitInheritance(input_api, output_api):
4393 """Checks that if new Java test classes have inheritance.
4394 Either the new test class is JUnit3 test or it is a JUnit4 test class
4395 with a base class, either case is undesirable.
4396 """
4397 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
4398
4399 sources = lambda x: input_api.FilterSourceFile(
4400 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
4401 errors = []
4402 for f in input_api.AffectedFiles(file_filter=sources):
4403 if not f.OldContents():
4404 class_declaration_start_flag = False
4405 for line_num, line in f.ChangedContents():
4406 if class_declaration_pattern.search(line):
4407 class_declaration_start_flag = True
4408 if class_declaration_start_flag and ' extends ' in line:
4409 errors.append('%s:%d' % (f.LocalPath(), line_num))
4410 if '{' in line:
4411 class_declaration_start_flag = False
4412
4413 results = []
4414 if errors:
4415 results.append(
4416 output_api.PresubmitPromptWarning(
4417 'The newly created files include Test classes that inherits from base'
4418 ' class. Please do not use inheritance in JUnit4 tests or add new'
4419 ' JUnit3 tests. Contact yolandyan@chromium.org if you have any'
4420 ' questions.', errors))
4421 return results
4422
4423
4424def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4425 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4426 deprecated_annotation_import_pattern = input_api.re.compile(
4427 r'^import android\.test\.suitebuilder\.annotation\..*;',
4428 input_api.re.MULTILINE)
4429 sources = lambda x: input_api.FilterSourceFile(
4430 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4431 errors = []
4432 for f in input_api.AffectedFiles(file_filter=sources):
4433 for line_num, line in f.ChangedContents():
4434 if deprecated_annotation_import_pattern.search(line):
4435 errors.append("%s:%d" % (f.LocalPath(), line_num))
4436
4437 results = []
4438 if errors:
4439 results.append(
4440 output_api.PresubmitError(
4441 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244442 ' deprecated since API level 24. Please use androidx.test.filters'
4443 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504444 ' Contact yolandyan@chromium.org if you have any questions.',
4445 errors))
4446 return results
4447
4448
4449def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4450 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514451 file_filter = lambda f: (f.LocalPath().endswith(
4452 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4453 LocalPath() or '/res/drawable-ldrtl/'.replace(
4454 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504455 errors = []
4456 for f in input_api.AffectedFiles(include_deletes=False,
4457 file_filter=file_filter):
4458 errors.append(' %s' % f.LocalPath())
4459
4460 results = []
4461 if errors:
4462 results.append(
4463 output_api.PresubmitError(
4464 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4465 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4466 '/res/drawable-ldrtl/.\n'
4467 'Contact newt@chromium.org if you have questions.', errors))
4468 return results
4469
4470
4471def _CheckAndroidWebkitImports(input_api, output_api):
4472 """Checks that code uses org.chromium.base.Callback instead of
4473 android.webview.ValueCallback except in the WebView glue layer
4474 and WebLayer.
4475 """
4476 valuecallback_import_pattern = input_api.re.compile(
4477 r'^import android\.webkit\.ValueCallback;$')
4478
4479 errors = []
4480
4481 sources = lambda affected_file: input_api.FilterSourceFile(
4482 affected_file,
4483 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4484 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314485 r'^android_webview/glue/.*',
4486 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504487 )),
4488 files_to_check=[r'.*\.java$'])
4489
4490 for f in input_api.AffectedSourceFiles(sources):
4491 for line_num, line in f.ChangedContents():
4492 if valuecallback_import_pattern.search(line):
4493 errors.append("%s:%d" % (f.LocalPath(), line_num))
4494
4495 results = []
4496
4497 if errors:
4498 results.append(
4499 output_api.PresubmitError(
4500 'android.webkit.ValueCallback usage is detected outside of the glue'
4501 ' layer. To stay compatible with the support library, android.webkit.*'
4502 ' classes should only be used inside the glue layer and'
4503 ' org.chromium.base.Callback should be used instead.', errors))
4504
4505 return results
4506
4507
4508def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4509 """Checks Android XML styles """
4510
4511 # Return early if no relevant files were modified.
4512 if not any(
4513 _IsXmlOrGrdFile(input_api, f.LocalPath())
4514 for f in input_api.AffectedFiles(include_deletes=False)):
4515 return []
4516
4517 import sys
4518 original_sys_path = sys.path
4519 try:
4520 sys.path = sys.path + [
4521 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4522 'android', 'checkxmlstyle')
4523 ]
4524 import checkxmlstyle
4525 finally:
4526 # Restore sys.path to what it was before.
4527 sys.path = original_sys_path
4528
4529 if is_check_on_upload:
4530 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4531 else:
4532 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4533
4534
4535def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4536 """Checks Android Infobar Deprecation """
4537
4538 import sys
4539 original_sys_path = sys.path
4540 try:
4541 sys.path = sys.path + [
4542 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4543 'android', 'infobar_deprecation')
4544 ]
4545 import infobar_deprecation
4546 finally:
4547 # Restore sys.path to what it was before.
4548 sys.path = original_sys_path
4549
4550 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4551
4552
4553class _PydepsCheckerResult:
4554 def __init__(self, cmd, pydeps_path, process, old_contents):
4555 self._cmd = cmd
4556 self._pydeps_path = pydeps_path
4557 self._process = process
4558 self._old_contents = old_contents
4559
4560 def GetError(self):
4561 """Returns an error message, or None."""
4562 import difflib
Andrew Grieved27620b62023-07-13 16:35:074563 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:504564 if self._process.wait() != 0:
4565 # STDERR should already be printed.
4566 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:504567 if self._old_contents != new_contents:
4568 diff = '\n'.join(
4569 difflib.context_diff(self._old_contents, new_contents))
4570 return ('File is stale: {}\n'
4571 'Diff (apply to fix):\n'
4572 '{}\n'
4573 'To regenerate, run:\n\n'
4574 ' {}').format(self._pydeps_path, diff, self._cmd)
4575 return None
4576
4577
4578class PydepsChecker:
4579 def __init__(self, input_api, pydeps_files):
4580 self._file_cache = {}
4581 self._input_api = input_api
4582 self._pydeps_files = pydeps_files
4583
4584 def _LoadFile(self, path):
4585 """Returns the list of paths within a .pydeps file relative to //."""
4586 if path not in self._file_cache:
4587 with open(path, encoding='utf-8') as f:
4588 self._file_cache[path] = f.read()
4589 return self._file_cache[path]
4590
4591 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594592 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504593 pydeps_data = self._LoadFile(pydeps_path)
4594 uses_gn_paths = '--gn-paths' in pydeps_data
4595 entries = (l for l in pydeps_data.splitlines()
4596 if not l.startswith('#'))
4597 if uses_gn_paths:
4598 # Paths look like: //foo/bar/baz
4599 return (e[2:] for e in entries)
4600 else:
4601 # Paths look like: path/relative/to/file.pydeps
4602 os_path = self._input_api.os_path
4603 pydeps_dir = os_path.dirname(pydeps_path)
4604 return (os_path.normpath(os_path.join(pydeps_dir, e))
4605 for e in entries)
4606
4607 def _CreateFilesToPydepsMap(self):
4608 """Returns a map of local_path -> list_of_pydeps."""
4609 ret = {}
4610 for pydep_local_path in self._pydeps_files:
4611 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4612 ret.setdefault(path, []).append(pydep_local_path)
4613 return ret
4614
4615 def ComputeAffectedPydeps(self):
4616 """Returns an iterable of .pydeps files that might need regenerating."""
4617 affected_pydeps = set()
4618 file_to_pydeps_map = None
4619 for f in self._input_api.AffectedFiles(include_deletes=True):
4620 local_path = f.LocalPath()
4621 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4622 # subrepositories. We can't figure out which files change, so re-check
4623 # all files.
4624 # Changes to print_python_deps.py affect all .pydeps.
4625 if local_path in ('DEPS', 'PRESUBMIT.py'
4626 ) or local_path.endswith('print_python_deps.py'):
4627 return self._pydeps_files
4628 elif local_path.endswith('.pydeps'):
4629 if local_path in self._pydeps_files:
4630 affected_pydeps.add(local_path)
4631 elif local_path.endswith('.py'):
4632 if file_to_pydeps_map is None:
4633 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4634 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4635 return affected_pydeps
4636
4637 def DetermineIfStaleAsync(self, pydeps_path):
4638 """Runs print_python_deps.py to see if the files is stale."""
4639 import os
4640
4641 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4642 if old_pydeps_data:
4643 cmd = old_pydeps_data[1][1:].strip()
4644 if '--output' not in cmd:
4645 cmd += ' --output ' + pydeps_path
4646 old_contents = old_pydeps_data[2:]
4647 else:
4648 # A default cmd that should work in most cases (as long as pydeps filename
4649 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4650 # file is empty/new.
4651 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4652 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4653 old_contents = []
4654 env = dict(os.environ)
4655 env['PYTHONDONTWRITEBYTECODE'] = '1'
4656 process = self._input_api.subprocess.Popen(
4657 cmd + ' --output ""',
4658 shell=True,
4659 env=env,
4660 stdout=self._input_api.subprocess.PIPE,
4661 encoding='utf-8')
4662 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404663
4664
Tibor Goldschwendt360793f72019-06-25 18:23:494665def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504666 args = {}
4667 with open('build/config/gclient_args.gni', 'r') as f:
4668 for line in f:
4669 line = line.strip()
4670 if not line or line.startswith('#'):
4671 continue
4672 attribute, value = line.split('=')
4673 args[attribute.strip()] = value.strip()
4674 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494675
4676
Saagar Sanghavifceeaae2020-08-12 16:40:364677def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504678 """Checks if a .pydeps file needs to be regenerated."""
4679 # This check is for Python dependency lists (.pydeps files), and involves
4680 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4681 # doesn't work on Windows and Mac, so skip it on other platforms.
4682 if not input_api.platform.startswith('linux'):
4683 return []
Erik Staabc734cd7a2021-11-23 03:11:524684
Sam Maiera6e76d72022-02-11 21:43:504685 results = []
4686 # First, check for new / deleted .pydeps.
4687 for f in input_api.AffectedFiles(include_deletes=True):
4688 # Check whether we are running the presubmit check for a file in src.
4689 # f.LocalPath is relative to repo (src, or internal repo).
4690 # os_path.exists is relative to src repo.
4691 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4692 # to src and we can conclude that the pydeps is in src.
4693 if f.LocalPath().endswith('.pydeps'):
4694 if input_api.os_path.exists(f.LocalPath()):
4695 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4696 results.append(
4697 output_api.PresubmitError(
4698 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4699 'remove %s' % f.LocalPath()))
4700 elif f.Action() != 'D' and f.LocalPath(
4701 ) not in _ALL_PYDEPS_FILES:
4702 results.append(
4703 output_api.PresubmitError(
4704 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4705 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404706
Sam Maiera6e76d72022-02-11 21:43:504707 if results:
4708 return results
4709
4710 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4711 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4712 affected_pydeps = set(checker.ComputeAffectedPydeps())
4713 affected_android_pydeps = affected_pydeps.intersection(
4714 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4715 if affected_android_pydeps and not is_android:
4716 results.append(
4717 output_api.PresubmitPromptOrNotify(
4718 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594719 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504720 'run because you are not using an Android checkout. To validate that\n'
4721 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4722 'use the android-internal-presubmit optional trybot.\n'
4723 'Possibly stale pydeps files:\n{}'.format(
4724 '\n'.join(affected_android_pydeps))))
4725
4726 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4727 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4728 # Process these concurrently, as each one takes 1-2 seconds.
4729 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4730 for result in pydep_results:
4731 error_msg = result.GetError()
4732 if error_msg:
4733 results.append(output_api.PresubmitError(error_msg))
4734
agrievef32bcc72016-04-04 14:57:404735 return results
4736
agrievef32bcc72016-04-04 14:57:404737
Saagar Sanghavifceeaae2020-08-12 16:40:364738def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504739 """Checks to make sure no header files have |Singleton<|."""
4740
4741 def FileFilter(affected_file):
4742 # It's ok for base/memory/singleton.h to have |Singleton<|.
4743 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314744 (r"^base/memory/singleton\.h$",
4745 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504746 return input_api.FilterSourceFile(affected_file,
4747 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434748
Sam Maiera6e76d72022-02-11 21:43:504749 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4750 files = []
4751 for f in input_api.AffectedSourceFiles(FileFilter):
4752 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4753 or f.LocalPath().endswith('.hpp')
4754 or f.LocalPath().endswith('.inl')):
4755 contents = input_api.ReadFile(f)
4756 for line in contents.splitlines(False):
4757 if (not line.lstrip().startswith('//')
4758 and # Strip C++ comment.
4759 pattern.search(line)):
4760 files.append(f)
4761 break
glidere61efad2015-02-18 17:39:434762
Sam Maiera6e76d72022-02-11 21:43:504763 if files:
4764 return [
4765 output_api.PresubmitError(
4766 'Found base::Singleton<T> in the following header files.\n' +
4767 'Please move them to an appropriate source file so that the ' +
4768 'template gets instantiated in a single compilation unit.',
4769 files)
4770 ]
4771 return []
glidere61efad2015-02-18 17:39:434772
4773
jchaffraix@chromium.orgfd20b902014-05-09 02:14:534774_DEPRECATED_CSS = [
4775 # Values
4776 ( "-webkit-box", "flex" ),
4777 ( "-webkit-inline-box", "inline-flex" ),
4778 ( "-webkit-flex", "flex" ),
4779 ( "-webkit-inline-flex", "inline-flex" ),
4780 ( "-webkit-min-content", "min-content" ),
4781 ( "-webkit-max-content", "max-content" ),
4782
4783 # Properties
4784 ( "-webkit-background-clip", "background-clip" ),
4785 ( "-webkit-background-origin", "background-origin" ),
4786 ( "-webkit-background-size", "background-size" ),
4787 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444788 ( "-webkit-user-select", "user-select" ),
jchaffraix@chromium.orgfd20b902014-05-09 02:14:534789
4790 # Functions
4791 ( "-webkit-gradient", "gradient" ),
4792 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4793 ( "-webkit-linear-gradient", "linear-gradient" ),
4794 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4795 ( "-webkit-radial-gradient", "radial-gradient" ),
4796 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4797]
4798
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204799
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494800# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364801def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504802 """ Make sure that we don't use deprecated CSS
4803 properties, functions or values. Our external
4804 documentation and iOS CSS for dom distiller
4805 (reader mode) are ignored by the hooks as it
4806 needs to be consumed by WebKit. """
4807 results = []
4808 file_inclusion_pattern = [r".+\.css$"]
4809 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4810 input_api.DEFAULT_FILES_TO_SKIP +
4811 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4812 r"^native_client_sdk"))
4813 file_filter = lambda f: input_api.FilterSourceFile(
4814 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4815 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4816 for line_num, line in fpath.ChangedContents():
4817 for (deprecated_value, value) in _DEPRECATED_CSS:
4818 if deprecated_value in line:
4819 results.append(
4820 output_api.PresubmitError(
4821 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4822 (fpath.LocalPath(), line_num, deprecated_value,
4823 value)))
4824 return results
jchaffraix@chromium.orgfd20b902014-05-09 02:14:534825
mohan.reddyf21db962014-10-16 12:26:474826
Saagar Sanghavifceeaae2020-08-12 16:40:364827def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504828 bad_files = {}
4829 for f in input_api.AffectedFiles(include_deletes=False):
4830 if (f.LocalPath().startswith('third_party')
4831 and not f.LocalPath().startswith('third_party/blink')
4832 and not f.LocalPath().startswith('third_party\\blink')):
4833 continue
rlanday6802cf632017-05-30 17:48:364834
Sam Maiera6e76d72022-02-11 21:43:504835 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4836 continue
rlanday6802cf632017-05-30 17:48:364837
Sam Maiera6e76d72022-02-11 21:43:504838 relative_includes = [
4839 line for _, line in f.ChangedContents()
4840 if "#include" in line and "../" in line
4841 ]
4842 if not relative_includes:
4843 continue
4844 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364845
Sam Maiera6e76d72022-02-11 21:43:504846 if not bad_files:
4847 return []
rlanday6802cf632017-05-30 17:48:364848
Sam Maiera6e76d72022-02-11 21:43:504849 error_descriptions = []
4850 for file_path, bad_lines in bad_files.items():
4851 error_description = file_path
4852 for line in bad_lines:
4853 error_description += '\n ' + line
4854 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364855
Sam Maiera6e76d72022-02-11 21:43:504856 results = []
4857 results.append(
4858 output_api.PresubmitError(
4859 'You added one or more relative #include paths (including "../").\n'
4860 'These shouldn\'t be used because they can be used to include headers\n'
4861 'from code that\'s not correctly specified as a dependency in the\n'
4862 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364863
Sam Maiera6e76d72022-02-11 21:43:504864 return results
rlanday6802cf632017-05-30 17:48:364865
Takeshi Yoshinoe387aa32017-08-02 13:16:134866
Saagar Sanghavifceeaae2020-08-12 16:40:364867def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504868 """Check that nobody tries to include a cc file. It's a relatively
4869 common error which results in duplicate symbols in object
4870 files. This may not always break the build until someone later gets
4871 very confusing linking errors."""
4872 results = []
4873 for f in input_api.AffectedFiles(include_deletes=False):
4874 # We let third_party code do whatever it wants
4875 if (f.LocalPath().startswith('third_party')
4876 and not f.LocalPath().startswith('third_party/blink')
4877 and not f.LocalPath().startswith('third_party\\blink')):
4878 continue
Daniel Bratell65b033262019-04-23 08:17:064879
Sam Maiera6e76d72022-02-11 21:43:504880 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4881 continue
Daniel Bratell65b033262019-04-23 08:17:064882
Sam Maiera6e76d72022-02-11 21:43:504883 for _, line in f.ChangedContents():
4884 if line.startswith('#include "'):
4885 included_file = line.split('"')[1]
4886 if _IsCPlusPlusFile(input_api, included_file):
4887 # The most common naming for external files with C++ code,
4888 # apart from standard headers, is to call them foo.inc, but
4889 # Chromium sometimes uses foo-inc.cc so allow that as well.
4890 if not included_file.endswith(('.h', '-inc.cc')):
4891 results.append(
4892 output_api.PresubmitError(
4893 'Only header files or .inc files should be included in other\n'
4894 'C++ files. Compiling the contents of a cc file more than once\n'
4895 'will cause duplicate information in the build which may later\n'
4896 'result in strange link_errors.\n' +
4897 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064898
Sam Maiera6e76d72022-02-11 21:43:504899 return results
Daniel Bratell65b033262019-04-23 08:17:064900
4901
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204902def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504903 if not isinstance(key, ast.Str):
4904 return 'Key at line %d must be a string literal' % key.lineno
4905 if not isinstance(value, ast.Dict):
4906 return 'Value at line %d must be a dict' % value.lineno
4907 if len(value.keys) != 1:
4908 return 'Dict at line %d must have single entry' % value.lineno
4909 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4910 return (
4911 'Entry at line %d must have a string literal \'filepath\' as key' %
4912 value.lineno)
4913 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134914
Takeshi Yoshinoe387aa32017-08-02 13:16:134915
Sergey Ulanov4af16052018-11-08 02:41:464916def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504917 if not isinstance(key, ast.Str):
4918 return 'Key at line %d must be a string literal' % key.lineno
4919 if not isinstance(value, ast.List):
4920 return 'Value at line %d must be a list' % value.lineno
4921 for element in value.elts:
4922 if not isinstance(element, ast.Str):
4923 return 'Watchlist elements on line %d is not a string' % key.lineno
4924 if not email_regex.match(element.s):
4925 return ('Watchlist element on line %d doesn\'t look like a valid '
4926 + 'email: %s') % (key.lineno, element.s)
4927 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134928
Takeshi Yoshinoe387aa32017-08-02 13:16:134929
Sergey Ulanov4af16052018-11-08 02:41:464930def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504931 mismatch_template = (
4932 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4933 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134934
Sam Maiera6e76d72022-02-11 21:43:504935 email_regex = input_api.re.compile(
4936 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464937
Sam Maiera6e76d72022-02-11 21:43:504938 ast = input_api.ast
4939 i = 0
4940 last_key = ''
4941 while True:
4942 if i >= len(wd_dict.keys):
4943 if i >= len(w_dict.keys):
4944 return None
4945 return mismatch_template % ('missing',
4946 'line %d' % w_dict.keys[i].lineno)
4947 elif i >= len(w_dict.keys):
4948 return (mismatch_template %
4949 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134950
Sam Maiera6e76d72022-02-11 21:43:504951 wd_key = wd_dict.keys[i]
4952 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134953
Sam Maiera6e76d72022-02-11 21:43:504954 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4955 wd_dict.values[i], ast)
4956 if result is not None:
4957 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134958
Sam Maiera6e76d72022-02-11 21:43:504959 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4960 email_regex)
4961 if result is not None:
4962 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204963
Sam Maiera6e76d72022-02-11 21:43:504964 if wd_key.s != w_key.s:
4965 return mismatch_template % ('%s at line %d' %
4966 (wd_key.s, wd_key.lineno),
4967 '%s at line %d' %
4968 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204969
Sam Maiera6e76d72022-02-11 21:43:504970 if wd_key.s < last_key:
4971 return (
4972 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4973 % (wd_key.lineno, w_key.lineno))
4974 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204975
Sam Maiera6e76d72022-02-11 21:43:504976 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204977
4978
Sergey Ulanov4af16052018-11-08 02:41:464979def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504980 ast = input_api.ast
4981 if not isinstance(expression, ast.Expression):
4982 return 'WATCHLISTS file must contain a valid expression'
4983 dictionary = expression.body
4984 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4985 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204986
Sam Maiera6e76d72022-02-11 21:43:504987 first_key = dictionary.keys[0]
4988 first_value = dictionary.values[0]
4989 second_key = dictionary.keys[1]
4990 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204991
Sam Maiera6e76d72022-02-11 21:43:504992 if (not isinstance(first_key, ast.Str)
4993 or first_key.s != 'WATCHLIST_DEFINITIONS'
4994 or not isinstance(first_value, ast.Dict)):
4995 return ('The first entry of the dict in WATCHLISTS file must be '
4996 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204997
Sam Maiera6e76d72022-02-11 21:43:504998 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4999 or not isinstance(second_value, ast.Dict)):
5000 return ('The second entry of the dict in WATCHLISTS file must be '
5001 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205002
Sam Maiera6e76d72022-02-11 21:43:505003 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135004
5005
Saagar Sanghavifceeaae2020-08-12 16:40:365006def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505007 for f in input_api.AffectedFiles(include_deletes=False):
5008 if f.LocalPath() == 'WATCHLISTS':
5009 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135010
Sam Maiera6e76d72022-02-11 21:43:505011 try:
5012 # First, make sure that it can be evaluated.
5013 input_api.ast.literal_eval(contents)
5014 # Get an AST tree for it and scan the tree for detailed style checking.
5015 expression = input_api.ast.parse(contents,
5016 filename='WATCHLISTS',
5017 mode='eval')
5018 except ValueError as e:
5019 return [
5020 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5021 long_text=repr(e))
5022 ]
5023 except SyntaxError as e:
5024 return [
5025 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5026 long_text=repr(e))
5027 ]
5028 except TypeError as e:
5029 return [
5030 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5031 long_text=repr(e))
5032 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135033
Sam Maiera6e76d72022-02-11 21:43:505034 result = _CheckWATCHLISTSSyntax(expression, input_api)
5035 if result is not None:
5036 return [output_api.PresubmitError(result)]
5037 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135038
Sam Maiera6e76d72022-02-11 21:43:505039 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135040
Sean Kaucb7c9b32022-10-25 21:25:525041def CheckGnRebasePath(input_api, output_api):
5042 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
5043
5044 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5045 Chromium is sometimes built outside of the source tree.
5046 """
5047
5048 def gn_files(f):
5049 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5050
5051 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
5052 problems = []
5053 for f in input_api.AffectedSourceFiles(gn_files):
5054 for line_num, line in f.ChangedContents():
5055 if rebase_path_regex.search(line):
5056 problems.append(
5057 'Absolute path in rebase_path() in %s:%d' %
5058 (f.LocalPath(), line_num))
5059
5060 if problems:
5061 return [
5062 output_api.PresubmitPromptWarning(
5063 'Using an absolute path in rebase_path()',
5064 items=sorted(problems),
5065 long_text=(
5066 'rebase_path() should use root_build_dir instead of "/" ',
5067 'since builds can be initiated from outside of the source ',
5068 'root.'))
5069 ]
5070 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135071
Andrew Grieve1b290e4a22020-11-24 20:07:015072def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505073 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015074
Sam Maiera6e76d72022-02-11 21:43:505075 As documented at //build/docs/writing_gn_templates.md
5076 """
Andrew Grieve1b290e4a22020-11-24 20:07:015077
Sam Maiera6e76d72022-02-11 21:43:505078 def gn_files(f):
5079 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015080
Sam Maiera6e76d72022-02-11 21:43:505081 problems = []
5082 for f in input_api.AffectedSourceFiles(gn_files):
5083 for line_num, line in f.ChangedContents():
5084 if 'forward_variables_from(invoker, "*")' in line:
5085 problems.append(
5086 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5087 (f.LocalPath(), line_num))
5088
5089 if problems:
5090 return [
5091 output_api.PresubmitPromptWarning(
5092 'forward_variables_from("*") without exclusions',
5093 items=sorted(problems),
5094 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595095 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505096 'explicitly listed in forward_variables_from(). For more '
5097 'details, see:\n'
5098 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5099 'build/docs/writing_gn_templates.md'
5100 '#Using-forward_variables_from'))
5101 ]
5102 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015103
Saagar Sanghavifceeaae2020-08-12 16:40:365104def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505105 """Checks that newly added header files have corresponding GN changes.
5106 Note that this is only a heuristic. To be precise, run script:
5107 build/check_gn_headers.py.
5108 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195109
Sam Maiera6e76d72022-02-11 21:43:505110 def headers(f):
5111 return input_api.FilterSourceFile(
5112 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195113
Sam Maiera6e76d72022-02-11 21:43:505114 new_headers = []
5115 for f in input_api.AffectedSourceFiles(headers):
5116 if f.Action() != 'A':
5117 continue
5118 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195119
Sam Maiera6e76d72022-02-11 21:43:505120 def gn_files(f):
5121 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195122
Sam Maiera6e76d72022-02-11 21:43:505123 all_gn_changed_contents = ''
5124 for f in input_api.AffectedSourceFiles(gn_files):
5125 for _, line in f.ChangedContents():
5126 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195127
Sam Maiera6e76d72022-02-11 21:43:505128 problems = []
5129 for header in new_headers:
5130 basename = input_api.os_path.basename(header)
5131 if basename not in all_gn_changed_contents:
5132 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195133
Sam Maiera6e76d72022-02-11 21:43:505134 if problems:
5135 return [
5136 output_api.PresubmitPromptWarning(
5137 'Missing GN changes for new header files',
5138 items=sorted(problems),
5139 long_text=
5140 'Please double check whether newly added header files need '
5141 'corresponding changes in gn or gni files.\nThis checking is only a '
5142 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5143 'Read https://crbug.com/661774 for more info.')
5144 ]
5145 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195146
5147
Saagar Sanghavifceeaae2020-08-12 16:40:365148def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505149 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025150
Sam Maiera6e76d72022-02-11 21:43:505151 This assumes we won't intentionally reference one product from the other
5152 product.
5153 """
5154 all_problems = []
5155 test_cases = [{
5156 "filename_postfix": "google_chrome_strings.grd",
5157 "correct_name": "Chrome",
5158 "incorrect_name": "Chromium",
5159 }, {
Thiago Perrotta099034f2023-06-05 18:10:205160 "filename_postfix": "google_chrome_strings.grd",
5161 "correct_name": "Chrome",
5162 "incorrect_name": "Chrome for Testing",
5163 }, {
Sam Maiera6e76d72022-02-11 21:43:505164 "filename_postfix": "chromium_strings.grd",
5165 "correct_name": "Chromium",
5166 "incorrect_name": "Chrome",
5167 }]
Michael Giuffridad3bc8672018-10-25 22:48:025168
Sam Maiera6e76d72022-02-11 21:43:505169 for test_case in test_cases:
5170 problems = []
5171 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5172 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025173
Sam Maiera6e76d72022-02-11 21:43:505174 # Check each new line. Can yield false positives in multiline comments, but
5175 # easier than trying to parse the XML because messages can have nested
5176 # children, and associating message elements with affected lines is hard.
5177 for f in input_api.AffectedSourceFiles(filename_filter):
5178 for line_num, line in f.ChangedContents():
5179 if "<message" in line or "<!--" in line or "-->" in line:
5180 continue
5181 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205182 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5183 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5184 continue
Sam Maiera6e76d72022-02-11 21:43:505185 problems.append("Incorrect product name in %s:%d" %
5186 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025187
Sam Maiera6e76d72022-02-11 21:43:505188 if problems:
5189 message = (
5190 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5191 % (test_case["correct_name"], test_case["correct_name"],
5192 test_case["incorrect_name"]))
5193 all_problems.append(
5194 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025195
Sam Maiera6e76d72022-02-11 21:43:505196 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025197
5198
Saagar Sanghavifceeaae2020-08-12 16:40:365199def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505200 """Avoid large files, especially binary files, in the repository since
5201 git doesn't scale well for those. They will be in everyone's repo
5202 clones forever, forever making Chromium slower to clone and work
5203 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365204
Sam Maiera6e76d72022-02-11 21:43:505205 # Uploading files to cloud storage is not trivial so we don't want
5206 # to set the limit too low, but the upper limit for "normal" large
5207 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5208 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255209 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365210
Sam Maiera6e76d72022-02-11 21:43:505211 too_large_files = []
5212 for f in input_api.AffectedFiles():
5213 # Check both added and modified files (but not deleted files).
5214 if f.Action() in ('A', 'M'):
5215 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185216 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505217 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365218
Sam Maiera6e76d72022-02-11 21:43:505219 if too_large_files:
5220 message = (
5221 'Do not commit large files to git since git scales badly for those.\n'
5222 +
5223 'Instead put the large files in cloud storage and use DEPS to\n' +
5224 'fetch them.\n' + '\n'.join(too_large_files))
5225 return [
5226 output_api.PresubmitError('Too large files found in commit',
5227 long_text=message + '\n')
5228 ]
5229 else:
5230 return []
Daniel Bratell93eb6c62019-04-29 20:13:365231
Max Morozb47503b2019-08-08 21:03:275232
Saagar Sanghavifceeaae2020-08-12 16:40:365233def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505234 """Checks specific for fuzz target sources."""
5235 EXPORTED_SYMBOLS = [
5236 'LLVMFuzzerInitialize',
5237 'LLVMFuzzerCustomMutator',
5238 'LLVMFuzzerCustomCrossOver',
5239 'LLVMFuzzerMutate',
5240 ]
Max Morozb47503b2019-08-08 21:03:275241
Sam Maiera6e76d72022-02-11 21:43:505242 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275243
Sam Maiera6e76d72022-02-11 21:43:505244 def FilterFile(affected_file):
5245 """Ignore libFuzzer source code."""
5246 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315247 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275248
Sam Maiera6e76d72022-02-11 21:43:505249 return input_api.FilterSourceFile(affected_file,
5250 files_to_check=[files_to_check],
5251 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275252
Sam Maiera6e76d72022-02-11 21:43:505253 files_with_missing_header = []
5254 for f in input_api.AffectedSourceFiles(FilterFile):
5255 contents = input_api.ReadFile(f, 'r')
5256 if REQUIRED_HEADER in contents:
5257 continue
Max Morozb47503b2019-08-08 21:03:275258
Sam Maiera6e76d72022-02-11 21:43:505259 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5260 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275261
Sam Maiera6e76d72022-02-11 21:43:505262 if not files_with_missing_header:
5263 return []
Max Morozb47503b2019-08-08 21:03:275264
Sam Maiera6e76d72022-02-11 21:43:505265 long_text = (
5266 'If you define any of the libFuzzer optional functions (%s), it is '
5267 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5268 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5269 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5270 'to access command line arguments passed to the fuzzer. Instead, prefer '
5271 'static initialization and shared resources as documented in '
5272 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5273 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5274 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275275
Sam Maiera6e76d72022-02-11 21:43:505276 return [
5277 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5278 REQUIRED_HEADER,
5279 items=files_with_missing_header,
5280 long_text=long_text)
5281 ]
Max Morozb47503b2019-08-08 21:03:275282
5283
Mohamed Heikald048240a2019-11-12 16:57:375284def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505285 """
5286 Warns authors who add images into the repo to make sure their images are
5287 optimized before committing.
5288 """
5289 images_added = False
5290 image_paths = []
5291 errors = []
5292 filter_lambda = lambda x: input_api.FilterSourceFile(
5293 x,
5294 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5295 DEFAULT_FILES_TO_SKIP),
5296 files_to_check=[r'.*\/(drawable|mipmap)'])
5297 for f in input_api.AffectedFiles(include_deletes=False,
5298 file_filter=filter_lambda):
5299 local_path = f.LocalPath().lower()
5300 if any(
5301 local_path.endswith(extension)
5302 for extension in _IMAGE_EXTENSIONS):
5303 images_added = True
5304 image_paths.append(f)
5305 if images_added:
5306 errors.append(
5307 output_api.PresubmitPromptWarning(
5308 'It looks like you are trying to commit some images. If these are '
5309 'non-test-only images, please make sure to read and apply the tips in '
5310 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5311 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5312 'FYI only and will not block your CL on the CQ.', image_paths))
5313 return errors
Mohamed Heikald048240a2019-11-12 16:57:375314
5315
Saagar Sanghavifceeaae2020-08-12 16:40:365316def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505317 """Groups upload checks that target android code."""
5318 results = []
5319 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5320 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5321 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5322 results.extend(_CheckAndroidToastUsage(input_api, output_api))
5323 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
5324 results.extend(_CheckAndroidTestJUnitFrameworkImport(
5325 input_api, output_api))
5326 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5327 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5328 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5329 results.extend(_CheckNewImagesWarning(input_api, output_api))
5330 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5331 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5332 return results
5333
Becky Zhou7c69b50992018-12-10 19:37:575334
Saagar Sanghavifceeaae2020-08-12 16:40:365335def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505336 """Groups commit checks that target android code."""
5337 results = []
5338 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5339 return results
dgnaa68d5e2015-06-10 10:08:225340
Chris Hall59f8d0c72020-05-01 07:31:195341# TODO(chrishall): could we additionally match on any path owned by
5342# ui/accessibility/OWNERS ?
5343_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315344 r"^chrome/browser.*/accessibility/",
5345 r"^chrome/browser/extensions/api/automation.*/",
5346 r"^chrome/renderer/extensions/accessibility_.*",
5347 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:175348 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315349 r"^content/browser/accessibility/",
5350 r"^content/renderer/accessibility/",
5351 r"^content/tests/data/accessibility/",
5352 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175353 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:315354 r"^ui/accessibility/",
5355 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195356)
5357
Saagar Sanghavifceeaae2020-08-12 16:40:365358def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505359 """Checks that commits to accessibility code contain an AX-Relnotes field in
5360 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195361
Sam Maiera6e76d72022-02-11 21:43:505362 def FileFilter(affected_file):
5363 paths = _ACCESSIBILITY_PATHS
5364 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195365
Sam Maiera6e76d72022-02-11 21:43:505366 # Only consider changes affecting accessibility paths.
5367 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5368 return []
Akihiro Ota08108e542020-05-20 15:30:535369
Sam Maiera6e76d72022-02-11 21:43:505370 # AX-Relnotes can appear in either the description or the footer.
5371 # When searching the description, require 'AX-Relnotes:' to appear at the
5372 # beginning of a line.
5373 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5374 description_has_relnotes = any(
5375 ax_regex.match(line)
5376 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195377
Sam Maiera6e76d72022-02-11 21:43:505378 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5379 'AX-Relnotes', [])
5380 if description_has_relnotes or footer_relnotes:
5381 return []
Chris Hall59f8d0c72020-05-01 07:31:195382
Sam Maiera6e76d72022-02-11 21:43:505383 # TODO(chrishall): link to Relnotes documentation in message.
5384 message = (
5385 "Missing 'AX-Relnotes:' field required for accessibility changes"
5386 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5387 "user-facing changes"
5388 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5389 "user-facing effects"
5390 "\n if this is confusing or annoying then please contact members "
5391 "of ui/accessibility/OWNERS.")
5392
5393 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225394
Mark Schillacie5a0be22022-01-19 00:38:395395
5396_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315397 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395398)
5399
5400_ACCESSIBILITY_TREE_TEST_PATH = (
Aaron Leventhal267119f2023-08-18 22:45:345401 r"^content/test/data/accessibility/accname/"
5402 ".*-expected-(mac|win|uia-win|auralinux).txt",
5403 r"^content/test/data/accessibility/aria/"
5404 ".*-expected-(mac|win|uia-win|auralinux).txt",
5405 r"^content/test/data/accessibility/css/"
5406 ".*-expected-(mac|win|uia-win|auralinux).txt",
5407 r"^content/test/data/accessibility/event/"
5408 ".*-expected-(mac|win|uia-win|auralinux).txt",
5409 r"^content/test/data/accessibility/html/"
5410 ".*-expected-(mac|win|uia-win|auralinux).txt",
Mark Schillacie5a0be22022-01-19 00:38:395411)
5412
5413_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315414 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395415)
5416
5417_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315418 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395419)
5420
5421def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505422 """Checks that commits that include a newly added, renamed/moved, or deleted
5423 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5424 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395425
Sam Maiera6e76d72022-02-11 21:43:505426 def FilePathFilter(affected_file):
5427 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5428 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395429
Sam Maiera6e76d72022-02-11 21:43:505430 def AndroidFilePathFilter(affected_file):
5431 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5432 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395433
Sam Maiera6e76d72022-02-11 21:43:505434 # Only consider changes in the events test data path with html type.
5435 if not any(
5436 input_api.AffectedFiles(include_deletes=True,
5437 file_filter=FilePathFilter)):
5438 return []
Mark Schillacie5a0be22022-01-19 00:38:395439
Sam Maiera6e76d72022-02-11 21:43:505440 # If the commit contains any change to the Android test file, ignore.
5441 if any(
5442 input_api.AffectedFiles(include_deletes=True,
5443 file_filter=AndroidFilePathFilter)):
5444 return []
Mark Schillacie5a0be22022-01-19 00:38:395445
Sam Maiera6e76d72022-02-11 21:43:505446 # Only consider changes that are adding/renaming or deleting a file
5447 message = []
5448 for f in input_api.AffectedFiles(include_deletes=True,
5449 file_filter=FilePathFilter):
Aaron Leventhal267119f2023-08-18 22:45:345450 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505451 message = (
Aaron Leventhal267119f2023-08-18 22:45:345452 "It appears that you are adding platform expectations for a"
Aaron Leventhal0de81072023-08-21 21:26:525453 "\ndump_accessibility_events* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505454 "\na corresponding change for Android."
Aaron Leventhal267119f2023-08-18 22:45:345455 "\nPlease include the test from:"
Sam Maiera6e76d72022-02-11 21:43:505456 "\n content/public/android/javatests/src/org/chromium/"
5457 "content/browser/accessibility/"
5458 "WebContentsAccessibilityEventsTest.java"
5459 "\nIf this message is confusing or annoying, please contact"
5460 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395461
Sam Maiera6e76d72022-02-11 21:43:505462 # If no message was set, return empty.
5463 if not len(message):
5464 return []
5465
5466 return [output_api.PresubmitPromptWarning(message)]
5467
Mark Schillacie5a0be22022-01-19 00:38:395468
5469def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505470 """Checks that commits that include a newly added, renamed/moved, or deleted
5471 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5472 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395473
Sam Maiera6e76d72022-02-11 21:43:505474 def FilePathFilter(affected_file):
5475 paths = _ACCESSIBILITY_TREE_TEST_PATH
5476 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395477
Sam Maiera6e76d72022-02-11 21:43:505478 def AndroidFilePathFilter(affected_file):
5479 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5480 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395481
Sam Maiera6e76d72022-02-11 21:43:505482 # Only consider changes in the various tree test data paths with html type.
5483 if not any(
5484 input_api.AffectedFiles(include_deletes=True,
5485 file_filter=FilePathFilter)):
5486 return []
Mark Schillacie5a0be22022-01-19 00:38:395487
Sam Maiera6e76d72022-02-11 21:43:505488 # If the commit contains any change to the Android test file, ignore.
5489 if any(
5490 input_api.AffectedFiles(include_deletes=True,
5491 file_filter=AndroidFilePathFilter)):
5492 return []
Mark Schillacie5a0be22022-01-19 00:38:395493
Sam Maiera6e76d72022-02-11 21:43:505494 # Only consider changes that are adding/renaming or deleting a file
5495 message = []
5496 for f in input_api.AffectedFiles(include_deletes=True,
5497 file_filter=FilePathFilter):
Aaron Leventhal0de81072023-08-21 21:26:525498 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505499 message = (
Aaron Leventhal0de81072023-08-21 21:26:525500 "It appears that you are adding platform expectations for a"
5501 "\ndump_accessibility_tree* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505502 "\na corresponding change for Android."
5503 "\nPlease include (or remove) the test from:"
5504 "\n content/public/android/javatests/src/org/chromium/"
5505 "content/browser/accessibility/"
5506 "WebContentsAccessibilityTreeTest.java"
5507 "\nIf this message is confusing or annoying, please contact"
5508 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395509
Sam Maiera6e76d72022-02-11 21:43:505510 # If no message was set, return empty.
5511 if not len(message):
5512 return []
5513
5514 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395515
5516
Bruce Dawson33806592022-11-16 01:44:515517def CheckEsLintConfigChanges(input_api, output_api):
5518 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
5519 modified. This is important because enabling an error in .eslintrc.js can
5520 trigger errors in any .js or .ts files in its directory, leading to hidden
5521 presubmit errors."""
5522 results = []
5523 eslint_filter = lambda f: input_api.FilterSourceFile(
5524 f, files_to_check=[r'.*\.eslintrc\.js$'])
5525 for f in input_api.AffectedFiles(include_deletes=False,
5526 file_filter=eslint_filter):
5527 local_dir = input_api.os_path.dirname(f.LocalPath())
5528 # Use / characters so that the commands printed work on any OS.
5529 local_dir = local_dir.replace(input_api.os_path.sep, '/')
5530 if local_dir:
5531 local_dir += '/'
5532 results.append(
5533 output_api.PresubmitNotifyResult(
5534 '%(file)s modified. Consider running \'git cl presubmit --files '
5535 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
5536 'files before landing this change.' %
5537 { 'file' : f.LocalPath(), 'dir' : local_dir}))
5538 return results
5539
5540
seanmccullough4a9356252021-04-08 19:54:095541# string pattern, sequence of strings to show when pattern matches,
5542# error flag. True if match is a presubmit error, otherwise it's a warning.
5543_NON_INCLUSIVE_TERMS = (
5544 (
5545 # Note that \b pattern in python re is pretty particular. In this
5546 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5547 # ...' will not. This may require some tweaking to catch these cases
5548 # without triggering a lot of false positives. Leaving it naive and
5549 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:025550 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:095551 (
5552 'Please don\'t use blacklist, whitelist, ' # nocheck
5553 'or slave in your', # nocheck
5554 'code and make every effort to use other terms. Using "// nocheck"',
5555 '"# nocheck" or "<!-- nocheck -->"',
5556 'at the end of the offending line will bypass this PRESUBMIT error',
5557 'but avoid using this whenever possible. Reach out to',
5558 'community@chromium.org if you have questions'),
5559 True),)
5560
Saagar Sanghavifceeaae2020-08-12 16:40:365561def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505562 """Checks common to both upload and commit."""
5563 results = []
Eric Boren6fd2b932018-01-25 15:05:085564 results.extend(
Sam Maiera6e76d72022-02-11 21:43:505565 input_api.canned_checks.PanProjectChecks(
5566 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:085567
Sam Maiera6e76d72022-02-11 21:43:505568 author = input_api.change.author_email
5569 if author and author not in _KNOWN_ROBOTS:
5570 results.extend(
5571 input_api.canned_checks.CheckAuthorizedAuthor(
5572 input_api, output_api))
marja@chromium.org2299dcf2012-11-15 19:56:245573
Sam Maiera6e76d72022-02-11 21:43:505574 results.extend(
5575 input_api.canned_checks.CheckChangeHasNoTabs(
5576 input_api,
5577 output_api,
5578 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
5579 results.extend(
5580 input_api.RunTests(
5581 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:175582
Bruce Dawsonc8054482022-03-28 15:33:375583 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:505584 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:375585 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:505586 results.extend(
5587 input_api.RunTests(
5588 input_api.canned_checks.CheckDirMetadataFormat(
5589 input_api, output_api, dirmd_bin)))
5590 results.extend(
5591 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
5592 input_api, output_api))
5593 results.extend(
5594 input_api.canned_checks.CheckNoNewMetadataInOwners(
5595 input_api, output_api))
5596 results.extend(
5597 input_api.canned_checks.CheckInclusiveLanguage(
5598 input_api,
5599 output_api,
5600 excluded_directories_relative_path=[
5601 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
5602 ],
5603 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:595604
Aleksey Khoroshilov2978c942022-06-13 16:14:125605 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:475606 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:125607 for f in input_api.AffectedFiles(include_deletes=False,
5608 file_filter=presubmit_py_filter):
5609 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
5610 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
5611 # The PRESUBMIT.py file (and the directory containing it) might have
5612 # been affected by being moved or removed, so only try to run the tests
5613 # if they still exist.
5614 if not input_api.os_path.exists(test_file):
5615 continue
Sam Maiera6e76d72022-02-11 21:43:505616
Aleksey Khoroshilov2978c942022-06-13 16:14:125617 results.extend(
5618 input_api.canned_checks.RunUnitTestsInDirectory(
5619 input_api,
5620 output_api,
5621 full_path,
Takuto Ikuta40def482023-06-02 02:23:495622 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:505623 return results
maruel@chromium.org1f7b4172010-01-28 01:17:345624
maruel@chromium.orgb337cb5b2011-01-23 21:24:055625
Saagar Sanghavifceeaae2020-08-12 16:40:365626def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505627 problems = [
5628 f.LocalPath() for f in input_api.AffectedFiles()
5629 if f.LocalPath().endswith(('.orig', '.rej'))
5630 ]
5631 # Cargo.toml.orig files are part of third-party crates downloaded from
5632 # crates.io and should be included.
5633 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5634 if problems:
5635 return [
5636 output_api.PresubmitError("Don't commit .rej and .orig files.",
5637 problems)
5638 ]
5639 else:
5640 return []
enne@chromium.orgb8079ae4a2012-12-05 19:56:495641
5642
Saagar Sanghavifceeaae2020-08-12 16:40:365643def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505644 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5645 macro_re = input_api.re.compile(
5646 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5647 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5648 input_api.re.MULTILINE)
5649 extension_re = input_api.re.compile(r'\.[a-z]+$')
5650 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005651 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505652 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005653 # The build-config macros are allowed to be used in build_config.h
5654 # without including itself.
5655 if f.LocalPath() == config_h_file:
5656 continue
Sam Maiera6e76d72022-02-11 21:43:505657 if not f.LocalPath().endswith(
5658 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5659 continue
5660 found_line_number = None
5661 found_macro = None
5662 all_lines = input_api.ReadFile(f, 'r').splitlines()
5663 for line_num, line in enumerate(all_lines):
5664 match = macro_re.search(line)
5665 if match:
5666 found_line_number = line_num
5667 found_macro = match.group(2)
5668 break
5669 if not found_line_number:
5670 continue
Kent Tamura5a8755d2017-06-29 23:37:075671
Sam Maiera6e76d72022-02-11 21:43:505672 found_include_line = -1
5673 for line_num, line in enumerate(all_lines):
5674 if include_re.search(line):
5675 found_include_line = line_num
5676 break
5677 if found_include_line >= 0 and found_include_line < found_line_number:
5678 continue
Kent Tamura5a8755d2017-06-29 23:37:075679
Sam Maiera6e76d72022-02-11 21:43:505680 if not f.LocalPath().endswith('.h'):
5681 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5682 try:
5683 content = input_api.ReadFile(primary_header_path, 'r')
5684 if include_re.search(content):
5685 continue
5686 except IOError:
5687 pass
5688 errors.append('%s:%d %s macro is used without first including build/'
5689 'build_config.h.' %
5690 (f.LocalPath(), found_line_number, found_macro))
5691 if errors:
5692 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5693 return []
Kent Tamura5a8755d2017-06-29 23:37:075694
5695
Lei Zhang1c12a22f2021-05-12 11:28:455696def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505697 stl_include_re = input_api.re.compile(r'^#include\s+<('
5698 r'algorithm|'
5699 r'array|'
5700 r'limits|'
5701 r'list|'
5702 r'map|'
5703 r'memory|'
5704 r'queue|'
5705 r'set|'
5706 r'string|'
5707 r'unordered_map|'
5708 r'unordered_set|'
5709 r'utility|'
5710 r'vector)>')
5711 std_namespace_re = input_api.re.compile(r'std::')
5712 errors = []
5713 for f in input_api.AffectedFiles():
5714 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5715 continue
Lei Zhang1c12a22f2021-05-12 11:28:455716
Sam Maiera6e76d72022-02-11 21:43:505717 uses_std_namespace = False
5718 has_stl_include = False
5719 for line in f.NewContents():
5720 if has_stl_include and uses_std_namespace:
5721 break
Lei Zhang1c12a22f2021-05-12 11:28:455722
Sam Maiera6e76d72022-02-11 21:43:505723 if not has_stl_include and stl_include_re.search(line):
5724 has_stl_include = True
5725 continue
Lei Zhang1c12a22f2021-05-12 11:28:455726
Bruce Dawson4a5579a2022-04-08 17:11:365727 if not uses_std_namespace and (std_namespace_re.search(line)
5728 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505729 uses_std_namespace = True
5730 continue
Lei Zhang1c12a22f2021-05-12 11:28:455731
Sam Maiera6e76d72022-02-11 21:43:505732 if has_stl_include and not uses_std_namespace:
5733 errors.append(
5734 '%s: Includes STL header(s) but does not reference std::' %
5735 f.LocalPath())
5736 if errors:
5737 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5738 return []
Lei Zhang1c12a22f2021-05-12 11:28:455739
5740
Xiaohan Wang42d96c22022-01-20 17:23:115741def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505742 """Check for sensible looking, totally invalid OS macros."""
5743 preprocessor_statement = input_api.re.compile(r'^\s*#')
5744 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5745 results = []
5746 for lnum, line in f.ChangedContents():
5747 if preprocessor_statement.search(line):
5748 for match in os_macro.finditer(line):
5749 results.append(
5750 ' %s:%d: %s' %
5751 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5752 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5753 return results
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545754
5755
Xiaohan Wang42d96c22022-01-20 17:23:115756def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505757 """Check all affected files for invalid OS macros."""
5758 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005759 # The OS_ macros are allowed to be used in build/build_config.h.
5760 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505761 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005762 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5763 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505764 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545765
Sam Maiera6e76d72022-02-11 21:43:505766 if not bad_macros:
5767 return []
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545768
Sam Maiera6e76d72022-02-11 21:43:505769 return [
5770 output_api.PresubmitError(
5771 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5772 'defined in build_config.h):', bad_macros)
5773 ]
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545774
lliabraa35bab3932014-10-01 12:16:445775
5776def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505777 """Check all affected files for invalid "if defined" macros."""
5778 ALWAYS_DEFINED_MACROS = (
5779 "TARGET_CPU_PPC",
5780 "TARGET_CPU_PPC64",
5781 "TARGET_CPU_68K",
5782 "TARGET_CPU_X86",
5783 "TARGET_CPU_ARM",
5784 "TARGET_CPU_MIPS",
5785 "TARGET_CPU_SPARC",
5786 "TARGET_CPU_ALPHA",
5787 "TARGET_IPHONE_SIMULATOR",
5788 "TARGET_OS_EMBEDDED",
5789 "TARGET_OS_IPHONE",
5790 "TARGET_OS_MAC",
5791 "TARGET_OS_UNIX",
5792 "TARGET_OS_WIN32",
5793 )
5794 ifdef_macro = input_api.re.compile(
5795 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5796 results = []
5797 for lnum, line in f.ChangedContents():
5798 for match in ifdef_macro.finditer(line):
5799 if match.group(1) in ALWAYS_DEFINED_MACROS:
5800 always_defined = ' %s is always defined. ' % match.group(1)
5801 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5802 results.append(
5803 ' %s:%d %s\n\t%s' %
5804 (f.LocalPath(), lnum, always_defined, did_you_mean))
5805 return results
lliabraa35bab3932014-10-01 12:16:445806
5807
Saagar Sanghavifceeaae2020-08-12 16:40:365808def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505809 """Check all affected files for invalid "if defined" macros."""
5810 bad_macros = []
5811 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5812 for f in input_api.AffectedFiles():
5813 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5814 continue
5815 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5816 bad_macros.extend(
5817 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445818
Sam Maiera6e76d72022-02-11 21:43:505819 if not bad_macros:
5820 return []
lliabraa35bab3932014-10-01 12:16:445821
Sam Maiera6e76d72022-02-11 21:43:505822 return [
5823 output_api.PresubmitError(
5824 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5825 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5826 bad_macros)
5827 ]
lliabraa35bab3932014-10-01 12:16:445828
5829
Saagar Sanghavifceeaae2020-08-12 16:40:365830def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505831 """Check for same IPC rules described in
5832 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5833 """
5834 base_pattern = r'IPC_ENUM_TRAITS\('
5835 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5836 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045837
Sam Maiera6e76d72022-02-11 21:43:505838 problems = []
5839 for f in input_api.AffectedSourceFiles(None):
5840 local_path = f.LocalPath()
5841 if not local_path.endswith('.h'):
5842 continue
5843 for line_number, line in f.ChangedContents():
5844 if inclusion_pattern.search(
5845 line) and not comment_pattern.search(line):
5846 problems.append('%s:%d\n %s' %
5847 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045848
Sam Maiera6e76d72022-02-11 21:43:505849 if problems:
5850 return [
5851 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5852 problems)
5853 ]
5854 else:
5855 return []
mlamouria82272622014-09-16 18:45:045856
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545857
Saagar Sanghavifceeaae2020-08-12 16:40:365858def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505859 """Check to make sure no files being submitted have long paths.
5860 This causes issues on Windows.
5861 """
5862 problems = []
5863 for f in input_api.AffectedTestableFiles():
5864 local_path = f.LocalPath()
5865 # Windows has a path limit of 260 characters. Limit path length to 200 so
5866 # that we have some extra for the prefix on dev machines and the bots.
5867 if len(local_path) > 200:
5868 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055869
Sam Maiera6e76d72022-02-11 21:43:505870 if problems:
5871 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5872 else:
5873 return []
Stephen Martinis97a394142018-06-07 23:06:055874
5875
Saagar Sanghavifceeaae2020-08-12 16:40:365876def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505877 """Check that header files have proper guards against multiple inclusion.
5878 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365879 should include the string "no-include-guard-because-multiply-included" or
5880 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505881 """
Daniel Bratell8ba52722018-03-02 16:06:145882
Sam Maiera6e76d72022-02-11 21:43:505883 def is_chromium_header_file(f):
5884 # We only check header files under the control of the Chromium
5885 # project. That is, those outside third_party apart from
5886 # third_party/blink.
5887 # We also exclude *_message_generator.h headers as they use
5888 # include guards in a special, non-typical way.
5889 file_with_path = input_api.os_path.normpath(f.LocalPath())
5890 return (file_with_path.endswith('.h')
5891 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335892 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505893 and (not file_with_path.startswith('third_party')
5894 or file_with_path.startswith(
5895 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145896
Sam Maiera6e76d72022-02-11 21:43:505897 def replace_special_with_underscore(string):
5898 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145899
Sam Maiera6e76d72022-02-11 21:43:505900 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145901
Sam Maiera6e76d72022-02-11 21:43:505902 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5903 guard_name = None
5904 guard_line_number = None
5905 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145906
Sam Maiera6e76d72022-02-11 21:43:505907 file_with_path = input_api.os_path.normpath(f.LocalPath())
5908 base_file_name = input_api.os_path.splitext(
5909 input_api.os_path.basename(file_with_path))[0]
5910 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145911
Sam Maiera6e76d72022-02-11 21:43:505912 expected_guard = replace_special_with_underscore(
5913 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145914
Sam Maiera6e76d72022-02-11 21:43:505915 # For "path/elem/file_name.h" we should really only accept
5916 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5917 # are too many (1000+) files with slight deviations from the
5918 # coding style. The most important part is that the include guard
5919 # is there, and that it's unique, not the name so this check is
5920 # forgiving for existing files.
5921 #
5922 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145923
Sam Maiera6e76d72022-02-11 21:43:505924 guard_name_pattern_list = [
5925 # Anything with the right suffix (maybe with an extra _).
5926 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145927
Sam Maiera6e76d72022-02-11 21:43:505928 # To cover include guards with old Blink style.
5929 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145930
Sam Maiera6e76d72022-02-11 21:43:505931 # Anything including the uppercase name of the file.
5932 r'\w*' + input_api.re.escape(
5933 replace_special_with_underscore(upper_base_file_name)) +
5934 r'\w*',
5935 ]
5936 guard_name_pattern = '|'.join(guard_name_pattern_list)
5937 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5938 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145939
Sam Maiera6e76d72022-02-11 21:43:505940 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365941 if ('no-include-guard-because-multiply-included' in line
5942 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505943 guard_name = 'DUMMY' # To not trigger check outside the loop.
5944 break
Daniel Bratell8ba52722018-03-02 16:06:145945
Sam Maiera6e76d72022-02-11 21:43:505946 if guard_name is None:
5947 match = guard_pattern.match(line)
5948 if match:
5949 guard_name = match.group(1)
5950 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145951
Sam Maiera6e76d72022-02-11 21:43:505952 # We allow existing files to use include guards whose names
5953 # don't match the chromium style guide, but new files should
5954 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495955 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165956 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505957 errors.append(
5958 output_api.PresubmitPromptWarning(
5959 'Header using the wrong include guard name %s'
5960 % guard_name, [
5961 '%s:%d' %
5962 (f.LocalPath(), line_number + 1)
5963 ], 'Expected: %r\nFound: %r' %
5964 (expected_guard, guard_name)))
5965 else:
5966 # The line after #ifndef should have a #define of the same name.
5967 if line_number == guard_line_number + 1:
5968 expected_line = '#define %s' % guard_name
5969 if line != expected_line:
5970 errors.append(
5971 output_api.PresubmitPromptWarning(
5972 'Missing "%s" for include guard' %
5973 expected_line,
5974 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5975 'Expected: %r\nGot: %r' %
5976 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145977
Sam Maiera6e76d72022-02-11 21:43:505978 if not seen_guard_end and line == '#endif // %s' % guard_name:
5979 seen_guard_end = True
5980 elif seen_guard_end:
5981 if line.strip() != '':
5982 errors.append(
5983 output_api.PresubmitPromptWarning(
5984 'Include guard %s not covering the whole file'
5985 % (guard_name), [f.LocalPath()]))
5986 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145987
Sam Maiera6e76d72022-02-11 21:43:505988 if guard_name is None:
5989 errors.append(
5990 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495991 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505992 'Recommended name: %s\n'
5993 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365994 '"no-include-guard-because-multiply-included" or\n'
5995 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505996 % (f.LocalPath(), expected_guard)))
5997
5998 return errors
Daniel Bratell8ba52722018-03-02 16:06:145999
6000
Saagar Sanghavifceeaae2020-08-12 16:40:366001def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506002 """Check source code and known ascii text files for Windows style line
6003 endings.
6004 """
Bruce Dawson5efbdc652022-04-11 19:29:516005 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236006
Sam Maiera6e76d72022-02-11 21:43:506007 file_inclusion_pattern = (known_text_files,
6008 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
6009 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:236010
Sam Maiera6e76d72022-02-11 21:43:506011 problems = []
6012 source_file_filter = lambda f: input_api.FilterSourceFile(
6013 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
6014 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516015 # Ignore test files that contain crlf intentionally.
6016 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346017 continue
Sam Maiera6e76d72022-02-11 21:43:506018 include_file = False
6019 for line in input_api.ReadFile(f, 'r').splitlines(True):
6020 if line.endswith('\r\n'):
6021 include_file = True
6022 if include_file:
6023 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236024
Sam Maiera6e76d72022-02-11 21:43:506025 if problems:
6026 return [
6027 output_api.PresubmitPromptWarning(
6028 'Are you sure that you want '
6029 'these files to contain Windows style line endings?\n' +
6030 '\n'.join(problems))
6031 ]
mostynbb639aca52015-01-07 20:31:236032
Sam Maiera6e76d72022-02-11 21:43:506033 return []
6034
mostynbb639aca52015-01-07 20:31:236035
Evan Stade6cfc964c12021-05-18 20:21:166036def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506037 """Check that .icon files (which are fragments of C++) have license headers.
6038 """
Evan Stade6cfc964c12021-05-18 20:21:166039
Sam Maiera6e76d72022-02-11 21:43:506040 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166041
Sam Maiera6e76d72022-02-11 21:43:506042 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6043 return input_api.canned_checks.CheckLicense(input_api,
6044 output_api,
6045 source_file_filter=icons)
6046
Evan Stade6cfc964c12021-05-18 20:21:166047
Jose Magana2b456f22021-03-09 23:26:406048def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506049 """Check source code for use of Chrome App technologies being
6050 deprecated.
6051 """
Jose Magana2b456f22021-03-09 23:26:406052
Sam Maiera6e76d72022-02-11 21:43:506053 def _CheckForDeprecatedTech(input_api,
6054 output_api,
6055 detection_list,
6056 files_to_check=None,
6057 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406058
Sam Maiera6e76d72022-02-11 21:43:506059 if (files_to_check or files_to_skip):
6060 source_file_filter = lambda f: input_api.FilterSourceFile(
6061 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6062 else:
6063 source_file_filter = None
6064
6065 problems = []
6066
6067 for f in input_api.AffectedSourceFiles(source_file_filter):
6068 if f.Action() == 'D':
6069 continue
6070 for _, line in f.ChangedContents():
6071 if any(detect in line for detect in detection_list):
6072 problems.append(f.LocalPath())
6073
6074 return problems
6075
6076 # to avoid this presubmit script triggering warnings
6077 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406078
6079 problems = []
6080
Sam Maiera6e76d72022-02-11 21:43:506081 # NMF: any files with extensions .nmf or NMF
6082 _NMF_FILES = r'\.(nmf|NMF)$'
6083 problems += _CheckForDeprecatedTech(
6084 input_api,
6085 output_api,
6086 detection_list=[''], # any change to the file will trigger warning
6087 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406088
Sam Maiera6e76d72022-02-11 21:43:506089 # MANIFEST: any manifest.json that in its diff includes "app":
6090 _MANIFEST_FILES = r'(manifest\.json)$'
6091 problems += _CheckForDeprecatedTech(
6092 input_api,
6093 output_api,
6094 detection_list=['"app":'],
6095 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406096
Sam Maiera6e76d72022-02-11 21:43:506097 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6098 problems += _CheckForDeprecatedTech(
6099 input_api,
6100 output_api,
6101 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316102 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406103
Gao Shenga79ebd42022-08-08 17:25:596104 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506105 problems += _CheckForDeprecatedTech(
6106 input_api,
6107 output_api,
6108 detection_list=['#include "ppapi', '#include <ppapi'],
6109 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6110 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316111 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406112
Sam Maiera6e76d72022-02-11 21:43:506113 if problems:
6114 return [
6115 output_api.PresubmitPromptWarning(
6116 'You are adding/modifying code'
6117 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6118 ' PNaCl, PPAPI). See this blog post for more details:\n'
6119 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6120 'and this documentation for options to replace these technologies:\n'
6121 'https://developer.chrome.com/docs/apps/migration/\n' +
6122 '\n'.join(problems))
6123 ]
Jose Magana2b456f22021-03-09 23:26:406124
Sam Maiera6e76d72022-02-11 21:43:506125 return []
Jose Magana2b456f22021-03-09 23:26:406126
mostynbb639aca52015-01-07 20:31:236127
Saagar Sanghavifceeaae2020-08-12 16:40:366128def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506129 """Checks that all source files use SYSLOG properly."""
6130 syslog_files = []
6131 for f in input_api.AffectedSourceFiles(src_file_filter):
6132 for line_number, line in f.ChangedContents():
6133 if 'SYSLOG' in line:
6134 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566135
Sam Maiera6e76d72022-02-11 21:43:506136 if syslog_files:
6137 return [
6138 output_api.PresubmitPromptWarning(
6139 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6140 ' calls.\nFiles to check:\n',
6141 items=syslog_files)
6142 ]
6143 return []
pastarmovj89f7ee12016-09-20 14:58:136144
6145
maruel@chromium.org1f7b4172010-01-28 01:17:346146def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506147 if input_api.version < [2, 0, 0]:
6148 return [
6149 output_api.PresubmitError(
6150 "Your depot_tools is out of date. "
6151 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6152 "but your version is %d.%d.%d" % tuple(input_api.version))
6153 ]
6154 results = []
6155 results.extend(
6156 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6157 return results
maruel@chromium.orgca8d19842009-02-19 16:33:126158
6159
6160def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506161 if input_api.version < [2, 0, 0]:
6162 return [
6163 output_api.PresubmitError(
6164 "Your depot_tools is out of date. "
6165 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6166 "but your version is %d.%d.%d" % tuple(input_api.version))
6167 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366168
Sam Maiera6e76d72022-02-11 21:43:506169 results = []
6170 # Make sure the tree is 'open'.
6171 results.extend(
6172 input_api.canned_checks.CheckTreeIsOpen(
6173 input_api,
6174 output_api,
6175 json_url='http://chromium-status.appspot.com/current?format=json'))
maruel@chromium.org806e98e2010-03-19 17:49:276176
Sam Maiera6e76d72022-02-11 21:43:506177 results.extend(
6178 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6179 results.extend(
6180 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6181 results.extend(
6182 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6183 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506184 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146185
6186
Saagar Sanghavifceeaae2020-08-12 16:40:366187def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506188 """Check string ICU syntax validity and if translation screenshots exist."""
6189 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6190 # footer is set to true.
6191 git_footers = input_api.change.GitFootersFromDescription()
6192 skip_screenshot_check_footer = [
6193 footer.lower() for footer in git_footers.get(
6194 u'Skip-Translation-Screenshots-Check', [])
6195 ]
6196 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026197
Sam Maiera6e76d72022-02-11 21:43:506198 import os
6199 import re
6200 import sys
6201 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146202
Sam Maiera6e76d72022-02-11 21:43:506203 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6204 if (f.Action() == 'A' or f.Action() == 'M'))
6205 removed_paths = set(f.LocalPath()
6206 for f in input_api.AffectedFiles(include_deletes=True)
6207 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146208
Sam Maiera6e76d72022-02-11 21:43:506209 affected_grds = [
6210 f for f in input_api.AffectedFiles()
6211 if f.LocalPath().endswith(('.grd', '.grdp'))
6212 ]
6213 affected_grds = [
6214 f for f in affected_grds if not 'testdata' in f.LocalPath()
6215 ]
6216 if not affected_grds:
6217 return []
meacer8c0d3832019-12-26 21:46:166218
Sam Maiera6e76d72022-02-11 21:43:506219 affected_png_paths = [
6220 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
6221 if (f.LocalPath().endswith('.png'))
6222 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146223
Sam Maiera6e76d72022-02-11 21:43:506224 # Check for screenshots. Developers can upload screenshots using
6225 # tools/translation/upload_screenshots.py which finds and uploads
6226 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6227 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6228 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6229 #
6230 # The logic here is as follows:
6231 #
6232 # - If the CL has a .png file under the screenshots directory for a grd
6233 # file, warn the developer. Actual images should never be checked into the
6234 # Chrome repo.
6235 #
6236 # - If the CL contains modified or new messages in grd files and doesn't
6237 # contain the corresponding .sha1 files, warn the developer to add images
6238 # and upload them via tools/translation/upload_screenshots.py.
6239 #
6240 # - If the CL contains modified or new messages in grd files and the
6241 # corresponding .sha1 files, everything looks good.
6242 #
6243 # - If the CL contains removed messages in grd files but the corresponding
6244 # .sha1 files aren't removed, warn the developer to remove them.
6245 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306246 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506247 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476248 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506249 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146250
Sam Maiera6e76d72022-02-11 21:43:506251 # This checks verifies that the ICU syntax of messages this CL touched is
6252 # valid, and reports any found syntax errors.
6253 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6254 # without developers being aware of them. Later on, such ICU syntax errors
6255 # break message extraction for translation, hence would block Chromium
6256 # translations until they are fixed.
6257 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306258 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6259 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146260
Sam Maiera6e76d72022-02-11 21:43:506261 def _CheckScreenshotAdded(screenshots_dir, message_id):
6262 sha1_path = input_api.os_path.join(screenshots_dir,
6263 message_id + '.png.sha1')
6264 if sha1_path not in new_or_added_paths:
6265 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306266 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256267 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146268
Bruce Dawson55776c42022-12-09 17:23:476269 def _CheckScreenshotModified(screenshots_dir, message_id):
6270 sha1_path = input_api.os_path.join(screenshots_dir,
6271 message_id + '.png.sha1')
6272 if sha1_path not in new_or_added_paths:
6273 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306274 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256275 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306276
6277 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256278 return sha1_pattern.search(
6279 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6280 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476281
Sam Maiera6e76d72022-02-11 21:43:506282 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6283 sha1_path = input_api.os_path.join(screenshots_dir,
6284 message_id + '.png.sha1')
6285 if input_api.os_path.exists(
6286 sha1_path) and sha1_path not in removed_paths:
6287 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146288
Sam Maiera6e76d72022-02-11 21:43:506289 def _ValidateIcuSyntax(text, level, signatures):
6290 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146291
Sam Maiera6e76d72022-02-11 21:43:506292 Check if text looks similar to ICU and checks for ICU syntax correctness
6293 in this case. Reports various issues with ICU syntax and values of
6294 variants. Supports checking of nested messages. Accumulate information of
6295 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266296
Sam Maiera6e76d72022-02-11 21:43:506297 Args:
6298 text: a string to check.
6299 level: a number of current nesting level.
6300 signatures: an accumulator, a list of tuple of (level, variable,
6301 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266302
Sam Maiera6e76d72022-02-11 21:43:506303 Returns:
6304 None if a string is not ICU or no issue detected.
6305 A tuple of (message, start index, end index) if an issue detected.
6306 """
6307 valid_types = {
6308 'plural': (frozenset(
6309 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6310 'other']), frozenset(['=1', 'other'])),
6311 'selectordinal': (frozenset(
6312 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6313 'other']), frozenset(['one', 'other'])),
6314 'select': (frozenset(), frozenset(['other'])),
6315 }
Rainhard Findlingfc31844c52020-05-15 09:58:266316
Sam Maiera6e76d72022-02-11 21:43:506317 # Check if the message looks like an attempt to use ICU
6318 # plural. If yes - check if its syntax strictly matches ICU format.
6319 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6320 text)
6321 if not like:
6322 signatures.append((level, None, None, None))
6323 return
Rainhard Findlingfc31844c52020-05-15 09:58:266324
Sam Maiera6e76d72022-02-11 21:43:506325 # Check for valid prefix and suffix
6326 m = re.match(
6327 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6328 r'(plural|selectordinal|select),\s*'
6329 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6330 if not m:
6331 return (('This message looks like an ICU plural, '
6332 'but does not follow ICU syntax.'), like.start(),
6333 like.end())
6334 starting, variable, kind, variant_pairs = m.groups()
6335 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6336 m.start(4))
6337 if depth:
6338 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6339 len(text))
6340 first = text[0]
6341 ending = text[last_pos:]
6342 if not starting:
6343 return ('Invalid ICU format. No initial opening bracket',
6344 last_pos - 1, last_pos)
6345 if not ending or '}' not in ending:
6346 return ('Invalid ICU format. No final closing bracket',
6347 last_pos - 1, last_pos)
6348 elif first != '{':
6349 return ((
6350 'Invalid ICU format. Extra characters at the start of a complex '
6351 'message (go/icu-message-migration): "%s"') % starting, 0,
6352 len(starting))
6353 elif ending != '}':
6354 return ((
6355 'Invalid ICU format. Extra characters at the end of a complex '
6356 'message (go/icu-message-migration): "%s"') % ending,
6357 last_pos - 1, len(text) - 1)
6358 if kind not in valid_types:
6359 return (('Unknown ICU message type %s. '
6360 'Valid types are: plural, select, selectordinal') % kind,
6361 0, 0)
6362 known, required = valid_types[kind]
6363 defined_variants = set()
6364 for variant, variant_range, value, value_range in variants:
6365 start, end = variant_range
6366 if variant in defined_variants:
6367 return ('Variant "%s" is defined more than once' % variant,
6368 start, end)
6369 elif known and variant not in known:
6370 return ('Variant "%s" is not valid for %s message' %
6371 (variant, kind), start, end)
6372 defined_variants.add(variant)
6373 # Check for nested structure
6374 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6375 if res:
6376 return (res[0], res[1] + value_range[0] + 1,
6377 res[2] + value_range[0] + 1)
6378 missing = required - defined_variants
6379 if missing:
6380 return ('Required variants missing: %s' % ', '.join(missing), 0,
6381 len(text))
6382 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266383
Sam Maiera6e76d72022-02-11 21:43:506384 def _ParseIcuVariants(text, offset=0):
6385 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266386
Sam Maiera6e76d72022-02-11 21:43:506387 Builds a tuple of variant names and values, as well as
6388 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266389
Sam Maiera6e76d72022-02-11 21:43:506390 Args:
6391 text: a string to parse
6392 offset: additional offset to add to positions in the text to get correct
6393 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266394
Sam Maiera6e76d72022-02-11 21:43:506395 Returns:
6396 List of tuples, each tuple consist of four fields: variant name,
6397 variant name span (tuple of two integers), variant value, value
6398 span (tuple of two integers).
6399 """
6400 depth, start, end = 0, -1, -1
6401 variants = []
6402 key = None
6403 for idx, char in enumerate(text):
6404 if char == '{':
6405 if not depth:
6406 start = idx
6407 chunk = text[end + 1:start]
6408 key = chunk.strip()
6409 pos = offset + end + 1 + chunk.find(key)
6410 span = (pos, pos + len(key))
6411 depth += 1
6412 elif char == '}':
6413 if not depth:
6414 return variants, depth, offset + idx
6415 depth -= 1
6416 if not depth:
6417 end = idx
6418 variants.append((key, span, text[start:end + 1],
6419 (offset + start, offset + end + 1)))
6420 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266421
Sam Maiera6e76d72022-02-11 21:43:506422 try:
6423 old_sys_path = sys.path
6424 sys.path = sys.path + [
6425 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6426 'translation')
6427 ]
6428 from helper import grd_helper
6429 finally:
6430 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266431
Sam Maiera6e76d72022-02-11 21:43:506432 for f in affected_grds:
6433 file_path = f.LocalPath()
6434 old_id_to_msg_map = {}
6435 new_id_to_msg_map = {}
6436 # Note that this code doesn't check if the file has been deleted. This is
6437 # OK because it only uses the old and new file contents and doesn't load
6438 # the file via its path.
6439 # It's also possible that a file's content refers to a renamed or deleted
6440 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6441 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6442 # .grdp files.
6443 if file_path.endswith('.grdp'):
6444 if f.OldContents():
6445 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6446 '\n'.join(f.OldContents()))
6447 if f.NewContents():
6448 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6449 '\n'.join(f.NewContents()))
6450 else:
6451 file_dir = input_api.os_path.dirname(file_path) or '.'
6452 if f.OldContents():
6453 old_id_to_msg_map = grd_helper.GetGrdMessages(
6454 StringIO('\n'.join(f.OldContents())), file_dir)
6455 if f.NewContents():
6456 new_id_to_msg_map = grd_helper.GetGrdMessages(
6457 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266458
Sam Maiera6e76d72022-02-11 21:43:506459 grd_name, ext = input_api.os_path.splitext(
6460 input_api.os_path.basename(file_path))
6461 screenshots_dir = input_api.os_path.join(
6462 input_api.os_path.dirname(file_path),
6463 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266464
Sam Maiera6e76d72022-02-11 21:43:506465 # Compute added, removed and modified message IDs.
6466 old_ids = set(old_id_to_msg_map)
6467 new_ids = set(new_id_to_msg_map)
6468 added_ids = new_ids - old_ids
6469 removed_ids = old_ids - new_ids
6470 modified_ids = set([])
6471 for key in old_ids.intersection(new_ids):
6472 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6473 new_id_to_msg_map[key].ContentsAsXml('', True)):
6474 # The message content itself changed. Require an updated screenshot.
6475 modified_ids.add(key)
6476 elif old_id_to_msg_map[key].attrs['meaning'] != \
6477 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:306478 # The message meaning changed. We later check for a screenshot.
6479 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146480
Sam Maiera6e76d72022-02-11 21:43:506481 if run_screenshot_check:
6482 # Check the screenshot directory for .png files. Warn if there is any.
6483 for png_path in affected_png_paths:
6484 if png_path.startswith(screenshots_dir):
6485 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146486
Sam Maiera6e76d72022-02-11 21:43:506487 for added_id in added_ids:
6488 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096489
Sam Maiera6e76d72022-02-11 21:43:506490 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476491 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146492
Sam Maiera6e76d72022-02-11 21:43:506493 for removed_id in removed_ids:
6494 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6495
6496 # Check new and changed strings for ICU syntax errors.
6497 for key in added_ids.union(modified_ids):
6498 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6499 err = _ValidateIcuSyntax(msg, 0, [])
6500 if err is not None:
6501 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6502
6503 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266504 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506505 if unnecessary_screenshots:
6506 results.append(
6507 output_api.PresubmitError(
6508 'Do not include actual screenshots in the changelist. Run '
6509 'tools/translate/upload_screenshots.py to upload them instead:',
6510 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146511
Sam Maiera6e76d72022-02-11 21:43:506512 if missing_sha1:
6513 results.append(
6514 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:476515 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:506516 'To ensure the best translations, take screenshots of the relevant UI '
6517 '(https://g.co/chrome/translation) and add these files to your '
6518 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146519
Jens Mueller054652c2023-05-10 15:12:306520 if invalid_sha1:
6521 results.append(
6522 output_api.PresubmitError(
6523 'The following files do not seem to contain valid sha1 hashes. '
6524 'Make sure they contain hashes created by '
6525 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
6526
Bruce Dawson55776c42022-12-09 17:23:476527 if missing_sha1_modified:
6528 results.append(
6529 output_api.PresubmitError(
6530 'You are modifying UI strings or their meanings.\n'
6531 'To ensure the best translations, take screenshots of the relevant UI '
6532 '(https://g.co/chrome/translation) and add these files to your '
6533 'changelist:', sorted(missing_sha1_modified)))
6534
Sam Maiera6e76d72022-02-11 21:43:506535 if unnecessary_sha1_files:
6536 results.append(
6537 output_api.PresubmitError(
6538 'You removed strings associated with these files. Remove:',
6539 sorted(unnecessary_sha1_files)))
6540 else:
6541 results.append(
6542 output_api.PresubmitPromptOrNotify('Skipping translation '
6543 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146544
Sam Maiera6e76d72022-02-11 21:43:506545 if icu_syntax_errors:
6546 results.append(
6547 output_api.PresubmitPromptWarning(
6548 'ICU syntax errors were found in the following strings (problems or '
6549 'feedback? Contact rainhard@chromium.org):',
6550 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:266551
Sam Maiera6e76d72022-02-11 21:43:506552 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:126553
6554
Saagar Sanghavifceeaae2020-08-12 16:40:366555def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:126556 repo_root=None,
6557 translation_expectations_path=None,
6558 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:506559 import sys
6560 affected_grds = [
6561 f for f in input_api.AffectedFiles()
6562 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
6563 ]
6564 if not affected_grds:
6565 return []
6566
6567 try:
6568 old_sys_path = sys.path
6569 sys.path = sys.path + [
6570 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6571 'translation')
6572 ]
6573 from helper import git_helper
6574 from helper import translation_helper
6575 finally:
6576 sys.path = old_sys_path
6577
6578 # Check that translation expectations can be parsed and we can get a list of
6579 # translatable grd files. |repo_root| and |translation_expectations_path| are
6580 # only passed by tests.
6581 if not repo_root:
6582 repo_root = input_api.PresubmitLocalPath()
6583 if not translation_expectations_path:
6584 translation_expectations_path = input_api.os_path.join(
6585 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
6586 if not grd_files:
6587 grd_files = git_helper.list_grds_in_repository(repo_root)
6588
6589 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:596590 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:506591 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
6592 'tests')
6593 grd_files = [p for p in grd_files if ignore_path not in p]
6594
6595 try:
6596 translation_helper.get_translatable_grds(
6597 repo_root, grd_files, translation_expectations_path)
6598 except Exception as e:
6599 return [
6600 output_api.PresubmitNotifyResult(
6601 'Failed to get a list of translatable grd files. This happens when:\n'
6602 ' - One of the modified grd or grdp files cannot be parsed or\n'
6603 ' - %s is not updated.\n'
6604 'Stack:\n%s' % (translation_expectations_path, str(e)))
6605 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:126606 return []
6607
Ken Rockotc31f4832020-05-29 18:58:516608
Saagar Sanghavifceeaae2020-08-12 16:40:366609def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506610 """Changes to [Stable] mojom types must preserve backward-compatibility."""
6611 changed_mojoms = input_api.AffectedFiles(
6612 include_deletes=True,
6613 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:526614
Bruce Dawson344ab262022-06-04 11:35:106615 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:506616 return []
6617
6618 delta = []
6619 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:506620 delta.append({
6621 'filename': mojom.LocalPath(),
6622 'old': '\n'.join(mojom.OldContents()) or None,
6623 'new': '\n'.join(mojom.NewContents()) or None,
6624 })
6625
6626 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:216627 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:506628 input_api.os_path.join(
6629 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
6630 'check_stable_mojom_compatibility.py'), '--src-root',
6631 input_api.PresubmitLocalPath()
6632 ],
6633 stdin=input_api.subprocess.PIPE,
6634 stdout=input_api.subprocess.PIPE,
6635 stderr=input_api.subprocess.PIPE,
6636 universal_newlines=True)
6637 (x, error) = process.communicate(input=input_api.json.dumps(delta))
6638 if process.returncode:
6639 return [
6640 output_api.PresubmitError(
6641 'One or more [Stable] mojom definitions appears to have been changed '
6642 'in a way that is not backward-compatible.',
6643 long_text=error)
6644 ]
Erik Staabc734cd7a2021-11-23 03:11:526645 return []
6646
Dominic Battre645d42342020-12-04 16:14:106647def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506648 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106649
Sam Maiera6e76d72022-02-11 21:43:506650 def FilterFile(affected_file):
6651 """Accept only .cc files and the like."""
6652 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6653 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6654 input_api.DEFAULT_FILES_TO_SKIP)
6655 return input_api.FilterSourceFile(
6656 affected_file,
6657 files_to_check=file_inclusion_pattern,
6658 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106659
Sam Maiera6e76d72022-02-11 21:43:506660 def ModifiedLines(affected_file):
6661 """Returns a list of tuples (line number, line text) of added and removed
6662 lines.
Dominic Battre645d42342020-12-04 16:14:106663
Sam Maiera6e76d72022-02-11 21:43:506664 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106665
Sam Maiera6e76d72022-02-11 21:43:506666 This relies on the scm diff output describing each changed code section
6667 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106668
Sam Maiera6e76d72022-02-11 21:43:506669 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6670 """
6671 line_num = 0
6672 modified_lines = []
6673 for line in affected_file.GenerateScmDiff().splitlines():
6674 # Extract <new line num> of the patch fragment (see format above).
6675 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6676 line)
6677 if m:
6678 line_num = int(m.groups(1)[0])
6679 continue
6680 if ((line.startswith('+') and not line.startswith('++'))
6681 or (line.startswith('-') and not line.startswith('--'))):
6682 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106683
Sam Maiera6e76d72022-02-11 21:43:506684 if not line.startswith('-'):
6685 line_num += 1
6686 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106687
Sam Maiera6e76d72022-02-11 21:43:506688 def FindLineWith(lines, needle):
6689 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106690
Sam Maiera6e76d72022-02-11 21:43:506691 If 0 or >1 lines contain `needle`, -1 is returned.
6692 """
6693 matching_line_numbers = [
6694 # + 1 for 1-based counting of line numbers.
6695 i + 1 for i, line in enumerate(lines) if needle in line
6696 ]
6697 return matching_line_numbers[0] if len(
6698 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106699
Sam Maiera6e76d72022-02-11 21:43:506700 def ModifiedPrefMigration(affected_file):
6701 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6702 # Determine first and last lines of MigrateObsolete.*Pref functions.
6703 new_contents = affected_file.NewContents()
6704 range_1 = (FindLineWith(new_contents,
6705 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6706 FindLineWith(new_contents,
6707 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6708 range_2 = (FindLineWith(new_contents,
6709 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6710 FindLineWith(new_contents,
6711 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6712 if (-1 in range_1 + range_2):
6713 raise Exception(
6714 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6715 )
Dominic Battre645d42342020-12-04 16:14:106716
Sam Maiera6e76d72022-02-11 21:43:506717 # Check whether any of the modified lines are part of the
6718 # MigrateObsolete.*Pref functions.
6719 for line_nr, line in ModifiedLines(affected_file):
6720 if (range_1[0] <= line_nr <= range_1[1]
6721 or range_2[0] <= line_nr <= range_2[1]):
6722 return True
6723 return False
Dominic Battre645d42342020-12-04 16:14:106724
Sam Maiera6e76d72022-02-11 21:43:506725 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6726 browser_prefs_file_pattern = input_api.re.compile(
6727 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106728
Sam Maiera6e76d72022-02-11 21:43:506729 changes = input_api.AffectedFiles(include_deletes=True,
6730 file_filter=FilterFile)
6731 potential_problems = []
6732 for f in changes:
6733 for line in f.GenerateScmDiff().splitlines():
6734 # Check deleted lines for pref registrations.
6735 if (line.startswith('-') and not line.startswith('--')
6736 and register_pref_pattern.search(line)):
6737 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106738
Sam Maiera6e76d72022-02-11 21:43:506739 if browser_prefs_file_pattern.search(f.LocalPath()):
6740 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6741 # assume that they knew that they have to deprecate preferences and don't
6742 # warn.
6743 try:
6744 if ModifiedPrefMigration(f):
6745 return []
6746 except Exception as e:
6747 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106748
Sam Maiera6e76d72022-02-11 21:43:506749 if potential_problems:
6750 return [
6751 output_api.PresubmitPromptWarning(
6752 'Discovered possible removal of preference registrations.\n\n'
6753 'Please make sure to properly deprecate preferences by clearing their\n'
6754 'value for a couple of milestones before finally removing the code.\n'
6755 'Otherwise data may stay in the preferences files forever. See\n'
6756 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6757 'chrome/browser/prefs/README.md for examples.\n'
6758 'This may be a false positive warning (e.g. if you move preference\n'
6759 'registrations to a different place).\n', potential_problems)
6760 ]
6761 return []
6762
Matt Stark6ef08872021-07-29 01:21:466763
6764def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506765 """Changes to GRD files must be consistent for tools to read them."""
6766 changed_grds = input_api.AffectedFiles(
6767 include_deletes=False,
6768 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6769 errors = []
6770 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6771 for matcher, msg in _INVALID_GRD_FILE_LINE]
6772 for grd in changed_grds:
6773 for i, line in enumerate(grd.NewContents()):
6774 for matcher, msg in invalid_file_regexes:
6775 if matcher.search(line):
6776 errors.append(
6777 output_api.PresubmitError(
6778 'Problem on {grd}:{i} - {msg}'.format(
6779 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6780 return errors
6781
Kevin McNee967dd2d22021-11-15 16:09:296782
Henrique Ferreiro2a4b55942021-11-29 23:45:366783def CheckAssertAshOnlyCode(input_api, output_api):
6784 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6785 assert(is_chromeos_ash).
6786 """
6787
6788 def FileFilter(affected_file):
6789 """Includes directories known to be Ash only."""
6790 return input_api.FilterSourceFile(
6791 affected_file,
6792 files_to_check=(
6793 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6794 r'.*/ash/.*BUILD\.gn'), # Any path component.
6795 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6796
6797 errors = []
6798 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566799 for f in input_api.AffectedFiles(include_deletes=False,
6800 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366801 if (not pattern.search(input_api.ReadFile(f))):
6802 errors.append(
6803 output_api.PresubmitError(
6804 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6805 'possible, please create and issue and add a comment such '
6806 'as:\n # TODO(https://crbug.com/XXX): add '
6807 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6808 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276809
6810
Kalvin Lee84ad17a2023-09-25 11:14:416811def _IsMiraclePtrDisallowed(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506812 path = affected_file.LocalPath()
6813 if not _IsCPlusPlusFile(input_api, path):
6814 return False
6815
Kalvin Lee84ad17a2023-09-25 11:14:416816 # Renderer code is generally allowed to use MiraclePtr.
6817 # These directories, however, are specifically disallowed.
6818 if ("third_party/blink/renderer/core/" in path
6819 or "third_party/blink/renderer/platform/heap/" in path
6820 or "third_party/blink/renderer/platform/wtf/" in path):
Sam Maiera6e76d72022-02-11 21:43:506821 return True
6822
6823 # Blink's public/web API is only used/included by Renderer-only code. Note
6824 # that public/platform API may be used in non-Renderer processes (e.g. there
6825 # are some includes in code used by Utility, PDF, or Plugin processes).
6826 if "/blink/public/web/" in path:
6827 return True
6828
6829 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276830 return False
6831
Lukasz Anforowicz7016d05e2021-11-30 03:56:276832# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6833# by the Chromium Clang Plugin (which will be preferable because it will
6834# 1) report errors earlier - at compile-time and 2) cover more rules).
6835def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506836 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6837 errors = []
6838 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6839 # C++ comment.
6840 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:416841 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:506842 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6843 if raw_ptr_matcher.search(line):
6844 errors.append(
6845 output_api.PresubmitError(
6846 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:416847 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:506848 '(as documented in the "Pointers to unprotected memory" '\
6849 'section in //base/memory/raw_ptr.md)'.format(
6850 path=f.LocalPath(), line=line_num)))
6851 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566852
mikt9337567c2023-09-08 18:38:176853def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
6854 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
6855 removed as it is managed by the memory safety team internally.
6856 Do not add / remove it manually."""
6857 paths = set([])
6858 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
6859 # boundary, but not in a C++ comment.
6860 macro_matcher = input_api.re.compile(
6861 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
6862 for f in input_api.AffectedFiles():
6863 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
6864 continue
6865 if macro_matcher.search(f.GenerateScmDiff()):
6866 paths.add(f.LocalPath())
6867 if not paths:
6868 return []
6869 return [output_api.PresubmitPromptWarning(
6870 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
6871 'the memory safety team (chrome-memory-safety@). ' \
6872 'Please contact us to add/delete the uses of the macro.',
6873 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:566874
6875def CheckPythonShebang(input_api, output_api):
6876 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6877 system-wide python.
6878 """
6879 errors = []
6880 sources = lambda affected_file: input_api.FilterSourceFile(
6881 affected_file,
6882 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6883 r'third_party/blink/web_tests/external/') + input_api.
6884 DEFAULT_FILES_TO_SKIP),
6885 files_to_check=[r'.*\.py$'])
6886 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276887 for line_num, line in f.ChangedContents():
6888 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6889 errors.append(f.LocalPath())
6890 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566891
6892 result = []
6893 for file in errors:
6894 result.append(
6895 output_api.PresubmitError(
6896 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6897 file))
6898 return result
James Shen81cc0e22022-06-15 21:10:456899
6900
6901def CheckBatchAnnotation(input_api, output_api):
6902 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6903 is not an instrumentation test, disregard."""
6904
6905 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6906 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6907 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6908 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6909 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:596910 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:456911
ckitagawae8fd23b2022-06-17 15:29:386912 missing_annotation_errors = []
6913 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456914
6915 def _FilterFile(affected_file):
6916 return input_api.FilterSourceFile(
6917 affected_file,
6918 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6919 files_to_check=[r'.*Test\.java$'])
6920
6921 for f in input_api.AffectedSourceFiles(_FilterFile):
6922 batch_matched = None
6923 do_not_batch_matched = None
6924 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:596925 test_annotation_declaration_matched = None
James Shen81cc0e22022-06-15 21:10:456926 for line in f.NewContents():
6927 if robolectric_test.search(line) or uiautomator_test.search(line):
6928 # Skip Robolectric and UiAutomator tests.
6929 is_instrumentation_test = False
6930 break
6931 if not batch_matched:
6932 batch_matched = batch_annotation.search(line)
6933 if not do_not_batch_matched:
6934 do_not_batch_matched = do_not_batch_annotation.search(line)
6935 test_class_declaration_matched = test_class_declaration.search(
6936 line)
Mark Schillaci8ef0d872023-07-18 22:07:596937 test_annotation_declaration_matched = test_annotation_declaration.search(line)
6938 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:456939 break
Mark Schillaci8ef0d872023-07-18 22:07:596940 if test_annotation_declaration_matched:
6941 continue
James Shen81cc0e22022-06-15 21:10:456942 if (is_instrumentation_test and
6943 not batch_matched and
6944 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246945 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386946 if (not is_instrumentation_test and
6947 (batch_matched or
6948 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246949 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456950
6951 results = []
6952
ckitagawae8fd23b2022-06-17 15:29:386953 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456954 results.append(
6955 output_api.PresubmitPromptWarning(
6956 """
Andrew Grieve43a5cf82023-09-08 15:09:466957A change was made to an on-device test that has neither been annotated with
6958@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
6959this is an existing test, please consider adding it if you are sufficiently
6960familiar with the test (but do so as a separate change).
6961
Jens Mueller2085ff82023-02-27 11:54:496962See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:386963""", missing_annotation_errors))
6964 if extra_annotation_errors:
6965 results.append(
6966 output_api.PresubmitPromptWarning(
6967 """
6968Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6969""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456970
6971 return results
Sam Maier4cef9242022-10-03 14:21:246972
6973
6974def CheckMockAnnotation(input_api, output_api):
6975 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6976 classes with @Mock or @Spy. If this is not an instrumentation test,
6977 disregard."""
6978
6979 # This is just trying to be approximately correct. We are not writing a
6980 # Java parser, so special cases like statically importing mock() then
6981 # calling an unrelated non-mockito spy() function will cause a false
6982 # positive.
6983 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6984 mock_static_import = input_api.re.compile(
6985 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6986 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6987 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6988 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6989 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6990 fully_qualified_mock_function = input_api.re.compile(
6991 r'Mockito\.' + mock_or_spy_function_call)
6992 statically_imported_mock_function = input_api.re.compile(
6993 r'\W' + mock_or_spy_function_call)
6994 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6995 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6996
6997 def _DoClassLookup(class_name, class_name_map, package):
6998 found = class_name_map.get(class_name)
6999 if found is not None:
7000 return found
7001 else:
7002 return package + '.' + class_name
7003
7004 def _FilterFile(affected_file):
7005 return input_api.FilterSourceFile(
7006 affected_file,
7007 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7008 files_to_check=[r'.*Test\.java$'])
7009
7010 mocked_by_function_classes = set()
7011 mocked_by_annotation_classes = set()
7012 class_to_filename = {}
7013 for f in input_api.AffectedSourceFiles(_FilterFile):
7014 mock_function_regex = fully_qualified_mock_function
7015 next_line_is_annotated = False
7016 fully_qualified_class_map = {}
7017 package = None
7018
7019 for line in f.NewContents():
7020 if robolectric_test.search(line) or uiautomator_test.search(line):
7021 # Skip Robolectric and UiAutomator tests.
7022 break
7023
7024 m = package_name.search(line)
7025 if m:
7026 package = m.group(1)
7027 continue
7028
7029 if mock_static_import.search(line):
7030 mock_function_regex = statically_imported_mock_function
7031 continue
7032
7033 m = import_class.search(line)
7034 if m:
7035 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
7036 continue
7037
7038 if next_line_is_annotated:
7039 next_line_is_annotated = False
7040 fully_qualified_class = _DoClassLookup(
7041 field_type.search(line).group(1), fully_qualified_class_map,
7042 package)
7043 mocked_by_annotation_classes.add(fully_qualified_class)
7044 continue
7045
7046 if mock_annotation.search(line):
Sam Maierb8a66a02023-10-10 13:50:557047 field_type_search = field_type.search(line)
7048 if field_type_search:
7049 fully_qualified_class = _DoClassLookup(
7050 field_type_search.group(1), fully_qualified_class_map,
7051 package)
7052 mocked_by_annotation_classes.add(fully_qualified_class)
7053 else:
7054 next_line_is_annotated = True
Sam Maier4cef9242022-10-03 14:21:247055 continue
7056
7057 m = mock_function_regex.search(line)
7058 if m:
7059 fully_qualified_class = _DoClassLookup(m.group(1),
7060 fully_qualified_class_map, package)
7061 # Skipping builtin classes, since they don't get optimized.
7062 if fully_qualified_class.startswith(
7063 'android.') or fully_qualified_class.startswith(
7064 'java.'):
7065 continue
7066 class_to_filename[fully_qualified_class] = str(f.LocalPath())
7067 mocked_by_function_classes.add(fully_qualified_class)
7068
7069 results = []
7070 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
7071 if missed_classes:
7072 error_locations = []
7073 for c in missed_classes:
7074 error_locations.append(c + ' in ' + class_to_filename[c])
7075 results.append(
7076 output_api.PresubmitPromptWarning(
7077 """
7078Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
70791) If the mocked variable can be a class member, annotate the member with
7080 @Mock/@Spy.
70812) If the mocked variable cannot be a class member, create a dummy member
7082 variable of that type, annotated with @Mock/@Spy. This dummy does not need
7083 to be used or initialized in any way.
70843) If the mocked type is definitely not going to be optimized, whether it's a
7085 builtin type which we don't ship, or a class you know R8 will treat
7086 specially, you can ignore this warning.
7087""", error_locations))
7088
7089 return results
Mike Dougherty1b8be712022-10-20 00:15:137090
7091def CheckNoJsInIos(input_api, output_api):
7092 """Checks to make sure that JavaScript files are not used on iOS."""
7093
7094 def _FilterFile(affected_file):
7095 return input_api.FilterSourceFile(
7096 affected_file,
7097 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367098 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7099 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137100 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7101
Mike Dougherty4d1050b2023-03-14 15:59:537102 deleted_files = []
7103
7104 # Collect filenames of all removed JS files.
7105 for f in input_api.AffectedSourceFiles(_FilterFile):
7106 local_path = f.LocalPath()
7107
7108 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7109 deleted_files.append(input_api.os_path.basename(local_path))
7110
Mike Dougherty1b8be712022-10-20 00:15:137111 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537112 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137113 warning_paths = []
7114
7115 for f in input_api.AffectedSourceFiles(_FilterFile):
7116 local_path = f.LocalPath()
7117
7118 if input_api.os_path.splitext(local_path)[1] == '.js':
7119 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537120 if input_api.os_path.basename(local_path) in deleted_files:
7121 # This script was probably moved rather than newly created.
7122 # Present a warning instead of an error for these cases.
7123 moved_paths.append(local_path)
7124 else:
7125 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137126 elif f.Action() != 'D':
7127 warning_paths.append(local_path)
7128
7129 results = []
7130
7131 if warning_paths:
7132 results.append(output_api.PresubmitPromptWarning(
7133 'TypeScript is now fully supported for iOS feature scripts. '
7134 'Consider converting JavaScript files to TypeScript. See '
7135 '//ios/web/public/js_messaging/README.md for more details.',
7136 warning_paths))
7137
Mike Dougherty4d1050b2023-03-14 15:59:537138 if moved_paths:
7139 results.append(output_api.PresubmitPromptWarning(
7140 'Do not use JavaScript on iOS for new files as TypeScript is '
7141 'fully supported. (If this is a moved file, you may leave the '
7142 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7143 'for help using scripts on iOS.', moved_paths))
7144
Mike Dougherty1b8be712022-10-20 00:15:137145 if error_paths:
7146 results.append(output_api.PresubmitError(
7147 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7148 'See //ios/web/public/js_messaging/README.md for help using '
7149 'scripts on iOS.', error_paths))
7150
7151 return results
Hans Wennborg23a81d52023-03-24 16:38:137152
7153def CheckLibcxxRevisionsMatch(input_api, output_api):
7154 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487155 # Disable check for changes to sub-repositories.
7156 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257157 return []
Hans Wennborg23a81d52023-03-24 16:38:137158
7159 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7160
7161 file_filter = lambda f: f.LocalPath().replace(
7162 input_api.os_path.sep, '/') in DEPS_FILES
7163 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7164 if not changed_deps_files:
7165 return []
7166
7167 def LibcxxRevision(file):
7168 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7169 *file.split('/'))
7170 return input_api.re.search(
7171 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7172 input_api.ReadFile(file)).group(1)
7173
7174 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7175 return []
7176
7177 return [output_api.PresubmitError(
7178 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7179 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427180
7181
7182def CheckDanglingUntriaged(input_api, output_api):
7183 """Warn developers adding DanglingUntriaged raw_ptr."""
7184
7185 # Ignore during git presubmit --all.
7186 #
7187 # This would be too costly, because this would check every lines of every
7188 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7189 # source code, but only once to apply every checks. It seems the bots like
7190 # `win-presubmit` are particularly sensitive to reading the files. Adding
7191 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7192 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397193 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427194
7195 def FilterFile(file):
7196 return input_api.FilterSourceFile(
7197 file,
7198 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7199 files_to_skip=[r"^base/allocator.*"],
7200 )
7201
7202 count = 0
7203 for f in input_api.AffectedSourceFiles(FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397204 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7205 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427206
7207 # Most likely, nothing changed:
7208 if count == 0:
7209 return []
7210
7211 # Congrats developers for improving it:
7212 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397213 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427214 return [output_api.PresubmitNotifyResult(message)]
7215
7216 # Check for 'DanglingUntriaged-notes' in the description:
7217 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7218 if any(
7219 notes_regex.match(line)
7220 for line in input_api.change.DescriptionText().splitlines()):
7221 return []
7222
7223 # Check for DanglingUntriaged-notes in the git footer:
7224 if input_api.change.GitFootersFromDescription().get(
7225 "DanglingUntriaged-notes", []):
7226 return []
7227
7228 message = (
Arthur Sonzogni9eafd222023-11-10 08:50:397229 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n" +
7230 "avoid adding new ones\n" +
7231 "\n" +
7232 "See documentation:\n" +
7233 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n" +
7234 "\n" +
7235 "See also the guide to fix dangling pointers:\n" +
7236 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n" +
7237 "\n" +
7238 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197239 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Arthur Sonzogni9eafd222023-11-10 08:50:397240 "pointers>"
Arthur Sonzogni7109bd32023-10-03 10:34:427241 )
7242 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497243
7244def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7245 """Checks that non-static constexpr definitions in headers are inline."""
7246 # In a properly formatted file, constexpr definitions inside classes or
7247 # structs will have additional whitespace at the beginning of the line.
7248 # The pattern looks for variables initialized as constexpr kVar = ...; or
7249 # constexpr kVar{...};
7250 # The pattern does not match expressions that have braces in kVar to avoid
7251 # matching constexpr functions.
7252 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
7253 attribute_pattern = input_api.re.compile(r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
7254 problems = []
7255 for f in input_api.AffectedFiles():
7256 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7257 continue
7258
7259 for line_number, line in f.ChangedContents():
7260 line = attribute_pattern.sub('', line)
7261 if pattern.search(line):
7262 problems.append(
7263 f"{f.LocalPath()}: {line_number}\n {line}")
7264
7265 if problems:
7266 return [
7267 output_api.PresubmitPromptWarning(
7268 'Consider inlining constexpr variable definitions in headers '
7269 'outside of classes to avoid unnecessary copies of the '
7270 'constant. See https://abseil.io/tips/168 for more details.',
7271 problems)
7272 ]
7273 else:
7274 return []