blob: 2d79683857c3cd05d427c24806bbb438a8903e97 [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
14from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1217
Dirk Prankee3c9c62d2021-05-18 18:35:5918# This line is 'magic' in that git-cl looks for it to decide whether to
19# use Python3 instead of Python2 when running the code in this file.
20USE_PYTHON3 = True
21
[email protected]379e7dd2010-01-28 17:39:2122_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1823 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3124 (r"chrome/android/webapk/shell_apk/src/org/chromium"
25 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0826 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3127 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4728 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3129 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2630 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5231 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3132 r"^media/test/data/.*.ts",
33 r"^native_client_sdksrc/build_tools/make_rules.py",
34 r"^native_client_sdk/src/build_tools/make_simple.py",
35 r"^native_client_sdk/src/tools/.*.mk",
36 r"^net/tools/spdyshark/.*",
37 r"^skia/.*",
38 r"^third_party/blink/.*",
39 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4640 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3141 r"^third_party/sqlite/.*",
42 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5443 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5344 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2045 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3146 r".+/pnacl_shim\.c$",
47 r"^gpu/config/.*_list_json\.cc$",
48 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1449 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3150 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5451 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3152 r"tools/perf/page_sets/webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4053)
[email protected]ca8d1982009-02-19 16:33:1254
John Abd-El-Malek759fea62021-03-13 03:41:1455_EXCLUDED_SET_NO_PARENT_PATHS = (
56 # It's for historical reasons that blink isn't a top level directory, where
57 # it would be allowed to have "set noparent" to avoid top level owners
58 # accidentally +1ing changes.
59 'third_party/blink/OWNERS',
60)
61
wnwenbdc444e2016-05-25 13:44:1562
[email protected]06e6d0ff2012-12-11 01:36:4463# Fragment of a regular expression that matches C++ and Objective-C++
64# implementation files.
65_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
66
wnwenbdc444e2016-05-25 13:44:1567
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1968# Fragment of a regular expression that matches C++ and Objective-C++
69# header files.
70_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
71
72
Aleksey Khoroshilov9b28c032022-06-03 16:35:3273# Paths with sources that don't use //base.
74_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3175 r"^chrome/browser/browser_switcher/bho/",
76 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3277)
78
79
[email protected]06e6d0ff2012-12-11 01:36:4480# Regular expression that matches code only used for test binaries
81# (best effort).
82_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3183 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4484 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1385 # Test suite files, like:
86 # foo_browsertest.cc
87 # bar_unittest_mac.cc (suffix)
88 # baz_unittests.cc (plural)
89 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1290 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1891 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2192 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3193 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:4394 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:3195 r'content/shell/.*',
danakj89f47082020-09-02 17:53:4396 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:3197 r'content/web_test/.*',
[email protected]7b054982013-11-27 00:44:4798 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:3199 r'mojo/examples/.*',
[email protected]8176de12014-06-20 19:07:08100 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:31101 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41102 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31103 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17104 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31105 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41106 # Chromium Codelab
Bruce Dawson40fece62022-09-16 19:58:31107 r'codelabs/*'
[email protected]06e6d0ff2012-12-11 01:36:44108)
[email protected]ca8d1982009-02-19 16:33:12109
Daniel Bratell609102be2019-03-27 20:53:21110_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15111
[email protected]eea609a2011-11-18 13:10:12112_TEST_ONLY_WARNING = (
113 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55114 'production code. If you are doing this from inside another method\n'
115 'named as *ForTesting(), then consider exposing things to have tests\n'
116 'make that same call directly.\n'
117 'If that is not possible, you may put a comment on the same line with\n'
118 ' // IN-TEST \n'
119 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
120 'method and can be ignored. Do not do this inside production code.\n'
121 'The android-binary-size trybot will block if the method exists in the\n'
122 'release apk.')
[email protected]eea609a2011-11-18 13:10:12123
124
Daniel Chenga44a1bcd2022-03-15 20:00:15125@dataclass
126class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34127 # String pattern. If the pattern begins with a slash, the pattern will be
128 # treated as a regular expression instead.
129 pattern: str
130 # Explanation as a sequence of strings. Each string in the sequence will be
131 # printed on its own line.
132 explanation: Sequence[str]
133 # Whether or not to treat this ban as a fatal error. If unspecified,
134 # defaults to true.
135 treat_as_error: Optional[bool] = None
136 # Paths that should be excluded from the ban check. Each string is a regular
137 # expression that will be matched against the path of the file being checked
138 # relative to the root of the source tree.
139 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28140
Daniel Chenga44a1bcd2022-03-15 20:00:15141
Daniel Cheng917ce542022-03-15 20:46:57142_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15143 BanRule(
144 'import java.net.URI;',
145 (
146 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
147 ),
148 excluded_paths=(
149 (r'net/android/javatests/src/org/chromium/net/'
150 'AndroidProxySelectorTest\.java'),
151 r'components/cronet/',
152 r'third_party/robolectric/local/',
153 ),
Michael Thiessen44457642020-02-06 00:24:15154 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15155 BanRule(
156 'import android.annotation.TargetApi;',
157 (
158 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
159 'RequiresApi ensures that any calls are guarded by the appropriate '
160 'SDK_INT check. See https://crbug.com/1116486.',
161 ),
162 ),
163 BanRule(
164 'import android.support.test.rule.UiThreadTestRule;',
165 (
166 'Do not use UiThreadTestRule, just use '
167 '@org.chromium.base.test.UiThreadTest on test methods that should run '
168 'on the UI thread. See https://crbug.com/1111893.',
169 ),
170 ),
171 BanRule(
172 'import android.support.test.annotation.UiThreadTest;',
173 ('Do not use android.support.test.annotation.UiThreadTest, use '
174 'org.chromium.base.test.UiThreadTest instead. See '
175 'https://crbug.com/1111893.',
176 ),
177 ),
178 BanRule(
179 'import android.support.test.rule.ActivityTestRule;',
180 (
181 'Do not use ActivityTestRule, use '
182 'org.chromium.base.test.BaseActivityTestRule instead.',
183 ),
184 excluded_paths=(
185 'components/cronet/',
186 ),
187 ),
188)
wnwenbdc444e2016-05-25 13:44:15189
Daniel Cheng917ce542022-03-15 20:46:57190_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15191 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41192 'StrictMode.allowThreadDiskReads()',
193 (
194 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
195 'directly.',
196 ),
197 False,
198 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15199 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41200 'StrictMode.allowThreadDiskWrites()',
201 (
202 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
203 'directly.',
204 ),
205 False,
206 ),
Daniel Cheng917ce542022-03-15 20:46:57207 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36208 '.waitForIdleSync()',
209 (
210 'Do not use waitForIdleSync as it masks underlying issues. There is '
211 'almost always something else you should wait on instead.',
212 ),
213 False,
214 ),
Ashley Newson09cbd602022-10-26 11:40:14215 BanRule(
Ashley Newsoneb6f5ce2022-10-26 14:45:42216 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14217 (
218 'Do not call android.content.Context.registerReceiver (or an override) '
219 'directly. Use one of the wrapper methods defined in '
220 'org.chromium.base.ContextUtils, such as '
221 'registerProtectedBroadcastReceiver, '
222 'registerExportedBroadcastReceiver, or '
223 'registerNonExportedBroadcastReceiver. See their documentation for '
224 'which one to use.',
225 ),
226 True,
227 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57228 r'.*Test[^a-z]',
229 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14230 'base/android/java/src/org/chromium/base/ContextUtils.java',
231 ),
232 ),
Ted Chocd5b327b12022-11-05 02:13:22233 BanRule(
234 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
235 (
236 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
237 'IntProperty because it will avoid unnecessary autoboxing of '
238 'primitives.',
239 ),
240 ),
Peilin Wangbba4a8652022-11-10 16:33:57241 BanRule(
242 'requestLayout()',
243 (
244 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
245 'which emits a trace event with additional information to help with '
246 'scroll jank investigations. See http://crbug.com/1354176.',
247 ),
248 False,
249 excluded_paths=(
250 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
251 ),
252 ),
Eric Stevensona9a980972017-09-23 00:04:41253)
254
Clement Yan9b330cb2022-11-17 05:25:29255_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
256 BanRule(
257 r'/\bchrome\.send\b',
258 (
259 '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).',
260 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
261 ),
262 True,
263 (
264 r'^(?!ash\/webui).+',
265 # TODO(crbug.com/1385601): pre-existing violations still need to be
266 # cleaned up.
267 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
268 'ash/webui/common/resources/quick_unlock/lock_screen_constants.js',
269 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
270 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.js',
271 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
272 'ash/webui/multidevice_debug/resources/logs.js',
273 'ash/webui/multidevice_debug/resources/webui.js',
274 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
275 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
276 'ash/webui/scanning/resources/scanning_browser_proxy.js',
277 ),
278 ),
279)
280
Daniel Cheng917ce542022-03-15 20:46:57281_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15282 BanRule(
[email protected]127f18ec2012-06-16 05:05:59283 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20284 (
285 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59286 'prohibited. Please use CrTrackingArea instead.',
287 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
288 ),
289 False,
290 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15291 BanRule(
[email protected]eaae1972014-04-16 04:17:26292 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20293 (
294 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59295 'instead.',
296 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
297 ),
298 False,
299 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15300 BanRule(
[email protected]127f18ec2012-06-16 05:05:59301 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20302 (
303 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59304 'Please use |convertPoint:(point) fromView:nil| instead.',
305 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
306 ),
307 True,
308 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15309 BanRule(
[email protected]127f18ec2012-06-16 05:05:59310 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20311 (
312 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59313 'Please use |convertPoint:(point) toView:nil| instead.',
314 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
315 ),
316 True,
317 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15318 BanRule(
[email protected]127f18ec2012-06-16 05:05:59319 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20320 (
321 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59322 'Please use |convertRect:(point) fromView:nil| instead.',
323 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
324 ),
325 True,
326 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15327 BanRule(
[email protected]127f18ec2012-06-16 05:05:59328 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20329 (
330 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59331 'Please use |convertRect:(point) toView:nil| instead.',
332 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
333 ),
334 True,
335 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15336 BanRule(
[email protected]127f18ec2012-06-16 05:05:59337 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20338 (
339 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59340 'Please use |convertSize:(point) fromView:nil| instead.',
341 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
342 ),
343 True,
344 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15345 BanRule(
[email protected]127f18ec2012-06-16 05:05:59346 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20347 (
348 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59349 'Please use |convertSize:(point) toView:nil| instead.',
350 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
351 ),
352 True,
353 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15354 BanRule(
jif65398702016-10-27 10:19:48355 r"/\s+UTF8String\s*]",
356 (
357 'The use of -[NSString UTF8String] is dangerous as it can return null',
358 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
359 'Please use |SysNSStringToUTF8| instead.',
360 ),
361 True,
362 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15363 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34364 r'__unsafe_unretained',
365 (
366 'The use of __unsafe_unretained is almost certainly wrong, unless',
367 'when interacting with NSFastEnumeration or NSInvocation.',
368 'Please use __weak in files build with ARC, nothing otherwise.',
369 ),
370 False,
371 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15372 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13373 'freeWhenDone:NO',
374 (
375 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
376 'Foundation types is prohibited.',
377 ),
378 True,
379 ),
[email protected]127f18ec2012-06-16 05:05:59380)
381
Sylvain Defresnea8b73d252018-02-28 15:45:54382_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15383 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54384 r'/\bTEST[(]',
385 (
386 'TEST() macro should not be used in Objective-C++ code as it does not ',
387 'drain the autorelease pool at the end of the test. Use TEST_F() ',
388 'macro instead with a fixture inheriting from PlatformTest (or a ',
389 'typedef).'
390 ),
391 True,
392 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15393 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54394 r'/\btesting::Test\b',
395 (
396 'testing::Test should not be used in Objective-C++ code as it does ',
397 'not drain the autorelease pool at the end of the test. Use ',
398 'PlatformTest instead.'
399 ),
400 True,
401 ),
Ewann2ecc8d72022-07-18 07:41:23402 BanRule(
403 ' systemImageNamed:',
404 (
405 '+[UIImage systemImageNamed:] should not be used to create symbols.',
406 'Instead use a wrapper defined in:',
407 'ios/chrome/browser/ui/icons/chrome_symbol.h'
408 ),
409 True,
Ewann450a2ef2022-07-19 14:38:23410 excluded_paths=(
411 'ios/chrome/browser/ui/icons/chrome_symbol.mm',
412 ),
Ewann2ecc8d72022-07-18 07:41:23413 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54414)
415
Daniel Cheng917ce542022-03-15 20:46:57416_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15417 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05418 r'/\bEXPECT_OCMOCK_VERIFY\b',
419 (
420 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
421 'it is meant for GTests. Use [mock verify] instead.'
422 ),
423 True,
424 ),
425)
426
Daniel Cheng917ce542022-03-15 20:46:57427_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15428 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04429 r'/\busing namespace ',
430 (
431 'Using directives ("using namespace x") are banned by the Google Style',
432 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
433 'Explicitly qualify symbols or use using declarations ("using x::foo").',
434 ),
435 True,
436 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
437 ),
Antonio Gomes07300d02019-03-13 20:59:57438 # Make sure that gtest's FRIEND_TEST() macro is not used; the
439 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
440 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15441 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20442 'FRIEND_TEST(',
443 (
[email protected]e3c945502012-06-26 20:01:49444 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20445 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
446 ),
447 False,
[email protected]7345da02012-11-27 14:31:49448 (),
[email protected]23e6cbc2012-06-16 18:51:20449 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15450 BanRule(
tomhudsone2c14d552016-05-26 17:07:46451 'setMatrixClip',
452 (
453 'Overriding setMatrixClip() is prohibited; ',
454 'the base function is deprecated. ',
455 ),
456 True,
457 (),
458 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15459 BanRule(
[email protected]52657f62013-05-20 05:30:31460 'SkRefPtr',
461 (
462 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22463 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31464 ),
465 True,
466 (),
467 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15468 BanRule(
[email protected]52657f62013-05-20 05:30:31469 'SkAutoRef',
470 (
471 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22472 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31473 ),
474 True,
475 (),
476 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15477 BanRule(
[email protected]52657f62013-05-20 05:30:31478 'SkAutoTUnref',
479 (
480 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22481 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31482 ),
483 True,
484 (),
485 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15486 BanRule(
[email protected]52657f62013-05-20 05:30:31487 'SkAutoUnref',
488 (
489 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
490 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22491 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31492 ),
493 True,
494 (),
495 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15496 BanRule(
[email protected]d89eec82013-12-03 14:10:59497 r'/HANDLE_EINTR\(.*close',
498 (
499 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
500 'descriptor will be closed, and it is incorrect to retry the close.',
501 'Either call close directly and ignore its return value, or wrap close',
502 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
503 ),
504 True,
505 (),
506 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15507 BanRule(
[email protected]d89eec82013-12-03 14:10:59508 r'/IGNORE_EINTR\((?!.*close)',
509 (
510 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
511 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
512 ),
513 True,
514 (
515 # Files that #define IGNORE_EINTR.
Bruce Dawson40fece62022-09-16 19:58:31516 r'^base/posix/eintr_wrapper\.h$',
517 r'^ppapi/tests/test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59518 ),
519 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15520 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43521 r'/v8::Extension\(',
522 (
523 'Do not introduce new v8::Extensions into the code base, use',
524 'gin::Wrappable instead. See http://crbug.com/334679',
525 ),
526 True,
[email protected]f55c90ee62014-04-12 00:50:03527 (
Bruce Dawson40fece62022-09-16 19:58:31528 r'extensions/renderer/safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03529 ),
[email protected]ec5b3f02014-04-04 18:43:43530 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15531 BanRule(
jame2d1a952016-04-02 00:27:10532 '#pragma comment(lib,',
533 (
534 'Specify libraries to link with in build files and not in the source.',
535 ),
536 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41537 (
Bruce Dawson40fece62022-09-16 19:58:31538 r'^base/third_party/symbolize/.*',
539 r'^third_party/abseil-cpp/.*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41540 ),
jame2d1a952016-04-02 00:27:10541 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15542 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02543 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59544 (
545 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
546 ),
547 False,
548 (),
549 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15550 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02551 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59552 (
553 'Consider using THREAD_CHECKER macros instead of the class directly.',
554 ),
555 False,
556 (),
557 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15558 BanRule(
Sean Maher03efef12022-09-23 22:43:13559 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
560 (
561 'It is not allowed to call these methods from the subclasses ',
562 'of Sequenced or SingleThread task runners.',
563 ),
564 True,
565 (),
566 ),
567 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06568 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
569 (
570 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
571 'deprecated (http://crbug.com/634507). Please avoid converting away',
572 'from the Time types in Chromium code, especially if any math is',
573 'being done on time values. For interfacing with platform/library',
574 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
575 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48576 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06577 'other use cases, please contact base/time/OWNERS.',
578 ),
579 False,
580 (),
581 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15582 BanRule(
dbeamb6f4fde2017-06-15 04:03:06583 'CallJavascriptFunctionUnsafe',
584 (
585 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
586 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
587 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
588 ),
589 False,
590 (
Bruce Dawson40fece62022-09-16 19:58:31591 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
592 r'^content/public/browser/web_ui\.h$',
593 r'^content/public/test/test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06594 ),
595 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15596 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24597 'leveldb::DB::Open',
598 (
599 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
600 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
601 "Chrome's tracing, making their memory usage visible.",
602 ),
603 True,
604 (
605 r'^third_party/leveldatabase/.*\.(cc|h)$',
606 ),
Gabriel Charette0592c3a2017-07-26 12:02:04607 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15608 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08609 'leveldb::NewMemEnv',
610 (
611 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58612 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
613 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08614 ),
615 True,
616 (
617 r'^third_party/leveldatabase/.*\.(cc|h)$',
618 ),
619 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15620 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47621 'RunLoop::QuitCurrent',
622 (
Robert Liao64b7ab22017-08-04 23:03:43623 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
624 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47625 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41626 False,
Gabriel Charetted9839bc2017-07-29 14:17:47627 (),
Gabriel Charettea44975052017-08-21 23:14:04628 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15629 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04630 'base::ScopedMockTimeMessageLoopTaskRunner',
631 (
Gabriel Charette87cc1af2018-04-25 20:52:51632 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11633 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51634 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
635 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
636 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04637 ),
Gabriel Charette87cc1af2018-04-25 20:52:51638 False,
Gabriel Charettea44975052017-08-21 23:14:04639 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57640 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15641 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44642 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57643 (
644 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02645 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57646 ),
647 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16648 # Abseil's benchmarks never linked into chrome.
649 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38650 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15651 BanRule(
Peter Kasting991618a62019-06-17 22:00:09652 r'/\bstd::stoi\b',
653 (
654 'std::stoi uses exceptions to communicate results. ',
655 'Use base::StringToInt() instead.',
656 ),
657 True,
658 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
659 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15660 BanRule(
Peter Kasting991618a62019-06-17 22:00:09661 r'/\bstd::stol\b',
662 (
663 'std::stol uses exceptions to communicate results. ',
664 'Use base::StringToInt() instead.',
665 ),
666 True,
667 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
668 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15669 BanRule(
Peter Kasting991618a62019-06-17 22:00:09670 r'/\bstd::stoul\b',
671 (
672 'std::stoul uses exceptions to communicate results. ',
673 'Use base::StringToUint() instead.',
674 ),
675 True,
676 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
677 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15678 BanRule(
Peter Kasting991618a62019-06-17 22:00:09679 r'/\bstd::stoll\b',
680 (
681 'std::stoll uses exceptions to communicate results. ',
682 'Use base::StringToInt64() instead.',
683 ),
684 True,
685 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
686 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15687 BanRule(
Peter Kasting991618a62019-06-17 22:00:09688 r'/\bstd::stoull\b',
689 (
690 'std::stoull uses exceptions to communicate results. ',
691 'Use base::StringToUint64() instead.',
692 ),
693 True,
694 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
695 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15696 BanRule(
Peter Kasting991618a62019-06-17 22:00:09697 r'/\bstd::stof\b',
698 (
699 'std::stof uses exceptions to communicate results. ',
700 'For locale-independent values, e.g. reading numbers from disk',
701 'profiles, use base::StringToDouble().',
702 'For user-visible values, parse using ICU.',
703 ),
704 True,
705 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
706 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15707 BanRule(
Peter Kasting991618a62019-06-17 22:00:09708 r'/\bstd::stod\b',
709 (
710 'std::stod uses exceptions to communicate results. ',
711 'For locale-independent values, e.g. reading numbers from disk',
712 'profiles, use base::StringToDouble().',
713 'For user-visible values, parse using ICU.',
714 ),
715 True,
716 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
717 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15718 BanRule(
Peter Kasting991618a62019-06-17 22:00:09719 r'/\bstd::stold\b',
720 (
721 'std::stold uses exceptions to communicate results. ',
722 'For locale-independent values, e.g. reading numbers from disk',
723 'profiles, use base::StringToDouble().',
724 'For user-visible values, parse using ICU.',
725 ),
726 True,
727 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
728 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15729 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45730 r'/\bstd::to_string\b',
731 (
732 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09733 'For locale-independent strings, e.g. writing numbers to disk',
734 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45735 'For user-visible strings, use base::FormatNumber() and',
736 'the related functions in base/i18n/number_formatting.h.',
737 ),
Peter Kasting991618a62019-06-17 22:00:09738 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21739 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45740 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15741 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45742 r'/\bstd::shared_ptr\b',
743 (
744 'std::shared_ptr should not be used. Use scoped_refptr instead.',
745 ),
746 True,
Ulan Degenbaev947043882021-02-10 14:02:31747 [
748 # Needed for interop with third-party library.
749 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57750 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58751 '^third_party/blink/renderer/bindings/core/v8/' +
752 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58753 '^gin/array_buffer\.(cc|h)',
754 '^chrome/services/sharing/nearby/',
Stephen Nuskoe09c8ef22022-09-29 00:47:28755 # Needed for interop with third-party library libunwindstack.
Stephen Nuskoe51c1382022-09-26 15:49:03756 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
Meilin Wang00efc7c2021-05-13 01:12:42757 # gRPC provides some C++ libraries that use std::shared_ptr<>.
Yeunjoo Choi1b644402022-08-25 02:36:10758 '^chromeos/ash/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59759 '^chromecast/cast_core/grpc',
760 '^chromecast/cast_core/runtime/browser',
Yue Shef83d95202022-09-26 20:23:45761 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Wez5f56be52021-05-04 09:30:58762 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Fabrice de Gans3b875422022-04-19 19:40:26763 '^base/fuchsia/filtered_service_directory\.(cc|h)',
764 '^base/fuchsia/service_directory_test_base\.h',
Wez5f56be52021-05-04 09:30:58765 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57766 # Needed for clang plugin tests
767 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57768 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21769 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15770 BanRule(
Peter Kasting991618a62019-06-17 22:00:09771 r'/\bstd::weak_ptr\b',
772 (
773 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
774 ),
775 True,
776 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
777 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15778 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21779 r'/\blong long\b',
780 (
781 'long long is banned. Use stdint.h if you need a 64 bit number.',
782 ),
783 False, # Only a warning since it is already used.
784 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
785 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15786 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44787 r'/\b(absl|std)::any\b',
Daniel Chengc05fcc62022-01-12 16:54:29788 (
Daniel Chenga44a1bcd2022-03-15 20:00:15789 'absl::any / std::any are not safe to use in a component build.',
Daniel Chengc05fcc62022-01-12 16:54:29790 ),
791 True,
792 # Not an error in third party folders, though it probably should be :)
793 [_THIRD_PARTY_EXCEPT_BLINK],
794 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15795 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21796 r'/\bstd::bind\b',
797 (
798 'std::bind is banned because of lifetime risks.',
799 'Use base::BindOnce or base::BindRepeating instead.',
800 ),
801 True,
802 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
803 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15804 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44805 (
806 r'/\b(?:'
807 r'std::linear_congruential_engine|std::mersenne_twister_engine|'
808 r'std::subtract_with_carry_engine|std::discard_block_engine|'
809 r'std::independent_bits_engine|std::shuffle_order_engine|'
810 r'std::minstd_rand0|std::minstd_rand|'
811 r'std::mt19937|std::mt19937_64|'
812 r'std::ranlux24_base|std::ranlux48_base|std::ranlux24|std::ranlux48|'
813 r'std::knuth_b|'
814 r'std::default_random_engine|'
815 r'std::random_device'
816 r')\b'
817 ),
818 (
819 'STL random number engines and generators are banned. Use the ',
820 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
821 'base::RandomBitGenerator.'
822 ),
823 True,
824 [
825 # Not an error in third_party folders.
826 _THIRD_PARTY_EXCEPT_BLINK,
827 # Various tools which build outside of Chrome.
828 r'testing/libfuzzer',
829 r'tools/android/io_benchmark/',
830 # Fuzzers are allowed to use standard library random number generators
831 # since fuzzing speed + reproducibility is important.
832 r'tools/ipc_fuzzer/',
833 r'.+_fuzzer\.cc$',
834 r'.+_fuzzertest\.cc$',
835 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
836 # the standard library's random number generators, and should be
837 # migrated to the //base equivalent.
838 r'ash/ambient/model/ambient_topic_queue\.cc',
839 r'base/allocator/partition_allocator/partition_alloc_unittest\.cc',
840 r'base/ranges/algorithm_unittest\.cc',
841 r'base/test/launcher/test_launcher\.cc',
842 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
843 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
844 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
845 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
846 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
847 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
848 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
849 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
850 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
851 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
852 r'chrome/chrome_cleaner/logging/detailed_info_sampler\.cc',
853 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
854 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
855 r'components/metrics/metrics_state_manager\.cc',
856 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
857 r'components/zucchini/disassembler_elf_unittest\.cc',
858 r'content/browser/webid/federated_auth_request_impl\.cc',
859 r'content/browser/webid/federated_auth_request_impl\.cc',
860 r'media/cast/test/utility/udp_proxy\.h',
861 r'sql/recover_module/module_unittest\.cc',
862 ],
863 ),
864 BanRule(
Peter Kasting4f35bfc2022-10-18 18:39:12865 r'/\babsl::bind_front\b',
866 (
Daniel Cheng192683f2022-11-01 20:52:44867 'absl::bind_front is banned. Use base::BindOnce() or '
868 'base::BindRepeating() instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12869 ),
870 True,
871 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
872 ),
873 BanRule(
874 r'/\bABSL_FLAG\b',
875 (
876 'ABSL_FLAG is banned. Use base::CommandLine instead.',
877 ),
878 True,
879 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
880 ),
881 BanRule(
882 r'/\babsl::c_',
883 (
884 'Abseil container utilities are banned. Use base/ranges/algorithm.h',
885 'instead.',
886 ),
887 True,
888 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
889 ),
890 BanRule(
891 r'/\babsl::FunctionRef\b',
892 (
893 'absl::FunctionRef is banned. Use base::FunctionRef instead.',
894 ),
895 True,
896 [
897 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
898 # interoperability.
899 r'^base/functional/bind_internal\.h',
900 # base::FunctionRef is implemented on top of absl::FunctionRef.
901 r'^base/functional/function_ref.*\..+',
902 # Not an error in third_party folders.
903 _THIRD_PARTY_EXCEPT_BLINK,
904 ],
905 ),
906 BanRule(
907 r'/\babsl::(Insecure)?BitGen\b',
908 (
Daniel Cheng192683f2022-11-01 20:52:44909 'absl random number generators are banned. Use the helpers in '
910 'base/rand_util.h instead, e.g. base::RandBytes() or ',
911 'base::RandomBitGenerator.'
Peter Kasting4f35bfc2022-10-18 18:39:12912 ),
913 True,
914 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
915 ),
916 BanRule(
917 r'/\babsl::Span\b',
918 (
919 'absl::Span is banned. Use base::span instead.',
920 ),
921 True,
922 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
923 ),
924 BanRule(
925 r'/\babsl::StatusOr\b',
926 (
927 'absl::StatusOr is banned. Use base::expected instead.',
928 ),
929 True,
Adithya Srinivasanb2041882022-10-21 19:34:20930 [
931 # Needed to use liburlpattern API.
932 r'third_party/blink/renderer/core/url_pattern/.*',
933 # Not an error in third_party folders.
934 _THIRD_PARTY_EXCEPT_BLINK
935 ],
Peter Kasting4f35bfc2022-10-18 18:39:12936 ),
937 BanRule(
938 r'/\babsl::StrFormat\b',
939 (
940 'absl::StrFormat is banned for now. Use base::StringPrintf instead.',
941 ),
942 True,
943 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
944 ),
945 BanRule(
946 r'/\babsl::string_view\b',
947 (
948 'absl::string_view is banned. Use base::StringPiece instead.',
949 ),
950 True,
Adithya Srinivasanb2041882022-10-21 19:34:20951 [
952 # Needed to use liburlpattern API.
953 r'third_party/blink/renderer/core/url_pattern/.*',
954 # Not an error in third_party folders.
955 _THIRD_PARTY_EXCEPT_BLINK
956 ],
Peter Kasting4f35bfc2022-10-18 18:39:12957 ),
958 BanRule(
959 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
960 (
961 'Abseil string utilities are banned. Use base/strings instead.',
962 ),
963 True,
964 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
965 ),
966 BanRule(
967 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
968 (
969 'Abseil synchronization primitives are banned. Use',
970 'base/synchronization instead.',
971 ),
972 True,
973 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
974 ),
975 BanRule(
976 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
977 (
978 'Abseil\'s time library is banned. Use base/time instead.',
979 ),
980 True,
981 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
982 ),
983 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:03984 r'/\bstd::optional\b',
985 (
986 'std::optional is banned. Use absl::optional instead.',
987 ),
988 True,
989 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
990 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15991 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21992 r'/\b#include <chrono>\b',
993 (
994 '<chrono> overlaps with Time APIs in base. Keep using',
995 'base classes.',
996 ),
997 True,
998 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
999 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151000 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211001 r'/\b#include <exception>\b',
1002 (
1003 'Exceptions are banned and disabled in Chromium.',
1004 ),
1005 True,
1006 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1007 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151008 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211009 r'/\bstd::function\b',
1010 (
Colin Blundellea615d422021-05-12 09:35:411011 'std::function is banned. Instead use base::OnceCallback or ',
1012 'base::RepeatingCallback, which directly support Chromium\'s weak ',
1013 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:211014 ),
Daniel Chenge5583e3c2022-09-22 00:19:411015 True,
Daniel Chengcd23b8b2022-09-16 17:16:241016 [
1017 # Has tests that template trait helpers don't unintentionally match
1018 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:411019 r'base/functional/callback_helpers_unittest\.cc',
1020 # Required to implement interfaces from the third-party perfetto
1021 # library.
1022 r'base/tracing/perfetto_task_runner\.cc',
1023 r'base/tracing/perfetto_task_runner\.h',
1024 # Needed for interop with the third-party nearby library type
1025 # location::nearby::connections::ResultCallback.
1026 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1027 # Needed for interop with the internal libassistant library.
1028 'chromeos/ash/services/libassistant/callback_utils\.h',
1029 # Needed for interop with Fuchsia fidl APIs.
1030 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1031 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1032 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1033 # Required to interop with interfaces from the third-party perfetto
1034 # library.
1035 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1036 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1037 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1038 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1039 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1040 'services/tracing/public/cpp/perfetto/producer_client\.h',
1041 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1042 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1043 # Required for interop with the third-party webrtc library.
1044 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1045 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
1046
1047 # TODO(https://crbug.com/1364577): Various uses that should be
1048 # migrated to something else.
1049 # Should use base::OnceCallback or base::RepeatingCallback.
1050 'base/allocator/dispatcher/initializer_unittest\.cc',
1051 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1052 'chrome/browser/ash/accessibility/speech_monitor\.h',
1053 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1054 'chromecast/base/observer_unittest\.cc',
1055 'chromecast/browser/cast_web_view\.h',
1056 'chromecast/public/cast_media_shlib\.h',
1057 'device/bluetooth/floss/exported_callback_manager\.h',
1058 'device/bluetooth/floss/floss_dbus_client\.h',
1059 'device/fido/cable/v2_handshake_unittest\.cc',
1060 'device/fido/pin\.cc',
1061 'services/tracing/perfetto/test_utils\.h',
1062 # Should use base::FunctionRef.
1063 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1064 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1065 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1066 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1067 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1068 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1069 # Does not need std::function at all.
1070 'components/omnibox/browser/autocomplete_result\.cc',
1071 'device/fido/win/webauthn_api\.cc',
1072 'media/audio/alsa/alsa_util\.cc',
1073 'media/remoting/stream_provider\.h',
1074 'sql/vfs_wrapper\.cc',
1075 # TODO(https://crbug.com/1364585): Remove usage and exception list
1076 # entries.
1077 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1078 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1079 # TODO(https://crbug.com/1364579): Remove usage and exception list
1080 # entry.
1081 'ui/views/controls/focus_ring\.h',
1082
1083 # Various pre-existing uses in //tools that is low-priority to fix.
1084 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1085 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1086 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1087 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1088 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
1089
Daniel Chengcd23b8b2022-09-16 17:16:241090 # Not an error in third_party folders.
1091 _THIRD_PARTY_EXCEPT_BLINK
1092 ],
Daniel Bratell609102be2019-03-27 20:53:211093 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151094 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211095 r'/\b#include <random>\b',
1096 (
1097 'Do not use any random number engines from <random>. Instead',
1098 'use base::RandomBitGenerator.',
1099 ),
1100 True,
1101 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1102 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151103 BanRule(
Tom Andersona95e12042020-09-09 23:08:001104 r'/\b#include <X11/',
1105 (
1106 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
1107 ),
1108 True,
1109 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1110 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151111 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211112 r'/\bstd::ratio\b',
1113 (
1114 'std::ratio is banned by the Google Style Guide.',
1115 ),
1116 True,
1117 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451118 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151119 BanRule(
Gabriel Charetted90bcc92021-09-21 00:23:101120 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:381121 (
Gabriel Charetted90bcc92021-09-21 00:23:101122 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:381123 ),
Gabriel Charette04b138f2018-08-06 00:03:221124 False,
Francois Doray43670e32017-09-27 12:40:381125 (),
1126 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151127 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:581128 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:191129 (
1130 'RunMessageLoop is deprecated, use RunLoop instead.',
1131 ),
1132 False,
1133 (),
1134 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151135 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441136 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191137 (
1138 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
1139 ),
1140 False,
1141 (),
1142 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151143 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441144 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191145 (
1146 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1147 "if you're convinced you need this.",
1148 ),
1149 False,
1150 (),
1151 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151152 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441153 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191154 (
1155 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041156 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191157 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1158 'async events instead of flushing threads.',
1159 ),
1160 False,
1161 (),
1162 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151163 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191164 r'MessageLoopRunner',
1165 (
1166 'MessageLoopRunner is deprecated, use RunLoop instead.',
1167 ),
1168 False,
1169 (),
1170 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151171 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441172 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191173 (
1174 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1175 "gab@ if you found a use case where this is the only solution.",
1176 ),
1177 False,
1178 (),
1179 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151180 BanRule(
Victor Costane48a2e82019-03-15 22:02:341181 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161182 (
Victor Costane48a2e82019-03-15 22:02:341183 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161184 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1185 ),
1186 True,
1187 (
1188 r'^sql/initialization\.(cc|h)$',
1189 r'^third_party/sqlite/.*\.(c|cc|h)$',
1190 ),
1191 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151192 BanRule(
Austin Sullivand661ab52022-11-16 08:55:151193 'CREATE VIEW',
1194 (
1195 'SQL views are disabled in Chromium feature code',
1196 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1197 ),
1198 True,
1199 (
1200 _THIRD_PARTY_EXCEPT_BLINK,
1201 # sql/ itself uses views when using memory-mapped IO.
1202 r'^sql/.*',
1203 # Various performance tools that do not build as part of Chrome.
1204 r'^infra/.*',
1205 r'^tools/perf.*',
1206 r'.*perfetto.*',
1207 ),
1208 ),
1209 BanRule(
1210 'CREATE VIRTUAL TABLE',
1211 (
1212 'SQL virtual tables are disabled in Chromium feature code',
1213 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1214 ),
1215 True,
1216 (
1217 _THIRD_PARTY_EXCEPT_BLINK,
1218 # sql/ itself uses virtual tables in the recovery module and tests.
1219 r'^sql/.*',
1220 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1221 r'third_party/blink/web_tests/storage/websql/.*'
1222 # Various performance tools that do not build as part of Chrome.
1223 r'^tools/perf.*',
1224 r'.*perfetto.*',
1225 ),
1226 ),
1227 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441228 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471229 (
1230 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1231 'base::RandomShuffle instead.'
1232 ),
1233 True,
1234 (),
1235 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151236 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241237 'ios/web/public/test/http_server',
1238 (
1239 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1240 ),
1241 False,
1242 (),
1243 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151244 BanRule(
Robert Liao764c9492019-01-24 18:46:281245 'GetAddressOf',
1246 (
1247 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531248 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111249 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531250 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281251 ),
1252 True,
1253 (),
1254 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151255 BanRule(
Ben Lewisa9514602019-04-29 17:53:051256 'SHFileOperation',
1257 (
1258 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1259 'complex functions to achieve the same goals. Use IFileOperation for ',
1260 'any esoteric actions instead.'
1261 ),
1262 True,
1263 (),
1264 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151265 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511266 'StringFromGUID2',
1267 (
1268 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241269 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511270 ),
1271 True,
1272 (
Daniel Chenga44a1bcd2022-03-15 20:00:151273 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511274 ),
1275 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151276 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511277 'StringFromCLSID',
1278 (
1279 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241280 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511281 ),
1282 True,
1283 (
Daniel Chenga44a1bcd2022-03-15 20:00:151284 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511285 ),
1286 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151287 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131288 'kCFAllocatorNull',
1289 (
1290 'The use of kCFAllocatorNull with the NoCopy creation of ',
1291 'CoreFoundation types is prohibited.',
1292 ),
1293 True,
1294 (),
1295 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151296 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291297 'mojo::ConvertTo',
1298 (
1299 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1300 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1301 'StringTraits if you would like to convert between custom types and',
1302 'the wire format of mojom types.'
1303 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221304 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291305 (
David Dorwin13dc48b2022-06-03 21:18:421306 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1307 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291308 r'^third_party/blink/.*\.(cc|h)$',
1309 r'^content/renderer/.*\.(cc|h)$',
1310 ),
1311 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151312 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161313 'GetInterfaceProvider',
1314 (
1315 'InterfaceProvider is deprecated.',
1316 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1317 'or Platform::GetBrowserInterfaceBroker.'
1318 ),
1319 False,
1320 (),
1321 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151322 BanRule(
Robert Liao1d78df52019-11-11 20:02:011323 'CComPtr',
1324 (
1325 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1326 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1327 'details.'
1328 ),
1329 False,
1330 (),
1331 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151332 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201333 r'/\b(IFACE|STD)METHOD_?\(',
1334 (
1335 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1336 'Instead, always use IFACEMETHODIMP in the declaration.'
1337 ),
1338 False,
1339 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1340 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151341 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471342 'set_owned_by_client',
1343 (
1344 'set_owned_by_client is deprecated.',
1345 'views::View already owns the child views by default. This introduces ',
1346 'a competing ownership model which makes the code difficult to reason ',
1347 'about. See http://crbug.com/1044687 for more details.'
1348 ),
1349 False,
1350 (),
1351 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151352 BanRule(
Peter Boström7ff41522021-07-29 03:43:271353 'RemoveAllChildViewsWithoutDeleting',
1354 (
1355 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1356 'This method is deemed dangerous as, unless raw pointers are re-added,',
1357 'calls to this method introduce memory leaks.'
1358 ),
1359 False,
1360 (),
1361 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151362 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121363 r'/\bTRACE_EVENT_ASYNC_',
1364 (
1365 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1366 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1367 ),
1368 False,
1369 (
1370 r'^base/trace_event/.*',
1371 r'^base/tracing/.*',
1372 ),
1373 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151374 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431375 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1376 (
1377 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1378 'dumps and may spam crash reports. Consider if the throttled',
1379 'variants suffice instead.',
1380 ),
1381 False,
1382 (),
1383 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151384 BanRule(
Robert Liao22f66a52021-04-10 00:57:521385 'RoInitialize',
1386 (
Robert Liao48018922021-04-16 23:03:021387 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521388 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1389 'instead. See http://crbug.com/1197722 for more information.'
1390 ),
1391 True,
Robert Liao48018922021-04-16 23:03:021392 (
Bruce Dawson40fece62022-09-16 19:58:311393 r'^base/win/scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021394 ),
Robert Liao22f66a52021-04-10 00:57:521395 ),
Patrick Monettec343bb982022-06-01 17:18:451396 BanRule(
1397 r'base::Watchdog',
1398 (
1399 'base::Watchdog is deprecated because it creates its own thread.',
1400 'Instead, manually start a timer on a SequencedTaskRunner.',
1401 ),
1402 False,
1403 (),
1404 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091405 BanRule(
1406 'base::Passed',
1407 (
1408 'Do not use base::Passed. It is a legacy helper for capturing ',
1409 'move-only types with base::BindRepeating, but invoking the ',
1410 'resulting RepeatingCallback moves the captured value out of ',
1411 'the callback storage, and subsequent invocations may pass the ',
1412 'value in a valid but undefined state. Prefer base::BindOnce().',
1413 'See http://crbug.com/1326449 for context.'
1414 ),
1415 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481416 (
1417 # False positive, but it is also fine to let bind internals reference
1418 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241419 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481420 r'^base[\\/]functional[\\/]bind_internal\.h',
1421 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091422 ),
Daniel Cheng2248b332022-07-27 06:16:591423 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431424 r'base::Feature k',
1425 (
1426 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1427 'directly declaring/defining features.'
1428 ),
1429 True,
1430 [
1431 _THIRD_PARTY_EXCEPT_BLINK,
1432 ],
1433 ),
Robert Ogden92101dcb2022-10-19 23:49:361434 BanRule(
1435 r'\bchartorune\b',
1436 (
1437 'chartorune is not memory-safe, unless you can guarantee the input ',
1438 'string is always null-terminated. Otherwise, please use charntorune ',
1439 'from libphonenumber instead.'
1440 ),
1441 True,
1442 [
1443 _THIRD_PARTY_EXCEPT_BLINK,
1444 # Exceptions to this rule should have a fuzzer.
1445 ],
1446 ),
[email protected]127f18ec2012-06-16 05:05:591447)
1448
Daniel Cheng92c15e32022-03-16 17:48:221449_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1450 BanRule(
1451 'handle<shared_buffer>',
1452 (
1453 'Please use one of the more specific shared memory types instead:',
1454 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1455 ' mojo_base.mojom.WritableSharedMemoryRegion',
1456 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1457 ),
1458 True,
1459 ),
1460)
1461
mlamouria82272622014-09-16 18:45:041462_IPC_ENUM_TRAITS_DEPRECATED = (
1463 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501464 'See http://www.chromium.org/Home/chromium-security/education/'
1465 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041466
Stephen Martinis97a394142018-06-07 23:06:051467_LONG_PATH_ERROR = (
1468 'Some files included in this CL have file names that are too long (> 200'
1469 ' characters). If committed, these files will cause issues on Windows. See'
1470 ' https://crbug.com/612667 for more details.'
1471)
1472
Shenghua Zhangbfaa38b82017-11-16 21:58:021473_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:311474 r".*/AppHooksImpl\.java",
1475 r".*/BuildHooksAndroidImpl\.java",
1476 r".*/LicenseContentProvider\.java",
1477 r".*/PlatformServiceBridgeImpl.java",
1478 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021479]
[email protected]127f18ec2012-06-16 05:05:591480
Mohamed Heikald048240a2019-11-12 16:57:371481# List of image extensions that are used as resources in chromium.
1482_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1483
Sean Kau46e29bc2017-08-28 16:31:161484# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401485_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:311486 r'test/data/',
1487 r'testing/buildbot/',
1488 r'^components/policy/resources/policy_templates\.json$',
1489 r'^third_party/protobuf/',
1490 r'^third_party/blink/perf_tests/speedometer/resources/todomvc/learn.json',
1491 r'^third_party/blink/renderer/devtools/protocol\.json$',
1492 r'^third_party/blink/web_tests/external/wpt/',
1493 r'^tools/perf/',
1494 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311495 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:311496 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:161497]
1498
Andrew Grieveb773bad2020-06-05 18:00:381499# These are not checked on the public chromium-presubmit trybot.
1500# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041501# checkouts.
agrievef32bcc72016-04-04 14:57:401502_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381503 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381504]
1505
1506
1507_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101508 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041509 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361510 'base/android/jni_generator/jni_generator.pydeps',
1511 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361512 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041513 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361514 'build/android/gyp/aar.pydeps',
1515 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271516 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361517 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381518 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361519 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021520 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221521 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111522 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361523 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361524 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361525 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111526 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041527 'build/android/gyp/create_app_bundle_apks.pydeps',
1528 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361529 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121530 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091531 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221532 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401533 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001534 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361535 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421536 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041537 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361538 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361539 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211540 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361541 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361542 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361543 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581544 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361545 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141546 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261547 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471548 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041549 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361550 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361551 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101552 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361553 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221554 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361555 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221556 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101557 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461558 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301559 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241560 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361561 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461562 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561563 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361564 'build/android/incremental_install/generate_android_manifest.pydeps',
1565 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321566 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041567 'build/android/resource_sizes.pydeps',
1568 'build/android/test_runner.pydeps',
1569 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361570 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361571 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321572 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271573 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1574 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041575 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001576 'components/cronet/tools/generate_javadoc.pydeps',
1577 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381578 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001579 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381580 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181581 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411582 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1583 'testing/merge_scripts/standard_gtest_merge.pydeps',
1584 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1585 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041586 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421587 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251588 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421589 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131590 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501591 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411592 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1593 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061594 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221595 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451596 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401597]
1598
wnwenbdc444e2016-05-25 13:44:151599
agrievef32bcc72016-04-04 14:57:401600_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1601
1602
Eric Boren6fd2b932018-01-25 15:05:081603# Bypass the AUTHORS check for these accounts.
1604_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591605 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451606 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591607 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521608 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231609 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471610 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461611 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:181612 'lacros-sdk-version-roller', 'chrome-automated-expectation',
1613 'chromium-automated-expectation')
Eric Boren835d71f2018-09-07 21:09:041614 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271615 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041616 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161617 for s in ('chromium-internal-autoroll',)
1618 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:551619 for s in ('swarming-tasks',)
1620 ) | set('%[email protected]' % s
1621 for s in ('global-integration-try-builder',
1622 'global-integration-ci-builder'))
Eric Boren6fd2b932018-01-25 15:05:081623
Matt Stark6ef08872021-07-29 01:21:461624_INVALID_GRD_FILE_LINE = [
1625 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1626]
Eric Boren6fd2b932018-01-25 15:05:081627
Daniel Bratell65b033262019-04-23 08:17:061628def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501629 """Returns True if this file contains C++-like code (and not Python,
1630 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061631
Sam Maiera6e76d72022-02-11 21:43:501632 ext = input_api.os_path.splitext(file_path)[1]
1633 # This list is compatible with CppChecker.IsCppFile but we should
1634 # consider adding ".c" to it. If we do that we can use this function
1635 # at more places in the code.
1636 return ext in (
1637 '.h',
1638 '.cc',
1639 '.cpp',
1640 '.m',
1641 '.mm',
1642 )
1643
Daniel Bratell65b033262019-04-23 08:17:061644
1645def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501646 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061647
1648
1649def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501650 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061651
1652
1653def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501654 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061655
Mohamed Heikal5e5b7922020-10-29 18:57:591656
Erik Staabc734cd7a2021-11-23 03:11:521657def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501658 ext = input_api.os_path.splitext(file_path)[1]
1659 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521660
1661
Mohamed Heikal5e5b7922020-10-29 18:57:591662def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501663 """Prevent additions of dependencies from the upstream repo on //clank."""
1664 # clank can depend on clank
1665 if input_api.change.RepositoryRoot().endswith('clank'):
1666 return []
1667 build_file_patterns = [
1668 r'(.+/)?BUILD\.gn',
1669 r'.+\.gni',
1670 ]
1671 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1672 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591673
Sam Maiera6e76d72022-02-11 21:43:501674 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591675
Sam Maiera6e76d72022-02-11 21:43:501676 def FilterFile(affected_file):
1677 return input_api.FilterSourceFile(affected_file,
1678 files_to_check=build_file_patterns,
1679 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591680
Sam Maiera6e76d72022-02-11 21:43:501681 problems = []
1682 for f in input_api.AffectedSourceFiles(FilterFile):
1683 local_path = f.LocalPath()
1684 for line_number, line in f.ChangedContents():
1685 if (bad_pattern.search(line)):
1686 problems.append('%s:%d\n %s' %
1687 (local_path, line_number, line.strip()))
1688 if problems:
1689 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1690 else:
1691 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591692
1693
Saagar Sanghavifceeaae2020-08-12 16:40:361694def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501695 """Attempts to prevent use of functions intended only for testing in
1696 non-testing code. For now this is just a best-effort implementation
1697 that ignores header files and may have some false positives. A
1698 better implementation would probably need a proper C++ parser.
1699 """
1700 # We only scan .cc files and the like, as the declaration of
1701 # for-testing functions in header files are hard to distinguish from
1702 # calls to such functions without a proper C++ parser.
1703 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191704
Sam Maiera6e76d72022-02-11 21:43:501705 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1706 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1707 base_function_pattern)
1708 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1709 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1710 exclusion_pattern = input_api.re.compile(
1711 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1712 (base_function_pattern, base_function_pattern))
1713 # Avoid a false positive in this case, where the method name, the ::, and
1714 # the closing { are all on different lines due to line wrapping.
1715 # HelperClassForTesting::
1716 # HelperClassForTesting(
1717 # args)
1718 # : member(0) {}
1719 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191720
Sam Maiera6e76d72022-02-11 21:43:501721 def FilterFile(affected_file):
1722 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1723 input_api.DEFAULT_FILES_TO_SKIP)
1724 return input_api.FilterSourceFile(
1725 affected_file,
1726 files_to_check=file_inclusion_pattern,
1727 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191728
Sam Maiera6e76d72022-02-11 21:43:501729 problems = []
1730 for f in input_api.AffectedSourceFiles(FilterFile):
1731 local_path = f.LocalPath()
1732 in_method_defn = False
1733 for line_number, line in f.ChangedContents():
1734 if (inclusion_pattern.search(line)
1735 and not comment_pattern.search(line)
1736 and not exclusion_pattern.search(line)
1737 and not allowlist_pattern.search(line)
1738 and not in_method_defn):
1739 problems.append('%s:%d\n %s' %
1740 (local_path, line_number, line.strip()))
1741 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191742
Sam Maiera6e76d72022-02-11 21:43:501743 if problems:
1744 return [
1745 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1746 ]
1747 else:
1748 return []
[email protected]55459852011-08-10 15:17:191749
1750
Saagar Sanghavifceeaae2020-08-12 16:40:361751def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501752 """This is a simplified version of
1753 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1754 """
1755 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1756 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1757 name_pattern = r'ForTest(s|ing)?'
1758 # Describes an occurrence of "ForTest*" inside a // comment.
1759 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1760 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1761 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1762 # Catch calls.
1763 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1764 # Ignore definitions. (Comments are ignored separately.)
1765 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231766
Sam Maiera6e76d72022-02-11 21:43:501767 problems = []
1768 sources = lambda x: input_api.FilterSourceFile(
1769 x,
1770 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1771 DEFAULT_FILES_TO_SKIP),
1772 files_to_check=[r'.*\.java$'])
1773 for f in input_api.AffectedFiles(include_deletes=False,
1774 file_filter=sources):
1775 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231776 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501777 for line_number, line in f.ChangedContents():
1778 if is_inside_javadoc and javadoc_end_re.search(line):
1779 is_inside_javadoc = False
1780 if not is_inside_javadoc and javadoc_start_re.search(line):
1781 is_inside_javadoc = True
1782 if is_inside_javadoc:
1783 continue
1784 if (inclusion_re.search(line) and not comment_re.search(line)
1785 and not annotation_re.search(line)
1786 and not exclusion_re.search(line)):
1787 problems.append('%s:%d\n %s' %
1788 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231789
Sam Maiera6e76d72022-02-11 21:43:501790 if problems:
1791 return [
1792 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1793 ]
1794 else:
1795 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231796
1797
Saagar Sanghavifceeaae2020-08-12 16:40:361798def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501799 """Checks to make sure no .h files include <iostream>."""
1800 files = []
1801 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1802 input_api.re.MULTILINE)
1803 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1804 if not f.LocalPath().endswith('.h'):
1805 continue
1806 contents = input_api.ReadFile(f)
1807 if pattern.search(contents):
1808 files.append(f)
[email protected]10689ca2011-09-02 02:31:541809
Sam Maiera6e76d72022-02-11 21:43:501810 if len(files):
1811 return [
1812 output_api.PresubmitError(
1813 'Do not #include <iostream> in header files, since it inserts static '
1814 'initialization into every file including the header. Instead, '
1815 '#include <ostream>. See http://crbug.com/94794', files)
1816 ]
1817 return []
1818
[email protected]10689ca2011-09-02 02:31:541819
Aleksey Khoroshilov9b28c032022-06-03 16:35:321820def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501821 """Checks no windows headers with StrCat redefined are included directly."""
1822 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:321823 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
1824 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
1825 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
1826 _NON_BASE_DEPENDENT_PATHS)
1827 sources_filter = lambda f: input_api.FilterSourceFile(
1828 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
1829
Sam Maiera6e76d72022-02-11 21:43:501830 pattern_deny = input_api.re.compile(
1831 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1832 input_api.re.MULTILINE)
1833 pattern_allow = input_api.re.compile(
1834 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:321835 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:501836 contents = input_api.ReadFile(f)
1837 if pattern_deny.search(
1838 contents) and not pattern_allow.search(contents):
1839 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431840
Sam Maiera6e76d72022-02-11 21:43:501841 if len(files):
1842 return [
1843 output_api.PresubmitError(
1844 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1845 'directly since they pollute code with StrCat macro. Instead, '
1846 'include matching header from base/win. See http://crbug.com/856536',
1847 files)
1848 ]
1849 return []
Danil Chapovalov3518f362018-08-11 16:13:431850
[email protected]10689ca2011-09-02 02:31:541851
Saagar Sanghavifceeaae2020-08-12 16:40:361852def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501853 """Checks to make sure no source files use UNIT_TEST."""
1854 problems = []
1855 for f in input_api.AffectedFiles():
1856 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1857 continue
[email protected]72df4e782012-06-21 16:28:181858
Sam Maiera6e76d72022-02-11 21:43:501859 for line_num, line in f.ChangedContents():
1860 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1861 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181862
Sam Maiera6e76d72022-02-11 21:43:501863 if not problems:
1864 return []
1865 return [
1866 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1867 '\n'.join(problems))
1868 ]
1869
[email protected]72df4e782012-06-21 16:28:181870
Saagar Sanghavifceeaae2020-08-12 16:40:361871def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501872 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341873
Sam Maiera6e76d72022-02-11 21:43:501874 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1875 instead of DISABLED_. To filter false positives, reports are only generated
1876 if a corresponding MAYBE_ line exists.
1877 """
1878 problems = []
Dominic Battre033531052018-09-24 15:45:341879
Sam Maiera6e76d72022-02-11 21:43:501880 # The following two patterns are looked for in tandem - is a test labeled
1881 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1882 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1883 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341884
Sam Maiera6e76d72022-02-11 21:43:501885 # This is for the case that a test is disabled on all platforms.
1886 full_disable_pattern = input_api.re.compile(
1887 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1888 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341889
Sam Maiera6e76d72022-02-11 21:43:501890 for f in input_api.AffectedFiles(False):
1891 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1892 continue
Dominic Battre033531052018-09-24 15:45:341893
Sam Maiera6e76d72022-02-11 21:43:501894 # Search for MABYE_, DISABLE_ pairs.
1895 disable_lines = {} # Maps of test name to line number.
1896 maybe_lines = {}
1897 for line_num, line in f.ChangedContents():
1898 disable_match = disable_pattern.search(line)
1899 if disable_match:
1900 disable_lines[disable_match.group(1)] = line_num
1901 maybe_match = maybe_pattern.search(line)
1902 if maybe_match:
1903 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341904
Sam Maiera6e76d72022-02-11 21:43:501905 # Search for DISABLE_ occurrences within a TEST() macro.
1906 disable_tests = set(disable_lines.keys())
1907 maybe_tests = set(maybe_lines.keys())
1908 for test in disable_tests.intersection(maybe_tests):
1909 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341910
Sam Maiera6e76d72022-02-11 21:43:501911 contents = input_api.ReadFile(f)
1912 full_disable_match = full_disable_pattern.search(contents)
1913 if full_disable_match:
1914 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341915
Sam Maiera6e76d72022-02-11 21:43:501916 if not problems:
1917 return []
1918 return [
1919 output_api.PresubmitPromptWarning(
1920 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1921 '\n'.join(problems))
1922 ]
1923
Dominic Battre033531052018-09-24 15:45:341924
Nina Satragnof7660532021-09-20 18:03:351925def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501926 """Checks to make sure tests disabled conditionally are not missing a
1927 corresponding MAYBE_ prefix.
1928 """
1929 # Expect at least a lowercase character in the test name. This helps rule out
1930 # false positives with macros wrapping the actual tests name.
1931 define_maybe_pattern = input_api.re.compile(
1932 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191933 # The test_maybe_pattern needs to handle all of these forms. The standard:
1934 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1935 # With a wrapper macro around the test name:
1936 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1937 # And the odd-ball NACL_BROWSER_TEST_f format:
1938 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1939 # The optional E2E_ENABLED-style is handled with (\w*\()?
1940 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1941 # trailing ')'.
1942 test_maybe_pattern = (
1943 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501944 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1945 warnings = []
Nina Satragnof7660532021-09-20 18:03:351946
Sam Maiera6e76d72022-02-11 21:43:501947 # Read the entire files. We can't just read the affected lines, forgetting to
1948 # add MAYBE_ on a change would not show up otherwise.
1949 for f in input_api.AffectedFiles(False):
1950 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1951 continue
1952 contents = input_api.ReadFile(f)
1953 lines = contents.splitlines(True)
1954 current_position = 0
1955 warning_test_names = set()
1956 for line_num, line in enumerate(lines, start=1):
1957 current_position += len(line)
1958 maybe_match = define_maybe_pattern.search(line)
1959 if maybe_match:
1960 test_name = maybe_match.group('test_name')
1961 # Do not warn twice for the same test.
1962 if (test_name in warning_test_names):
1963 continue
1964 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351965
Sam Maiera6e76d72022-02-11 21:43:501966 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1967 # the current position.
1968 test_match = input_api.re.compile(
1969 test_maybe_pattern.format(test_name=test_name),
1970 input_api.re.MULTILINE).search(contents, current_position)
1971 suite_match = input_api.re.compile(
1972 suite_maybe_pattern.format(test_name=test_name),
1973 input_api.re.MULTILINE).search(contents, current_position)
1974 if not test_match and not suite_match:
1975 warnings.append(
1976 output_api.PresubmitPromptWarning(
1977 '%s:%d found MAYBE_ defined without corresponding test %s'
1978 % (f.LocalPath(), line_num, test_name)))
1979 return warnings
1980
[email protected]72df4e782012-06-21 16:28:181981
Saagar Sanghavifceeaae2020-08-12 16:40:361982def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501983 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1984 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:161985 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:501986 input_api.re.MULTILINE)
1987 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1988 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1989 continue
1990 for lnum, line in f.ChangedContents():
1991 if input_api.re.search(pattern, line):
1992 errors.append(
1993 output_api.PresubmitError((
1994 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1995 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1996 (f.LocalPath(), lnum)))
1997 return errors
danakj61c1aa22015-10-26 19:55:521998
1999
Weilun Shia487fad2020-10-28 00:10:342000# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2001# more reliable way. See
2002# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192003
wnwenbdc444e2016-05-25 13:44:152004
Saagar Sanghavifceeaae2020-08-12 16:40:362005def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502006 """Check that FlakyTest annotation is our own instead of the android one"""
2007 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2008 files = []
2009 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2010 if f.LocalPath().endswith('Test.java'):
2011 if pattern.search(input_api.ReadFile(f)):
2012 files.append(f)
2013 if len(files):
2014 return [
2015 output_api.PresubmitError(
2016 'Use org.chromium.base.test.util.FlakyTest instead of '
2017 'android.test.FlakyTest', files)
2018 ]
2019 return []
mcasasb7440c282015-02-04 14:52:192020
wnwenbdc444e2016-05-25 13:44:152021
Saagar Sanghavifceeaae2020-08-12 16:40:362022def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502023 """Make sure .DEPS.git is never modified manually."""
2024 if any(f.LocalPath().endswith('.DEPS.git')
2025 for f in input_api.AffectedFiles()):
2026 return [
2027 output_api.PresubmitError(
2028 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2029 'automated system based on what\'s in DEPS and your changes will be\n'
2030 'overwritten.\n'
2031 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2032 'get-the-code#Rolling_DEPS\n'
2033 'for more information')
2034 ]
2035 return []
[email protected]2a8ac9c2011-10-19 17:20:442036
2037
Saagar Sanghavifceeaae2020-08-12 16:40:362038def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502039 """Checks that DEPS file deps are from allowed_hosts."""
2040 # Run only if DEPS file has been modified to annoy fewer bystanders.
2041 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2042 return []
2043 # Outsource work to gclient verify
2044 try:
2045 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2046 'third_party', 'depot_tools',
2047 'gclient.py')
2048 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322049 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502050 stderr=input_api.subprocess.STDOUT)
2051 return []
2052 except input_api.subprocess.CalledProcessError as error:
2053 return [
2054 output_api.PresubmitError(
2055 'DEPS file must have only git dependencies.',
2056 long_text=error.output)
2057 ]
tandriief664692014-09-23 14:51:472058
2059
Mario Sanchez Prada2472cab2019-09-18 10:58:312060def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152061 ban_rule):
Allen Bauer84778682022-09-22 16:28:562062 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312063
Sam Maiera6e76d72022-02-11 21:43:502064 Returns an string composed of the name of the file, the line number where the
2065 match has been found and the additional text passed as |message| in case the
2066 target type name matches the text inside the line passed as parameter.
2067 """
2068 result = []
Peng Huang9c5949a02020-06-11 19:20:542069
Daniel Chenga44a1bcd2022-03-15 20:00:152070 # Ignore comments about banned types.
2071 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502072 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152073 # A // nocheck comment will bypass this error.
2074 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502075 return result
2076
2077 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152078 if ban_rule.pattern[0:1] == '/':
2079 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502080 if input_api.re.search(regex, line):
2081 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152082 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502083 matched = True
2084
2085 if matched:
2086 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152087 for line in ban_rule.explanation:
2088 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502089
danakjd18e8892020-12-17 17:42:012090 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312091
2092
Saagar Sanghavifceeaae2020-08-12 16:40:362093def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502094 """Make sure that banned functions are not used."""
2095 warnings = []
2096 errors = []
[email protected]127f18ec2012-06-16 05:05:592097
Sam Maiera6e76d72022-02-11 21:43:502098 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152099 if not excluded_paths:
2100 return False
2101
Sam Maiera6e76d72022-02-11 21:43:502102 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312103 # Consistently use / as path separator to simplify the writing of regex
2104 # expressions.
2105 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502106 for item in excluded_paths:
2107 if input_api.re.match(item, local_path):
2108 return True
2109 return False
wnwenbdc444e2016-05-25 13:44:152110
Sam Maiera6e76d72022-02-11 21:43:502111 def IsIosObjcFile(affected_file):
2112 local_path = affected_file.LocalPath()
2113 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2114 '.h'):
2115 return False
2116 basename = input_api.os_path.basename(local_path)
2117 if 'ios' in basename.split('_'):
2118 return True
2119 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2120 if sep and 'ios' in local_path.split(sep):
2121 return True
2122 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542123
Daniel Chenga44a1bcd2022-03-15 20:00:152124 def CheckForMatch(affected_file, line_num: int, line: str,
2125 ban_rule: BanRule):
2126 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2127 return
2128
Sam Maiera6e76d72022-02-11 21:43:502129 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152130 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502131 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152132 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502133 errors.extend(problems)
2134 else:
2135 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152136
Sam Maiera6e76d72022-02-11 21:43:502137 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2138 for f in input_api.AffectedFiles(file_filter=file_filter):
2139 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152140 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2141 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412142
Clement Yan9b330cb2022-11-17 05:25:292143 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2144 for f in input_api.AffectedFiles(file_filter=file_filter):
2145 for line_num, line in f.ChangedContents():
2146 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2147 CheckForMatch(f, line_num, line, ban_rule)
2148
Sam Maiera6e76d72022-02-11 21:43:502149 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2150 for f in input_api.AffectedFiles(file_filter=file_filter):
2151 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152152 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2153 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592154
Sam Maiera6e76d72022-02-11 21:43:502155 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2156 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152157 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2158 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542159
Sam Maiera6e76d72022-02-11 21:43:502160 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2161 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2162 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152163 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2164 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052165
Sam Maiera6e76d72022-02-11 21:43:502166 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2167 for f in input_api.AffectedFiles(file_filter=file_filter):
2168 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152169 for ban_rule in _BANNED_CPP_FUNCTIONS:
2170 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592171
Daniel Cheng92c15e32022-03-16 17:48:222172 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2173 for f in input_api.AffectedFiles(file_filter=file_filter):
2174 for line_num, line in f.ChangedContents():
2175 for ban_rule in _BANNED_MOJOM_PATTERNS:
2176 CheckForMatch(f, line_num, line, ban_rule)
2177
2178
Sam Maiera6e76d72022-02-11 21:43:502179 result = []
2180 if (warnings):
2181 result.append(
2182 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2183 '\n'.join(warnings)))
2184 if (errors):
2185 result.append(
2186 output_api.PresubmitError('Banned functions were used.\n' +
2187 '\n'.join(errors)))
2188 return result
[email protected]127f18ec2012-06-16 05:05:592189
Allen Bauer84778682022-09-22 16:28:562190def CheckNoLayoutCallsInTests(input_api, output_api):
2191 """Make sure there are no explicit calls to View::Layout() in tests"""
2192 warnings = []
2193 ban_rule = BanRule(
2194 r'/(\.|->)Layout\(\);',
2195 (
2196 'Direct calls to View::Layout() are not allowed in tests. '
2197 'If the view must be laid out here, use RunScheduledLayout(view). It '
2198 'is found in //ui/views/test/views_test_utils.h. '
2199 'See http://crbug.com/1350521 for more details.',
2200 ),
2201 False,
2202 )
2203 file_filter = lambda f: input_api.re.search(
2204 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2205 for f in input_api.AffectedFiles(file_filter = file_filter):
2206 for line_num, line in f.ChangedContents():
2207 problems = _GetMessageForMatchingType(input_api, f,
2208 line_num, line,
2209 ban_rule)
2210 if problems:
2211 warnings.extend(problems)
2212 result = []
2213 if (warnings):
2214 result.append(
2215 output_api.PresubmitPromptWarning(
2216 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2217 return result
[email protected]127f18ec2012-06-16 05:05:592218
Michael Thiessen44457642020-02-06 00:24:152219def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502220 """Make sure that banned java imports are not used."""
2221 errors = []
Michael Thiessen44457642020-02-06 00:24:152222
Sam Maiera6e76d72022-02-11 21:43:502223 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2224 for f in input_api.AffectedFiles(file_filter=file_filter):
2225 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152226 for ban_rule in _BANNED_JAVA_IMPORTS:
2227 # Consider merging this into the above function. There is no
2228 # real difference anymore other than helping with a little
2229 # bit of boilerplate text. Doing so means things like
2230 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502231 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152232 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502233 if problems:
2234 errors.extend(problems)
2235 result = []
2236 if (errors):
2237 result.append(
2238 output_api.PresubmitError('Banned imports were used.\n' +
2239 '\n'.join(errors)))
2240 return result
Michael Thiessen44457642020-02-06 00:24:152241
2242
Saagar Sanghavifceeaae2020-08-12 16:40:362243def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502244 """Make sure that banned functions are not used."""
2245 files = []
2246 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2247 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2248 if not f.LocalPath().endswith('.h'):
2249 continue
Bruce Dawson4c4c2922022-05-02 18:07:332250 if f.LocalPath().endswith('com_imported_mstscax.h'):
2251 continue
Sam Maiera6e76d72022-02-11 21:43:502252 contents = input_api.ReadFile(f)
2253 if pattern.search(contents):
2254 files.append(f)
[email protected]6c063c62012-07-11 19:11:062255
Sam Maiera6e76d72022-02-11 21:43:502256 if files:
2257 return [
2258 output_api.PresubmitError(
2259 'Do not use #pragma once in header files.\n'
2260 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2261 files)
2262 ]
2263 return []
[email protected]6c063c62012-07-11 19:11:062264
[email protected]127f18ec2012-06-16 05:05:592265
Saagar Sanghavifceeaae2020-08-12 16:40:362266def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502267 """Checks to make sure we don't introduce use of foo ? true : false."""
2268 problems = []
2269 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2270 for f in input_api.AffectedFiles():
2271 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2272 continue
[email protected]e7479052012-09-19 00:26:122273
Sam Maiera6e76d72022-02-11 21:43:502274 for line_num, line in f.ChangedContents():
2275 if pattern.match(line):
2276 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:122277
Sam Maiera6e76d72022-02-11 21:43:502278 if not problems:
2279 return []
2280 return [
2281 output_api.PresubmitPromptWarning(
2282 'Please consider avoiding the "? true : false" pattern if possible.\n'
2283 + '\n'.join(problems))
2284 ]
[email protected]e7479052012-09-19 00:26:122285
2286
Saagar Sanghavifceeaae2020-08-12 16:40:362287def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502288 """Runs checkdeps on #include and import statements added in this
2289 change. Breaking - rules is an error, breaking ! rules is a
2290 warning.
2291 """
2292 # Return early if no relevant file types were modified.
2293 for f in input_api.AffectedFiles():
2294 path = f.LocalPath()
2295 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2296 or _IsJavaFile(input_api, path)):
2297 break
[email protected]55f9f382012-07-31 11:02:182298 else:
Sam Maiera6e76d72022-02-11 21:43:502299 return []
rhalavati08acd232017-04-03 07:23:282300
Sam Maiera6e76d72022-02-11 21:43:502301 import sys
2302 # We need to wait until we have an input_api object and use this
2303 # roundabout construct to import checkdeps because this file is
2304 # eval-ed and thus doesn't have __file__.
2305 original_sys_path = sys.path
2306 try:
2307 sys.path = sys.path + [
2308 input_api.os_path.join(input_api.PresubmitLocalPath(),
2309 'buildtools', 'checkdeps')
2310 ]
2311 import checkdeps
2312 from rules import Rule
2313 finally:
2314 # Restore sys.path to what it was before.
2315 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:182316
Sam Maiera6e76d72022-02-11 21:43:502317 added_includes = []
2318 added_imports = []
2319 added_java_imports = []
2320 for f in input_api.AffectedFiles():
2321 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2322 changed_lines = [line for _, line in f.ChangedContents()]
2323 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2324 elif _IsProtoFile(input_api, f.LocalPath()):
2325 changed_lines = [line for _, line in f.ChangedContents()]
2326 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2327 elif _IsJavaFile(input_api, f.LocalPath()):
2328 changed_lines = [line for _, line in f.ChangedContents()]
2329 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242330
Sam Maiera6e76d72022-02-11 21:43:502331 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2332
2333 error_descriptions = []
2334 warning_descriptions = []
2335 error_subjects = set()
2336 warning_subjects = set()
2337
2338 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2339 added_includes):
2340 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2341 description_with_path = '%s\n %s' % (path, rule_description)
2342 if rule_type == Rule.DISALLOW:
2343 error_descriptions.append(description_with_path)
2344 error_subjects.add("#includes")
2345 else:
2346 warning_descriptions.append(description_with_path)
2347 warning_subjects.add("#includes")
2348
2349 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2350 added_imports):
2351 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2352 description_with_path = '%s\n %s' % (path, rule_description)
2353 if rule_type == Rule.DISALLOW:
2354 error_descriptions.append(description_with_path)
2355 error_subjects.add("imports")
2356 else:
2357 warning_descriptions.append(description_with_path)
2358 warning_subjects.add("imports")
2359
2360 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2361 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2362 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2363 description_with_path = '%s\n %s' % (path, rule_description)
2364 if rule_type == Rule.DISALLOW:
2365 error_descriptions.append(description_with_path)
2366 error_subjects.add("imports")
2367 else:
2368 warning_descriptions.append(description_with_path)
2369 warning_subjects.add("imports")
2370
2371 results = []
2372 if error_descriptions:
2373 results.append(
2374 output_api.PresubmitError(
2375 'You added one or more %s that violate checkdeps rules.' %
2376 " and ".join(error_subjects), error_descriptions))
2377 if warning_descriptions:
2378 results.append(
2379 output_api.PresubmitPromptOrNotify(
2380 'You added one or more %s of files that are temporarily\n'
2381 'allowed but being removed. Can you avoid introducing the\n'
2382 '%s? See relevant DEPS file(s) for details and contacts.' %
2383 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2384 warning_descriptions))
2385 return results
[email protected]55f9f382012-07-31 11:02:182386
2387
Saagar Sanghavifceeaae2020-08-12 16:40:362388def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502389 """Check that all files have their permissions properly set."""
2390 if input_api.platform == 'win32':
2391 return []
2392 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2393 'tools', 'checkperms',
2394 'checkperms.py')
2395 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322396 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502397 input_api.change.RepositoryRoot()
2398 ]
2399 with input_api.CreateTemporaryFile() as file_list:
2400 for f in input_api.AffectedFiles():
2401 # checkperms.py file/directory arguments must be relative to the
2402 # repository.
2403 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2404 file_list.close()
2405 args += ['--file-list', file_list.name]
2406 try:
2407 input_api.subprocess.check_output(args)
2408 return []
2409 except input_api.subprocess.CalledProcessError as error:
2410 return [
2411 output_api.PresubmitError('checkperms.py failed:',
2412 long_text=error.output.decode(
2413 'utf-8', 'ignore'))
2414 ]
[email protected]fbcafe5a2012-08-08 15:31:222415
2416
Saagar Sanghavifceeaae2020-08-12 16:40:362417def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502418 """Makes sure we don't include ui/aura/window_property.h
2419 in header files.
2420 """
2421 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2422 errors = []
2423 for f in input_api.AffectedFiles():
2424 if not f.LocalPath().endswith('.h'):
2425 continue
2426 for line_num, line in f.ChangedContents():
2427 if pattern.match(line):
2428 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:492429
Sam Maiera6e76d72022-02-11 21:43:502430 results = []
2431 if errors:
2432 results.append(
2433 output_api.PresubmitError(
2434 'Header files should not include ui/aura/window_property.h',
2435 errors))
2436 return results
[email protected]c8278b32012-10-30 20:35:492437
2438
Omer Katzcc77ea92021-04-26 10:23:282439def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502440 """Makes sure we don't include any headers from
2441 third_party/blink/renderer/platform/heap/impl or
2442 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2443 third_party/blink/renderer/platform/heap
2444 """
2445 impl_pattern = input_api.re.compile(
2446 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2447 v8_wrapper_pattern = input_api.re.compile(
2448 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2449 )
Bruce Dawson40fece62022-09-16 19:58:312450 # Consistently use / as path separator to simplify the writing of regex
2451 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502452 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312453 r"^third_party/blink/renderer/platform/heap/.*",
2454 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502455 errors = []
Omer Katzcc77ea92021-04-26 10:23:282456
Sam Maiera6e76d72022-02-11 21:43:502457 for f in input_api.AffectedFiles(file_filter=file_filter):
2458 for line_num, line in f.ChangedContents():
2459 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2460 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282461
Sam Maiera6e76d72022-02-11 21:43:502462 results = []
2463 if errors:
2464 results.append(
2465 output_api.PresubmitError(
2466 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2467 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2468 'relevant counterparts from third_party/blink/renderer/platform/heap',
2469 errors))
2470 return results
Omer Katzcc77ea92021-04-26 10:23:282471
2472
[email protected]70ca77752012-11-20 03:45:032473def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502474 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2475 errors = []
2476 for line_num, line in f.ChangedContents():
2477 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2478 # First-level headers in markdown look a lot like version control
2479 # conflict markers. http://daringfireball.net/projects/markdown/basics
2480 continue
2481 if pattern.match(line):
2482 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2483 return errors
[email protected]70ca77752012-11-20 03:45:032484
2485
Saagar Sanghavifceeaae2020-08-12 16:40:362486def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502487 """Usually this is not intentional and will cause a compile failure."""
2488 errors = []
2489 for f in input_api.AffectedFiles():
2490 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032491
Sam Maiera6e76d72022-02-11 21:43:502492 results = []
2493 if errors:
2494 results.append(
2495 output_api.PresubmitError(
2496 'Version control conflict markers found, please resolve.',
2497 errors))
2498 return results
[email protected]70ca77752012-11-20 03:45:032499
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202500
Saagar Sanghavifceeaae2020-08-12 16:40:362501def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502502 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2503 errors = []
2504 for f in input_api.AffectedFiles():
2505 for line_num, line in f.ChangedContents():
2506 if pattern.search(line):
2507 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162508
Sam Maiera6e76d72022-02-11 21:43:502509 results = []
2510 if errors:
2511 results.append(
2512 output_api.PresubmitPromptWarning(
2513 'Found Google support URL addressed by answer number. Please replace '
2514 'with a p= identifier instead. See crbug.com/679462\n',
2515 errors))
2516 return results
estadee17314a02017-01-12 16:22:162517
[email protected]70ca77752012-11-20 03:45:032518
Saagar Sanghavifceeaae2020-08-12 16:40:362519def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502520 def FilterFile(affected_file):
2521 """Filter function for use with input_api.AffectedSourceFiles,
2522 below. This filters out everything except non-test files from
2523 top-level directories that generally speaking should not hard-code
2524 service URLs (e.g. src/android_webview/, src/content/ and others).
2525 """
2526 return input_api.FilterSourceFile(
2527 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312528 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502529 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2530 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442531
Sam Maiera6e76d72022-02-11 21:43:502532 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2533 '\.(com|net)[^"]*"')
2534 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2535 pattern = input_api.re.compile(base_pattern)
2536 problems = [] # items are (filename, line_number, line)
2537 for f in input_api.AffectedSourceFiles(FilterFile):
2538 for line_num, line in f.ChangedContents():
2539 if not comment_pattern.search(line) and pattern.search(line):
2540 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442541
Sam Maiera6e76d72022-02-11 21:43:502542 if problems:
2543 return [
2544 output_api.PresubmitPromptOrNotify(
2545 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2546 'Are you sure this is correct?', [
2547 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2548 for problem in problems
2549 ])
2550 ]
2551 else:
2552 return []
[email protected]06e6d0ff2012-12-11 01:36:442553
2554
Saagar Sanghavifceeaae2020-08-12 16:40:362555def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502556 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292557
Sam Maiera6e76d72022-02-11 21:43:502558 def FileFilter(affected_file):
2559 """Includes directories known to be Chrome OS only."""
2560 return input_api.FilterSourceFile(
2561 affected_file,
2562 files_to_check=(
2563 '^ash/',
2564 '^chromeos/', # Top-level src/chromeos.
2565 '.*/chromeos/', # Any path component.
2566 '^components/arc',
2567 '^components/exo'),
2568 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292569
Sam Maiera6e76d72022-02-11 21:43:502570 prefs = []
2571 priority_prefs = []
2572 for f in input_api.AffectedFiles(file_filter=FileFilter):
2573 for line_num, line in f.ChangedContents():
2574 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2575 line):
2576 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2577 prefs.append(' %s' % line)
2578 if input_api.re.search(
2579 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2580 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2581 priority_prefs.append(' %s' % line)
2582
2583 results = []
2584 if (prefs):
2585 results.append(
2586 output_api.PresubmitPromptWarning(
2587 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2588 'by browser sync settings. If these prefs should be controlled by OS '
2589 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2590 '\n'.join(prefs)))
2591 if (priority_prefs):
2592 results.append(
2593 output_api.PresubmitPromptWarning(
2594 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2595 'controlled by browser sync settings. If these prefs should be '
2596 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2597 'instead.\n' + '\n'.join(prefs)))
2598 return results
James Cook6b6597c2019-11-06 22:05:292599
2600
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492601# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362602def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502603 """Makes sure there are no abbreviations in the name of PNG files.
2604 The native_client_sdk directory is excluded because it has auto-generated PNG
2605 files for documentation.
2606 """
2607 errors = []
2608 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Bruce Dawson40fece62022-09-16 19:58:312609 files_to_skip = [r'^native_client_sdk/',
2610 r'^services/test/',
2611 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182612 ]
Sam Maiera6e76d72022-02-11 21:43:502613 file_filter = lambda f: input_api.FilterSourceFile(
2614 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2615 for f in input_api.AffectedFiles(include_deletes=False,
2616 file_filter=file_filter):
2617 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272618
Sam Maiera6e76d72022-02-11 21:43:502619 results = []
2620 if errors:
2621 results.append(
2622 output_api.PresubmitError(
2623 'The name of PNG files should not have abbreviations. \n'
2624 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2625 'Contact [email protected] if you have questions.', errors))
2626 return results
[email protected]d2530012013-01-25 16:39:272627
Evan Stade7cd4a2c2022-08-04 23:37:252628def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2629 """Heuristically identifies product icons based on their file name and reminds
2630 contributors not to add them to the Chromium repository.
2631 """
2632 errors = []
2633 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2634 file_filter = lambda f: input_api.FilterSourceFile(
2635 f, files_to_check=files_to_check)
2636 for f in input_api.AffectedFiles(include_deletes=False,
2637 file_filter=file_filter):
2638 errors.append(' %s' % f.LocalPath())
2639
2640 results = []
2641 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082642 # Give warnings instead of errors on presubmit --all and presubmit
2643 # --files.
2644 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2645 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252646 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082647 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252648 'Trademarked images should not be added to the public repo. '
2649 'See crbug.com/944754', errors))
2650 return results
2651
[email protected]d2530012013-01-25 16:39:272652
Daniel Cheng4dcdb6b2017-04-13 08:30:172653def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502654 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172655
Sam Maiera6e76d72022-02-11 21:43:502656 Args:
2657 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2658 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172659 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502660 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172661 if rule.startswith('+') or rule.startswith('!')
2662 ])
Sam Maiera6e76d72022-02-11 21:43:502663 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2664 add_rules.update([
2665 rule[1:] for rule in rules
2666 if rule.startswith('+') or rule.startswith('!')
2667 ])
2668 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172669
2670
2671def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502672 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172673
Sam Maiera6e76d72022-02-11 21:43:502674 # Stubs for handling special syntax in the root DEPS file.
2675 class _VarImpl:
2676 def __init__(self, local_scope):
2677 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172678
Sam Maiera6e76d72022-02-11 21:43:502679 def Lookup(self, var_name):
2680 """Implements the Var syntax."""
2681 try:
2682 return self._local_scope['vars'][var_name]
2683 except KeyError:
2684 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172685
Sam Maiera6e76d72022-02-11 21:43:502686 local_scope = {}
2687 global_scope = {
2688 'Var': _VarImpl(local_scope).Lookup,
2689 'Str': str,
2690 }
Dirk Pranke1b9e06382021-05-14 01:16:222691
Sam Maiera6e76d72022-02-11 21:43:502692 exec(contents, global_scope, local_scope)
2693 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172694
2695
2696def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502697 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2698 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412699
Sam Maiera6e76d72022-02-11 21:43:502700 For a directory (rather than a specific filename) we fake a path to
2701 a specific filename by adding /DEPS. This is chosen as a file that
2702 will seldom or never be subject to per-file include_rules.
2703 """
2704 # We ignore deps entries on auto-generated directories.
2705 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082706
Sam Maiera6e76d72022-02-11 21:43:502707 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2708 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172709
Sam Maiera6e76d72022-02-11 21:43:502710 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172711
Sam Maiera6e76d72022-02-11 21:43:502712 results = set()
2713 for added_dep in added_deps:
2714 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2715 continue
2716 # Assume that a rule that ends in .h is a rule for a specific file.
2717 if added_dep.endswith('.h'):
2718 results.add(added_dep)
2719 else:
2720 results.add(os_path.join(added_dep, 'DEPS'))
2721 return results
[email protected]f32e2d1e2013-07-26 21:39:082722
2723
Saagar Sanghavifceeaae2020-08-12 16:40:362724def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502725 """When a dependency prefixed with + is added to a DEPS file, we
2726 want to make sure that the change is reviewed by an OWNER of the
2727 target file or directory, to avoid layering violations from being
2728 introduced. This check verifies that this happens.
2729 """
2730 # We rely on Gerrit's code-owners to check approvals.
2731 # input_api.gerrit is always set for Chromium, but other projects
2732 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102733 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502734 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302735 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502736 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302737 try:
2738 if (input_api.change.issue and
2739 input_api.gerrit.IsOwnersOverrideApproved(
2740 input_api.change.issue)):
2741 # Skip OWNERS check when Owners-Override label is approved. This is
2742 # intended for global owners, trusted bots, and on-call sheriffs.
2743 # Review is still required for these changes.
2744 return []
2745 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:242746 return [output_api.PresubmitPromptWarning(
2747 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232748
Sam Maiera6e76d72022-02-11 21:43:502749 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242750
Bruce Dawson40fece62022-09-16 19:58:312751 # Consistently use / as path separator to simplify the writing of regex
2752 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502753 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312754 r"^third_party/blink/.*",
2755 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502756 for f in input_api.AffectedFiles(include_deletes=False,
2757 file_filter=file_filter):
2758 filename = input_api.os_path.basename(f.LocalPath())
2759 if filename == 'DEPS':
2760 virtual_depended_on_files.update(
2761 _CalculateAddedDeps(input_api.os_path,
2762 '\n'.join(f.OldContents()),
2763 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552764
Sam Maiera6e76d72022-02-11 21:43:502765 if not virtual_depended_on_files:
2766 return []
[email protected]e871964c2013-05-13 14:14:552767
Sam Maiera6e76d72022-02-11 21:43:502768 if input_api.is_committing:
2769 if input_api.tbr:
2770 return [
2771 output_api.PresubmitNotifyResult(
2772 '--tbr was specified, skipping OWNERS check for DEPS additions'
2773 )
2774 ]
Daniel Cheng3008dc12022-05-13 04:02:112775 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2776 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502777 if input_api.dry_run:
2778 return [
2779 output_api.PresubmitNotifyResult(
2780 'This is a dry run, skipping OWNERS check for DEPS additions'
2781 )
2782 ]
2783 if not input_api.change.issue:
2784 return [
2785 output_api.PresubmitError(
2786 "DEPS approval by OWNERS check failed: this change has "
2787 "no change number, so we can't check it for approvals.")
2788 ]
2789 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412790 else:
Sam Maiera6e76d72022-02-11 21:43:502791 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552792
Sam Maiera6e76d72022-02-11 21:43:502793 owner_email, reviewers = (
2794 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2795 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552796
Sam Maiera6e76d72022-02-11 21:43:502797 owner_email = owner_email or input_api.change.author_email
2798
2799 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2800 virtual_depended_on_files, reviewers.union([owner_email]), [])
2801 missing_files = [
2802 f for f in virtual_depended_on_files
2803 if approval_status[f] != input_api.owners_client.APPROVED
2804 ]
2805
2806 # We strip the /DEPS part that was added by
2807 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2808 # directory.
2809 def StripDeps(path):
2810 start_deps = path.rfind('/DEPS')
2811 if start_deps != -1:
2812 return path[:start_deps]
2813 else:
2814 return path
2815
2816 unapproved_dependencies = [
2817 "'+%s'," % StripDeps(path) for path in missing_files
2818 ]
2819
2820 if unapproved_dependencies:
2821 output_list = [
2822 output(
2823 'You need LGTM from owners of depends-on paths in DEPS that were '
2824 'modified in this CL:\n %s' %
2825 '\n '.join(sorted(unapproved_dependencies)))
2826 ]
2827 suggested_owners = input_api.owners_client.SuggestOwners(
2828 missing_files, exclude=[owner_email])
2829 output_list.append(
2830 output('Suggested missing target path OWNERS:\n %s' %
2831 '\n '.join(suggested_owners or [])))
2832 return output_list
2833
2834 return []
[email protected]e871964c2013-05-13 14:14:552835
2836
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492837# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362838def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502839 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2840 files_to_skip = (
2841 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2842 input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:312843 r"^base/logging\.h$",
2844 r"^base/logging\.cc$",
2845 r"^base/task/thread_pool/task_tracker\.cc$",
2846 r"^chrome/app/chrome_main_delegate\.cc$",
2847 r"^chrome/browser/chrome_browser_main\.cc$",
2848 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
2849 r"^chrome/browser/browser_switcher/bho/.*",
2850 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
2851 r"^chrome/chrome_cleaner/.*",
2852 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
2853 r"^chrome/installer/setup/.*",
2854 r"^chromecast/",
2855 r"^components/browser_watcher/dump_stability_report_main_win\.cc$",
2856 r"^components/media_control/renderer/media_playback_options\.cc$",
2857 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:502858 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312859 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:502860 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:312861 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:502862 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312863 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
2864 r"^courgette/courgette_minimal_tool\.cc$",
2865 r"^courgette/courgette_tool\.cc$",
2866 r"^extensions/renderer/logging_native_handler\.cc$",
2867 r"^fuchsia_web/common/init_logging\.cc$",
2868 r"^fuchsia_web/runners/common/web_component\.cc$",
2869 r"^fuchsia_web/shell/.*_shell\.cc$",
2870 r"^headless/app/headless_shell\.cc$",
2871 r"^ipc/ipc_logging\.cc$",
2872 r"^native_client_sdk/",
2873 r"^remoting/base/logging\.h$",
2874 r"^remoting/host/.*",
2875 r"^sandbox/linux/.*",
2876 r"^storage/browser/file_system/dump_file_system\.cc$",
2877 r"^tools/",
2878 r"^ui/base/resource/data_pack\.cc$",
2879 r"^ui/aura/bench/bench_main\.cc$",
2880 r"^ui/ozone/platform/cast/",
2881 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:502882 r"xwmstartupcheck\.cc$"))
2883 source_file_filter = lambda x: input_api.FilterSourceFile(
2884 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402885
Sam Maiera6e76d72022-02-11 21:43:502886 log_info = set([])
2887 printf = set([])
[email protected]85218562013-11-22 07:41:402888
Sam Maiera6e76d72022-02-11 21:43:502889 for f in input_api.AffectedSourceFiles(source_file_filter):
2890 for _, line in f.ChangedContents():
2891 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2892 log_info.add(f.LocalPath())
2893 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2894 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372895
Sam Maiera6e76d72022-02-11 21:43:502896 if input_api.re.search(r"\bprintf\(", line):
2897 printf.add(f.LocalPath())
2898 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2899 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402900
Sam Maiera6e76d72022-02-11 21:43:502901 if log_info:
2902 return [
2903 output_api.PresubmitError(
2904 'These files spam the console log with LOG(INFO):',
2905 items=log_info)
2906 ]
2907 if printf:
2908 return [
2909 output_api.PresubmitError(
2910 'These files spam the console log with printf/fprintf:',
2911 items=printf)
2912 ]
2913 return []
[email protected]85218562013-11-22 07:41:402914
2915
Saagar Sanghavifceeaae2020-08-12 16:40:362916def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502917 """These types are all expected to hold locks while in scope and
2918 so should never be anonymous (which causes them to be immediately
2919 destroyed)."""
2920 they_who_must_be_named = [
2921 'base::AutoLock',
2922 'base::AutoReset',
2923 'base::AutoUnlock',
2924 'SkAutoAlphaRestore',
2925 'SkAutoBitmapShaderInstall',
2926 'SkAutoBlitterChoose',
2927 'SkAutoBounderCommit',
2928 'SkAutoCallProc',
2929 'SkAutoCanvasRestore',
2930 'SkAutoCommentBlock',
2931 'SkAutoDescriptor',
2932 'SkAutoDisableDirectionCheck',
2933 'SkAutoDisableOvalCheck',
2934 'SkAutoFree',
2935 'SkAutoGlyphCache',
2936 'SkAutoHDC',
2937 'SkAutoLockColors',
2938 'SkAutoLockPixels',
2939 'SkAutoMalloc',
2940 'SkAutoMaskFreeImage',
2941 'SkAutoMutexAcquire',
2942 'SkAutoPathBoundsUpdate',
2943 'SkAutoPDFRelease',
2944 'SkAutoRasterClipValidate',
2945 'SkAutoRef',
2946 'SkAutoTime',
2947 'SkAutoTrace',
2948 'SkAutoUnref',
2949 ]
2950 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2951 # bad: base::AutoLock(lock.get());
2952 # not bad: base::AutoLock lock(lock.get());
2953 bad_pattern = input_api.re.compile(anonymous)
2954 # good: new base::AutoLock(lock.get())
2955 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2956 errors = []
[email protected]49aa76a2013-12-04 06:59:162957
Sam Maiera6e76d72022-02-11 21:43:502958 for f in input_api.AffectedFiles():
2959 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2960 continue
2961 for linenum, line in f.ChangedContents():
2962 if bad_pattern.search(line) and not good_pattern.search(line):
2963 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162964
Sam Maiera6e76d72022-02-11 21:43:502965 if errors:
2966 return [
2967 output_api.PresubmitError(
2968 'These lines create anonymous variables that need to be named:',
2969 items=errors)
2970 ]
2971 return []
[email protected]49aa76a2013-12-04 06:59:162972
2973
Saagar Sanghavifceeaae2020-08-12 16:40:362974def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502975 # Returns whether |template_str| is of the form <T, U...> for some types T
2976 # and U. Assumes that |template_str| is already in the form <...>.
2977 def HasMoreThanOneArg(template_str):
2978 # Level of <...> nesting.
2979 nesting = 0
2980 for c in template_str:
2981 if c == '<':
2982 nesting += 1
2983 elif c == '>':
2984 nesting -= 1
2985 elif c == ',' and nesting == 1:
2986 return True
2987 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532988
Sam Maiera6e76d72022-02-11 21:43:502989 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2990 sources = lambda affected_file: input_api.FilterSourceFile(
2991 affected_file,
2992 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2993 DEFAULT_FILES_TO_SKIP),
2994 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552995
Sam Maiera6e76d72022-02-11 21:43:502996 # Pattern to capture a single "<...>" block of template arguments. It can
2997 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2998 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2999 # latter would likely require counting that < and > match, which is not
3000 # expressible in regular languages. Should the need arise, one can introduce
3001 # limited counting (matching up to a total number of nesting depth), which
3002 # should cover all practical cases for already a low nesting limit.
3003 template_arg_pattern = (
3004 r'<[^>]*' # Opening block of <.
3005 r'>([^<]*>)?') # Closing block of >.
3006 # Prefix expressing that whatever follows is not already inside a <...>
3007 # block.
3008 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3009 null_construct_pattern = input_api.re.compile(
3010 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3011 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553012
Sam Maiera6e76d72022-02-11 21:43:503013 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3014 template_arg_no_array_pattern = (
3015 r'<[^>]*[^]]' # Opening block of <.
3016 r'>([^(<]*[^]]>)?') # Closing block of >.
3017 # Prefix saying that what follows is the start of an expression.
3018 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3019 # Suffix saying that what follows are call parentheses with a non-empty list
3020 # of arguments.
3021 nonempty_arg_list_pattern = r'\(([^)]|$)'
3022 # Put the template argument into a capture group for deeper examination later.
3023 return_construct_pattern = input_api.re.compile(
3024 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3025 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553026
Sam Maiera6e76d72022-02-11 21:43:503027 problems_constructor = []
3028 problems_nullptr = []
3029 for f in input_api.AffectedSourceFiles(sources):
3030 for line_number, line in f.ChangedContents():
3031 # Disallow:
3032 # return std::unique_ptr<T>(foo);
3033 # bar = std::unique_ptr<T>(foo);
3034 # But allow:
3035 # return std::unique_ptr<T[]>(foo);
3036 # bar = std::unique_ptr<T[]>(foo);
3037 # And also allow cases when the second template argument is present. Those
3038 # cases cannot be handled by std::make_unique:
3039 # return std::unique_ptr<T, U>(foo);
3040 # bar = std::unique_ptr<T, U>(foo);
3041 local_path = f.LocalPath()
3042 return_construct_result = return_construct_pattern.search(line)
3043 if return_construct_result and not HasMoreThanOneArg(
3044 return_construct_result.group('template_arg')):
3045 problems_constructor.append(
3046 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3047 # Disallow:
3048 # std::unique_ptr<T>()
3049 if null_construct_pattern.search(line):
3050 problems_nullptr.append(
3051 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053052
Sam Maiera6e76d72022-02-11 21:43:503053 errors = []
3054 if problems_nullptr:
3055 errors.append(
3056 output_api.PresubmitPromptWarning(
3057 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3058 problems_nullptr))
3059 if problems_constructor:
3060 errors.append(
3061 output_api.PresubmitError(
3062 'The following files use explicit std::unique_ptr constructor. '
3063 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3064 'std::make_unique is not an option.', problems_constructor))
3065 return errors
Peter Kasting4844e46e2018-02-23 07:27:103066
3067
Saagar Sanghavifceeaae2020-08-12 16:40:363068def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503069 """Checks if any new user action has been added."""
3070 if any('actions.xml' == input_api.os_path.basename(f)
3071 for f in input_api.LocalPaths()):
3072 # If actions.xml is already included in the changelist, the PRESUBMIT
3073 # for actions.xml will do a more complete presubmit check.
3074 return []
3075
3076 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3077 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3078 input_api.DEFAULT_FILES_TO_SKIP)
3079 file_filter = lambda f: input_api.FilterSourceFile(
3080 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3081
3082 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3083 current_actions = None
3084 for f in input_api.AffectedFiles(file_filter=file_filter):
3085 for line_num, line in f.ChangedContents():
3086 match = input_api.re.search(action_re, line)
3087 if match:
3088 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3089 # loaded only once.
3090 if not current_actions:
3091 with open(
3092 'tools/metrics/actions/actions.xml') as actions_f:
3093 current_actions = actions_f.read()
3094 # Search for the matched user action name in |current_actions|.
3095 for action_name in match.groups():
3096 action = 'name="{0}"'.format(action_name)
3097 if action not in current_actions:
3098 return [
3099 output_api.PresubmitPromptWarning(
3100 'File %s line %d: %s is missing in '
3101 'tools/metrics/actions/actions.xml. Please run '
3102 'tools/metrics/actions/extract_actions.py to update.'
3103 % (f.LocalPath(), line_num, action_name))
3104 ]
[email protected]999261d2014-03-03 20:08:083105 return []
3106
[email protected]999261d2014-03-03 20:08:083107
Daniel Cheng13ca61a882017-08-25 15:11:253108def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503109 import sys
3110 sys.path = sys.path + [
3111 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3112 'json_comment_eater')
3113 ]
3114 import json_comment_eater
3115 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:253116
3117
[email protected]99171a92014-06-03 08:44:473118def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:173119 try:
Sam Maiera6e76d72022-02-11 21:43:503120 contents = input_api.ReadFile(filename)
3121 if eat_comments:
3122 json_comment_eater = _ImportJSONCommentEater(input_api)
3123 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:173124
Sam Maiera6e76d72022-02-11 21:43:503125 input_api.json.loads(contents)
3126 except ValueError as e:
3127 return e
Andrew Grieve4deedb12022-02-03 21:34:503128 return None
3129
3130
Sam Maiera6e76d72022-02-11 21:43:503131def _GetIDLParseError(input_api, filename):
3132 try:
3133 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:283134 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:343135 if not char.isascii():
3136 return (
3137 'Non-ascii character "%s" (ord %d) found at offset %d.' %
3138 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:503139 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
3140 'tools', 'json_schema_compiler',
3141 'idl_schema.py')
3142 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:283143 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:503144 stdin=input_api.subprocess.PIPE,
3145 stdout=input_api.subprocess.PIPE,
3146 stderr=input_api.subprocess.PIPE,
3147 universal_newlines=True)
3148 (_, error) = process.communicate(input=contents)
3149 return error or None
3150 except ValueError as e:
3151 return e
agrievef32bcc72016-04-04 14:57:403152
agrievef32bcc72016-04-04 14:57:403153
Sam Maiera6e76d72022-02-11 21:43:503154def CheckParseErrors(input_api, output_api):
3155 """Check that IDL and JSON files do not contain syntax errors."""
3156 actions = {
3157 '.idl': _GetIDLParseError,
3158 '.json': _GetJSONParseError,
3159 }
3160 # Most JSON files are preprocessed and support comments, but these do not.
3161 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313162 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:503163 ]
3164 # Only run IDL checker on files in these directories.
3165 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313166 r'^chrome/common/extensions/api/',
3167 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:503168 ]
agrievef32bcc72016-04-04 14:57:403169
Sam Maiera6e76d72022-02-11 21:43:503170 def get_action(affected_file):
3171 filename = affected_file.LocalPath()
3172 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:403173
Sam Maiera6e76d72022-02-11 21:43:503174 def FilterFile(affected_file):
3175 action = get_action(affected_file)
3176 if not action:
3177 return False
3178 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403179
Sam Maiera6e76d72022-02-11 21:43:503180 if _MatchesFile(input_api,
3181 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3182 return False
3183
3184 if (action == _GetIDLParseError
3185 and not _MatchesFile(input_api, idl_included_patterns, path)):
3186 return False
3187 return True
3188
3189 results = []
3190 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3191 include_deletes=False):
3192 action = get_action(affected_file)
3193 kwargs = {}
3194 if (action == _GetJSONParseError
3195 and _MatchesFile(input_api, json_no_comments_patterns,
3196 affected_file.LocalPath())):
3197 kwargs['eat_comments'] = False
3198 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3199 **kwargs)
3200 if parse_error:
3201 results.append(
3202 output_api.PresubmitError(
3203 '%s could not be parsed: %s' %
3204 (affected_file.LocalPath(), parse_error)))
3205 return results
3206
3207
3208def CheckJavaStyle(input_api, output_api):
3209 """Runs checkstyle on changed java files and returns errors if any exist."""
3210
3211 # Return early if no java files were modified.
3212 if not any(
3213 _IsJavaFile(input_api, f.LocalPath())
3214 for f in input_api.AffectedFiles()):
3215 return []
3216
3217 import sys
3218 original_sys_path = sys.path
3219 try:
3220 sys.path = sys.path + [
3221 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3222 'android', 'checkstyle')
3223 ]
3224 import checkstyle
3225 finally:
3226 # Restore sys.path to what it was before.
3227 sys.path = original_sys_path
3228
3229 return checkstyle.RunCheckstyle(
3230 input_api,
3231 output_api,
3232 'tools/android/checkstyle/chromium-style-5.0.xml',
3233 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3234
3235
3236def CheckPythonDevilInit(input_api, output_api):
3237 """Checks to make sure devil is initialized correctly in python scripts."""
3238 script_common_initialize_pattern = input_api.re.compile(
3239 r'script_common\.InitializeEnvironment\(')
3240 devil_env_config_initialize = input_api.re.compile(
3241 r'devil_env\.config\.Initialize\(')
3242
3243 errors = []
3244
3245 sources = lambda affected_file: input_api.FilterSourceFile(
3246 affected_file,
3247 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313248 r'^build/android/devil_chromium\.py',
3249 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503250 )),
3251 files_to_check=[r'.*\.py$'])
3252
3253 for f in input_api.AffectedSourceFiles(sources):
3254 for line_num, line in f.ChangedContents():
3255 if (script_common_initialize_pattern.search(line)
3256 or devil_env_config_initialize.search(line)):
3257 errors.append("%s:%d" % (f.LocalPath(), line_num))
3258
3259 results = []
3260
3261 if errors:
3262 results.append(
3263 output_api.PresubmitError(
3264 'Devil initialization should always be done using '
3265 'devil_chromium.Initialize() in the chromium project, to use better '
3266 'defaults for dependencies (ex. up-to-date version of adb).',
3267 errors))
3268
3269 return results
3270
3271
3272def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313273 # Consistently use / as path separator to simplify the writing of regex
3274 # expressions.
3275 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503276 for pattern in patterns:
3277 if input_api.re.search(pattern, path):
3278 return True
3279 return False
3280
3281
Daniel Chenga37c03db2022-05-12 17:20:343282def _ChangeHasSecurityReviewer(input_api, owners_file):
3283 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503284
Daniel Chenga37c03db2022-05-12 17:20:343285 Args:
3286 input_api: The presubmit input API.
3287 owners_file: OWNERS file with required reviewers. Typically, this is
3288 something like ipc/SECURITY_OWNERS.
3289
3290 Note: if the presubmit is running for commit rather than for upload, this
3291 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503292 """
Daniel Chengd88244472022-05-16 09:08:473293 # Owners-Override should bypass all additional OWNERS enforcement checks.
3294 # A CR+1 vote will still be required to land this change.
3295 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3296 input_api.change.issue)):
3297 return True
3298
Daniel Chenga37c03db2022-05-12 17:20:343299 owner_email, reviewers = (
3300 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113301 input_api,
3302 None,
3303 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503304
Daniel Chenga37c03db2022-05-12 17:20:343305 security_owners = input_api.owners_client.ListOwners(owners_file)
3306 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503307
Daniel Chenga37c03db2022-05-12 17:20:343308
3309@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253310class _SecurityProblemWithItems:
3311 problem: str
3312 items: Sequence[str]
3313
3314
3315@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343316class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253317 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343318 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253319 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343320
3321
3322def _FindMissingSecurityOwners(input_api,
3323 output_api,
3324 file_patterns: Sequence[str],
3325 excluded_patterns: Sequence[str],
3326 required_owners_file: str,
3327 custom_rule_function: Optional[Callable] = None
3328 ) -> _MissingSecurityOwnersResult:
3329 """Find OWNERS files missing per-file rules for security-sensitive files.
3330
3331 Args:
3332 input_api: the PRESUBMIT input API object.
3333 output_api: the PRESUBMIT output API object.
3334 file_patterns: basename patterns that require a corresponding per-file
3335 security restriction.
3336 excluded_patterns: path patterns that should be exempted from
3337 requiring a security restriction.
3338 required_owners_file: path to the required OWNERS file, e.g.
3339 ipc/SECURITY_OWNERS
3340 cc_alias: If not None, email that will be CCed automatically if the
3341 change contains security-sensitive files, as determined by
3342 `file_patterns` and `excluded_patterns`.
3343 custom_rule_function: If not None, will be called with `input_api` and
3344 the current file under consideration. Returning True will add an
3345 exact match per-file rule check for the current file.
3346 """
3347
3348 # `to_check` is a mapping of an OWNERS file path to Patterns.
3349 #
3350 # Patterns is a dictionary mapping glob patterns (suitable for use in
3351 # per-file rules) to a PatternEntry.
3352 #
Sam Maiera6e76d72022-02-11 21:43:503353 # PatternEntry is a dictionary with two keys:
3354 # - 'files': the files that are matched by this pattern
3355 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343356 #
Sam Maiera6e76d72022-02-11 21:43:503357 # For example, if we expect OWNERS file to contain rules for *.mojom and
3358 # *_struct_traits*.*, Patterns might look like this:
3359 # {
3360 # '*.mojom': {
3361 # 'files': ...,
3362 # 'rules': [
3363 # 'per-file *.mojom=set noparent',
3364 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3365 # ],
3366 # },
3367 # '*_struct_traits*.*': {
3368 # 'files': ...,
3369 # 'rules': [
3370 # 'per-file *_struct_traits*.*=set noparent',
3371 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3372 # ],
3373 # },
3374 # }
3375 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343376 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503377
Daniel Chenga37c03db2022-05-12 17:20:343378 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503379 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473380 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503381 if owners_file not in to_check:
3382 to_check[owners_file] = {}
3383 if pattern not in to_check[owners_file]:
3384 to_check[owners_file][pattern] = {
3385 'files': [],
3386 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343387 f'per-file {pattern}=set noparent',
3388 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503389 ]
3390 }
Daniel Chenged57a162022-05-25 02:56:343391 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343392 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503393
Daniel Chenga37c03db2022-05-12 17:20:343394 # Only enforce security OWNERS rules for a directory if that directory has a
3395 # file that matches `file_patterns`. For example, if a directory only
3396 # contains *.mojom files and no *_messages*.h files, the check should only
3397 # ensure that rules for *.mojom files are present.
3398 for file in input_api.AffectedFiles(include_deletes=False):
3399 file_basename = input_api.os_path.basename(file.LocalPath())
3400 if custom_rule_function is not None and custom_rule_function(
3401 input_api, file):
3402 AddPatternToCheck(file, file_basename)
3403 continue
Sam Maiera6e76d72022-02-11 21:43:503404
Daniel Chenga37c03db2022-05-12 17:20:343405 if any(
3406 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3407 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503408 continue
3409
3410 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343411 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3412 # file's basename.
3413 if input_api.fnmatch.fnmatch(file_basename, pattern):
3414 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503415 break
3416
Daniel Chenga37c03db2022-05-12 17:20:343417 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253418
3419 # Check if any newly added lines in OWNERS files intersect with required
3420 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3421 # This is a hack, but is needed because the OWNERS check (by design) ignores
3422 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3423 # OWNER and have that newly-added OWNER self-approve their own addition.
3424 newly_covered_files = []
3425 for file in input_api.AffectedFiles(include_deletes=False):
3426 if not file.LocalPath() in to_check:
3427 continue
3428 for _, line in file.ChangedContents():
3429 for _, entry in to_check[file.LocalPath()].items():
3430 if line in entry['rules']:
3431 newly_covered_files.extend(entry['files'])
3432
3433 missing_reviewer_problems = None
3434 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343435 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253436 missing_reviewer_problems = _SecurityProblemWithItems(
3437 f'Review from an owner in {required_owners_file} is required for '
3438 'the following newly-added files:',
3439 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503440
3441 # Go through the OWNERS files to check, filtering out rules that are already
3442 # present in that OWNERS file.
3443 for owners_file, patterns in to_check.items():
3444 try:
Daniel Cheng171dad8d2022-05-21 00:40:253445 lines = set(
3446 input_api.ReadFile(
3447 input_api.os_path.join(input_api.change.RepositoryRoot(),
3448 owners_file)).splitlines())
3449 for entry in patterns.values():
3450 entry['rules'] = [
3451 rule for rule in entry['rules'] if rule not in lines
3452 ]
Sam Maiera6e76d72022-02-11 21:43:503453 except IOError:
3454 # No OWNERS file, so all the rules are definitely missing.
3455 continue
3456
3457 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253458 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343459
Sam Maiera6e76d72022-02-11 21:43:503460 for owners_file, patterns in to_check.items():
3461 missing_lines = []
3462 files = []
3463 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343464 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503465 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503466 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253467 joined_missing_lines = '\n'.join(line for line in missing_lines)
3468 owners_file_problems.append(
3469 _SecurityProblemWithItems(
3470 'Found missing OWNERS lines for security-sensitive files. '
3471 f'Please add the following lines to {owners_file}:\n'
3472 f'{joined_missing_lines}\n\nTo ensure security review for:',
3473 files))
Daniel Chenga37c03db2022-05-12 17:20:343474
Daniel Cheng171dad8d2022-05-21 00:40:253475 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343476 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253477 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343478
3479
3480def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3481 # Whether or not a file affects IPC is (mostly) determined by a simple list
3482 # of filename patterns.
3483 file_patterns = [
3484 # Legacy IPC:
3485 '*_messages.cc',
3486 '*_messages*.h',
3487 '*_param_traits*.*',
3488 # Mojo IPC:
3489 '*.mojom',
3490 '*_mojom_traits*.*',
3491 '*_type_converter*.*',
3492 # Android native IPC:
3493 '*.aidl',
3494 ]
3495
Daniel Chenga37c03db2022-05-12 17:20:343496 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463497 # These third_party directories do not contain IPCs, but contain files
3498 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343499 'third_party/crashpad/*',
3500 'third_party/blink/renderer/platform/bindings/*',
3501 'third_party/protobuf/benchmarks/python/*',
3502 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473503 # Enum-only mojoms used for web metrics, so no security review needed.
3504 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343505 # These files are just used to communicate between class loaders running
3506 # in the same process.
3507 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3508 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3509 ]
3510
3511 def IsMojoServiceManifestFile(input_api, file):
3512 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3513 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3514 if not manifest_pattern.search(file.LocalPath()):
3515 return False
3516
3517 if test_manifest_pattern.search(file.LocalPath()):
3518 return False
3519
3520 # All actual service manifest files should contain at least one
3521 # qualified reference to service_manager::Manifest.
3522 return any('service_manager::Manifest' in line
3523 for line in file.NewContents())
3524
3525 return _FindMissingSecurityOwners(
3526 input_api,
3527 output_api,
3528 file_patterns,
3529 excluded_patterns,
3530 'ipc/SECURITY_OWNERS',
3531 custom_rule_function=IsMojoServiceManifestFile)
3532
3533
3534def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3535 file_patterns = [
3536 # Component specifications.
3537 '*.cml', # Component Framework v2.
3538 '*.cmx', # Component Framework v1.
3539
3540 # Fuchsia IDL protocol specifications.
3541 '*.fidl',
3542 ]
3543
3544 # Don't check for owners files for changes in these directories.
3545 excluded_patterns = [
3546 'third_party/crashpad/*',
3547 ]
3548
3549 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3550 excluded_patterns,
3551 'build/fuchsia/SECURITY_OWNERS')
3552
3553
3554def CheckSecurityOwners(input_api, output_api):
3555 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3556 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3557 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3558 input_api, output_api)
3559
3560 if ipc_results.has_security_sensitive_files:
3561 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503562
3563 results = []
Daniel Chenga37c03db2022-05-12 17:20:343564
Daniel Cheng171dad8d2022-05-21 00:40:253565 missing_reviewer_problems = []
3566 if ipc_results.missing_reviewer_problem:
3567 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3568 if fuchsia_results.missing_reviewer_problem:
3569 missing_reviewer_problems.append(
3570 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343571
Daniel Cheng171dad8d2022-05-21 00:40:253572 # Missing reviewers are an error unless there's no issue number
3573 # associated with this branch; in that case, the presubmit is being run
3574 # with --all or --files.
3575 #
3576 # Note that upload should never be an error; otherwise, it would be
3577 # impossible to upload changes at all.
3578 if input_api.is_committing and input_api.change.issue:
3579 make_presubmit_message = output_api.PresubmitError
3580 else:
3581 make_presubmit_message = output_api.PresubmitNotifyResult
3582 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503583 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253584 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343585
Daniel Cheng171dad8d2022-05-21 00:40:253586 owners_file_problems = []
3587 owners_file_problems.extend(ipc_results.owners_file_problems)
3588 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343589
Daniel Cheng171dad8d2022-05-21 00:40:253590 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113591 # Missing per-file rules are always an error. While swarming and caching
3592 # means that uploading a patchset with updated OWNERS files and sending
3593 # it to the CQ again should not have a large incremental cost, it is
3594 # still frustrating to discover the error only after the change has
3595 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343596 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253597 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503598
3599 return results
3600
3601
3602def _GetFilesUsingSecurityCriticalFunctions(input_api):
3603 """Checks affected files for changes to security-critical calls. This
3604 function checks the full change diff, to catch both additions/changes
3605 and removals.
3606
3607 Returns a dict keyed by file name, and the value is a set of detected
3608 functions.
3609 """
3610 # Map of function pretty name (displayed in an error) to the pattern to
3611 # match it with.
3612 _PATTERNS_TO_CHECK = {
3613 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3614 }
3615 _PATTERNS_TO_CHECK = {
3616 k: input_api.re.compile(v)
3617 for k, v in _PATTERNS_TO_CHECK.items()
3618 }
3619
Sam Maiera6e76d72022-02-11 21:43:503620 # We don't want to trigger on strings within this file.
3621 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343622 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503623
3624 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3625 files_to_functions = {}
3626 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3627 diff = f.GenerateScmDiff()
3628 for line in diff.split('\n'):
3629 # Not using just RightHandSideLines() because removing a
3630 # call to a security-critical function can be just as important
3631 # as adding or changing the arguments.
3632 if line.startswith('-') or (line.startswith('+')
3633 and not line.startswith('++')):
3634 for name, pattern in _PATTERNS_TO_CHECK.items():
3635 if pattern.search(line):
3636 path = f.LocalPath()
3637 if not path in files_to_functions:
3638 files_to_functions[path] = set()
3639 files_to_functions[path].add(name)
3640 return files_to_functions
3641
3642
3643def CheckSecurityChanges(input_api, output_api):
3644 """Checks that changes involving security-critical functions are reviewed
3645 by the security team.
3646 """
3647 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3648 if not len(files_to_functions):
3649 return []
3650
Sam Maiera6e76d72022-02-11 21:43:503651 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343652 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503653 return []
3654
Daniel Chenga37c03db2022-05-12 17:20:343655 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503656 'that need to be reviewed by {}.\n'.format(owners_file)
3657 for path, names in files_to_functions.items():
3658 msg += ' {}\n'.format(path)
3659 for name in names:
3660 msg += ' {}\n'.format(name)
3661 msg += '\n'
3662
3663 if input_api.is_committing:
3664 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033665 else:
Sam Maiera6e76d72022-02-11 21:43:503666 output = output_api.PresubmitNotifyResult
3667 return [output(msg)]
3668
3669
3670def CheckSetNoParent(input_api, output_api):
3671 """Checks that set noparent is only used together with an OWNERS file in
3672 //build/OWNERS.setnoparent (see also
3673 //docs/code_reviews.md#owners-files-details)
3674 """
3675 # Return early if no OWNERS files were modified.
3676 if not any(f.LocalPath().endswith('OWNERS')
3677 for f in input_api.AffectedFiles(include_deletes=False)):
3678 return []
3679
3680 errors = []
3681
3682 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3683 allowed_owners_files = set()
3684 with open(allowed_owners_files_file, 'r') as f:
3685 for line in f:
3686 line = line.strip()
3687 if not line or line.startswith('#'):
3688 continue
3689 allowed_owners_files.add(line)
3690
3691 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3692
3693 for f in input_api.AffectedFiles(include_deletes=False):
3694 if not f.LocalPath().endswith('OWNERS'):
3695 continue
3696
3697 found_owners_files = set()
3698 found_set_noparent_lines = dict()
3699
3700 # Parse the OWNERS file.
3701 for lineno, line in enumerate(f.NewContents(), 1):
3702 line = line.strip()
3703 if line.startswith('set noparent'):
3704 found_set_noparent_lines[''] = lineno
3705 if line.startswith('file://'):
3706 if line in allowed_owners_files:
3707 found_owners_files.add('')
3708 if line.startswith('per-file'):
3709 match = per_file_pattern.match(line)
3710 if match:
3711 glob = match.group(1).strip()
3712 directive = match.group(2).strip()
3713 if directive == 'set noparent':
3714 found_set_noparent_lines[glob] = lineno
3715 if directive.startswith('file://'):
3716 if directive in allowed_owners_files:
3717 found_owners_files.add(glob)
3718
3719 # Check that every set noparent line has a corresponding file:// line
3720 # listed in build/OWNERS.setnoparent. An exception is made for top level
3721 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493722 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3723 if (linux_path.count('/') != 1
3724 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503725 for set_noparent_line in found_set_noparent_lines:
3726 if set_noparent_line in found_owners_files:
3727 continue
3728 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493729 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503730 found_set_noparent_lines[set_noparent_line]))
3731
3732 results = []
3733 if errors:
3734 if input_api.is_committing:
3735 output = output_api.PresubmitError
3736 else:
3737 output = output_api.PresubmitPromptWarning
3738 results.append(
3739 output(
3740 'Found the following "set noparent" restrictions in OWNERS files that '
3741 'do not include owners from build/OWNERS.setnoparent:',
3742 long_text='\n\n'.join(errors)))
3743 return results
3744
3745
3746def CheckUselessForwardDeclarations(input_api, output_api):
3747 """Checks that added or removed lines in non third party affected
3748 header files do not lead to new useless class or struct forward
3749 declaration.
3750 """
3751 results = []
3752 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3753 input_api.re.MULTILINE)
3754 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3755 input_api.re.MULTILINE)
3756 for f in input_api.AffectedFiles(include_deletes=False):
3757 if (f.LocalPath().startswith('third_party')
3758 and not f.LocalPath().startswith('third_party/blink')
3759 and not f.LocalPath().startswith('third_party\\blink')):
3760 continue
3761
3762 if not f.LocalPath().endswith('.h'):
3763 continue
3764
3765 contents = input_api.ReadFile(f)
3766 fwd_decls = input_api.re.findall(class_pattern, contents)
3767 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3768
3769 useless_fwd_decls = []
3770 for decl in fwd_decls:
3771 count = sum(1 for _ in input_api.re.finditer(
3772 r'\b%s\b' % input_api.re.escape(decl), contents))
3773 if count == 1:
3774 useless_fwd_decls.append(decl)
3775
3776 if not useless_fwd_decls:
3777 continue
3778
3779 for line in f.GenerateScmDiff().splitlines():
3780 if (line.startswith('-') and not line.startswith('--')
3781 or line.startswith('+') and not line.startswith('++')):
3782 for decl in useless_fwd_decls:
3783 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3784 results.append(
3785 output_api.PresubmitPromptWarning(
3786 '%s: %s forward declaration is no longer needed'
3787 % (f.LocalPath(), decl)))
3788 useless_fwd_decls.remove(decl)
3789
3790 return results
3791
3792
3793def _CheckAndroidDebuggableBuild(input_api, output_api):
3794 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3795 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3796 this is a debuggable build of Android.
3797 """
3798 build_type_check_pattern = input_api.re.compile(
3799 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3800
3801 errors = []
3802
3803 sources = lambda affected_file: input_api.FilterSourceFile(
3804 affected_file,
3805 files_to_skip=(
3806 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3807 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313808 r"^android_webview/support_library/boundary_interfaces/",
3809 r"^chrome/android/webapk/.*",
3810 r'^third_party/.*',
3811 r"tools/android/customtabs_benchmark/.*",
3812 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:503813 )),
3814 files_to_check=[r'.*\.java$'])
3815
3816 for f in input_api.AffectedSourceFiles(sources):
3817 for line_num, line in f.ChangedContents():
3818 if build_type_check_pattern.search(line):
3819 errors.append("%s:%d" % (f.LocalPath(), line_num))
3820
3821 results = []
3822
3823 if errors:
3824 results.append(
3825 output_api.PresubmitPromptWarning(
3826 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3827 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3828
3829 return results
3830
3831# TODO: add unit tests
3832def _CheckAndroidToastUsage(input_api, output_api):
3833 """Checks that code uses org.chromium.ui.widget.Toast instead of
3834 android.widget.Toast (Chromium Toast doesn't force hardware
3835 acceleration on low-end devices, saving memory).
3836 """
3837 toast_import_pattern = input_api.re.compile(
3838 r'^import android\.widget\.Toast;$')
3839
3840 errors = []
3841
3842 sources = lambda affected_file: input_api.FilterSourceFile(
3843 affected_file,
3844 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:313845 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
3846 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:503847 files_to_check=[r'.*\.java$'])
3848
3849 for f in input_api.AffectedSourceFiles(sources):
3850 for line_num, line in f.ChangedContents():
3851 if toast_import_pattern.search(line):
3852 errors.append("%s:%d" % (f.LocalPath(), line_num))
3853
3854 results = []
3855
3856 if errors:
3857 results.append(
3858 output_api.PresubmitError(
3859 'android.widget.Toast usage is detected. Android toasts use hardware'
3860 ' acceleration, and can be\ncostly on low-end devices. Please use'
3861 ' org.chromium.ui.widget.Toast instead.\n'
3862 'Contact [email protected] if you have any questions.',
3863 errors))
3864
3865 return results
3866
3867
3868def _CheckAndroidCrLogUsage(input_api, output_api):
3869 """Checks that new logs using org.chromium.base.Log:
3870 - Are using 'TAG' as variable name for the tags (warn)
3871 - Are using a tag that is shorter than 20 characters (error)
3872 """
3873
3874 # Do not check format of logs in the given files
3875 cr_log_check_excluded_paths = [
3876 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:313877 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:503878 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:313879 r"^android_webview/glue/java/src/com/android/"
3880 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:503881 # The customtabs_benchmark is a small app that does not depend on Chromium
3882 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:313883 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:503884 ]
3885
3886 cr_log_import_pattern = input_api.re.compile(
3887 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3888 class_in_base_pattern = input_api.re.compile(
3889 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3890 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3891 input_api.re.MULTILINE)
3892 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3893 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3894 log_decl_pattern = input_api.re.compile(
3895 r'static final String TAG = "(?P<name>(.*))"')
3896 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3897
3898 REF_MSG = ('See docs/android_logging.md for more info.')
3899 sources = lambda x: input_api.FilterSourceFile(
3900 x,
3901 files_to_check=[r'.*\.java$'],
3902 files_to_skip=cr_log_check_excluded_paths)
3903
3904 tag_decl_errors = []
3905 tag_length_errors = []
3906 tag_errors = []
3907 tag_with_dot_errors = []
3908 util_log_errors = []
3909
3910 for f in input_api.AffectedSourceFiles(sources):
3911 file_content = input_api.ReadFile(f)
3912 has_modified_logs = False
3913 # Per line checks
3914 if (cr_log_import_pattern.search(file_content)
3915 or (class_in_base_pattern.search(file_content)
3916 and not has_some_log_import_pattern.search(file_content))):
3917 # Checks to run for files using cr log
3918 for line_num, line in f.ChangedContents():
3919 if rough_log_decl_pattern.search(line):
3920 has_modified_logs = True
3921
3922 # Check if the new line is doing some logging
3923 match = log_call_pattern.search(line)
3924 if match:
3925 has_modified_logs = True
3926
3927 # Make sure it uses "TAG"
3928 if not match.group('tag') == 'TAG':
3929 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3930 else:
3931 # Report non cr Log function calls in changed lines
3932 for line_num, line in f.ChangedContents():
3933 if log_call_pattern.search(line):
3934 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3935
3936 # Per file checks
3937 if has_modified_logs:
3938 # Make sure the tag is using the "cr" prefix and is not too long
3939 match = log_decl_pattern.search(file_content)
3940 tag_name = match.group('name') if match else None
3941 if not tag_name:
3942 tag_decl_errors.append(f.LocalPath())
3943 elif len(tag_name) > 20:
3944 tag_length_errors.append(f.LocalPath())
3945 elif '.' in tag_name:
3946 tag_with_dot_errors.append(f.LocalPath())
3947
3948 results = []
3949 if tag_decl_errors:
3950 results.append(
3951 output_api.PresubmitPromptWarning(
3952 'Please define your tags using the suggested format: .\n'
3953 '"private static final String TAG = "<package tag>".\n'
3954 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3955 tag_decl_errors))
3956
3957 if tag_length_errors:
3958 results.append(
3959 output_api.PresubmitError(
3960 'The tag length is restricted by the system to be at most '
3961 '20 characters.\n' + REF_MSG, tag_length_errors))
3962
3963 if tag_errors:
3964 results.append(
3965 output_api.PresubmitPromptWarning(
3966 'Please use a variable named "TAG" for your log tags.\n' +
3967 REF_MSG, tag_errors))
3968
3969 if util_log_errors:
3970 results.append(
3971 output_api.PresubmitPromptWarning(
3972 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3973 util_log_errors))
3974
3975 if tag_with_dot_errors:
3976 results.append(
3977 output_api.PresubmitPromptWarning(
3978 'Dot in log tags cause them to be elided in crash reports.\n' +
3979 REF_MSG, tag_with_dot_errors))
3980
3981 return results
3982
3983
3984def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3985 """Checks that junit.framework.* is no longer used."""
3986 deprecated_junit_framework_pattern = input_api.re.compile(
3987 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3988 sources = lambda x: input_api.FilterSourceFile(
3989 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3990 errors = []
3991 for f in input_api.AffectedFiles(file_filter=sources):
3992 for line_num, line in f.ChangedContents():
3993 if deprecated_junit_framework_pattern.search(line):
3994 errors.append("%s:%d" % (f.LocalPath(), line_num))
3995
3996 results = []
3997 if errors:
3998 results.append(
3999 output_api.PresubmitError(
4000 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
4001 '(org.junit.*) from //third_party/junit. Contact [email protected]'
4002 ' if you have any question.', errors))
4003 return results
4004
4005
4006def _CheckAndroidTestJUnitInheritance(input_api, output_api):
4007 """Checks that if new Java test classes have inheritance.
4008 Either the new test class is JUnit3 test or it is a JUnit4 test class
4009 with a base class, either case is undesirable.
4010 """
4011 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
4012
4013 sources = lambda x: input_api.FilterSourceFile(
4014 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
4015 errors = []
4016 for f in input_api.AffectedFiles(file_filter=sources):
4017 if not f.OldContents():
4018 class_declaration_start_flag = False
4019 for line_num, line in f.ChangedContents():
4020 if class_declaration_pattern.search(line):
4021 class_declaration_start_flag = True
4022 if class_declaration_start_flag and ' extends ' in line:
4023 errors.append('%s:%d' % (f.LocalPath(), line_num))
4024 if '{' in line:
4025 class_declaration_start_flag = False
4026
4027 results = []
4028 if errors:
4029 results.append(
4030 output_api.PresubmitPromptWarning(
4031 'The newly created files include Test classes that inherits from base'
4032 ' class. Please do not use inheritance in JUnit4 tests or add new'
4033 ' JUnit3 tests. Contact [email protected] if you have any'
4034 ' questions.', errors))
4035 return results
4036
4037
4038def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4039 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4040 deprecated_annotation_import_pattern = input_api.re.compile(
4041 r'^import android\.test\.suitebuilder\.annotation\..*;',
4042 input_api.re.MULTILINE)
4043 sources = lambda x: input_api.FilterSourceFile(
4044 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4045 errors = []
4046 for f in input_api.AffectedFiles(file_filter=sources):
4047 for line_num, line in f.ChangedContents():
4048 if deprecated_annotation_import_pattern.search(line):
4049 errors.append("%s:%d" % (f.LocalPath(), line_num))
4050
4051 results = []
4052 if errors:
4053 results.append(
4054 output_api.PresubmitError(
4055 'Annotations in android.test.suitebuilder.annotation have been'
4056 ' deprecated since API level 24. Please use android.support.test.filters'
4057 ' from //third_party/android_support_test_runner:runner_java instead.'
4058 ' Contact [email protected] if you have any questions.',
4059 errors))
4060 return results
4061
4062
4063def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4064 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514065 file_filter = lambda f: (f.LocalPath().endswith(
4066 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4067 LocalPath() or '/res/drawable-ldrtl/'.replace(
4068 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504069 errors = []
4070 for f in input_api.AffectedFiles(include_deletes=False,
4071 file_filter=file_filter):
4072 errors.append(' %s' % f.LocalPath())
4073
4074 results = []
4075 if errors:
4076 results.append(
4077 output_api.PresubmitError(
4078 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4079 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4080 '/res/drawable-ldrtl/.\n'
4081 'Contact [email protected] if you have questions.', errors))
4082 return results
4083
4084
4085def _CheckAndroidWebkitImports(input_api, output_api):
4086 """Checks that code uses org.chromium.base.Callback instead of
4087 android.webview.ValueCallback except in the WebView glue layer
4088 and WebLayer.
4089 """
4090 valuecallback_import_pattern = input_api.re.compile(
4091 r'^import android\.webkit\.ValueCallback;$')
4092
4093 errors = []
4094
4095 sources = lambda affected_file: input_api.FilterSourceFile(
4096 affected_file,
4097 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4098 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314099 r'^android_webview/glue/.*',
4100 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504101 )),
4102 files_to_check=[r'.*\.java$'])
4103
4104 for f in input_api.AffectedSourceFiles(sources):
4105 for line_num, line in f.ChangedContents():
4106 if valuecallback_import_pattern.search(line):
4107 errors.append("%s:%d" % (f.LocalPath(), line_num))
4108
4109 results = []
4110
4111 if errors:
4112 results.append(
4113 output_api.PresubmitError(
4114 'android.webkit.ValueCallback usage is detected outside of the glue'
4115 ' layer. To stay compatible with the support library, android.webkit.*'
4116 ' classes should only be used inside the glue layer and'
4117 ' org.chromium.base.Callback should be used instead.', errors))
4118
4119 return results
4120
4121
4122def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4123 """Checks Android XML styles """
4124
4125 # Return early if no relevant files were modified.
4126 if not any(
4127 _IsXmlOrGrdFile(input_api, f.LocalPath())
4128 for f in input_api.AffectedFiles(include_deletes=False)):
4129 return []
4130
4131 import sys
4132 original_sys_path = sys.path
4133 try:
4134 sys.path = sys.path + [
4135 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4136 'android', 'checkxmlstyle')
4137 ]
4138 import checkxmlstyle
4139 finally:
4140 # Restore sys.path to what it was before.
4141 sys.path = original_sys_path
4142
4143 if is_check_on_upload:
4144 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4145 else:
4146 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4147
4148
4149def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4150 """Checks Android Infobar Deprecation """
4151
4152 import sys
4153 original_sys_path = sys.path
4154 try:
4155 sys.path = sys.path + [
4156 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4157 'android', 'infobar_deprecation')
4158 ]
4159 import infobar_deprecation
4160 finally:
4161 # Restore sys.path to what it was before.
4162 sys.path = original_sys_path
4163
4164 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4165
4166
4167class _PydepsCheckerResult:
4168 def __init__(self, cmd, pydeps_path, process, old_contents):
4169 self._cmd = cmd
4170 self._pydeps_path = pydeps_path
4171 self._process = process
4172 self._old_contents = old_contents
4173
4174 def GetError(self):
4175 """Returns an error message, or None."""
4176 import difflib
4177 if self._process.wait() != 0:
4178 # STDERR should already be printed.
4179 return 'Command failed: ' + self._cmd
4180 new_contents = self._process.stdout.read().splitlines()[2:]
4181 if self._old_contents != new_contents:
4182 diff = '\n'.join(
4183 difflib.context_diff(self._old_contents, new_contents))
4184 return ('File is stale: {}\n'
4185 'Diff (apply to fix):\n'
4186 '{}\n'
4187 'To regenerate, run:\n\n'
4188 ' {}').format(self._pydeps_path, diff, self._cmd)
4189 return None
4190
4191
4192class PydepsChecker:
4193 def __init__(self, input_api, pydeps_files):
4194 self._file_cache = {}
4195 self._input_api = input_api
4196 self._pydeps_files = pydeps_files
4197
4198 def _LoadFile(self, path):
4199 """Returns the list of paths within a .pydeps file relative to //."""
4200 if path not in self._file_cache:
4201 with open(path, encoding='utf-8') as f:
4202 self._file_cache[path] = f.read()
4203 return self._file_cache[path]
4204
4205 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594206 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504207 pydeps_data = self._LoadFile(pydeps_path)
4208 uses_gn_paths = '--gn-paths' in pydeps_data
4209 entries = (l for l in pydeps_data.splitlines()
4210 if not l.startswith('#'))
4211 if uses_gn_paths:
4212 # Paths look like: //foo/bar/baz
4213 return (e[2:] for e in entries)
4214 else:
4215 # Paths look like: path/relative/to/file.pydeps
4216 os_path = self._input_api.os_path
4217 pydeps_dir = os_path.dirname(pydeps_path)
4218 return (os_path.normpath(os_path.join(pydeps_dir, e))
4219 for e in entries)
4220
4221 def _CreateFilesToPydepsMap(self):
4222 """Returns a map of local_path -> list_of_pydeps."""
4223 ret = {}
4224 for pydep_local_path in self._pydeps_files:
4225 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4226 ret.setdefault(path, []).append(pydep_local_path)
4227 return ret
4228
4229 def ComputeAffectedPydeps(self):
4230 """Returns an iterable of .pydeps files that might need regenerating."""
4231 affected_pydeps = set()
4232 file_to_pydeps_map = None
4233 for f in self._input_api.AffectedFiles(include_deletes=True):
4234 local_path = f.LocalPath()
4235 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4236 # subrepositories. We can't figure out which files change, so re-check
4237 # all files.
4238 # Changes to print_python_deps.py affect all .pydeps.
4239 if local_path in ('DEPS', 'PRESUBMIT.py'
4240 ) or local_path.endswith('print_python_deps.py'):
4241 return self._pydeps_files
4242 elif local_path.endswith('.pydeps'):
4243 if local_path in self._pydeps_files:
4244 affected_pydeps.add(local_path)
4245 elif local_path.endswith('.py'):
4246 if file_to_pydeps_map is None:
4247 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4248 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4249 return affected_pydeps
4250
4251 def DetermineIfStaleAsync(self, pydeps_path):
4252 """Runs print_python_deps.py to see if the files is stale."""
4253 import os
4254
4255 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4256 if old_pydeps_data:
4257 cmd = old_pydeps_data[1][1:].strip()
4258 if '--output' not in cmd:
4259 cmd += ' --output ' + pydeps_path
4260 old_contents = old_pydeps_data[2:]
4261 else:
4262 # A default cmd that should work in most cases (as long as pydeps filename
4263 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4264 # file is empty/new.
4265 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4266 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4267 old_contents = []
4268 env = dict(os.environ)
4269 env['PYTHONDONTWRITEBYTECODE'] = '1'
4270 process = self._input_api.subprocess.Popen(
4271 cmd + ' --output ""',
4272 shell=True,
4273 env=env,
4274 stdout=self._input_api.subprocess.PIPE,
4275 encoding='utf-8')
4276 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404277
4278
Tibor Goldschwendt360793f72019-06-25 18:23:494279def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504280 args = {}
4281 with open('build/config/gclient_args.gni', 'r') as f:
4282 for line in f:
4283 line = line.strip()
4284 if not line or line.startswith('#'):
4285 continue
4286 attribute, value = line.split('=')
4287 args[attribute.strip()] = value.strip()
4288 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494289
4290
Saagar Sanghavifceeaae2020-08-12 16:40:364291def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504292 """Checks if a .pydeps file needs to be regenerated."""
4293 # This check is for Python dependency lists (.pydeps files), and involves
4294 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4295 # doesn't work on Windows and Mac, so skip it on other platforms.
4296 if not input_api.platform.startswith('linux'):
4297 return []
Erik Staabc734cd7a2021-11-23 03:11:524298
Sam Maiera6e76d72022-02-11 21:43:504299 results = []
4300 # First, check for new / deleted .pydeps.
4301 for f in input_api.AffectedFiles(include_deletes=True):
4302 # Check whether we are running the presubmit check for a file in src.
4303 # f.LocalPath is relative to repo (src, or internal repo).
4304 # os_path.exists is relative to src repo.
4305 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4306 # to src and we can conclude that the pydeps is in src.
4307 if f.LocalPath().endswith('.pydeps'):
4308 if input_api.os_path.exists(f.LocalPath()):
4309 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4310 results.append(
4311 output_api.PresubmitError(
4312 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4313 'remove %s' % f.LocalPath()))
4314 elif f.Action() != 'D' and f.LocalPath(
4315 ) not in _ALL_PYDEPS_FILES:
4316 results.append(
4317 output_api.PresubmitError(
4318 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4319 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404320
Sam Maiera6e76d72022-02-11 21:43:504321 if results:
4322 return results
4323
4324 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4325 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4326 affected_pydeps = set(checker.ComputeAffectedPydeps())
4327 affected_android_pydeps = affected_pydeps.intersection(
4328 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4329 if affected_android_pydeps and not is_android:
4330 results.append(
4331 output_api.PresubmitPromptOrNotify(
4332 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594333 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504334 'run because you are not using an Android checkout. To validate that\n'
4335 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4336 'use the android-internal-presubmit optional trybot.\n'
4337 'Possibly stale pydeps files:\n{}'.format(
4338 '\n'.join(affected_android_pydeps))))
4339
4340 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4341 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4342 # Process these concurrently, as each one takes 1-2 seconds.
4343 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4344 for result in pydep_results:
4345 error_msg = result.GetError()
4346 if error_msg:
4347 results.append(output_api.PresubmitError(error_msg))
4348
agrievef32bcc72016-04-04 14:57:404349 return results
4350
agrievef32bcc72016-04-04 14:57:404351
Saagar Sanghavifceeaae2020-08-12 16:40:364352def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504353 """Checks to make sure no header files have |Singleton<|."""
4354
4355 def FileFilter(affected_file):
4356 # It's ok for base/memory/singleton.h to have |Singleton<|.
4357 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314358 (r"^base/memory/singleton\.h$",
4359 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504360 return input_api.FilterSourceFile(affected_file,
4361 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434362
Sam Maiera6e76d72022-02-11 21:43:504363 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4364 files = []
4365 for f in input_api.AffectedSourceFiles(FileFilter):
4366 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4367 or f.LocalPath().endswith('.hpp')
4368 or f.LocalPath().endswith('.inl')):
4369 contents = input_api.ReadFile(f)
4370 for line in contents.splitlines(False):
4371 if (not line.lstrip().startswith('//')
4372 and # Strip C++ comment.
4373 pattern.search(line)):
4374 files.append(f)
4375 break
glidere61efad2015-02-18 17:39:434376
Sam Maiera6e76d72022-02-11 21:43:504377 if files:
4378 return [
4379 output_api.PresubmitError(
4380 'Found base::Singleton<T> in the following header files.\n' +
4381 'Please move them to an appropriate source file so that the ' +
4382 'template gets instantiated in a single compilation unit.',
4383 files)
4384 ]
4385 return []
glidere61efad2015-02-18 17:39:434386
4387
[email protected]fd20b902014-05-09 02:14:534388_DEPRECATED_CSS = [
4389 # Values
4390 ( "-webkit-box", "flex" ),
4391 ( "-webkit-inline-box", "inline-flex" ),
4392 ( "-webkit-flex", "flex" ),
4393 ( "-webkit-inline-flex", "inline-flex" ),
4394 ( "-webkit-min-content", "min-content" ),
4395 ( "-webkit-max-content", "max-content" ),
4396
4397 # Properties
4398 ( "-webkit-background-clip", "background-clip" ),
4399 ( "-webkit-background-origin", "background-origin" ),
4400 ( "-webkit-background-size", "background-size" ),
4401 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444402 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:534403
4404 # Functions
4405 ( "-webkit-gradient", "gradient" ),
4406 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4407 ( "-webkit-linear-gradient", "linear-gradient" ),
4408 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4409 ( "-webkit-radial-gradient", "radial-gradient" ),
4410 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4411]
4412
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204413
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494414# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364415def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504416 """ Make sure that we don't use deprecated CSS
4417 properties, functions or values. Our external
4418 documentation and iOS CSS for dom distiller
4419 (reader mode) are ignored by the hooks as it
4420 needs to be consumed by WebKit. """
4421 results = []
4422 file_inclusion_pattern = [r".+\.css$"]
4423 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4424 input_api.DEFAULT_FILES_TO_SKIP +
4425 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4426 r"^native_client_sdk"))
4427 file_filter = lambda f: input_api.FilterSourceFile(
4428 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4429 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4430 for line_num, line in fpath.ChangedContents():
4431 for (deprecated_value, value) in _DEPRECATED_CSS:
4432 if deprecated_value in line:
4433 results.append(
4434 output_api.PresubmitError(
4435 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4436 (fpath.LocalPath(), line_num, deprecated_value,
4437 value)))
4438 return results
[email protected]fd20b902014-05-09 02:14:534439
mohan.reddyf21db962014-10-16 12:26:474440
Saagar Sanghavifceeaae2020-08-12 16:40:364441def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504442 bad_files = {}
4443 for f in input_api.AffectedFiles(include_deletes=False):
4444 if (f.LocalPath().startswith('third_party')
4445 and not f.LocalPath().startswith('third_party/blink')
4446 and not f.LocalPath().startswith('third_party\\blink')):
4447 continue
rlanday6802cf632017-05-30 17:48:364448
Sam Maiera6e76d72022-02-11 21:43:504449 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4450 continue
rlanday6802cf632017-05-30 17:48:364451
Sam Maiera6e76d72022-02-11 21:43:504452 relative_includes = [
4453 line for _, line in f.ChangedContents()
4454 if "#include" in line and "../" in line
4455 ]
4456 if not relative_includes:
4457 continue
4458 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364459
Sam Maiera6e76d72022-02-11 21:43:504460 if not bad_files:
4461 return []
rlanday6802cf632017-05-30 17:48:364462
Sam Maiera6e76d72022-02-11 21:43:504463 error_descriptions = []
4464 for file_path, bad_lines in bad_files.items():
4465 error_description = file_path
4466 for line in bad_lines:
4467 error_description += '\n ' + line
4468 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364469
Sam Maiera6e76d72022-02-11 21:43:504470 results = []
4471 results.append(
4472 output_api.PresubmitError(
4473 'You added one or more relative #include paths (including "../").\n'
4474 'These shouldn\'t be used because they can be used to include headers\n'
4475 'from code that\'s not correctly specified as a dependency in the\n'
4476 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364477
Sam Maiera6e76d72022-02-11 21:43:504478 return results
rlanday6802cf632017-05-30 17:48:364479
Takeshi Yoshinoe387aa32017-08-02 13:16:134480
Saagar Sanghavifceeaae2020-08-12 16:40:364481def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504482 """Check that nobody tries to include a cc file. It's a relatively
4483 common error which results in duplicate symbols in object
4484 files. This may not always break the build until someone later gets
4485 very confusing linking errors."""
4486 results = []
4487 for f in input_api.AffectedFiles(include_deletes=False):
4488 # We let third_party code do whatever it wants
4489 if (f.LocalPath().startswith('third_party')
4490 and not f.LocalPath().startswith('third_party/blink')
4491 and not f.LocalPath().startswith('third_party\\blink')):
4492 continue
Daniel Bratell65b033262019-04-23 08:17:064493
Sam Maiera6e76d72022-02-11 21:43:504494 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4495 continue
Daniel Bratell65b033262019-04-23 08:17:064496
Sam Maiera6e76d72022-02-11 21:43:504497 for _, line in f.ChangedContents():
4498 if line.startswith('#include "'):
4499 included_file = line.split('"')[1]
4500 if _IsCPlusPlusFile(input_api, included_file):
4501 # The most common naming for external files with C++ code,
4502 # apart from standard headers, is to call them foo.inc, but
4503 # Chromium sometimes uses foo-inc.cc so allow that as well.
4504 if not included_file.endswith(('.h', '-inc.cc')):
4505 results.append(
4506 output_api.PresubmitError(
4507 'Only header files or .inc files should be included in other\n'
4508 'C++ files. Compiling the contents of a cc file more than once\n'
4509 'will cause duplicate information in the build which may later\n'
4510 'result in strange link_errors.\n' +
4511 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064512
Sam Maiera6e76d72022-02-11 21:43:504513 return results
Daniel Bratell65b033262019-04-23 08:17:064514
4515
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204516def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504517 if not isinstance(key, ast.Str):
4518 return 'Key at line %d must be a string literal' % key.lineno
4519 if not isinstance(value, ast.Dict):
4520 return 'Value at line %d must be a dict' % value.lineno
4521 if len(value.keys) != 1:
4522 return 'Dict at line %d must have single entry' % value.lineno
4523 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4524 return (
4525 'Entry at line %d must have a string literal \'filepath\' as key' %
4526 value.lineno)
4527 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134528
Takeshi Yoshinoe387aa32017-08-02 13:16:134529
Sergey Ulanov4af16052018-11-08 02:41:464530def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504531 if not isinstance(key, ast.Str):
4532 return 'Key at line %d must be a string literal' % key.lineno
4533 if not isinstance(value, ast.List):
4534 return 'Value at line %d must be a list' % value.lineno
4535 for element in value.elts:
4536 if not isinstance(element, ast.Str):
4537 return 'Watchlist elements on line %d is not a string' % key.lineno
4538 if not email_regex.match(element.s):
4539 return ('Watchlist element on line %d doesn\'t look like a valid '
4540 + 'email: %s') % (key.lineno, element.s)
4541 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134542
Takeshi Yoshinoe387aa32017-08-02 13:16:134543
Sergey Ulanov4af16052018-11-08 02:41:464544def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504545 mismatch_template = (
4546 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4547 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134548
Sam Maiera6e76d72022-02-11 21:43:504549 email_regex = input_api.re.compile(
4550 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464551
Sam Maiera6e76d72022-02-11 21:43:504552 ast = input_api.ast
4553 i = 0
4554 last_key = ''
4555 while True:
4556 if i >= len(wd_dict.keys):
4557 if i >= len(w_dict.keys):
4558 return None
4559 return mismatch_template % ('missing',
4560 'line %d' % w_dict.keys[i].lineno)
4561 elif i >= len(w_dict.keys):
4562 return (mismatch_template %
4563 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134564
Sam Maiera6e76d72022-02-11 21:43:504565 wd_key = wd_dict.keys[i]
4566 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134567
Sam Maiera6e76d72022-02-11 21:43:504568 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4569 wd_dict.values[i], ast)
4570 if result is not None:
4571 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134572
Sam Maiera6e76d72022-02-11 21:43:504573 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4574 email_regex)
4575 if result is not None:
4576 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204577
Sam Maiera6e76d72022-02-11 21:43:504578 if wd_key.s != w_key.s:
4579 return mismatch_template % ('%s at line %d' %
4580 (wd_key.s, wd_key.lineno),
4581 '%s at line %d' %
4582 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204583
Sam Maiera6e76d72022-02-11 21:43:504584 if wd_key.s < last_key:
4585 return (
4586 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4587 % (wd_key.lineno, w_key.lineno))
4588 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204589
Sam Maiera6e76d72022-02-11 21:43:504590 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204591
4592
Sergey Ulanov4af16052018-11-08 02:41:464593def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504594 ast = input_api.ast
4595 if not isinstance(expression, ast.Expression):
4596 return 'WATCHLISTS file must contain a valid expression'
4597 dictionary = expression.body
4598 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4599 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204600
Sam Maiera6e76d72022-02-11 21:43:504601 first_key = dictionary.keys[0]
4602 first_value = dictionary.values[0]
4603 second_key = dictionary.keys[1]
4604 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204605
Sam Maiera6e76d72022-02-11 21:43:504606 if (not isinstance(first_key, ast.Str)
4607 or first_key.s != 'WATCHLIST_DEFINITIONS'
4608 or not isinstance(first_value, ast.Dict)):
4609 return ('The first entry of the dict in WATCHLISTS file must be '
4610 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204611
Sam Maiera6e76d72022-02-11 21:43:504612 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4613 or not isinstance(second_value, ast.Dict)):
4614 return ('The second entry of the dict in WATCHLISTS file must be '
4615 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204616
Sam Maiera6e76d72022-02-11 21:43:504617 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134618
4619
Saagar Sanghavifceeaae2020-08-12 16:40:364620def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504621 for f in input_api.AffectedFiles(include_deletes=False):
4622 if f.LocalPath() == 'WATCHLISTS':
4623 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134624
Sam Maiera6e76d72022-02-11 21:43:504625 try:
4626 # First, make sure that it can be evaluated.
4627 input_api.ast.literal_eval(contents)
4628 # Get an AST tree for it and scan the tree for detailed style checking.
4629 expression = input_api.ast.parse(contents,
4630 filename='WATCHLISTS',
4631 mode='eval')
4632 except ValueError as e:
4633 return [
4634 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4635 long_text=repr(e))
4636 ]
4637 except SyntaxError as e:
4638 return [
4639 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4640 long_text=repr(e))
4641 ]
4642 except TypeError as e:
4643 return [
4644 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4645 long_text=repr(e))
4646 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134647
Sam Maiera6e76d72022-02-11 21:43:504648 result = _CheckWATCHLISTSSyntax(expression, input_api)
4649 if result is not None:
4650 return [output_api.PresubmitError(result)]
4651 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134652
Sam Maiera6e76d72022-02-11 21:43:504653 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134654
Sean Kaucb7c9b32022-10-25 21:25:524655def CheckGnRebasePath(input_api, output_api):
4656 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
4657
4658 Developers should use root_build_dir instead of "//" when using target_gen_dir because
4659 Chromium is sometimes built outside of the source tree.
4660 """
4661
4662 def gn_files(f):
4663 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
4664
4665 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
4666 problems = []
4667 for f in input_api.AffectedSourceFiles(gn_files):
4668 for line_num, line in f.ChangedContents():
4669 if rebase_path_regex.search(line):
4670 problems.append(
4671 'Absolute path in rebase_path() in %s:%d' %
4672 (f.LocalPath(), line_num))
4673
4674 if problems:
4675 return [
4676 output_api.PresubmitPromptWarning(
4677 'Using an absolute path in rebase_path()',
4678 items=sorted(problems),
4679 long_text=(
4680 'rebase_path() should use root_build_dir instead of "/" ',
4681 'since builds can be initiated from outside of the source ',
4682 'root.'))
4683 ]
4684 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134685
Andrew Grieve1b290e4a22020-11-24 20:07:014686def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504687 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014688
Sam Maiera6e76d72022-02-11 21:43:504689 As documented at //build/docs/writing_gn_templates.md
4690 """
Andrew Grieve1b290e4a22020-11-24 20:07:014691
Sam Maiera6e76d72022-02-11 21:43:504692 def gn_files(f):
4693 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014694
Sam Maiera6e76d72022-02-11 21:43:504695 problems = []
4696 for f in input_api.AffectedSourceFiles(gn_files):
4697 for line_num, line in f.ChangedContents():
4698 if 'forward_variables_from(invoker, "*")' in line:
4699 problems.append(
4700 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4701 (f.LocalPath(), line_num))
4702
4703 if problems:
4704 return [
4705 output_api.PresubmitPromptWarning(
4706 'forward_variables_from("*") without exclusions',
4707 items=sorted(problems),
4708 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594709 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504710 'explicitly listed in forward_variables_from(). For more '
4711 'details, see:\n'
4712 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4713 'build/docs/writing_gn_templates.md'
4714 '#Using-forward_variables_from'))
4715 ]
4716 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014717
Saagar Sanghavifceeaae2020-08-12 16:40:364718def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504719 """Checks that newly added header files have corresponding GN changes.
4720 Note that this is only a heuristic. To be precise, run script:
4721 build/check_gn_headers.py.
4722 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194723
Sam Maiera6e76d72022-02-11 21:43:504724 def headers(f):
4725 return input_api.FilterSourceFile(
4726 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194727
Sam Maiera6e76d72022-02-11 21:43:504728 new_headers = []
4729 for f in input_api.AffectedSourceFiles(headers):
4730 if f.Action() != 'A':
4731 continue
4732 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194733
Sam Maiera6e76d72022-02-11 21:43:504734 def gn_files(f):
4735 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194736
Sam Maiera6e76d72022-02-11 21:43:504737 all_gn_changed_contents = ''
4738 for f in input_api.AffectedSourceFiles(gn_files):
4739 for _, line in f.ChangedContents():
4740 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194741
Sam Maiera6e76d72022-02-11 21:43:504742 problems = []
4743 for header in new_headers:
4744 basename = input_api.os_path.basename(header)
4745 if basename not in all_gn_changed_contents:
4746 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194747
Sam Maiera6e76d72022-02-11 21:43:504748 if problems:
4749 return [
4750 output_api.PresubmitPromptWarning(
4751 'Missing GN changes for new header files',
4752 items=sorted(problems),
4753 long_text=
4754 'Please double check whether newly added header files need '
4755 'corresponding changes in gn or gni files.\nThis checking is only a '
4756 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4757 'Read https://crbug.com/661774 for more info.')
4758 ]
4759 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194760
4761
Saagar Sanghavifceeaae2020-08-12 16:40:364762def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504763 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024764
Sam Maiera6e76d72022-02-11 21:43:504765 This assumes we won't intentionally reference one product from the other
4766 product.
4767 """
4768 all_problems = []
4769 test_cases = [{
4770 "filename_postfix": "google_chrome_strings.grd",
4771 "correct_name": "Chrome",
4772 "incorrect_name": "Chromium",
4773 }, {
4774 "filename_postfix": "chromium_strings.grd",
4775 "correct_name": "Chromium",
4776 "incorrect_name": "Chrome",
4777 }]
Michael Giuffridad3bc8672018-10-25 22:48:024778
Sam Maiera6e76d72022-02-11 21:43:504779 for test_case in test_cases:
4780 problems = []
4781 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4782 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024783
Sam Maiera6e76d72022-02-11 21:43:504784 # Check each new line. Can yield false positives in multiline comments, but
4785 # easier than trying to parse the XML because messages can have nested
4786 # children, and associating message elements with affected lines is hard.
4787 for f in input_api.AffectedSourceFiles(filename_filter):
4788 for line_num, line in f.ChangedContents():
4789 if "<message" in line or "<!--" in line or "-->" in line:
4790 continue
4791 if test_case["incorrect_name"] in line:
4792 problems.append("Incorrect product name in %s:%d" %
4793 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024794
Sam Maiera6e76d72022-02-11 21:43:504795 if problems:
4796 message = (
4797 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4798 % (test_case["correct_name"], test_case["correct_name"],
4799 test_case["incorrect_name"]))
4800 all_problems.append(
4801 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024802
Sam Maiera6e76d72022-02-11 21:43:504803 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024804
4805
Saagar Sanghavifceeaae2020-08-12 16:40:364806def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504807 """Avoid large files, especially binary files, in the repository since
4808 git doesn't scale well for those. They will be in everyone's repo
4809 clones forever, forever making Chromium slower to clone and work
4810 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364811
Sam Maiera6e76d72022-02-11 21:43:504812 # Uploading files to cloud storage is not trivial so we don't want
4813 # to set the limit too low, but the upper limit for "normal" large
4814 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4815 # anything over 20 MB is exceptional.
4816 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364817
Sam Maiera6e76d72022-02-11 21:43:504818 too_large_files = []
4819 for f in input_api.AffectedFiles():
4820 # Check both added and modified files (but not deleted files).
4821 if f.Action() in ('A', 'M'):
4822 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4823 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4824 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364825
Sam Maiera6e76d72022-02-11 21:43:504826 if too_large_files:
4827 message = (
4828 'Do not commit large files to git since git scales badly for those.\n'
4829 +
4830 'Instead put the large files in cloud storage and use DEPS to\n' +
4831 'fetch them.\n' + '\n'.join(too_large_files))
4832 return [
4833 output_api.PresubmitError('Too large files found in commit',
4834 long_text=message + '\n')
4835 ]
4836 else:
4837 return []
Daniel Bratell93eb6c62019-04-29 20:13:364838
Max Morozb47503b2019-08-08 21:03:274839
Saagar Sanghavifceeaae2020-08-12 16:40:364840def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504841 """Checks specific for fuzz target sources."""
4842 EXPORTED_SYMBOLS = [
4843 'LLVMFuzzerInitialize',
4844 'LLVMFuzzerCustomMutator',
4845 'LLVMFuzzerCustomCrossOver',
4846 'LLVMFuzzerMutate',
4847 ]
Max Morozb47503b2019-08-08 21:03:274848
Sam Maiera6e76d72022-02-11 21:43:504849 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274850
Sam Maiera6e76d72022-02-11 21:43:504851 def FilterFile(affected_file):
4852 """Ignore libFuzzer source code."""
4853 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:314854 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:274855
Sam Maiera6e76d72022-02-11 21:43:504856 return input_api.FilterSourceFile(affected_file,
4857 files_to_check=[files_to_check],
4858 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274859
Sam Maiera6e76d72022-02-11 21:43:504860 files_with_missing_header = []
4861 for f in input_api.AffectedSourceFiles(FilterFile):
4862 contents = input_api.ReadFile(f, 'r')
4863 if REQUIRED_HEADER in contents:
4864 continue
Max Morozb47503b2019-08-08 21:03:274865
Sam Maiera6e76d72022-02-11 21:43:504866 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4867 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274868
Sam Maiera6e76d72022-02-11 21:43:504869 if not files_with_missing_header:
4870 return []
Max Morozb47503b2019-08-08 21:03:274871
Sam Maiera6e76d72022-02-11 21:43:504872 long_text = (
4873 'If you define any of the libFuzzer optional functions (%s), it is '
4874 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4875 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4876 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4877 'to access command line arguments passed to the fuzzer. Instead, prefer '
4878 'static initialization and shared resources as documented in '
4879 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4880 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4881 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274882
Sam Maiera6e76d72022-02-11 21:43:504883 return [
4884 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4885 REQUIRED_HEADER,
4886 items=files_with_missing_header,
4887 long_text=long_text)
4888 ]
Max Morozb47503b2019-08-08 21:03:274889
4890
Mohamed Heikald048240a2019-11-12 16:57:374891def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504892 """
4893 Warns authors who add images into the repo to make sure their images are
4894 optimized before committing.
4895 """
4896 images_added = False
4897 image_paths = []
4898 errors = []
4899 filter_lambda = lambda x: input_api.FilterSourceFile(
4900 x,
4901 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4902 DEFAULT_FILES_TO_SKIP),
4903 files_to_check=[r'.*\/(drawable|mipmap)'])
4904 for f in input_api.AffectedFiles(include_deletes=False,
4905 file_filter=filter_lambda):
4906 local_path = f.LocalPath().lower()
4907 if any(
4908 local_path.endswith(extension)
4909 for extension in _IMAGE_EXTENSIONS):
4910 images_added = True
4911 image_paths.append(f)
4912 if images_added:
4913 errors.append(
4914 output_api.PresubmitPromptWarning(
4915 'It looks like you are trying to commit some images. If these are '
4916 'non-test-only images, please make sure to read and apply the tips in '
4917 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4918 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4919 'FYI only and will not block your CL on the CQ.', image_paths))
4920 return errors
Mohamed Heikald048240a2019-11-12 16:57:374921
4922
Saagar Sanghavifceeaae2020-08-12 16:40:364923def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504924 """Groups upload checks that target android code."""
4925 results = []
4926 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4927 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4928 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4929 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4930 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4931 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4932 input_api, output_api))
4933 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4934 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4935 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4936 results.extend(_CheckNewImagesWarning(input_api, output_api))
4937 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4938 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4939 return results
4940
Becky Zhou7c69b50992018-12-10 19:37:574941
Saagar Sanghavifceeaae2020-08-12 16:40:364942def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504943 """Groups commit checks that target android code."""
4944 results = []
4945 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4946 return results
dgnaa68d5e2015-06-10 10:08:224947
Chris Hall59f8d0c72020-05-01 07:31:194948# TODO(chrishall): could we additionally match on any path owned by
4949# ui/accessibility/OWNERS ?
4950_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:314951 r"^chrome/browser.*/accessibility/",
4952 r"^chrome/browser/extensions/api/automation.*/",
4953 r"^chrome/renderer/extensions/accessibility_.*",
4954 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:174955 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:314956 r"^content/browser/accessibility/",
4957 r"^content/renderer/accessibility/",
4958 r"^content/tests/data/accessibility/",
4959 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:174960 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:314961 r"^ui/accessibility/",
4962 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:194963)
4964
Saagar Sanghavifceeaae2020-08-12 16:40:364965def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504966 """Checks that commits to accessibility code contain an AX-Relnotes field in
4967 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194968
Sam Maiera6e76d72022-02-11 21:43:504969 def FileFilter(affected_file):
4970 paths = _ACCESSIBILITY_PATHS
4971 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194972
Sam Maiera6e76d72022-02-11 21:43:504973 # Only consider changes affecting accessibility paths.
4974 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4975 return []
Akihiro Ota08108e542020-05-20 15:30:534976
Sam Maiera6e76d72022-02-11 21:43:504977 # AX-Relnotes can appear in either the description or the footer.
4978 # When searching the description, require 'AX-Relnotes:' to appear at the
4979 # beginning of a line.
4980 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4981 description_has_relnotes = any(
4982 ax_regex.match(line)
4983 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194984
Sam Maiera6e76d72022-02-11 21:43:504985 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4986 'AX-Relnotes', [])
4987 if description_has_relnotes or footer_relnotes:
4988 return []
Chris Hall59f8d0c72020-05-01 07:31:194989
Sam Maiera6e76d72022-02-11 21:43:504990 # TODO(chrishall): link to Relnotes documentation in message.
4991 message = (
4992 "Missing 'AX-Relnotes:' field required for accessibility changes"
4993 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4994 "user-facing changes"
4995 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4996 "user-facing effects"
4997 "\n if this is confusing or annoying then please contact members "
4998 "of ui/accessibility/OWNERS.")
4999
5000 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225001
Mark Schillacie5a0be22022-01-19 00:38:395002
5003_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315004 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395005)
5006
5007_ACCESSIBILITY_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315008 r"^content/test/data/accessibility/accname/.*\.html",
5009 r"^content/test/data/accessibility/aria/.*\.html",
5010 r"^content/test/data/accessibility/css/.*\.html",
5011 r"^content/test/data/accessibility/html/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395012)
5013
5014_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315015 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395016)
5017
5018_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315019 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395020)
5021
5022def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505023 """Checks that commits that include a newly added, renamed/moved, or deleted
5024 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5025 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395026
Sam Maiera6e76d72022-02-11 21:43:505027 def FilePathFilter(affected_file):
5028 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5029 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395030
Sam Maiera6e76d72022-02-11 21:43:505031 def AndroidFilePathFilter(affected_file):
5032 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5033 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395034
Sam Maiera6e76d72022-02-11 21:43:505035 # Only consider changes in the events test data path with html type.
5036 if not any(
5037 input_api.AffectedFiles(include_deletes=True,
5038 file_filter=FilePathFilter)):
5039 return []
Mark Schillacie5a0be22022-01-19 00:38:395040
Sam Maiera6e76d72022-02-11 21:43:505041 # If the commit contains any change to the Android test file, ignore.
5042 if any(
5043 input_api.AffectedFiles(include_deletes=True,
5044 file_filter=AndroidFilePathFilter)):
5045 return []
Mark Schillacie5a0be22022-01-19 00:38:395046
Sam Maiera6e76d72022-02-11 21:43:505047 # Only consider changes that are adding/renaming or deleting a file
5048 message = []
5049 for f in input_api.AffectedFiles(include_deletes=True,
5050 file_filter=FilePathFilter):
5051 if f.Action() == 'A' or f.Action() == 'D':
5052 message = (
5053 "It appears that you are adding, renaming or deleting"
5054 "\na dump_accessibility_events* test, but have not included"
5055 "\na corresponding change for Android."
5056 "\nPlease include (or remove) the test from:"
5057 "\n content/public/android/javatests/src/org/chromium/"
5058 "content/browser/accessibility/"
5059 "WebContentsAccessibilityEventsTest.java"
5060 "\nIf this message is confusing or annoying, please contact"
5061 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395062
Sam Maiera6e76d72022-02-11 21:43:505063 # If no message was set, return empty.
5064 if not len(message):
5065 return []
5066
5067 return [output_api.PresubmitPromptWarning(message)]
5068
Mark Schillacie5a0be22022-01-19 00:38:395069
5070def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505071 """Checks that commits that include a newly added, renamed/moved, or deleted
5072 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5073 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395074
Sam Maiera6e76d72022-02-11 21:43:505075 def FilePathFilter(affected_file):
5076 paths = _ACCESSIBILITY_TREE_TEST_PATH
5077 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395078
Sam Maiera6e76d72022-02-11 21:43:505079 def AndroidFilePathFilter(affected_file):
5080 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5081 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395082
Sam Maiera6e76d72022-02-11 21:43:505083 # Only consider changes in the various tree test data paths with html type.
5084 if not any(
5085 input_api.AffectedFiles(include_deletes=True,
5086 file_filter=FilePathFilter)):
5087 return []
Mark Schillacie5a0be22022-01-19 00:38:395088
Sam Maiera6e76d72022-02-11 21:43:505089 # If the commit contains any change to the Android test file, ignore.
5090 if any(
5091 input_api.AffectedFiles(include_deletes=True,
5092 file_filter=AndroidFilePathFilter)):
5093 return []
Mark Schillacie5a0be22022-01-19 00:38:395094
Sam Maiera6e76d72022-02-11 21:43:505095 # Only consider changes that are adding/renaming or deleting a file
5096 message = []
5097 for f in input_api.AffectedFiles(include_deletes=True,
5098 file_filter=FilePathFilter):
5099 if f.Action() == 'A' or f.Action() == 'D':
5100 message = (
5101 "It appears that you are adding, renaming or deleting"
5102 "\na dump_accessibility_tree* test, but have not included"
5103 "\na corresponding change for Android."
5104 "\nPlease include (or remove) the test from:"
5105 "\n content/public/android/javatests/src/org/chromium/"
5106 "content/browser/accessibility/"
5107 "WebContentsAccessibilityTreeTest.java"
5108 "\nIf this message is confusing or annoying, please contact"
5109 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395110
Sam Maiera6e76d72022-02-11 21:43:505111 # If no message was set, return empty.
5112 if not len(message):
5113 return []
5114
5115 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395116
5117
Bruce Dawson33806592022-11-16 01:44:515118def CheckEsLintConfigChanges(input_api, output_api):
5119 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
5120 modified. This is important because enabling an error in .eslintrc.js can
5121 trigger errors in any .js or .ts files in its directory, leading to hidden
5122 presubmit errors."""
5123 results = []
5124 eslint_filter = lambda f: input_api.FilterSourceFile(
5125 f, files_to_check=[r'.*\.eslintrc\.js$'])
5126 for f in input_api.AffectedFiles(include_deletes=False,
5127 file_filter=eslint_filter):
5128 local_dir = input_api.os_path.dirname(f.LocalPath())
5129 # Use / characters so that the commands printed work on any OS.
5130 local_dir = local_dir.replace(input_api.os_path.sep, '/')
5131 if local_dir:
5132 local_dir += '/'
5133 results.append(
5134 output_api.PresubmitNotifyResult(
5135 '%(file)s modified. Consider running \'git cl presubmit --files '
5136 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
5137 'files before landing this change.' %
5138 { 'file' : f.LocalPath(), 'dir' : local_dir}))
5139 return results
5140
5141
seanmccullough4a9356252021-04-08 19:54:095142# string pattern, sequence of strings to show when pattern matches,
5143# error flag. True if match is a presubmit error, otherwise it's a warning.
5144_NON_INCLUSIVE_TERMS = (
5145 (
5146 # Note that \b pattern in python re is pretty particular. In this
5147 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5148 # ...' will not. This may require some tweaking to catch these cases
5149 # without triggering a lot of false positives. Leaving it naive and
5150 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:325151 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:095152 (
5153 'Please don\'t use blacklist, whitelist, ' # nocheck
5154 'or slave in your', # nocheck
5155 'code and make every effort to use other terms. Using "// nocheck"',
5156 '"# nocheck" or "<!-- nocheck -->"',
5157 'at the end of the offending line will bypass this PRESUBMIT error',
5158 'but avoid using this whenever possible. Reach out to',
5159 '[email protected] if you have questions'),
5160 True),)
5161
Saagar Sanghavifceeaae2020-08-12 16:40:365162def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505163 """Checks common to both upload and commit."""
5164 results = []
Eric Boren6fd2b932018-01-25 15:05:085165 results.extend(
Sam Maiera6e76d72022-02-11 21:43:505166 input_api.canned_checks.PanProjectChecks(
5167 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:085168
Sam Maiera6e76d72022-02-11 21:43:505169 author = input_api.change.author_email
5170 if author and author not in _KNOWN_ROBOTS:
5171 results.extend(
5172 input_api.canned_checks.CheckAuthorizedAuthor(
5173 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:245174
Sam Maiera6e76d72022-02-11 21:43:505175 results.extend(
5176 input_api.canned_checks.CheckChangeHasNoTabs(
5177 input_api,
5178 output_api,
5179 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
5180 results.extend(
5181 input_api.RunTests(
5182 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:175183
Bruce Dawsonc8054482022-03-28 15:33:375184 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:505185 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:375186 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:505187 results.extend(
5188 input_api.RunTests(
5189 input_api.canned_checks.CheckDirMetadataFormat(
5190 input_api, output_api, dirmd_bin)))
5191 results.extend(
5192 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
5193 input_api, output_api))
5194 results.extend(
5195 input_api.canned_checks.CheckNoNewMetadataInOwners(
5196 input_api, output_api))
5197 results.extend(
5198 input_api.canned_checks.CheckInclusiveLanguage(
5199 input_api,
5200 output_api,
5201 excluded_directories_relative_path=[
5202 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
5203 ],
5204 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:595205
Aleksey Khoroshilov2978c942022-06-13 16:14:125206 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:475207 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:125208 for f in input_api.AffectedFiles(include_deletes=False,
5209 file_filter=presubmit_py_filter):
5210 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
5211 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
5212 # The PRESUBMIT.py file (and the directory containing it) might have
5213 # been affected by being moved or removed, so only try to run the tests
5214 # if they still exist.
5215 if not input_api.os_path.exists(test_file):
5216 continue
Sam Maiera6e76d72022-02-11 21:43:505217
Aleksey Khoroshilov2978c942022-06-13 16:14:125218 use_python3 = False
5219 with open(f.LocalPath()) as fp:
5220 use_python3 = any(
5221 line.startswith('USE_PYTHON3 = True')
5222 for line in fp.readlines())
5223
5224 results.extend(
5225 input_api.canned_checks.RunUnitTestsInDirectory(
5226 input_api,
5227 output_api,
5228 full_path,
5229 files_to_check=[r'^PRESUBMIT_test\.py$'],
5230 run_on_python2=not use_python3,
5231 run_on_python3=use_python3,
5232 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:505233 return results
[email protected]1f7b4172010-01-28 01:17:345234
[email protected]b337cb5b2011-01-23 21:24:055235
Saagar Sanghavifceeaae2020-08-12 16:40:365236def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505237 problems = [
5238 f.LocalPath() for f in input_api.AffectedFiles()
5239 if f.LocalPath().endswith(('.orig', '.rej'))
5240 ]
5241 # Cargo.toml.orig files are part of third-party crates downloaded from
5242 # crates.io and should be included.
5243 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5244 if problems:
5245 return [
5246 output_api.PresubmitError("Don't commit .rej and .orig files.",
5247 problems)
5248 ]
5249 else:
5250 return []
[email protected]b8079ae4a2012-12-05 19:56:495251
5252
Saagar Sanghavifceeaae2020-08-12 16:40:365253def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505254 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5255 macro_re = input_api.re.compile(
5256 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5257 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5258 input_api.re.MULTILINE)
5259 extension_re = input_api.re.compile(r'\.[a-z]+$')
5260 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005261 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505262 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005263 # The build-config macros are allowed to be used in build_config.h
5264 # without including itself.
5265 if f.LocalPath() == config_h_file:
5266 continue
Sam Maiera6e76d72022-02-11 21:43:505267 if not f.LocalPath().endswith(
5268 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5269 continue
5270 found_line_number = None
5271 found_macro = None
5272 all_lines = input_api.ReadFile(f, 'r').splitlines()
5273 for line_num, line in enumerate(all_lines):
5274 match = macro_re.search(line)
5275 if match:
5276 found_line_number = line_num
5277 found_macro = match.group(2)
5278 break
5279 if not found_line_number:
5280 continue
Kent Tamura5a8755d2017-06-29 23:37:075281
Sam Maiera6e76d72022-02-11 21:43:505282 found_include_line = -1
5283 for line_num, line in enumerate(all_lines):
5284 if include_re.search(line):
5285 found_include_line = line_num
5286 break
5287 if found_include_line >= 0 and found_include_line < found_line_number:
5288 continue
Kent Tamura5a8755d2017-06-29 23:37:075289
Sam Maiera6e76d72022-02-11 21:43:505290 if not f.LocalPath().endswith('.h'):
5291 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5292 try:
5293 content = input_api.ReadFile(primary_header_path, 'r')
5294 if include_re.search(content):
5295 continue
5296 except IOError:
5297 pass
5298 errors.append('%s:%d %s macro is used without first including build/'
5299 'build_config.h.' %
5300 (f.LocalPath(), found_line_number, found_macro))
5301 if errors:
5302 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5303 return []
Kent Tamura5a8755d2017-06-29 23:37:075304
5305
Lei Zhang1c12a22f2021-05-12 11:28:455306def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505307 stl_include_re = input_api.re.compile(r'^#include\s+<('
5308 r'algorithm|'
5309 r'array|'
5310 r'limits|'
5311 r'list|'
5312 r'map|'
5313 r'memory|'
5314 r'queue|'
5315 r'set|'
5316 r'string|'
5317 r'unordered_map|'
5318 r'unordered_set|'
5319 r'utility|'
5320 r'vector)>')
5321 std_namespace_re = input_api.re.compile(r'std::')
5322 errors = []
5323 for f in input_api.AffectedFiles():
5324 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5325 continue
Lei Zhang1c12a22f2021-05-12 11:28:455326
Sam Maiera6e76d72022-02-11 21:43:505327 uses_std_namespace = False
5328 has_stl_include = False
5329 for line in f.NewContents():
5330 if has_stl_include and uses_std_namespace:
5331 break
Lei Zhang1c12a22f2021-05-12 11:28:455332
Sam Maiera6e76d72022-02-11 21:43:505333 if not has_stl_include and stl_include_re.search(line):
5334 has_stl_include = True
5335 continue
Lei Zhang1c12a22f2021-05-12 11:28:455336
Bruce Dawson4a5579a2022-04-08 17:11:365337 if not uses_std_namespace and (std_namespace_re.search(line)
5338 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505339 uses_std_namespace = True
5340 continue
Lei Zhang1c12a22f2021-05-12 11:28:455341
Sam Maiera6e76d72022-02-11 21:43:505342 if has_stl_include and not uses_std_namespace:
5343 errors.append(
5344 '%s: Includes STL header(s) but does not reference std::' %
5345 f.LocalPath())
5346 if errors:
5347 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5348 return []
Lei Zhang1c12a22f2021-05-12 11:28:455349
5350
Xiaohan Wang42d96c22022-01-20 17:23:115351def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505352 """Check for sensible looking, totally invalid OS macros."""
5353 preprocessor_statement = input_api.re.compile(r'^\s*#')
5354 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5355 results = []
5356 for lnum, line in f.ChangedContents():
5357 if preprocessor_statement.search(line):
5358 for match in os_macro.finditer(line):
5359 results.append(
5360 ' %s:%d: %s' %
5361 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5362 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5363 return results
[email protected]b00342e7f2013-03-26 16:21:545364
5365
Xiaohan Wang42d96c22022-01-20 17:23:115366def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505367 """Check all affected files for invalid OS macros."""
5368 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005369 # The OS_ macros are allowed to be used in build/build_config.h.
5370 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505371 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005372 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5373 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505374 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:545375
Sam Maiera6e76d72022-02-11 21:43:505376 if not bad_macros:
5377 return []
[email protected]b00342e7f2013-03-26 16:21:545378
Sam Maiera6e76d72022-02-11 21:43:505379 return [
5380 output_api.PresubmitError(
5381 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5382 'defined in build_config.h):', bad_macros)
5383 ]
[email protected]b00342e7f2013-03-26 16:21:545384
lliabraa35bab3932014-10-01 12:16:445385
5386def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505387 """Check all affected files for invalid "if defined" macros."""
5388 ALWAYS_DEFINED_MACROS = (
5389 "TARGET_CPU_PPC",
5390 "TARGET_CPU_PPC64",
5391 "TARGET_CPU_68K",
5392 "TARGET_CPU_X86",
5393 "TARGET_CPU_ARM",
5394 "TARGET_CPU_MIPS",
5395 "TARGET_CPU_SPARC",
5396 "TARGET_CPU_ALPHA",
5397 "TARGET_IPHONE_SIMULATOR",
5398 "TARGET_OS_EMBEDDED",
5399 "TARGET_OS_IPHONE",
5400 "TARGET_OS_MAC",
5401 "TARGET_OS_UNIX",
5402 "TARGET_OS_WIN32",
5403 )
5404 ifdef_macro = input_api.re.compile(
5405 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5406 results = []
5407 for lnum, line in f.ChangedContents():
5408 for match in ifdef_macro.finditer(line):
5409 if match.group(1) in ALWAYS_DEFINED_MACROS:
5410 always_defined = ' %s is always defined. ' % match.group(1)
5411 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5412 results.append(
5413 ' %s:%d %s\n\t%s' %
5414 (f.LocalPath(), lnum, always_defined, did_you_mean))
5415 return results
lliabraa35bab3932014-10-01 12:16:445416
5417
Saagar Sanghavifceeaae2020-08-12 16:40:365418def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505419 """Check all affected files for invalid "if defined" macros."""
5420 bad_macros = []
5421 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5422 for f in input_api.AffectedFiles():
5423 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5424 continue
5425 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5426 bad_macros.extend(
5427 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445428
Sam Maiera6e76d72022-02-11 21:43:505429 if not bad_macros:
5430 return []
lliabraa35bab3932014-10-01 12:16:445431
Sam Maiera6e76d72022-02-11 21:43:505432 return [
5433 output_api.PresubmitError(
5434 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5435 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5436 bad_macros)
5437 ]
lliabraa35bab3932014-10-01 12:16:445438
5439
Saagar Sanghavifceeaae2020-08-12 16:40:365440def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505441 """Check for same IPC rules described in
5442 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5443 """
5444 base_pattern = r'IPC_ENUM_TRAITS\('
5445 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5446 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045447
Sam Maiera6e76d72022-02-11 21:43:505448 problems = []
5449 for f in input_api.AffectedSourceFiles(None):
5450 local_path = f.LocalPath()
5451 if not local_path.endswith('.h'):
5452 continue
5453 for line_number, line in f.ChangedContents():
5454 if inclusion_pattern.search(
5455 line) and not comment_pattern.search(line):
5456 problems.append('%s:%d\n %s' %
5457 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045458
Sam Maiera6e76d72022-02-11 21:43:505459 if problems:
5460 return [
5461 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5462 problems)
5463 ]
5464 else:
5465 return []
mlamouria82272622014-09-16 18:45:045466
[email protected]b00342e7f2013-03-26 16:21:545467
Saagar Sanghavifceeaae2020-08-12 16:40:365468def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505469 """Check to make sure no files being submitted have long paths.
5470 This causes issues on Windows.
5471 """
5472 problems = []
5473 for f in input_api.AffectedTestableFiles():
5474 local_path = f.LocalPath()
5475 # Windows has a path limit of 260 characters. Limit path length to 200 so
5476 # that we have some extra for the prefix on dev machines and the bots.
5477 if len(local_path) > 200:
5478 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055479
Sam Maiera6e76d72022-02-11 21:43:505480 if problems:
5481 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5482 else:
5483 return []
Stephen Martinis97a394142018-06-07 23:06:055484
5485
Saagar Sanghavifceeaae2020-08-12 16:40:365486def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505487 """Check that header files have proper guards against multiple inclusion.
5488 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365489 should include the string "no-include-guard-because-multiply-included" or
5490 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505491 """
Daniel Bratell8ba52722018-03-02 16:06:145492
Sam Maiera6e76d72022-02-11 21:43:505493 def is_chromium_header_file(f):
5494 # We only check header files under the control of the Chromium
5495 # project. That is, those outside third_party apart from
5496 # third_party/blink.
5497 # We also exclude *_message_generator.h headers as they use
5498 # include guards in a special, non-typical way.
5499 file_with_path = input_api.os_path.normpath(f.LocalPath())
5500 return (file_with_path.endswith('.h')
5501 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335502 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505503 and (not file_with_path.startswith('third_party')
5504 or file_with_path.startswith(
5505 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145506
Sam Maiera6e76d72022-02-11 21:43:505507 def replace_special_with_underscore(string):
5508 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145509
Sam Maiera6e76d72022-02-11 21:43:505510 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145511
Sam Maiera6e76d72022-02-11 21:43:505512 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5513 guard_name = None
5514 guard_line_number = None
5515 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145516
Sam Maiera6e76d72022-02-11 21:43:505517 file_with_path = input_api.os_path.normpath(f.LocalPath())
5518 base_file_name = input_api.os_path.splitext(
5519 input_api.os_path.basename(file_with_path))[0]
5520 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145521
Sam Maiera6e76d72022-02-11 21:43:505522 expected_guard = replace_special_with_underscore(
5523 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145524
Sam Maiera6e76d72022-02-11 21:43:505525 # For "path/elem/file_name.h" we should really only accept
5526 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5527 # are too many (1000+) files with slight deviations from the
5528 # coding style. The most important part is that the include guard
5529 # is there, and that it's unique, not the name so this check is
5530 # forgiving for existing files.
5531 #
5532 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145533
Sam Maiera6e76d72022-02-11 21:43:505534 guard_name_pattern_list = [
5535 # Anything with the right suffix (maybe with an extra _).
5536 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145537
Sam Maiera6e76d72022-02-11 21:43:505538 # To cover include guards with old Blink style.
5539 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145540
Sam Maiera6e76d72022-02-11 21:43:505541 # Anything including the uppercase name of the file.
5542 r'\w*' + input_api.re.escape(
5543 replace_special_with_underscore(upper_base_file_name)) +
5544 r'\w*',
5545 ]
5546 guard_name_pattern = '|'.join(guard_name_pattern_list)
5547 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5548 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145549
Sam Maiera6e76d72022-02-11 21:43:505550 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365551 if ('no-include-guard-because-multiply-included' in line
5552 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505553 guard_name = 'DUMMY' # To not trigger check outside the loop.
5554 break
Daniel Bratell8ba52722018-03-02 16:06:145555
Sam Maiera6e76d72022-02-11 21:43:505556 if guard_name is None:
5557 match = guard_pattern.match(line)
5558 if match:
5559 guard_name = match.group(1)
5560 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145561
Sam Maiera6e76d72022-02-11 21:43:505562 # We allow existing files to use include guards whose names
5563 # don't match the chromium style guide, but new files should
5564 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495565 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165566 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505567 errors.append(
5568 output_api.PresubmitPromptWarning(
5569 'Header using the wrong include guard name %s'
5570 % guard_name, [
5571 '%s:%d' %
5572 (f.LocalPath(), line_number + 1)
5573 ], 'Expected: %r\nFound: %r' %
5574 (expected_guard, guard_name)))
5575 else:
5576 # The line after #ifndef should have a #define of the same name.
5577 if line_number == guard_line_number + 1:
5578 expected_line = '#define %s' % guard_name
5579 if line != expected_line:
5580 errors.append(
5581 output_api.PresubmitPromptWarning(
5582 'Missing "%s" for include guard' %
5583 expected_line,
5584 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5585 'Expected: %r\nGot: %r' %
5586 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145587
Sam Maiera6e76d72022-02-11 21:43:505588 if not seen_guard_end and line == '#endif // %s' % guard_name:
5589 seen_guard_end = True
5590 elif seen_guard_end:
5591 if line.strip() != '':
5592 errors.append(
5593 output_api.PresubmitPromptWarning(
5594 'Include guard %s not covering the whole file'
5595 % (guard_name), [f.LocalPath()]))
5596 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145597
Sam Maiera6e76d72022-02-11 21:43:505598 if guard_name is None:
5599 errors.append(
5600 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495601 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505602 'Recommended name: %s\n'
5603 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365604 '"no-include-guard-because-multiply-included" or\n'
5605 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505606 % (f.LocalPath(), expected_guard)))
5607
5608 return errors
Daniel Bratell8ba52722018-03-02 16:06:145609
5610
Saagar Sanghavifceeaae2020-08-12 16:40:365611def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505612 """Check source code and known ascii text files for Windows style line
5613 endings.
5614 """
Bruce Dawson5efbdc652022-04-11 19:29:515615 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235616
Sam Maiera6e76d72022-02-11 21:43:505617 file_inclusion_pattern = (known_text_files,
5618 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5619 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235620
Sam Maiera6e76d72022-02-11 21:43:505621 problems = []
5622 source_file_filter = lambda f: input_api.FilterSourceFile(
5623 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5624 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515625 # Ignore test files that contain crlf intentionally.
5626 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345627 continue
Sam Maiera6e76d72022-02-11 21:43:505628 include_file = False
5629 for line in input_api.ReadFile(f, 'r').splitlines(True):
5630 if line.endswith('\r\n'):
5631 include_file = True
5632 if include_file:
5633 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235634
Sam Maiera6e76d72022-02-11 21:43:505635 if problems:
5636 return [
5637 output_api.PresubmitPromptWarning(
5638 'Are you sure that you want '
5639 'these files to contain Windows style line endings?\n' +
5640 '\n'.join(problems))
5641 ]
mostynbb639aca52015-01-07 20:31:235642
Sam Maiera6e76d72022-02-11 21:43:505643 return []
5644
mostynbb639aca52015-01-07 20:31:235645
Evan Stade6cfc964c12021-05-18 20:21:165646def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505647 """Check that .icon files (which are fragments of C++) have license headers.
5648 """
Evan Stade6cfc964c12021-05-18 20:21:165649
Sam Maiera6e76d72022-02-11 21:43:505650 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165651
Sam Maiera6e76d72022-02-11 21:43:505652 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5653 return input_api.canned_checks.CheckLicense(input_api,
5654 output_api,
5655 source_file_filter=icons)
5656
Evan Stade6cfc964c12021-05-18 20:21:165657
Jose Magana2b456f22021-03-09 23:26:405658def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505659 """Check source code for use of Chrome App technologies being
5660 deprecated.
5661 """
Jose Magana2b456f22021-03-09 23:26:405662
Sam Maiera6e76d72022-02-11 21:43:505663 def _CheckForDeprecatedTech(input_api,
5664 output_api,
5665 detection_list,
5666 files_to_check=None,
5667 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405668
Sam Maiera6e76d72022-02-11 21:43:505669 if (files_to_check or files_to_skip):
5670 source_file_filter = lambda f: input_api.FilterSourceFile(
5671 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5672 else:
5673 source_file_filter = None
5674
5675 problems = []
5676
5677 for f in input_api.AffectedSourceFiles(source_file_filter):
5678 if f.Action() == 'D':
5679 continue
5680 for _, line in f.ChangedContents():
5681 if any(detect in line for detect in detection_list):
5682 problems.append(f.LocalPath())
5683
5684 return problems
5685
5686 # to avoid this presubmit script triggering warnings
5687 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405688
5689 problems = []
5690
Sam Maiera6e76d72022-02-11 21:43:505691 # NMF: any files with extensions .nmf or NMF
5692 _NMF_FILES = r'\.(nmf|NMF)$'
5693 problems += _CheckForDeprecatedTech(
5694 input_api,
5695 output_api,
5696 detection_list=[''], # any change to the file will trigger warning
5697 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405698
Sam Maiera6e76d72022-02-11 21:43:505699 # MANIFEST: any manifest.json that in its diff includes "app":
5700 _MANIFEST_FILES = r'(manifest\.json)$'
5701 problems += _CheckForDeprecatedTech(
5702 input_api,
5703 output_api,
5704 detection_list=['"app":'],
5705 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405706
Sam Maiera6e76d72022-02-11 21:43:505707 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5708 problems += _CheckForDeprecatedTech(
5709 input_api,
5710 output_api,
5711 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:315712 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:405713
Gao Shenga79ebd42022-08-08 17:25:595714 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505715 problems += _CheckForDeprecatedTech(
5716 input_api,
5717 output_api,
5718 detection_list=['#include "ppapi', '#include <ppapi'],
5719 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5720 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:315721 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:405722
Sam Maiera6e76d72022-02-11 21:43:505723 if problems:
5724 return [
5725 output_api.PresubmitPromptWarning(
5726 'You are adding/modifying code'
5727 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5728 ' PNaCl, PPAPI). See this blog post for more details:\n'
5729 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5730 'and this documentation for options to replace these technologies:\n'
5731 'https://developer.chrome.com/docs/apps/migration/\n' +
5732 '\n'.join(problems))
5733 ]
Jose Magana2b456f22021-03-09 23:26:405734
Sam Maiera6e76d72022-02-11 21:43:505735 return []
Jose Magana2b456f22021-03-09 23:26:405736
mostynbb639aca52015-01-07 20:31:235737
Saagar Sanghavifceeaae2020-08-12 16:40:365738def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505739 """Checks that all source files use SYSLOG properly."""
5740 syslog_files = []
5741 for f in input_api.AffectedSourceFiles(src_file_filter):
5742 for line_number, line in f.ChangedContents():
5743 if 'SYSLOG' in line:
5744 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565745
Sam Maiera6e76d72022-02-11 21:43:505746 if syslog_files:
5747 return [
5748 output_api.PresubmitPromptWarning(
5749 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5750 ' calls.\nFiles to check:\n',
5751 items=syslog_files)
5752 ]
5753 return []
pastarmovj89f7ee12016-09-20 14:58:135754
5755
[email protected]1f7b4172010-01-28 01:17:345756def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505757 if input_api.version < [2, 0, 0]:
5758 return [
5759 output_api.PresubmitError(
5760 "Your depot_tools is out of date. "
5761 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5762 "but your version is %d.%d.%d" % tuple(input_api.version))
5763 ]
5764 results = []
5765 results.extend(
5766 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5767 return results
[email protected]ca8d1982009-02-19 16:33:125768
5769
5770def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505771 if input_api.version < [2, 0, 0]:
5772 return [
5773 output_api.PresubmitError(
5774 "Your depot_tools is out of date. "
5775 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5776 "but your version is %d.%d.%d" % tuple(input_api.version))
5777 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365778
Sam Maiera6e76d72022-02-11 21:43:505779 results = []
5780 # Make sure the tree is 'open'.
5781 results.extend(
5782 input_api.canned_checks.CheckTreeIsOpen(
5783 input_api,
5784 output_api,
5785 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275786
Sam Maiera6e76d72022-02-11 21:43:505787 results.extend(
5788 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5789 results.extend(
5790 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5791 results.extend(
5792 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5793 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505794 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145795
5796
Saagar Sanghavifceeaae2020-08-12 16:40:365797def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505798 """Check string ICU syntax validity and if translation screenshots exist."""
5799 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5800 # footer is set to true.
5801 git_footers = input_api.change.GitFootersFromDescription()
5802 skip_screenshot_check_footer = [
5803 footer.lower() for footer in git_footers.get(
5804 u'Skip-Translation-Screenshots-Check', [])
5805 ]
5806 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025807
Sam Maiera6e76d72022-02-11 21:43:505808 import os
5809 import re
5810 import sys
5811 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145812
Sam Maiera6e76d72022-02-11 21:43:505813 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5814 if (f.Action() == 'A' or f.Action() == 'M'))
5815 removed_paths = set(f.LocalPath()
5816 for f in input_api.AffectedFiles(include_deletes=True)
5817 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145818
Sam Maiera6e76d72022-02-11 21:43:505819 affected_grds = [
5820 f for f in input_api.AffectedFiles()
5821 if f.LocalPath().endswith(('.grd', '.grdp'))
5822 ]
5823 affected_grds = [
5824 f for f in affected_grds if not 'testdata' in f.LocalPath()
5825 ]
5826 if not affected_grds:
5827 return []
meacer8c0d3832019-12-26 21:46:165828
Sam Maiera6e76d72022-02-11 21:43:505829 affected_png_paths = [
5830 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5831 if (f.LocalPath().endswith('.png'))
5832 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145833
Sam Maiera6e76d72022-02-11 21:43:505834 # Check for screenshots. Developers can upload screenshots using
5835 # tools/translation/upload_screenshots.py which finds and uploads
5836 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5837 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5838 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5839 #
5840 # The logic here is as follows:
5841 #
5842 # - If the CL has a .png file under the screenshots directory for a grd
5843 # file, warn the developer. Actual images should never be checked into the
5844 # Chrome repo.
5845 #
5846 # - If the CL contains modified or new messages in grd files and doesn't
5847 # contain the corresponding .sha1 files, warn the developer to add images
5848 # and upload them via tools/translation/upload_screenshots.py.
5849 #
5850 # - If the CL contains modified or new messages in grd files and the
5851 # corresponding .sha1 files, everything looks good.
5852 #
5853 # - If the CL contains removed messages in grd files but the corresponding
5854 # .sha1 files aren't removed, warn the developer to remove them.
5855 unnecessary_screenshots = []
5856 missing_sha1 = []
5857 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145858
Sam Maiera6e76d72022-02-11 21:43:505859 # This checks verifies that the ICU syntax of messages this CL touched is
5860 # valid, and reports any found syntax errors.
5861 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5862 # without developers being aware of them. Later on, such ICU syntax errors
5863 # break message extraction for translation, hence would block Chromium
5864 # translations until they are fixed.
5865 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145866
Sam Maiera6e76d72022-02-11 21:43:505867 def _CheckScreenshotAdded(screenshots_dir, message_id):
5868 sha1_path = input_api.os_path.join(screenshots_dir,
5869 message_id + '.png.sha1')
5870 if sha1_path not in new_or_added_paths:
5871 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145872
Sam Maiera6e76d72022-02-11 21:43:505873 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5874 sha1_path = input_api.os_path.join(screenshots_dir,
5875 message_id + '.png.sha1')
5876 if input_api.os_path.exists(
5877 sha1_path) and sha1_path not in removed_paths:
5878 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145879
Sam Maiera6e76d72022-02-11 21:43:505880 def _ValidateIcuSyntax(text, level, signatures):
5881 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145882
Sam Maiera6e76d72022-02-11 21:43:505883 Check if text looks similar to ICU and checks for ICU syntax correctness
5884 in this case. Reports various issues with ICU syntax and values of
5885 variants. Supports checking of nested messages. Accumulate information of
5886 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265887
Sam Maiera6e76d72022-02-11 21:43:505888 Args:
5889 text: a string to check.
5890 level: a number of current nesting level.
5891 signatures: an accumulator, a list of tuple of (level, variable,
5892 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265893
Sam Maiera6e76d72022-02-11 21:43:505894 Returns:
5895 None if a string is not ICU or no issue detected.
5896 A tuple of (message, start index, end index) if an issue detected.
5897 """
5898 valid_types = {
5899 'plural': (frozenset(
5900 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5901 'other']), frozenset(['=1', 'other'])),
5902 'selectordinal': (frozenset(
5903 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5904 'other']), frozenset(['one', 'other'])),
5905 'select': (frozenset(), frozenset(['other'])),
5906 }
Rainhard Findlingfc31844c52020-05-15 09:58:265907
Sam Maiera6e76d72022-02-11 21:43:505908 # Check if the message looks like an attempt to use ICU
5909 # plural. If yes - check if its syntax strictly matches ICU format.
5910 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5911 text)
5912 if not like:
5913 signatures.append((level, None, None, None))
5914 return
Rainhard Findlingfc31844c52020-05-15 09:58:265915
Sam Maiera6e76d72022-02-11 21:43:505916 # Check for valid prefix and suffix
5917 m = re.match(
5918 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5919 r'(plural|selectordinal|select),\s*'
5920 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5921 if not m:
5922 return (('This message looks like an ICU plural, '
5923 'but does not follow ICU syntax.'), like.start(),
5924 like.end())
5925 starting, variable, kind, variant_pairs = m.groups()
5926 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5927 m.start(4))
5928 if depth:
5929 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5930 len(text))
5931 first = text[0]
5932 ending = text[last_pos:]
5933 if not starting:
5934 return ('Invalid ICU format. No initial opening bracket',
5935 last_pos - 1, last_pos)
5936 if not ending or '}' not in ending:
5937 return ('Invalid ICU format. No final closing bracket',
5938 last_pos - 1, last_pos)
5939 elif first != '{':
5940 return ((
5941 'Invalid ICU format. Extra characters at the start of a complex '
5942 'message (go/icu-message-migration): "%s"') % starting, 0,
5943 len(starting))
5944 elif ending != '}':
5945 return ((
5946 'Invalid ICU format. Extra characters at the end of a complex '
5947 'message (go/icu-message-migration): "%s"') % ending,
5948 last_pos - 1, len(text) - 1)
5949 if kind not in valid_types:
5950 return (('Unknown ICU message type %s. '
5951 'Valid types are: plural, select, selectordinal') % kind,
5952 0, 0)
5953 known, required = valid_types[kind]
5954 defined_variants = set()
5955 for variant, variant_range, value, value_range in variants:
5956 start, end = variant_range
5957 if variant in defined_variants:
5958 return ('Variant "%s" is defined more than once' % variant,
5959 start, end)
5960 elif known and variant not in known:
5961 return ('Variant "%s" is not valid for %s message' %
5962 (variant, kind), start, end)
5963 defined_variants.add(variant)
5964 # Check for nested structure
5965 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5966 if res:
5967 return (res[0], res[1] + value_range[0] + 1,
5968 res[2] + value_range[0] + 1)
5969 missing = required - defined_variants
5970 if missing:
5971 return ('Required variants missing: %s' % ', '.join(missing), 0,
5972 len(text))
5973 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265974
Sam Maiera6e76d72022-02-11 21:43:505975 def _ParseIcuVariants(text, offset=0):
5976 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265977
Sam Maiera6e76d72022-02-11 21:43:505978 Builds a tuple of variant names and values, as well as
5979 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265980
Sam Maiera6e76d72022-02-11 21:43:505981 Args:
5982 text: a string to parse
5983 offset: additional offset to add to positions in the text to get correct
5984 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265985
Sam Maiera6e76d72022-02-11 21:43:505986 Returns:
5987 List of tuples, each tuple consist of four fields: variant name,
5988 variant name span (tuple of two integers), variant value, value
5989 span (tuple of two integers).
5990 """
5991 depth, start, end = 0, -1, -1
5992 variants = []
5993 key = None
5994 for idx, char in enumerate(text):
5995 if char == '{':
5996 if not depth:
5997 start = idx
5998 chunk = text[end + 1:start]
5999 key = chunk.strip()
6000 pos = offset + end + 1 + chunk.find(key)
6001 span = (pos, pos + len(key))
6002 depth += 1
6003 elif char == '}':
6004 if not depth:
6005 return variants, depth, offset + idx
6006 depth -= 1
6007 if not depth:
6008 end = idx
6009 variants.append((key, span, text[start:end + 1],
6010 (offset + start, offset + end + 1)))
6011 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266012
Sam Maiera6e76d72022-02-11 21:43:506013 try:
6014 old_sys_path = sys.path
6015 sys.path = sys.path + [
6016 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6017 'translation')
6018 ]
6019 from helper import grd_helper
6020 finally:
6021 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266022
Sam Maiera6e76d72022-02-11 21:43:506023 for f in affected_grds:
6024 file_path = f.LocalPath()
6025 old_id_to_msg_map = {}
6026 new_id_to_msg_map = {}
6027 # Note that this code doesn't check if the file has been deleted. This is
6028 # OK because it only uses the old and new file contents and doesn't load
6029 # the file via its path.
6030 # It's also possible that a file's content refers to a renamed or deleted
6031 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6032 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6033 # .grdp files.
6034 if file_path.endswith('.grdp'):
6035 if f.OldContents():
6036 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6037 '\n'.join(f.OldContents()))
6038 if f.NewContents():
6039 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6040 '\n'.join(f.NewContents()))
6041 else:
6042 file_dir = input_api.os_path.dirname(file_path) or '.'
6043 if f.OldContents():
6044 old_id_to_msg_map = grd_helper.GetGrdMessages(
6045 StringIO('\n'.join(f.OldContents())), file_dir)
6046 if f.NewContents():
6047 new_id_to_msg_map = grd_helper.GetGrdMessages(
6048 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266049
Sam Maiera6e76d72022-02-11 21:43:506050 grd_name, ext = input_api.os_path.splitext(
6051 input_api.os_path.basename(file_path))
6052 screenshots_dir = input_api.os_path.join(
6053 input_api.os_path.dirname(file_path),
6054 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266055
Sam Maiera6e76d72022-02-11 21:43:506056 # Compute added, removed and modified message IDs.
6057 old_ids = set(old_id_to_msg_map)
6058 new_ids = set(new_id_to_msg_map)
6059 added_ids = new_ids - old_ids
6060 removed_ids = old_ids - new_ids
6061 modified_ids = set([])
6062 for key in old_ids.intersection(new_ids):
6063 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6064 new_id_to_msg_map[key].ContentsAsXml('', True)):
6065 # The message content itself changed. Require an updated screenshot.
6066 modified_ids.add(key)
6067 elif old_id_to_msg_map[key].attrs['meaning'] != \
6068 new_id_to_msg_map[key].attrs['meaning']:
6069 # The message meaning changed. Ensure there is a screenshot for it.
6070 sha1_path = input_api.os_path.join(screenshots_dir,
6071 key + '.png.sha1')
6072 if sha1_path not in new_or_added_paths and not \
6073 input_api.os_path.exists(sha1_path):
6074 # There is neither a previous screenshot nor is a new one added now.
6075 # Require a screenshot.
6076 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146077
Sam Maiera6e76d72022-02-11 21:43:506078 if run_screenshot_check:
6079 # Check the screenshot directory for .png files. Warn if there is any.
6080 for png_path in affected_png_paths:
6081 if png_path.startswith(screenshots_dir):
6082 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146083
Sam Maiera6e76d72022-02-11 21:43:506084 for added_id in added_ids:
6085 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096086
Sam Maiera6e76d72022-02-11 21:43:506087 for modified_id in modified_ids:
6088 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146089
Sam Maiera6e76d72022-02-11 21:43:506090 for removed_id in removed_ids:
6091 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6092
6093 # Check new and changed strings for ICU syntax errors.
6094 for key in added_ids.union(modified_ids):
6095 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6096 err = _ValidateIcuSyntax(msg, 0, [])
6097 if err is not None:
6098 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6099
6100 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266101 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506102 if unnecessary_screenshots:
6103 results.append(
6104 output_api.PresubmitError(
6105 'Do not include actual screenshots in the changelist. Run '
6106 'tools/translate/upload_screenshots.py to upload them instead:',
6107 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146108
Sam Maiera6e76d72022-02-11 21:43:506109 if missing_sha1:
6110 results.append(
6111 output_api.PresubmitError(
6112 'You are adding or modifying UI strings.\n'
6113 'To ensure the best translations, take screenshots of the relevant UI '
6114 '(https://g.co/chrome/translation) and add these files to your '
6115 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146116
Sam Maiera6e76d72022-02-11 21:43:506117 if unnecessary_sha1_files:
6118 results.append(
6119 output_api.PresubmitError(
6120 'You removed strings associated with these files. Remove:',
6121 sorted(unnecessary_sha1_files)))
6122 else:
6123 results.append(
6124 output_api.PresubmitPromptOrNotify('Skipping translation '
6125 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146126
Sam Maiera6e76d72022-02-11 21:43:506127 if icu_syntax_errors:
6128 results.append(
6129 output_api.PresubmitPromptWarning(
6130 'ICU syntax errors were found in the following strings (problems or '
6131 'feedback? Contact [email protected]):',
6132 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:266133
Sam Maiera6e76d72022-02-11 21:43:506134 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:126135
6136
Saagar Sanghavifceeaae2020-08-12 16:40:366137def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:126138 repo_root=None,
6139 translation_expectations_path=None,
6140 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:506141 import sys
6142 affected_grds = [
6143 f for f in input_api.AffectedFiles()
6144 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
6145 ]
6146 if not affected_grds:
6147 return []
6148
6149 try:
6150 old_sys_path = sys.path
6151 sys.path = sys.path + [
6152 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6153 'translation')
6154 ]
6155 from helper import git_helper
6156 from helper import translation_helper
6157 finally:
6158 sys.path = old_sys_path
6159
6160 # Check that translation expectations can be parsed and we can get a list of
6161 # translatable grd files. |repo_root| and |translation_expectations_path| are
6162 # only passed by tests.
6163 if not repo_root:
6164 repo_root = input_api.PresubmitLocalPath()
6165 if not translation_expectations_path:
6166 translation_expectations_path = input_api.os_path.join(
6167 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
6168 if not grd_files:
6169 grd_files = git_helper.list_grds_in_repository(repo_root)
6170
6171 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:596172 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:506173 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
6174 'tests')
6175 grd_files = [p for p in grd_files if ignore_path not in p]
6176
6177 try:
6178 translation_helper.get_translatable_grds(
6179 repo_root, grd_files, translation_expectations_path)
6180 except Exception as e:
6181 return [
6182 output_api.PresubmitNotifyResult(
6183 'Failed to get a list of translatable grd files. This happens when:\n'
6184 ' - One of the modified grd or grdp files cannot be parsed or\n'
6185 ' - %s is not updated.\n'
6186 'Stack:\n%s' % (translation_expectations_path, str(e)))
6187 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:126188 return []
6189
Ken Rockotc31f4832020-05-29 18:58:516190
Saagar Sanghavifceeaae2020-08-12 16:40:366191def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506192 """Changes to [Stable] mojom types must preserve backward-compatibility."""
6193 changed_mojoms = input_api.AffectedFiles(
6194 include_deletes=True,
6195 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:526196
Bruce Dawson344ab262022-06-04 11:35:106197 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:506198 return []
6199
6200 delta = []
6201 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:506202 delta.append({
6203 'filename': mojom.LocalPath(),
6204 'old': '\n'.join(mojom.OldContents()) or None,
6205 'new': '\n'.join(mojom.NewContents()) or None,
6206 })
6207
6208 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:216209 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:506210 input_api.os_path.join(
6211 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
6212 'check_stable_mojom_compatibility.py'), '--src-root',
6213 input_api.PresubmitLocalPath()
6214 ],
6215 stdin=input_api.subprocess.PIPE,
6216 stdout=input_api.subprocess.PIPE,
6217 stderr=input_api.subprocess.PIPE,
6218 universal_newlines=True)
6219 (x, error) = process.communicate(input=input_api.json.dumps(delta))
6220 if process.returncode:
6221 return [
6222 output_api.PresubmitError(
6223 'One or more [Stable] mojom definitions appears to have been changed '
6224 'in a way that is not backward-compatible.',
6225 long_text=error)
6226 ]
Erik Staabc734cd7a2021-11-23 03:11:526227 return []
6228
Dominic Battre645d42342020-12-04 16:14:106229def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506230 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106231
Sam Maiera6e76d72022-02-11 21:43:506232 def FilterFile(affected_file):
6233 """Accept only .cc files and the like."""
6234 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6235 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6236 input_api.DEFAULT_FILES_TO_SKIP)
6237 return input_api.FilterSourceFile(
6238 affected_file,
6239 files_to_check=file_inclusion_pattern,
6240 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106241
Sam Maiera6e76d72022-02-11 21:43:506242 def ModifiedLines(affected_file):
6243 """Returns a list of tuples (line number, line text) of added and removed
6244 lines.
Dominic Battre645d42342020-12-04 16:14:106245
Sam Maiera6e76d72022-02-11 21:43:506246 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106247
Sam Maiera6e76d72022-02-11 21:43:506248 This relies on the scm diff output describing each changed code section
6249 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106250
Sam Maiera6e76d72022-02-11 21:43:506251 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6252 """
6253 line_num = 0
6254 modified_lines = []
6255 for line in affected_file.GenerateScmDiff().splitlines():
6256 # Extract <new line num> of the patch fragment (see format above).
6257 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6258 line)
6259 if m:
6260 line_num = int(m.groups(1)[0])
6261 continue
6262 if ((line.startswith('+') and not line.startswith('++'))
6263 or (line.startswith('-') and not line.startswith('--'))):
6264 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106265
Sam Maiera6e76d72022-02-11 21:43:506266 if not line.startswith('-'):
6267 line_num += 1
6268 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106269
Sam Maiera6e76d72022-02-11 21:43:506270 def FindLineWith(lines, needle):
6271 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106272
Sam Maiera6e76d72022-02-11 21:43:506273 If 0 or >1 lines contain `needle`, -1 is returned.
6274 """
6275 matching_line_numbers = [
6276 # + 1 for 1-based counting of line numbers.
6277 i + 1 for i, line in enumerate(lines) if needle in line
6278 ]
6279 return matching_line_numbers[0] if len(
6280 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106281
Sam Maiera6e76d72022-02-11 21:43:506282 def ModifiedPrefMigration(affected_file):
6283 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6284 # Determine first and last lines of MigrateObsolete.*Pref functions.
6285 new_contents = affected_file.NewContents()
6286 range_1 = (FindLineWith(new_contents,
6287 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6288 FindLineWith(new_contents,
6289 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6290 range_2 = (FindLineWith(new_contents,
6291 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6292 FindLineWith(new_contents,
6293 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6294 if (-1 in range_1 + range_2):
6295 raise Exception(
6296 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6297 )
Dominic Battre645d42342020-12-04 16:14:106298
Sam Maiera6e76d72022-02-11 21:43:506299 # Check whether any of the modified lines are part of the
6300 # MigrateObsolete.*Pref functions.
6301 for line_nr, line in ModifiedLines(affected_file):
6302 if (range_1[0] <= line_nr <= range_1[1]
6303 or range_2[0] <= line_nr <= range_2[1]):
6304 return True
6305 return False
Dominic Battre645d42342020-12-04 16:14:106306
Sam Maiera6e76d72022-02-11 21:43:506307 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6308 browser_prefs_file_pattern = input_api.re.compile(
6309 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106310
Sam Maiera6e76d72022-02-11 21:43:506311 changes = input_api.AffectedFiles(include_deletes=True,
6312 file_filter=FilterFile)
6313 potential_problems = []
6314 for f in changes:
6315 for line in f.GenerateScmDiff().splitlines():
6316 # Check deleted lines for pref registrations.
6317 if (line.startswith('-') and not line.startswith('--')
6318 and register_pref_pattern.search(line)):
6319 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106320
Sam Maiera6e76d72022-02-11 21:43:506321 if browser_prefs_file_pattern.search(f.LocalPath()):
6322 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6323 # assume that they knew that they have to deprecate preferences and don't
6324 # warn.
6325 try:
6326 if ModifiedPrefMigration(f):
6327 return []
6328 except Exception as e:
6329 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106330
Sam Maiera6e76d72022-02-11 21:43:506331 if potential_problems:
6332 return [
6333 output_api.PresubmitPromptWarning(
6334 'Discovered possible removal of preference registrations.\n\n'
6335 'Please make sure to properly deprecate preferences by clearing their\n'
6336 'value for a couple of milestones before finally removing the code.\n'
6337 'Otherwise data may stay in the preferences files forever. See\n'
6338 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6339 'chrome/browser/prefs/README.md for examples.\n'
6340 'This may be a false positive warning (e.g. if you move preference\n'
6341 'registrations to a different place).\n', potential_problems)
6342 ]
6343 return []
6344
Matt Stark6ef08872021-07-29 01:21:466345
6346def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506347 """Changes to GRD files must be consistent for tools to read them."""
6348 changed_grds = input_api.AffectedFiles(
6349 include_deletes=False,
6350 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6351 errors = []
6352 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6353 for matcher, msg in _INVALID_GRD_FILE_LINE]
6354 for grd in changed_grds:
6355 for i, line in enumerate(grd.NewContents()):
6356 for matcher, msg in invalid_file_regexes:
6357 if matcher.search(line):
6358 errors.append(
6359 output_api.PresubmitError(
6360 'Problem on {grd}:{i} - {msg}'.format(
6361 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6362 return errors
6363
Kevin McNee967dd2d22021-11-15 16:09:296364
6365def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506366 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
6367 presence of MPArch features such as bfcache, prerendering, and fenced frames.
6368 """
Kevin McNee967dd2d22021-11-15 16:09:296369
Ian Vollickdba956c2022-04-20 23:53:456370 # Only consider top-level directories that (1) can use content APIs or
6371 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
6372 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:506373 files_to_check = (
Bruce Dawson40fece62022-09-16 19:58:316374 r'^(chrome|components|content|extensions|third_party/blink/renderer)/.+%s' %
Kevin McNee967dd2d22021-11-15 16:09:296375 _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:316376 r'^(chrome|components|content|extensions|third_party/blink/renderer)/.+%s' %
Sam Maiera6e76d72022-02-11 21:43:506377 _HEADER_EXTENSIONS,
6378 )
6379 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6380 input_api.DEFAULT_FILES_TO_SKIP)
6381 source_file_filter = lambda f: input_api.FilterSourceFile(
6382 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:296383
Kevin McNee29c0e8232022-08-05 15:36:096384 # Here we list the classes/methods we're monitoring. For the "fyi" cases,
6385 # we add the CL to the watchlist, but we don't omit a warning or have it be
6386 # included in the triage rotation.
Sam Maiera6e76d72022-02-11 21:43:506387 # Note that since these are are just regular expressions and we don't have
6388 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
6389 # could have a method named IsInMainFrame).
Kevin McNee29c0e8232022-08-05 15:36:096390 fyi_concerning_class_pattern = input_api.re.compile(
Sam Maiera6e76d72022-02-11 21:43:506391 r'WebContentsObserver|WebContentsUserData')
6392 # A subset of WebContentsObserver overrides where there's particular risk for
6393 # confusing tab and page level operations and data (e.g. incorrectly
6394 # resetting page state in DidFinishNavigation).
Kevin McNee29c0e8232022-08-05 15:36:096395 fyi_concerning_wco_methods = [
Sam Maiera6e76d72022-02-11 21:43:506396 'DidStartNavigation',
6397 'ReadyToCommitNavigation',
6398 'DidFinishNavigation',
6399 'RenderViewReady',
6400 'RenderViewDeleted',
6401 'RenderViewHostChanged',
Sam Maiera6e76d72022-02-11 21:43:506402 'DOMContentLoaded',
6403 'DidFinishLoad',
6404 ]
6405 concerning_nav_handle_methods = [
6406 'IsInMainFrame',
6407 ]
6408 concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:506409 'FromRenderFrameHost',
6410 'FromRenderViewHost',
Kevin McNee29c0e8232022-08-05 15:36:096411 ]
6412 fyi_concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:506413 'GetRenderViewHost',
6414 ]
6415 concerning_rfh_methods = [
6416 'GetParent',
6417 'GetMainFrame',
Kevin McNee29c0e8232022-08-05 15:36:096418 ]
6419 fyi_concerning_rfh_methods = [
Sam Maiera6e76d72022-02-11 21:43:506420 'GetFrameTreeNodeId',
6421 ]
Ian Vollickc825b1f2022-04-19 14:30:156422 concerning_rfhi_methods = [
6423 'is_main_frame',
6424 ]
Ian Vollicka77a73ea2022-04-06 18:08:016425 concerning_ftn_methods = [
6426 'IsMainFrame',
6427 ]
Ian Vollickdba956c2022-04-20 23:53:456428 concerning_blink_frame_methods = [
Ian Vollick4d785d22022-06-18 00:10:026429 'IsCrossOriginToNearestMainFrame',
Ian Vollickdba956c2022-04-20 23:53:456430 ]
Sam Maiera6e76d72022-02-11 21:43:506431 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
6432 item for sublist in [
Kevin McNee29c0e8232022-08-05 15:36:096433 concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:016434 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:156435 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:456436 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:506437 ] for item in sublist) + r')\(')
Kevin McNee29c0e8232022-08-05 15:36:096438 fyi_concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
6439 item for sublist in [
6440 fyi_concerning_wco_methods, fyi_concerning_web_contents_methods,
6441 fyi_concerning_rfh_methods,
6442 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:296443
Kevin McNee4eeec792022-02-14 20:02:046444 used_apis = set()
Kevin McNee29c0e8232022-08-05 15:36:096445 used_fyi_methods = False
Sam Maiera6e76d72022-02-11 21:43:506446 for f in input_api.AffectedFiles(include_deletes=False,
6447 file_filter=source_file_filter):
6448 for line_num, line in f.ChangedContents():
Kevin McNee29c0e8232022-08-05 15:36:096449 fyi_class_match = fyi_concerning_class_pattern.search(line)
6450 if fyi_class_match:
6451 used_fyi_methods = True
6452 fyi_method_match = fyi_concerning_method_pattern.search(line)
6453 if fyi_method_match:
6454 used_fyi_methods = True
Kevin McNee4eeec792022-02-14 20:02:046455 method_match = concerning_method_pattern.search(line)
6456 if method_match:
6457 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:506458
Kevin McNee4eeec792022-02-14 20:02:046459 if not used_apis:
Kevin McNee29c0e8232022-08-05 15:36:096460 if used_fyi_methods:
6461 output_api.AppendCC('[email protected]')
6462
Kevin McNee4eeec792022-02-14 20:02:046463 return []
Kevin McNee967dd2d22021-11-15 16:09:296464
Kevin McNee4eeec792022-02-14 20:02:046465 output_api.AppendCC('[email protected]')
6466 message = ('This change uses API(s) that are ambiguous in the presence of '
6467 'MPArch features such as bfcache, prerendering, and fenced '
6468 'frames.')
Kevin McNee29c0e8232022-08-05 15:36:096469 explanation = (
Kevin McNee4eeec792022-02-14 20:02:046470 'Please double check whether new code assumes that a WebContents only '
Kevin McNee29c0e8232022-08-05 15:36:096471 'contains a single page at a time. Notably, checking whether a frame '
6472 'is the \"main frame\" is not specific enough to determine whether it '
6473 'corresponds to the document reflected in the omnibox. A WebContents '
6474 'may have additional main frames for prerendered pages, bfcached '
6475 'pages, fenced frames, etc. '
6476 'See this doc [1] and the comments on the individual APIs '
Kevin McNee4eeec792022-02-14 20:02:046477 'for guidance and this doc [2] for context. The MPArch review '
6478 'watchlist has been CC\'d on this change to help identify any issues.\n'
6479 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
6480 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
6481 )
6482 return [
6483 output_api.PresubmitNotifyResult(message,
6484 items=list(used_apis),
Kevin McNee29c0e8232022-08-05 15:36:096485 long_text=explanation)
Kevin McNee4eeec792022-02-14 20:02:046486 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:366487
6488
6489def CheckAssertAshOnlyCode(input_api, output_api):
6490 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6491 assert(is_chromeos_ash).
6492 """
6493
6494 def FileFilter(affected_file):
6495 """Includes directories known to be Ash only."""
6496 return input_api.FilterSourceFile(
6497 affected_file,
6498 files_to_check=(
6499 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6500 r'.*/ash/.*BUILD\.gn'), # Any path component.
6501 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6502
6503 errors = []
6504 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566505 for f in input_api.AffectedFiles(include_deletes=False,
6506 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366507 if (not pattern.search(input_api.ReadFile(f))):
6508 errors.append(
6509 output_api.PresubmitError(
6510 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6511 'possible, please create and issue and add a comment such '
6512 'as:\n # TODO(https://crbug.com/XXX): add '
6513 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6514 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276515
6516
6517def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506518 path = affected_file.LocalPath()
6519 if not _IsCPlusPlusFile(input_api, path):
6520 return False
6521
6522 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6523 if "/renderer/" in path:
6524 return True
6525
6526 # Blink's public/web API is only used/included by Renderer-only code. Note
6527 # that public/platform API may be used in non-Renderer processes (e.g. there
6528 # are some includes in code used by Utility, PDF, or Plugin processes).
6529 if "/blink/public/web/" in path:
6530 return True
6531
6532 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276533 return False
6534
Lukasz Anforowicz7016d05e2021-11-30 03:56:276535# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6536# by the Chromium Clang Plugin (which will be preferable because it will
6537# 1) report errors earlier - at compile-time and 2) cover more rules).
6538def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506539 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6540 errors = []
6541 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6542 # C++ comment.
6543 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6544 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6545 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6546 if raw_ptr_matcher.search(line):
6547 errors.append(
6548 output_api.PresubmitError(
6549 'Problem on {path}:{line} - '\
6550 'raw_ptr<T> should not be used in Renderer-only code '\
6551 '(as documented in the "Pointers to unprotected memory" '\
6552 'section in //base/memory/raw_ptr.md)'.format(
6553 path=f.LocalPath(), line=line_num)))
6554 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566555
6556
6557def CheckPythonShebang(input_api, output_api):
6558 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6559 system-wide python.
6560 """
6561 errors = []
6562 sources = lambda affected_file: input_api.FilterSourceFile(
6563 affected_file,
6564 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6565 r'third_party/blink/web_tests/external/') + input_api.
6566 DEFAULT_FILES_TO_SKIP),
6567 files_to_check=[r'.*\.py$'])
6568 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276569 for line_num, line in f.ChangedContents():
6570 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6571 errors.append(f.LocalPath())
6572 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566573
6574 result = []
6575 for file in errors:
6576 result.append(
6577 output_api.PresubmitError(
6578 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6579 file))
6580 return result
James Shen81cc0e22022-06-15 21:10:456581
6582
6583def CheckBatchAnnotation(input_api, output_api):
6584 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6585 is not an instrumentation test, disregard."""
6586
6587 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6588 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6589 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6590 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6591 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6592
ckitagawae8fd23b2022-06-17 15:29:386593 missing_annotation_errors = []
6594 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456595
6596 def _FilterFile(affected_file):
6597 return input_api.FilterSourceFile(
6598 affected_file,
6599 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6600 files_to_check=[r'.*Test\.java$'])
6601
6602 for f in input_api.AffectedSourceFiles(_FilterFile):
6603 batch_matched = None
6604 do_not_batch_matched = None
6605 is_instrumentation_test = True
6606 for line in f.NewContents():
6607 if robolectric_test.search(line) or uiautomator_test.search(line):
6608 # Skip Robolectric and UiAutomator tests.
6609 is_instrumentation_test = False
6610 break
6611 if not batch_matched:
6612 batch_matched = batch_annotation.search(line)
6613 if not do_not_batch_matched:
6614 do_not_batch_matched = do_not_batch_annotation.search(line)
6615 test_class_declaration_matched = test_class_declaration.search(
6616 line)
6617 if test_class_declaration_matched:
6618 break
6619 if (is_instrumentation_test and
6620 not batch_matched and
6621 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246622 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386623 if (not is_instrumentation_test and
6624 (batch_matched or
6625 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246626 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456627
6628 results = []
6629
ckitagawae8fd23b2022-06-17 15:29:386630 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456631 results.append(
6632 output_api.PresubmitPromptWarning(
6633 """
6634Instrumentation tests should use either @Batch or @DoNotBatch. If tests are not
6635safe to run in batch, please use @DoNotBatch with reasons.
ckitagawae8fd23b2022-06-17 15:29:386636""", missing_annotation_errors))
6637 if extra_annotation_errors:
6638 results.append(
6639 output_api.PresubmitPromptWarning(
6640 """
6641Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6642""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456643
6644 return results
Sam Maier4cef9242022-10-03 14:21:246645
6646
6647def CheckMockAnnotation(input_api, output_api):
6648 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6649 classes with @Mock or @Spy. If this is not an instrumentation test,
6650 disregard."""
6651
6652 # This is just trying to be approximately correct. We are not writing a
6653 # Java parser, so special cases like statically importing mock() then
6654 # calling an unrelated non-mockito spy() function will cause a false
6655 # positive.
6656 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6657 mock_static_import = input_api.re.compile(
6658 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6659 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6660 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6661 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6662 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6663 fully_qualified_mock_function = input_api.re.compile(
6664 r'Mockito\.' + mock_or_spy_function_call)
6665 statically_imported_mock_function = input_api.re.compile(
6666 r'\W' + mock_or_spy_function_call)
6667 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6668 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6669
6670 def _DoClassLookup(class_name, class_name_map, package):
6671 found = class_name_map.get(class_name)
6672 if found is not None:
6673 return found
6674 else:
6675 return package + '.' + class_name
6676
6677 def _FilterFile(affected_file):
6678 return input_api.FilterSourceFile(
6679 affected_file,
6680 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6681 files_to_check=[r'.*Test\.java$'])
6682
6683 mocked_by_function_classes = set()
6684 mocked_by_annotation_classes = set()
6685 class_to_filename = {}
6686 for f in input_api.AffectedSourceFiles(_FilterFile):
6687 mock_function_regex = fully_qualified_mock_function
6688 next_line_is_annotated = False
6689 fully_qualified_class_map = {}
6690 package = None
6691
6692 for line in f.NewContents():
6693 if robolectric_test.search(line) or uiautomator_test.search(line):
6694 # Skip Robolectric and UiAutomator tests.
6695 break
6696
6697 m = package_name.search(line)
6698 if m:
6699 package = m.group(1)
6700 continue
6701
6702 if mock_static_import.search(line):
6703 mock_function_regex = statically_imported_mock_function
6704 continue
6705
6706 m = import_class.search(line)
6707 if m:
6708 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
6709 continue
6710
6711 if next_line_is_annotated:
6712 next_line_is_annotated = False
6713 fully_qualified_class = _DoClassLookup(
6714 field_type.search(line).group(1), fully_qualified_class_map,
6715 package)
6716 mocked_by_annotation_classes.add(fully_qualified_class)
6717 continue
6718
6719 if mock_annotation.search(line):
6720 next_line_is_annotated = True
6721 continue
6722
6723 m = mock_function_regex.search(line)
6724 if m:
6725 fully_qualified_class = _DoClassLookup(m.group(1),
6726 fully_qualified_class_map, package)
6727 # Skipping builtin classes, since they don't get optimized.
6728 if fully_qualified_class.startswith(
6729 'android.') or fully_qualified_class.startswith(
6730 'java.'):
6731 continue
6732 class_to_filename[fully_qualified_class] = str(f.LocalPath())
6733 mocked_by_function_classes.add(fully_qualified_class)
6734
6735 results = []
6736 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
6737 if missed_classes:
6738 error_locations = []
6739 for c in missed_classes:
6740 error_locations.append(c + ' in ' + class_to_filename[c])
6741 results.append(
6742 output_api.PresubmitPromptWarning(
6743 """
6744Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
67451) If the mocked variable can be a class member, annotate the member with
6746 @Mock/@Spy.
67472) If the mocked variable cannot be a class member, create a dummy member
6748 variable of that type, annotated with @Mock/@Spy. This dummy does not need
6749 to be used or initialized in any way.
67503) If the mocked type is definitely not going to be optimized, whether it's a
6751 builtin type which we don't ship, or a class you know R8 will treat
6752 specially, you can ignore this warning.
6753""", error_locations))
6754
6755 return results
Mike Dougherty1b8be712022-10-20 00:15:136756
6757def CheckNoJsInIos(input_api, output_api):
6758 """Checks to make sure that JavaScript files are not used on iOS."""
6759
6760 def _FilterFile(affected_file):
6761 return input_api.FilterSourceFile(
6762 affected_file,
6763 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
6764 (r'^ios/third_party/*', r'^third_party/*'),
6765 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
6766
6767 error_paths = []
6768 warning_paths = []
6769
6770 for f in input_api.AffectedSourceFiles(_FilterFile):
6771 local_path = f.LocalPath()
6772
6773 if input_api.os_path.splitext(local_path)[1] == '.js':
6774 if f.Action() == 'A':
6775 error_paths.append(local_path)
6776 elif f.Action() != 'D':
6777 warning_paths.append(local_path)
6778
6779 results = []
6780
6781 if warning_paths:
6782 results.append(output_api.PresubmitPromptWarning(
6783 'TypeScript is now fully supported for iOS feature scripts. '
6784 'Consider converting JavaScript files to TypeScript. See '
6785 '//ios/web/public/js_messaging/README.md for more details.',
6786 warning_paths))
6787
6788 if error_paths:
6789 results.append(output_api.PresubmitError(
6790 'Do not use JavaScript on iOS as TypeScript is fully supported. '
6791 'See //ios/web/public/js_messaging/README.md for help using '
6792 'scripts on iOS.', error_paths))
6793
6794 return results