blob: e112f4febe3a89620544f96a25e0272dd4b0eb22 [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)',
Bob Beck03509d282022-12-07 21:49:05757 # Needed for interop with third-party boringssl cert verifier
758 '^third_party/boringssl/',
759 '^net/cert/',
760 '^net/tools/cert_verify_tool/',
761 '^services/cert_verifier/',
762 '^components/certificate_transparency/',
763 '^components/media_router/common/providers/cast/certificate/',
Meilin Wang00efc7c2021-05-13 01:12:42764 # gRPC provides some C++ libraries that use std::shared_ptr<>.
Yeunjoo Choi1b644402022-08-25 02:36:10765 '^chromeos/ash/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59766 '^chromecast/cast_core/grpc',
767 '^chromecast/cast_core/runtime/browser',
Yue Shef83d95202022-09-26 20:23:45768 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Wez5f56be52021-05-04 09:30:58769 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Wez6da2e412022-11-23 11:28:48770 '^base/fuchsia/.*\.(cc|h)',
Wez5f56be52021-05-04 09:30:58771 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57772 # Needed for clang plugin tests
773 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57774 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21775 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15776 BanRule(
Peter Kasting991618a62019-06-17 22:00:09777 r'/\bstd::weak_ptr\b',
778 (
779 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
780 ),
781 True,
782 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
783 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15784 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21785 r'/\blong long\b',
786 (
787 'long long is banned. Use stdint.h if you need a 64 bit number.',
788 ),
789 False, # Only a warning since it is already used.
790 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
791 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15792 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44793 r'/\b(absl|std)::any\b',
Daniel Chengc05fcc62022-01-12 16:54:29794 (
Daniel Chenga44a1bcd2022-03-15 20:00:15795 'absl::any / std::any are not safe to use in a component build.',
Daniel Chengc05fcc62022-01-12 16:54:29796 ),
797 True,
798 # Not an error in third party folders, though it probably should be :)
799 [_THIRD_PARTY_EXCEPT_BLINK],
800 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15801 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21802 r'/\bstd::bind\b',
803 (
804 'std::bind is banned because of lifetime risks.',
805 'Use base::BindOnce or base::BindRepeating instead.',
806 ),
807 True,
808 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
809 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15810 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44811 (
812 r'/\b(?:'
813 r'std::linear_congruential_engine|std::mersenne_twister_engine|'
814 r'std::subtract_with_carry_engine|std::discard_block_engine|'
815 r'std::independent_bits_engine|std::shuffle_order_engine|'
816 r'std::minstd_rand0|std::minstd_rand|'
817 r'std::mt19937|std::mt19937_64|'
818 r'std::ranlux24_base|std::ranlux48_base|std::ranlux24|std::ranlux48|'
819 r'std::knuth_b|'
820 r'std::default_random_engine|'
821 r'std::random_device'
822 r')\b'
823 ),
824 (
825 'STL random number engines and generators are banned. Use the ',
826 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
827 'base::RandomBitGenerator.'
828 ),
829 True,
830 [
831 # Not an error in third_party folders.
832 _THIRD_PARTY_EXCEPT_BLINK,
833 # Various tools which build outside of Chrome.
834 r'testing/libfuzzer',
835 r'tools/android/io_benchmark/',
836 # Fuzzers are allowed to use standard library random number generators
837 # since fuzzing speed + reproducibility is important.
838 r'tools/ipc_fuzzer/',
839 r'.+_fuzzer\.cc$',
840 r'.+_fuzzertest\.cc$',
841 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
842 # the standard library's random number generators, and should be
843 # migrated to the //base equivalent.
844 r'ash/ambient/model/ambient_topic_queue\.cc',
845 r'base/allocator/partition_allocator/partition_alloc_unittest\.cc',
846 r'base/ranges/algorithm_unittest\.cc',
847 r'base/test/launcher/test_launcher\.cc',
848 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
849 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
850 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
851 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
852 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
853 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
854 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
855 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
856 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
857 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
858 r'chrome/chrome_cleaner/logging/detailed_info_sampler\.cc',
859 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
860 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
861 r'components/metrics/metrics_state_manager\.cc',
862 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
863 r'components/zucchini/disassembler_elf_unittest\.cc',
864 r'content/browser/webid/federated_auth_request_impl\.cc',
865 r'content/browser/webid/federated_auth_request_impl\.cc',
866 r'media/cast/test/utility/udp_proxy\.h',
867 r'sql/recover_module/module_unittest\.cc',
868 ],
869 ),
870 BanRule(
Peter Kasting4f35bfc2022-10-18 18:39:12871 r'/\babsl::bind_front\b',
872 (
Daniel Cheng192683f2022-11-01 20:52:44873 'absl::bind_front is banned. Use base::BindOnce() or '
874 'base::BindRepeating() instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12875 ),
876 True,
877 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
878 ),
879 BanRule(
880 r'/\bABSL_FLAG\b',
881 (
882 'ABSL_FLAG is banned. Use base::CommandLine instead.',
883 ),
884 True,
885 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
886 ),
887 BanRule(
888 r'/\babsl::c_',
889 (
890 'Abseil container utilities are banned. Use base/ranges/algorithm.h',
891 'instead.',
892 ),
893 True,
894 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
895 ),
896 BanRule(
897 r'/\babsl::FunctionRef\b',
898 (
899 'absl::FunctionRef is banned. Use base::FunctionRef instead.',
900 ),
901 True,
902 [
903 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
904 # interoperability.
905 r'^base/functional/bind_internal\.h',
906 # base::FunctionRef is implemented on top of absl::FunctionRef.
907 r'^base/functional/function_ref.*\..+',
908 # Not an error in third_party folders.
909 _THIRD_PARTY_EXCEPT_BLINK,
910 ],
911 ),
912 BanRule(
913 r'/\babsl::(Insecure)?BitGen\b',
914 (
Daniel Cheng192683f2022-11-01 20:52:44915 'absl random number generators are banned. Use the helpers in '
916 'base/rand_util.h instead, e.g. base::RandBytes() or ',
917 'base::RandomBitGenerator.'
Peter Kasting4f35bfc2022-10-18 18:39:12918 ),
919 True,
920 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
921 ),
922 BanRule(
923 r'/\babsl::Span\b',
924 (
925 'absl::Span is banned. Use base::span instead.',
926 ),
927 True,
928 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
929 ),
930 BanRule(
931 r'/\babsl::StatusOr\b',
932 (
933 'absl::StatusOr is banned. Use base::expected instead.',
934 ),
935 True,
Adithya Srinivasanb2041882022-10-21 19:34:20936 [
937 # Needed to use liburlpattern API.
938 r'third_party/blink/renderer/core/url_pattern/.*',
939 # Not an error in third_party folders.
940 _THIRD_PARTY_EXCEPT_BLINK
941 ],
Peter Kasting4f35bfc2022-10-18 18:39:12942 ),
943 BanRule(
944 r'/\babsl::StrFormat\b',
945 (
946 'absl::StrFormat is banned for now. Use base::StringPrintf instead.',
947 ),
948 True,
949 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
950 ),
951 BanRule(
952 r'/\babsl::string_view\b',
953 (
954 'absl::string_view is banned. Use base::StringPiece instead.',
955 ),
956 True,
Adithya Srinivasanb2041882022-10-21 19:34:20957 [
958 # Needed to use liburlpattern API.
959 r'third_party/blink/renderer/core/url_pattern/.*',
David Benjamin3a305f12022-11-19 00:10:03960 # Needed to use QUICHE API.
Victor Vasilieva13f1932022-12-02 15:27:24961 r'net/quic/.*',
962 r'net/spdy/.*',
David Benjamin3a305f12022-11-19 00:10:03963 r'net/test/embedded_test_server/.*',
Victor Vasilieva13f1932022-12-02 15:27:24964 r'net/third_party/quiche/.*',
965 r'services/network/web_transport\.cc',
Adithya Srinivasanb2041882022-10-21 19:34:20966 # Not an error in third_party folders.
967 _THIRD_PARTY_EXCEPT_BLINK
968 ],
Peter Kasting4f35bfc2022-10-18 18:39:12969 ),
970 BanRule(
971 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
972 (
973 'Abseil string utilities are banned. Use base/strings instead.',
974 ),
975 True,
976 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
977 ),
978 BanRule(
979 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
980 (
981 'Abseil synchronization primitives are banned. Use',
982 'base/synchronization instead.',
983 ),
984 True,
985 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
986 ),
987 BanRule(
988 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
989 (
990 'Abseil\'s time library is banned. Use base/time instead.',
991 ),
992 True,
993 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
994 ),
995 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:03996 r'/\bstd::optional\b',
997 (
998 'std::optional is banned. Use absl::optional instead.',
999 ),
1000 True,
1001 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1002 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151003 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211004 r'/\b#include <chrono>\b',
1005 (
1006 '<chrono> overlaps with Time APIs in base. Keep using',
1007 'base classes.',
1008 ),
1009 True,
1010 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1011 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151012 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211013 r'/\b#include <exception>\b',
1014 (
1015 'Exceptions are banned and disabled in Chromium.',
1016 ),
1017 True,
1018 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1019 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151020 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211021 r'/\bstd::function\b',
1022 (
Colin Blundellea615d422021-05-12 09:35:411023 'std::function is banned. Instead use base::OnceCallback or ',
1024 'base::RepeatingCallback, which directly support Chromium\'s weak ',
1025 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:211026 ),
Daniel Chenge5583e3c2022-09-22 00:19:411027 True,
Daniel Chengcd23b8b2022-09-16 17:16:241028 [
1029 # Has tests that template trait helpers don't unintentionally match
1030 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:411031 r'base/functional/callback_helpers_unittest\.cc',
1032 # Required to implement interfaces from the third-party perfetto
1033 # library.
1034 r'base/tracing/perfetto_task_runner\.cc',
1035 r'base/tracing/perfetto_task_runner\.h',
1036 # Needed for interop with the third-party nearby library type
1037 # location::nearby::connections::ResultCallback.
1038 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1039 # Needed for interop with the internal libassistant library.
1040 'chromeos/ash/services/libassistant/callback_utils\.h',
1041 # Needed for interop with Fuchsia fidl APIs.
1042 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1043 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1044 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1045 # Required to interop with interfaces from the third-party perfetto
1046 # library.
1047 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1048 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1049 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1050 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1051 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1052 'services/tracing/public/cpp/perfetto/producer_client\.h',
1053 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1054 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1055 # Required for interop with the third-party webrtc library.
1056 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1057 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
1058
1059 # TODO(https://crbug.com/1364577): Various uses that should be
1060 # migrated to something else.
1061 # Should use base::OnceCallback or base::RepeatingCallback.
1062 'base/allocator/dispatcher/initializer_unittest\.cc',
1063 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1064 'chrome/browser/ash/accessibility/speech_monitor\.h',
1065 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1066 'chromecast/base/observer_unittest\.cc',
1067 'chromecast/browser/cast_web_view\.h',
1068 'chromecast/public/cast_media_shlib\.h',
1069 'device/bluetooth/floss/exported_callback_manager\.h',
1070 'device/bluetooth/floss/floss_dbus_client\.h',
1071 'device/fido/cable/v2_handshake_unittest\.cc',
1072 'device/fido/pin\.cc',
1073 'services/tracing/perfetto/test_utils\.h',
1074 # Should use base::FunctionRef.
1075 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1076 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1077 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1078 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1079 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1080 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1081 # Does not need std::function at all.
1082 'components/omnibox/browser/autocomplete_result\.cc',
1083 'device/fido/win/webauthn_api\.cc',
1084 'media/audio/alsa/alsa_util\.cc',
1085 'media/remoting/stream_provider\.h',
1086 'sql/vfs_wrapper\.cc',
1087 # TODO(https://crbug.com/1364585): Remove usage and exception list
1088 # entries.
1089 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1090 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1091 # TODO(https://crbug.com/1364579): Remove usage and exception list
1092 # entry.
1093 'ui/views/controls/focus_ring\.h',
1094
1095 # Various pre-existing uses in //tools that is low-priority to fix.
1096 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1097 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1098 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1099 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1100 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
1101
Daniel Chengcd23b8b2022-09-16 17:16:241102 # Not an error in third_party folders.
1103 _THIRD_PARTY_EXCEPT_BLINK
1104 ],
Daniel Bratell609102be2019-03-27 20:53:211105 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151106 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211107 r'/\b#include <random>\b',
1108 (
1109 'Do not use any random number engines from <random>. Instead',
1110 'use base::RandomBitGenerator.',
1111 ),
1112 True,
1113 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1114 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151115 BanRule(
Tom Andersona95e12042020-09-09 23:08:001116 r'/\b#include <X11/',
1117 (
1118 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
1119 ),
1120 True,
1121 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1122 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151123 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211124 r'/\bstd::ratio\b',
1125 (
1126 'std::ratio is banned by the Google Style Guide.',
1127 ),
1128 True,
1129 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451130 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151131 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:581132 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:191133 (
1134 'RunMessageLoop is deprecated, use RunLoop instead.',
1135 ),
1136 False,
1137 (),
1138 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151139 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441140 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191141 (
1142 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1143 "if you're convinced you need this.",
1144 ),
1145 False,
1146 (),
1147 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151148 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441149 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191150 (
1151 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041152 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191153 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1154 'async events instead of flushing threads.',
1155 ),
1156 False,
1157 (),
1158 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151159 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191160 r'MessageLoopRunner',
1161 (
1162 'MessageLoopRunner is deprecated, use RunLoop instead.',
1163 ),
1164 False,
1165 (),
1166 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151167 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441168 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191169 (
1170 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1171 "gab@ if you found a use case where this is the only solution.",
1172 ),
1173 False,
1174 (),
1175 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151176 BanRule(
Victor Costane48a2e82019-03-15 22:02:341177 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161178 (
Victor Costane48a2e82019-03-15 22:02:341179 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161180 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1181 ),
1182 True,
1183 (
1184 r'^sql/initialization\.(cc|h)$',
1185 r'^third_party/sqlite/.*\.(c|cc|h)$',
1186 ),
1187 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151188 BanRule(
Austin Sullivand661ab52022-11-16 08:55:151189 'CREATE VIEW',
1190 (
1191 'SQL views are disabled in Chromium feature code',
1192 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1193 ),
1194 True,
1195 (
1196 _THIRD_PARTY_EXCEPT_BLINK,
1197 # sql/ itself uses views when using memory-mapped IO.
1198 r'^sql/.*',
1199 # Various performance tools that do not build as part of Chrome.
1200 r'^infra/.*',
1201 r'^tools/perf.*',
1202 r'.*perfetto.*',
1203 ),
1204 ),
1205 BanRule(
1206 'CREATE VIRTUAL TABLE',
1207 (
1208 'SQL virtual tables are disabled in Chromium feature code',
1209 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1210 ),
1211 True,
1212 (
1213 _THIRD_PARTY_EXCEPT_BLINK,
1214 # sql/ itself uses virtual tables in the recovery module and tests.
1215 r'^sql/.*',
1216 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1217 r'third_party/blink/web_tests/storage/websql/.*'
1218 # Various performance tools that do not build as part of Chrome.
1219 r'^tools/perf.*',
1220 r'.*perfetto.*',
1221 ),
1222 ),
1223 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441224 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471225 (
1226 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1227 'base::RandomShuffle instead.'
1228 ),
1229 True,
1230 (),
1231 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151232 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241233 'ios/web/public/test/http_server',
1234 (
1235 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1236 ),
1237 False,
1238 (),
1239 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151240 BanRule(
Robert Liao764c9492019-01-24 18:46:281241 'GetAddressOf',
1242 (
1243 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531244 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111245 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531246 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281247 ),
1248 True,
1249 (),
1250 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151251 BanRule(
Ben Lewisa9514602019-04-29 17:53:051252 'SHFileOperation',
1253 (
1254 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1255 'complex functions to achieve the same goals. Use IFileOperation for ',
1256 'any esoteric actions instead.'
1257 ),
1258 True,
1259 (),
1260 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151261 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511262 'StringFromGUID2',
1263 (
1264 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241265 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511266 ),
1267 True,
1268 (
Daniel Chenga44a1bcd2022-03-15 20:00:151269 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511270 ),
1271 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151272 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511273 'StringFromCLSID',
1274 (
1275 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241276 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511277 ),
1278 True,
1279 (
Daniel Chenga44a1bcd2022-03-15 20:00:151280 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511281 ),
1282 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151283 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131284 'kCFAllocatorNull',
1285 (
1286 'The use of kCFAllocatorNull with the NoCopy creation of ',
1287 'CoreFoundation types is prohibited.',
1288 ),
1289 True,
1290 (),
1291 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151292 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291293 'mojo::ConvertTo',
1294 (
1295 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1296 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1297 'StringTraits if you would like to convert between custom types and',
1298 'the wire format of mojom types.'
1299 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221300 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291301 (
David Dorwin13dc48b2022-06-03 21:18:421302 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1303 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291304 r'^third_party/blink/.*\.(cc|h)$',
1305 r'^content/renderer/.*\.(cc|h)$',
1306 ),
1307 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151308 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161309 'GetInterfaceProvider',
1310 (
1311 'InterfaceProvider is deprecated.',
1312 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1313 'or Platform::GetBrowserInterfaceBroker.'
1314 ),
1315 False,
1316 (),
1317 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151318 BanRule(
Robert Liao1d78df52019-11-11 20:02:011319 'CComPtr',
1320 (
1321 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1322 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1323 'details.'
1324 ),
1325 False,
1326 (),
1327 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151328 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201329 r'/\b(IFACE|STD)METHOD_?\(',
1330 (
1331 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1332 'Instead, always use IFACEMETHODIMP in the declaration.'
1333 ),
1334 False,
1335 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1336 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151337 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471338 'set_owned_by_client',
1339 (
1340 'set_owned_by_client is deprecated.',
1341 'views::View already owns the child views by default. This introduces ',
1342 'a competing ownership model which makes the code difficult to reason ',
1343 'about. See http://crbug.com/1044687 for more details.'
1344 ),
1345 False,
1346 (),
1347 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151348 BanRule(
Peter Boström7ff41522021-07-29 03:43:271349 'RemoveAllChildViewsWithoutDeleting',
1350 (
1351 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1352 'This method is deemed dangerous as, unless raw pointers are re-added,',
1353 'calls to this method introduce memory leaks.'
1354 ),
1355 False,
1356 (),
1357 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151358 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121359 r'/\bTRACE_EVENT_ASYNC_',
1360 (
1361 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1362 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1363 ),
1364 False,
1365 (
1366 r'^base/trace_event/.*',
1367 r'^base/tracing/.*',
1368 ),
1369 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151370 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431371 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1372 (
1373 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1374 'dumps and may spam crash reports. Consider if the throttled',
1375 'variants suffice instead.',
1376 ),
1377 False,
1378 (),
1379 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151380 BanRule(
Robert Liao22f66a52021-04-10 00:57:521381 'RoInitialize',
1382 (
Robert Liao48018922021-04-16 23:03:021383 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521384 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1385 'instead. See http://crbug.com/1197722 for more information.'
1386 ),
1387 True,
Robert Liao48018922021-04-16 23:03:021388 (
Bruce Dawson40fece62022-09-16 19:58:311389 r'^base/win/scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021390 ),
Robert Liao22f66a52021-04-10 00:57:521391 ),
Patrick Monettec343bb982022-06-01 17:18:451392 BanRule(
1393 r'base::Watchdog',
1394 (
1395 'base::Watchdog is deprecated because it creates its own thread.',
1396 'Instead, manually start a timer on a SequencedTaskRunner.',
1397 ),
1398 False,
1399 (),
1400 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091401 BanRule(
1402 'base::Passed',
1403 (
1404 'Do not use base::Passed. It is a legacy helper for capturing ',
1405 'move-only types with base::BindRepeating, but invoking the ',
1406 'resulting RepeatingCallback moves the captured value out of ',
1407 'the callback storage, and subsequent invocations may pass the ',
1408 'value in a valid but undefined state. Prefer base::BindOnce().',
1409 'See http://crbug.com/1326449 for context.'
1410 ),
1411 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481412 (
1413 # False positive, but it is also fine to let bind internals reference
1414 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241415 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481416 r'^base[\\/]functional[\\/]bind_internal\.h',
1417 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091418 ),
Daniel Cheng2248b332022-07-27 06:16:591419 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431420 r'base::Feature k',
1421 (
1422 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1423 'directly declaring/defining features.'
1424 ),
1425 True,
1426 [
1427 _THIRD_PARTY_EXCEPT_BLINK,
1428 ],
1429 ),
Robert Ogden92101dcb2022-10-19 23:49:361430 BanRule(
1431 r'\bchartorune\b',
1432 (
1433 'chartorune is not memory-safe, unless you can guarantee the input ',
1434 'string is always null-terminated. Otherwise, please use charntorune ',
1435 'from libphonenumber instead.'
1436 ),
1437 True,
1438 [
1439 _THIRD_PARTY_EXCEPT_BLINK,
1440 # Exceptions to this rule should have a fuzzer.
1441 ],
1442 ),
[email protected]127f18ec2012-06-16 05:05:591443)
1444
Daniel Cheng92c15e32022-03-16 17:48:221445_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1446 BanRule(
1447 'handle<shared_buffer>',
1448 (
1449 'Please use one of the more specific shared memory types instead:',
1450 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1451 ' mojo_base.mojom.WritableSharedMemoryRegion',
1452 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1453 ),
1454 True,
1455 ),
1456)
1457
mlamouria82272622014-09-16 18:45:041458_IPC_ENUM_TRAITS_DEPRECATED = (
1459 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501460 'See http://www.chromium.org/Home/chromium-security/education/'
1461 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041462
Stephen Martinis97a394142018-06-07 23:06:051463_LONG_PATH_ERROR = (
1464 'Some files included in this CL have file names that are too long (> 200'
1465 ' characters). If committed, these files will cause issues on Windows. See'
1466 ' https://crbug.com/612667 for more details.'
1467)
1468
Shenghua Zhangbfaa38b82017-11-16 21:58:021469_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:311470 r".*/AppHooksImpl\.java",
1471 r".*/BuildHooksAndroidImpl\.java",
1472 r".*/LicenseContentProvider\.java",
1473 r".*/PlatformServiceBridgeImpl.java",
1474 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021475]
[email protected]127f18ec2012-06-16 05:05:591476
Mohamed Heikald048240a2019-11-12 16:57:371477# List of image extensions that are used as resources in chromium.
1478_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1479
Sean Kau46e29bc2017-08-28 16:31:161480# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401481_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:311482 r'test/data/',
1483 r'testing/buildbot/',
1484 r'^components/policy/resources/policy_templates\.json$',
1485 r'^third_party/protobuf/',
1486 r'^third_party/blink/perf_tests/speedometer/resources/todomvc/learn.json',
1487 r'^third_party/blink/renderer/devtools/protocol\.json$',
1488 r'^third_party/blink/web_tests/external/wpt/',
1489 r'^tools/perf/',
1490 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311491 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:311492 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:161493]
1494
Andrew Grieveb773bad2020-06-05 18:00:381495# These are not checked on the public chromium-presubmit trybot.
1496# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041497# checkouts.
agrievef32bcc72016-04-04 14:57:401498_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381499 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381500]
1501
1502
1503_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101504 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041505 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361506 'base/android/jni_generator/jni_generator.pydeps',
1507 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361508 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041509 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361510 'build/android/gyp/aar.pydeps',
1511 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271512 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361513 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381514 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361515 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021516 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221517 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111518 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361519 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361520 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361521 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111522 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041523 'build/android/gyp/create_app_bundle_apks.pydeps',
1524 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361525 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121526 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091527 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221528 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401529 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001530 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361531 'build/android/gyp/dex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361532 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361533 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211534 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361535 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361536 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361537 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581538 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361539 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141540 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261541 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471542 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041543 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361544 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361545 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101546 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361547 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221548 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361549 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221550 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101551 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461552 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301553 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241554 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361555 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461556 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561557 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361558 'build/android/incremental_install/generate_android_manifest.pydeps',
1559 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321560 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041561 'build/android/resource_sizes.pydeps',
1562 'build/android/test_runner.pydeps',
1563 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361564 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361565 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321566 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271567 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1568 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041569 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001570 'components/cronet/tools/generate_javadoc.pydeps',
1571 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381572 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001573 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381574 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181575 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411576 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1577 'testing/merge_scripts/standard_gtest_merge.pydeps',
1578 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1579 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041580 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421581 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251582 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421583 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131584 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501585 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411586 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1587 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061588 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221589 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451590 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401591]
1592
wnwenbdc444e2016-05-25 13:44:151593
agrievef32bcc72016-04-04 14:57:401594_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1595
1596
Eric Boren6fd2b932018-01-25 15:05:081597# Bypass the AUTHORS check for these accounts.
1598_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591599 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451600 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591601 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521602 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231603 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471604 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461605 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:181606 'lacros-sdk-version-roller', 'chrome-automated-expectation',
1607 'chromium-automated-expectation')
Eric Boren835d71f2018-09-07 21:09:041608 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271609 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041610 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161611 for s in ('chromium-internal-autoroll',)
1612 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:551613 for s in ('swarming-tasks',)
1614 ) | set('%[email protected]' % s
1615 for s in ('global-integration-try-builder',
1616 'global-integration-ci-builder'))
Eric Boren6fd2b932018-01-25 15:05:081617
Matt Stark6ef08872021-07-29 01:21:461618_INVALID_GRD_FILE_LINE = [
1619 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1620]
Eric Boren6fd2b932018-01-25 15:05:081621
Daniel Bratell65b033262019-04-23 08:17:061622def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501623 """Returns True if this file contains C++-like code (and not Python,
1624 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061625
Sam Maiera6e76d72022-02-11 21:43:501626 ext = input_api.os_path.splitext(file_path)[1]
1627 # This list is compatible with CppChecker.IsCppFile but we should
1628 # consider adding ".c" to it. If we do that we can use this function
1629 # at more places in the code.
1630 return ext in (
1631 '.h',
1632 '.cc',
1633 '.cpp',
1634 '.m',
1635 '.mm',
1636 )
1637
Daniel Bratell65b033262019-04-23 08:17:061638
1639def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501640 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061641
1642
1643def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501644 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061645
1646
1647def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501648 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061649
Mohamed Heikal5e5b7922020-10-29 18:57:591650
Erik Staabc734cd7a2021-11-23 03:11:521651def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501652 ext = input_api.os_path.splitext(file_path)[1]
1653 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521654
1655
Mohamed Heikal5e5b7922020-10-29 18:57:591656def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501657 """Prevent additions of dependencies from the upstream repo on //clank."""
1658 # clank can depend on clank
1659 if input_api.change.RepositoryRoot().endswith('clank'):
1660 return []
1661 build_file_patterns = [
1662 r'(.+/)?BUILD\.gn',
1663 r'.+\.gni',
1664 ]
1665 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1666 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591667
Sam Maiera6e76d72022-02-11 21:43:501668 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591669
Sam Maiera6e76d72022-02-11 21:43:501670 def FilterFile(affected_file):
1671 return input_api.FilterSourceFile(affected_file,
1672 files_to_check=build_file_patterns,
1673 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591674
Sam Maiera6e76d72022-02-11 21:43:501675 problems = []
1676 for f in input_api.AffectedSourceFiles(FilterFile):
1677 local_path = f.LocalPath()
1678 for line_number, line in f.ChangedContents():
1679 if (bad_pattern.search(line)):
1680 problems.append('%s:%d\n %s' %
1681 (local_path, line_number, line.strip()))
1682 if problems:
1683 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1684 else:
1685 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591686
1687
Saagar Sanghavifceeaae2020-08-12 16:40:361688def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501689 """Attempts to prevent use of functions intended only for testing in
1690 non-testing code. For now this is just a best-effort implementation
1691 that ignores header files and may have some false positives. A
1692 better implementation would probably need a proper C++ parser.
1693 """
1694 # We only scan .cc files and the like, as the declaration of
1695 # for-testing functions in header files are hard to distinguish from
1696 # calls to such functions without a proper C++ parser.
1697 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191698
Sam Maiera6e76d72022-02-11 21:43:501699 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1700 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1701 base_function_pattern)
1702 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1703 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1704 exclusion_pattern = input_api.re.compile(
1705 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1706 (base_function_pattern, base_function_pattern))
1707 # Avoid a false positive in this case, where the method name, the ::, and
1708 # the closing { are all on different lines due to line wrapping.
1709 # HelperClassForTesting::
1710 # HelperClassForTesting(
1711 # args)
1712 # : member(0) {}
1713 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191714
Sam Maiera6e76d72022-02-11 21:43:501715 def FilterFile(affected_file):
1716 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1717 input_api.DEFAULT_FILES_TO_SKIP)
1718 return input_api.FilterSourceFile(
1719 affected_file,
1720 files_to_check=file_inclusion_pattern,
1721 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191722
Sam Maiera6e76d72022-02-11 21:43:501723 problems = []
1724 for f in input_api.AffectedSourceFiles(FilterFile):
1725 local_path = f.LocalPath()
1726 in_method_defn = False
1727 for line_number, line in f.ChangedContents():
1728 if (inclusion_pattern.search(line)
1729 and not comment_pattern.search(line)
1730 and not exclusion_pattern.search(line)
1731 and not allowlist_pattern.search(line)
1732 and not in_method_defn):
1733 problems.append('%s:%d\n %s' %
1734 (local_path, line_number, line.strip()))
1735 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191736
Sam Maiera6e76d72022-02-11 21:43:501737 if problems:
1738 return [
1739 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1740 ]
1741 else:
1742 return []
[email protected]55459852011-08-10 15:17:191743
1744
Saagar Sanghavifceeaae2020-08-12 16:40:361745def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501746 """This is a simplified version of
1747 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1748 """
1749 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1750 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1751 name_pattern = r'ForTest(s|ing)?'
1752 # Describes an occurrence of "ForTest*" inside a // comment.
1753 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1754 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1755 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1756 # Catch calls.
1757 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1758 # Ignore definitions. (Comments are ignored separately.)
1759 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231760
Sam Maiera6e76d72022-02-11 21:43:501761 problems = []
1762 sources = lambda x: input_api.FilterSourceFile(
1763 x,
1764 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1765 DEFAULT_FILES_TO_SKIP),
1766 files_to_check=[r'.*\.java$'])
1767 for f in input_api.AffectedFiles(include_deletes=False,
1768 file_filter=sources):
1769 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231770 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501771 for line_number, line in f.ChangedContents():
1772 if is_inside_javadoc and javadoc_end_re.search(line):
1773 is_inside_javadoc = False
1774 if not is_inside_javadoc and javadoc_start_re.search(line):
1775 is_inside_javadoc = True
1776 if is_inside_javadoc:
1777 continue
1778 if (inclusion_re.search(line) and not comment_re.search(line)
1779 and not annotation_re.search(line)
1780 and not exclusion_re.search(line)):
1781 problems.append('%s:%d\n %s' %
1782 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231783
Sam Maiera6e76d72022-02-11 21:43:501784 if problems:
1785 return [
1786 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1787 ]
1788 else:
1789 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231790
1791
Saagar Sanghavifceeaae2020-08-12 16:40:361792def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501793 """Checks to make sure no .h files include <iostream>."""
1794 files = []
1795 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1796 input_api.re.MULTILINE)
1797 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1798 if not f.LocalPath().endswith('.h'):
1799 continue
1800 contents = input_api.ReadFile(f)
1801 if pattern.search(contents):
1802 files.append(f)
[email protected]10689ca2011-09-02 02:31:541803
Sam Maiera6e76d72022-02-11 21:43:501804 if len(files):
1805 return [
1806 output_api.PresubmitError(
1807 'Do not #include <iostream> in header files, since it inserts static '
1808 'initialization into every file including the header. Instead, '
1809 '#include <ostream>. See http://crbug.com/94794', files)
1810 ]
1811 return []
1812
[email protected]10689ca2011-09-02 02:31:541813
Aleksey Khoroshilov9b28c032022-06-03 16:35:321814def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501815 """Checks no windows headers with StrCat redefined are included directly."""
1816 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:321817 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
1818 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
1819 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
1820 _NON_BASE_DEPENDENT_PATHS)
1821 sources_filter = lambda f: input_api.FilterSourceFile(
1822 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
1823
Sam Maiera6e76d72022-02-11 21:43:501824 pattern_deny = input_api.re.compile(
1825 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1826 input_api.re.MULTILINE)
1827 pattern_allow = input_api.re.compile(
1828 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:321829 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:501830 contents = input_api.ReadFile(f)
1831 if pattern_deny.search(
1832 contents) and not pattern_allow.search(contents):
1833 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431834
Sam Maiera6e76d72022-02-11 21:43:501835 if len(files):
1836 return [
1837 output_api.PresubmitError(
1838 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1839 'directly since they pollute code with StrCat macro. Instead, '
1840 'include matching header from base/win. See http://crbug.com/856536',
1841 files)
1842 ]
1843 return []
Danil Chapovalov3518f362018-08-11 16:13:431844
[email protected]10689ca2011-09-02 02:31:541845
Saagar Sanghavifceeaae2020-08-12 16:40:361846def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501847 """Checks to make sure no source files use UNIT_TEST."""
1848 problems = []
1849 for f in input_api.AffectedFiles():
1850 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1851 continue
[email protected]72df4e782012-06-21 16:28:181852
Sam Maiera6e76d72022-02-11 21:43:501853 for line_num, line in f.ChangedContents():
1854 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1855 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181856
Sam Maiera6e76d72022-02-11 21:43:501857 if not problems:
1858 return []
1859 return [
1860 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1861 '\n'.join(problems))
1862 ]
1863
[email protected]72df4e782012-06-21 16:28:181864
Saagar Sanghavifceeaae2020-08-12 16:40:361865def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501866 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341867
Sam Maiera6e76d72022-02-11 21:43:501868 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1869 instead of DISABLED_. To filter false positives, reports are only generated
1870 if a corresponding MAYBE_ line exists.
1871 """
1872 problems = []
Dominic Battre033531052018-09-24 15:45:341873
Sam Maiera6e76d72022-02-11 21:43:501874 # The following two patterns are looked for in tandem - is a test labeled
1875 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1876 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1877 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341878
Sam Maiera6e76d72022-02-11 21:43:501879 # This is for the case that a test is disabled on all platforms.
1880 full_disable_pattern = input_api.re.compile(
1881 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1882 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341883
Sam Maiera6e76d72022-02-11 21:43:501884 for f in input_api.AffectedFiles(False):
1885 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1886 continue
Dominic Battre033531052018-09-24 15:45:341887
Sam Maiera6e76d72022-02-11 21:43:501888 # Search for MABYE_, DISABLE_ pairs.
1889 disable_lines = {} # Maps of test name to line number.
1890 maybe_lines = {}
1891 for line_num, line in f.ChangedContents():
1892 disable_match = disable_pattern.search(line)
1893 if disable_match:
1894 disable_lines[disable_match.group(1)] = line_num
1895 maybe_match = maybe_pattern.search(line)
1896 if maybe_match:
1897 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341898
Sam Maiera6e76d72022-02-11 21:43:501899 # Search for DISABLE_ occurrences within a TEST() macro.
1900 disable_tests = set(disable_lines.keys())
1901 maybe_tests = set(maybe_lines.keys())
1902 for test in disable_tests.intersection(maybe_tests):
1903 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341904
Sam Maiera6e76d72022-02-11 21:43:501905 contents = input_api.ReadFile(f)
1906 full_disable_match = full_disable_pattern.search(contents)
1907 if full_disable_match:
1908 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341909
Sam Maiera6e76d72022-02-11 21:43:501910 if not problems:
1911 return []
1912 return [
1913 output_api.PresubmitPromptWarning(
1914 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1915 '\n'.join(problems))
1916 ]
1917
Dominic Battre033531052018-09-24 15:45:341918
Nina Satragnof7660532021-09-20 18:03:351919def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501920 """Checks to make sure tests disabled conditionally are not missing a
1921 corresponding MAYBE_ prefix.
1922 """
1923 # Expect at least a lowercase character in the test name. This helps rule out
1924 # false positives with macros wrapping the actual tests name.
1925 define_maybe_pattern = input_api.re.compile(
1926 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191927 # The test_maybe_pattern needs to handle all of these forms. The standard:
1928 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1929 # With a wrapper macro around the test name:
1930 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1931 # And the odd-ball NACL_BROWSER_TEST_f format:
1932 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1933 # The optional E2E_ENABLED-style is handled with (\w*\()?
1934 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1935 # trailing ')'.
1936 test_maybe_pattern = (
1937 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501938 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1939 warnings = []
Nina Satragnof7660532021-09-20 18:03:351940
Sam Maiera6e76d72022-02-11 21:43:501941 # Read the entire files. We can't just read the affected lines, forgetting to
1942 # add MAYBE_ on a change would not show up otherwise.
1943 for f in input_api.AffectedFiles(False):
1944 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1945 continue
1946 contents = input_api.ReadFile(f)
1947 lines = contents.splitlines(True)
1948 current_position = 0
1949 warning_test_names = set()
1950 for line_num, line in enumerate(lines, start=1):
1951 current_position += len(line)
1952 maybe_match = define_maybe_pattern.search(line)
1953 if maybe_match:
1954 test_name = maybe_match.group('test_name')
1955 # Do not warn twice for the same test.
1956 if (test_name in warning_test_names):
1957 continue
1958 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351959
Sam Maiera6e76d72022-02-11 21:43:501960 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1961 # the current position.
1962 test_match = input_api.re.compile(
1963 test_maybe_pattern.format(test_name=test_name),
1964 input_api.re.MULTILINE).search(contents, current_position)
1965 suite_match = input_api.re.compile(
1966 suite_maybe_pattern.format(test_name=test_name),
1967 input_api.re.MULTILINE).search(contents, current_position)
1968 if not test_match and not suite_match:
1969 warnings.append(
1970 output_api.PresubmitPromptWarning(
1971 '%s:%d found MAYBE_ defined without corresponding test %s'
1972 % (f.LocalPath(), line_num, test_name)))
1973 return warnings
1974
[email protected]72df4e782012-06-21 16:28:181975
Saagar Sanghavifceeaae2020-08-12 16:40:361976def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501977 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1978 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:161979 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:501980 input_api.re.MULTILINE)
1981 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1982 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1983 continue
1984 for lnum, line in f.ChangedContents():
1985 if input_api.re.search(pattern, line):
1986 errors.append(
1987 output_api.PresubmitError((
1988 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1989 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1990 (f.LocalPath(), lnum)))
1991 return errors
danakj61c1aa22015-10-26 19:55:521992
1993
Weilun Shia487fad2020-10-28 00:10:341994# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1995# more reliable way. See
1996# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191997
wnwenbdc444e2016-05-25 13:44:151998
Saagar Sanghavifceeaae2020-08-12 16:40:361999def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502000 """Check that FlakyTest annotation is our own instead of the android one"""
2001 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2002 files = []
2003 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2004 if f.LocalPath().endswith('Test.java'):
2005 if pattern.search(input_api.ReadFile(f)):
2006 files.append(f)
2007 if len(files):
2008 return [
2009 output_api.PresubmitError(
2010 'Use org.chromium.base.test.util.FlakyTest instead of '
2011 'android.test.FlakyTest', files)
2012 ]
2013 return []
mcasasb7440c282015-02-04 14:52:192014
wnwenbdc444e2016-05-25 13:44:152015
Saagar Sanghavifceeaae2020-08-12 16:40:362016def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502017 """Make sure .DEPS.git is never modified manually."""
2018 if any(f.LocalPath().endswith('.DEPS.git')
2019 for f in input_api.AffectedFiles()):
2020 return [
2021 output_api.PresubmitError(
2022 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2023 'automated system based on what\'s in DEPS and your changes will be\n'
2024 'overwritten.\n'
2025 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2026 'get-the-code#Rolling_DEPS\n'
2027 'for more information')
2028 ]
2029 return []
[email protected]2a8ac9c2011-10-19 17:20:442030
2031
Saagar Sanghavifceeaae2020-08-12 16:40:362032def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502033 """Checks that DEPS file deps are from allowed_hosts."""
2034 # Run only if DEPS file has been modified to annoy fewer bystanders.
2035 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2036 return []
2037 # Outsource work to gclient verify
2038 try:
2039 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2040 'third_party', 'depot_tools',
2041 'gclient.py')
2042 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322043 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502044 stderr=input_api.subprocess.STDOUT)
2045 return []
2046 except input_api.subprocess.CalledProcessError as error:
2047 return [
2048 output_api.PresubmitError(
2049 'DEPS file must have only git dependencies.',
2050 long_text=error.output)
2051 ]
tandriief664692014-09-23 14:51:472052
2053
Mario Sanchez Prada2472cab2019-09-18 10:58:312054def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152055 ban_rule):
Allen Bauer84778682022-09-22 16:28:562056 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312057
Sam Maiera6e76d72022-02-11 21:43:502058 Returns an string composed of the name of the file, the line number where the
2059 match has been found and the additional text passed as |message| in case the
2060 target type name matches the text inside the line passed as parameter.
2061 """
2062 result = []
Peng Huang9c5949a02020-06-11 19:20:542063
Daniel Chenga44a1bcd2022-03-15 20:00:152064 # Ignore comments about banned types.
2065 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502066 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152067 # A // nocheck comment will bypass this error.
2068 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502069 return result
2070
2071 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152072 if ban_rule.pattern[0:1] == '/':
2073 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502074 if input_api.re.search(regex, line):
2075 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152076 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502077 matched = True
2078
2079 if matched:
2080 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152081 for line in ban_rule.explanation:
2082 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502083
danakjd18e8892020-12-17 17:42:012084 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312085
2086
Saagar Sanghavifceeaae2020-08-12 16:40:362087def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502088 """Make sure that banned functions are not used."""
2089 warnings = []
2090 errors = []
[email protected]127f18ec2012-06-16 05:05:592091
Sam Maiera6e76d72022-02-11 21:43:502092 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152093 if not excluded_paths:
2094 return False
2095
Sam Maiera6e76d72022-02-11 21:43:502096 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312097 # Consistently use / as path separator to simplify the writing of regex
2098 # expressions.
2099 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502100 for item in excluded_paths:
2101 if input_api.re.match(item, local_path):
2102 return True
2103 return False
wnwenbdc444e2016-05-25 13:44:152104
Sam Maiera6e76d72022-02-11 21:43:502105 def IsIosObjcFile(affected_file):
2106 local_path = affected_file.LocalPath()
2107 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2108 '.h'):
2109 return False
2110 basename = input_api.os_path.basename(local_path)
2111 if 'ios' in basename.split('_'):
2112 return True
2113 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2114 if sep and 'ios' in local_path.split(sep):
2115 return True
2116 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542117
Daniel Chenga44a1bcd2022-03-15 20:00:152118 def CheckForMatch(affected_file, line_num: int, line: str,
2119 ban_rule: BanRule):
2120 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2121 return
2122
Sam Maiera6e76d72022-02-11 21:43:502123 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152124 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502125 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152126 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502127 errors.extend(problems)
2128 else:
2129 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152130
Sam Maiera6e76d72022-02-11 21:43:502131 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2132 for f in input_api.AffectedFiles(file_filter=file_filter):
2133 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152134 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2135 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412136
Clement Yan9b330cb2022-11-17 05:25:292137 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2138 for f in input_api.AffectedFiles(file_filter=file_filter):
2139 for line_num, line in f.ChangedContents():
2140 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2141 CheckForMatch(f, line_num, line, ban_rule)
2142
Sam Maiera6e76d72022-02-11 21:43:502143 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2144 for f in input_api.AffectedFiles(file_filter=file_filter):
2145 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152146 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2147 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592148
Sam Maiera6e76d72022-02-11 21:43:502149 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2150 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152151 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2152 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542153
Sam Maiera6e76d72022-02-11 21:43:502154 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2155 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2156 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152157 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2158 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052159
Sam Maiera6e76d72022-02-11 21:43:502160 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2161 for f in input_api.AffectedFiles(file_filter=file_filter):
2162 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152163 for ban_rule in _BANNED_CPP_FUNCTIONS:
2164 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592165
Daniel Cheng92c15e32022-03-16 17:48:222166 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2167 for f in input_api.AffectedFiles(file_filter=file_filter):
2168 for line_num, line in f.ChangedContents():
2169 for ban_rule in _BANNED_MOJOM_PATTERNS:
2170 CheckForMatch(f, line_num, line, ban_rule)
2171
2172
Sam Maiera6e76d72022-02-11 21:43:502173 result = []
2174 if (warnings):
2175 result.append(
2176 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2177 '\n'.join(warnings)))
2178 if (errors):
2179 result.append(
2180 output_api.PresubmitError('Banned functions were used.\n' +
2181 '\n'.join(errors)))
2182 return result
[email protected]127f18ec2012-06-16 05:05:592183
Allen Bauer84778682022-09-22 16:28:562184def CheckNoLayoutCallsInTests(input_api, output_api):
2185 """Make sure there are no explicit calls to View::Layout() in tests"""
2186 warnings = []
2187 ban_rule = BanRule(
2188 r'/(\.|->)Layout\(\);',
2189 (
2190 'Direct calls to View::Layout() are not allowed in tests. '
2191 'If the view must be laid out here, use RunScheduledLayout(view). It '
2192 'is found in //ui/views/test/views_test_utils.h. '
2193 'See http://crbug.com/1350521 for more details.',
2194 ),
2195 False,
2196 )
2197 file_filter = lambda f: input_api.re.search(
2198 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2199 for f in input_api.AffectedFiles(file_filter = file_filter):
2200 for line_num, line in f.ChangedContents():
2201 problems = _GetMessageForMatchingType(input_api, f,
2202 line_num, line,
2203 ban_rule)
2204 if problems:
2205 warnings.extend(problems)
2206 result = []
2207 if (warnings):
2208 result.append(
2209 output_api.PresubmitPromptWarning(
2210 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2211 return result
[email protected]127f18ec2012-06-16 05:05:592212
Michael Thiessen44457642020-02-06 00:24:152213def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502214 """Make sure that banned java imports are not used."""
2215 errors = []
Michael Thiessen44457642020-02-06 00:24:152216
Sam Maiera6e76d72022-02-11 21:43:502217 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2218 for f in input_api.AffectedFiles(file_filter=file_filter):
2219 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152220 for ban_rule in _BANNED_JAVA_IMPORTS:
2221 # Consider merging this into the above function. There is no
2222 # real difference anymore other than helping with a little
2223 # bit of boilerplate text. Doing so means things like
2224 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502225 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152226 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502227 if problems:
2228 errors.extend(problems)
2229 result = []
2230 if (errors):
2231 result.append(
2232 output_api.PresubmitError('Banned imports were used.\n' +
2233 '\n'.join(errors)))
2234 return result
Michael Thiessen44457642020-02-06 00:24:152235
2236
Saagar Sanghavifceeaae2020-08-12 16:40:362237def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502238 """Make sure that banned functions are not used."""
2239 files = []
2240 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2241 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2242 if not f.LocalPath().endswith('.h'):
2243 continue
Bruce Dawson4c4c2922022-05-02 18:07:332244 if f.LocalPath().endswith('com_imported_mstscax.h'):
2245 continue
Sam Maiera6e76d72022-02-11 21:43:502246 contents = input_api.ReadFile(f)
2247 if pattern.search(contents):
2248 files.append(f)
[email protected]6c063c62012-07-11 19:11:062249
Sam Maiera6e76d72022-02-11 21:43:502250 if files:
2251 return [
2252 output_api.PresubmitError(
2253 'Do not use #pragma once in header files.\n'
2254 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2255 files)
2256 ]
2257 return []
[email protected]6c063c62012-07-11 19:11:062258
[email protected]127f18ec2012-06-16 05:05:592259
Saagar Sanghavifceeaae2020-08-12 16:40:362260def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502261 """Checks to make sure we don't introduce use of foo ? true : false."""
2262 problems = []
2263 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2264 for f in input_api.AffectedFiles():
2265 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2266 continue
[email protected]e7479052012-09-19 00:26:122267
Sam Maiera6e76d72022-02-11 21:43:502268 for line_num, line in f.ChangedContents():
2269 if pattern.match(line):
2270 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:122271
Sam Maiera6e76d72022-02-11 21:43:502272 if not problems:
2273 return []
2274 return [
2275 output_api.PresubmitPromptWarning(
2276 'Please consider avoiding the "? true : false" pattern if possible.\n'
2277 + '\n'.join(problems))
2278 ]
[email protected]e7479052012-09-19 00:26:122279
2280
Saagar Sanghavifceeaae2020-08-12 16:40:362281def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502282 """Runs checkdeps on #include and import statements added in this
2283 change. Breaking - rules is an error, breaking ! rules is a
2284 warning.
2285 """
2286 # Return early if no relevant file types were modified.
2287 for f in input_api.AffectedFiles():
2288 path = f.LocalPath()
2289 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2290 or _IsJavaFile(input_api, path)):
2291 break
[email protected]55f9f382012-07-31 11:02:182292 else:
Sam Maiera6e76d72022-02-11 21:43:502293 return []
rhalavati08acd232017-04-03 07:23:282294
Sam Maiera6e76d72022-02-11 21:43:502295 import sys
2296 # We need to wait until we have an input_api object and use this
2297 # roundabout construct to import checkdeps because this file is
2298 # eval-ed and thus doesn't have __file__.
2299 original_sys_path = sys.path
2300 try:
2301 sys.path = sys.path + [
2302 input_api.os_path.join(input_api.PresubmitLocalPath(),
2303 'buildtools', 'checkdeps')
2304 ]
2305 import checkdeps
2306 from rules import Rule
2307 finally:
2308 # Restore sys.path to what it was before.
2309 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:182310
Sam Maiera6e76d72022-02-11 21:43:502311 added_includes = []
2312 added_imports = []
2313 added_java_imports = []
2314 for f in input_api.AffectedFiles():
2315 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2316 changed_lines = [line for _, line in f.ChangedContents()]
2317 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2318 elif _IsProtoFile(input_api, f.LocalPath()):
2319 changed_lines = [line for _, line in f.ChangedContents()]
2320 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2321 elif _IsJavaFile(input_api, f.LocalPath()):
2322 changed_lines = [line for _, line in f.ChangedContents()]
2323 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242324
Sam Maiera6e76d72022-02-11 21:43:502325 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2326
2327 error_descriptions = []
2328 warning_descriptions = []
2329 error_subjects = set()
2330 warning_subjects = set()
2331
2332 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2333 added_includes):
2334 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2335 description_with_path = '%s\n %s' % (path, rule_description)
2336 if rule_type == Rule.DISALLOW:
2337 error_descriptions.append(description_with_path)
2338 error_subjects.add("#includes")
2339 else:
2340 warning_descriptions.append(description_with_path)
2341 warning_subjects.add("#includes")
2342
2343 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2344 added_imports):
2345 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2346 description_with_path = '%s\n %s' % (path, rule_description)
2347 if rule_type == Rule.DISALLOW:
2348 error_descriptions.append(description_with_path)
2349 error_subjects.add("imports")
2350 else:
2351 warning_descriptions.append(description_with_path)
2352 warning_subjects.add("imports")
2353
2354 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2355 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2356 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2357 description_with_path = '%s\n %s' % (path, rule_description)
2358 if rule_type == Rule.DISALLOW:
2359 error_descriptions.append(description_with_path)
2360 error_subjects.add("imports")
2361 else:
2362 warning_descriptions.append(description_with_path)
2363 warning_subjects.add("imports")
2364
2365 results = []
2366 if error_descriptions:
2367 results.append(
2368 output_api.PresubmitError(
2369 'You added one or more %s that violate checkdeps rules.' %
2370 " and ".join(error_subjects), error_descriptions))
2371 if warning_descriptions:
2372 results.append(
2373 output_api.PresubmitPromptOrNotify(
2374 'You added one or more %s of files that are temporarily\n'
2375 'allowed but being removed. Can you avoid introducing the\n'
2376 '%s? See relevant DEPS file(s) for details and contacts.' %
2377 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2378 warning_descriptions))
2379 return results
[email protected]55f9f382012-07-31 11:02:182380
2381
Saagar Sanghavifceeaae2020-08-12 16:40:362382def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502383 """Check that all files have their permissions properly set."""
2384 if input_api.platform == 'win32':
2385 return []
2386 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2387 'tools', 'checkperms',
2388 'checkperms.py')
2389 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322390 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502391 input_api.change.RepositoryRoot()
2392 ]
2393 with input_api.CreateTemporaryFile() as file_list:
2394 for f in input_api.AffectedFiles():
2395 # checkperms.py file/directory arguments must be relative to the
2396 # repository.
2397 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2398 file_list.close()
2399 args += ['--file-list', file_list.name]
2400 try:
2401 input_api.subprocess.check_output(args)
2402 return []
2403 except input_api.subprocess.CalledProcessError as error:
2404 return [
2405 output_api.PresubmitError('checkperms.py failed:',
2406 long_text=error.output.decode(
2407 'utf-8', 'ignore'))
2408 ]
[email protected]fbcafe5a2012-08-08 15:31:222409
2410
Saagar Sanghavifceeaae2020-08-12 16:40:362411def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502412 """Makes sure we don't include ui/aura/window_property.h
2413 in header files.
2414 """
2415 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2416 errors = []
2417 for f in input_api.AffectedFiles():
2418 if not f.LocalPath().endswith('.h'):
2419 continue
2420 for line_num, line in f.ChangedContents():
2421 if pattern.match(line):
2422 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:492423
Sam Maiera6e76d72022-02-11 21:43:502424 results = []
2425 if errors:
2426 results.append(
2427 output_api.PresubmitError(
2428 'Header files should not include ui/aura/window_property.h',
2429 errors))
2430 return results
[email protected]c8278b32012-10-30 20:35:492431
2432
Omer Katzcc77ea92021-04-26 10:23:282433def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502434 """Makes sure we don't include any headers from
2435 third_party/blink/renderer/platform/heap/impl or
2436 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2437 third_party/blink/renderer/platform/heap
2438 """
2439 impl_pattern = input_api.re.compile(
2440 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2441 v8_wrapper_pattern = input_api.re.compile(
2442 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2443 )
Bruce Dawson40fece62022-09-16 19:58:312444 # Consistently use / as path separator to simplify the writing of regex
2445 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502446 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312447 r"^third_party/blink/renderer/platform/heap/.*",
2448 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502449 errors = []
Omer Katzcc77ea92021-04-26 10:23:282450
Sam Maiera6e76d72022-02-11 21:43:502451 for f in input_api.AffectedFiles(file_filter=file_filter):
2452 for line_num, line in f.ChangedContents():
2453 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2454 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282455
Sam Maiera6e76d72022-02-11 21:43:502456 results = []
2457 if errors:
2458 results.append(
2459 output_api.PresubmitError(
2460 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2461 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2462 'relevant counterparts from third_party/blink/renderer/platform/heap',
2463 errors))
2464 return results
Omer Katzcc77ea92021-04-26 10:23:282465
2466
[email protected]70ca77752012-11-20 03:45:032467def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502468 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2469 errors = []
2470 for line_num, line in f.ChangedContents():
2471 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2472 # First-level headers in markdown look a lot like version control
2473 # conflict markers. http://daringfireball.net/projects/markdown/basics
2474 continue
2475 if pattern.match(line):
2476 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2477 return errors
[email protected]70ca77752012-11-20 03:45:032478
2479
Saagar Sanghavifceeaae2020-08-12 16:40:362480def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502481 """Usually this is not intentional and will cause a compile failure."""
2482 errors = []
2483 for f in input_api.AffectedFiles():
2484 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032485
Sam Maiera6e76d72022-02-11 21:43:502486 results = []
2487 if errors:
2488 results.append(
2489 output_api.PresubmitError(
2490 'Version control conflict markers found, please resolve.',
2491 errors))
2492 return results
[email protected]70ca77752012-11-20 03:45:032493
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202494
Saagar Sanghavifceeaae2020-08-12 16:40:362495def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502496 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2497 errors = []
2498 for f in input_api.AffectedFiles():
2499 for line_num, line in f.ChangedContents():
2500 if pattern.search(line):
2501 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162502
Sam Maiera6e76d72022-02-11 21:43:502503 results = []
2504 if errors:
2505 results.append(
2506 output_api.PresubmitPromptWarning(
2507 'Found Google support URL addressed by answer number. Please replace '
2508 'with a p= identifier instead. See crbug.com/679462\n',
2509 errors))
2510 return results
estadee17314a02017-01-12 16:22:162511
[email protected]70ca77752012-11-20 03:45:032512
Saagar Sanghavifceeaae2020-08-12 16:40:362513def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502514 def FilterFile(affected_file):
2515 """Filter function for use with input_api.AffectedSourceFiles,
2516 below. This filters out everything except non-test files from
2517 top-level directories that generally speaking should not hard-code
2518 service URLs (e.g. src/android_webview/, src/content/ and others).
2519 """
2520 return input_api.FilterSourceFile(
2521 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312522 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502523 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2524 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442525
Sam Maiera6e76d72022-02-11 21:43:502526 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2527 '\.(com|net)[^"]*"')
2528 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2529 pattern = input_api.re.compile(base_pattern)
2530 problems = [] # items are (filename, line_number, line)
2531 for f in input_api.AffectedSourceFiles(FilterFile):
2532 for line_num, line in f.ChangedContents():
2533 if not comment_pattern.search(line) and pattern.search(line):
2534 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442535
Sam Maiera6e76d72022-02-11 21:43:502536 if problems:
2537 return [
2538 output_api.PresubmitPromptOrNotify(
2539 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2540 'Are you sure this is correct?', [
2541 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2542 for problem in problems
2543 ])
2544 ]
2545 else:
2546 return []
[email protected]06e6d0ff2012-12-11 01:36:442547
2548
Saagar Sanghavifceeaae2020-08-12 16:40:362549def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502550 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292551
Sam Maiera6e76d72022-02-11 21:43:502552 def FileFilter(affected_file):
2553 """Includes directories known to be Chrome OS only."""
2554 return input_api.FilterSourceFile(
2555 affected_file,
2556 files_to_check=(
2557 '^ash/',
2558 '^chromeos/', # Top-level src/chromeos.
2559 '.*/chromeos/', # Any path component.
2560 '^components/arc',
2561 '^components/exo'),
2562 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292563
Sam Maiera6e76d72022-02-11 21:43:502564 prefs = []
2565 priority_prefs = []
2566 for f in input_api.AffectedFiles(file_filter=FileFilter):
2567 for line_num, line in f.ChangedContents():
2568 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2569 line):
2570 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2571 prefs.append(' %s' % line)
2572 if input_api.re.search(
2573 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2574 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2575 priority_prefs.append(' %s' % line)
2576
2577 results = []
2578 if (prefs):
2579 results.append(
2580 output_api.PresubmitPromptWarning(
2581 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2582 'by browser sync settings. If these prefs should be controlled by OS '
2583 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2584 '\n'.join(prefs)))
2585 if (priority_prefs):
2586 results.append(
2587 output_api.PresubmitPromptWarning(
2588 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2589 'controlled by browser sync settings. If these prefs should be '
2590 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2591 'instead.\n' + '\n'.join(prefs)))
2592 return results
James Cook6b6597c2019-11-06 22:05:292593
2594
Saagar Sanghavifceeaae2020-08-12 16:40:362595def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502596 """Makes sure there are no abbreviations in the name of PNG files.
2597 The native_client_sdk directory is excluded because it has auto-generated PNG
2598 files for documentation.
2599 """
2600 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:172601 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:312602 files_to_skip = [r'^native_client_sdk/',
2603 r'^services/test/',
2604 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182605 ]
Sam Maiera6e76d72022-02-11 21:43:502606 file_filter = lambda f: input_api.FilterSourceFile(
2607 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:172608 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:502609 for f in input_api.AffectedFiles(include_deletes=False,
2610 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:172611 file_name = input_api.os_path.split(f.LocalPath())[1]
2612 if abbreviation.search(file_name):
2613 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272614
Sam Maiera6e76d72022-02-11 21:43:502615 results = []
2616 if errors:
2617 results.append(
2618 output_api.PresubmitError(
2619 'The name of PNG files should not have abbreviations. \n'
2620 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2621 'Contact [email protected] if you have questions.', errors))
2622 return results
[email protected]d2530012013-01-25 16:39:272623
Evan Stade7cd4a2c2022-08-04 23:37:252624def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2625 """Heuristically identifies product icons based on their file name and reminds
2626 contributors not to add them to the Chromium repository.
2627 """
2628 errors = []
2629 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2630 file_filter = lambda f: input_api.FilterSourceFile(
2631 f, files_to_check=files_to_check)
2632 for f in input_api.AffectedFiles(include_deletes=False,
2633 file_filter=file_filter):
2634 errors.append(' %s' % f.LocalPath())
2635
2636 results = []
2637 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082638 # Give warnings instead of errors on presubmit --all and presubmit
2639 # --files.
2640 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2641 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252642 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082643 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252644 'Trademarked images should not be added to the public repo. '
2645 'See crbug.com/944754', errors))
2646 return results
2647
[email protected]d2530012013-01-25 16:39:272648
Daniel Cheng4dcdb6b2017-04-13 08:30:172649def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502650 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172651
Sam Maiera6e76d72022-02-11 21:43:502652 Args:
2653 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2654 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172655 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502656 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172657 if rule.startswith('+') or rule.startswith('!')
2658 ])
Sam Maiera6e76d72022-02-11 21:43:502659 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2660 add_rules.update([
2661 rule[1:] for rule in rules
2662 if rule.startswith('+') or rule.startswith('!')
2663 ])
2664 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172665
2666
2667def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502668 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172669
Sam Maiera6e76d72022-02-11 21:43:502670 # Stubs for handling special syntax in the root DEPS file.
2671 class _VarImpl:
2672 def __init__(self, local_scope):
2673 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172674
Sam Maiera6e76d72022-02-11 21:43:502675 def Lookup(self, var_name):
2676 """Implements the Var syntax."""
2677 try:
2678 return self._local_scope['vars'][var_name]
2679 except KeyError:
2680 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172681
Sam Maiera6e76d72022-02-11 21:43:502682 local_scope = {}
2683 global_scope = {
2684 'Var': _VarImpl(local_scope).Lookup,
2685 'Str': str,
2686 }
Dirk Pranke1b9e06382021-05-14 01:16:222687
Sam Maiera6e76d72022-02-11 21:43:502688 exec(contents, global_scope, local_scope)
2689 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172690
2691
2692def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502693 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2694 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412695
Sam Maiera6e76d72022-02-11 21:43:502696 For a directory (rather than a specific filename) we fake a path to
2697 a specific filename by adding /DEPS. This is chosen as a file that
2698 will seldom or never be subject to per-file include_rules.
2699 """
2700 # We ignore deps entries on auto-generated directories.
2701 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082702
Sam Maiera6e76d72022-02-11 21:43:502703 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2704 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172705
Sam Maiera6e76d72022-02-11 21:43:502706 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172707
Sam Maiera6e76d72022-02-11 21:43:502708 results = set()
2709 for added_dep in added_deps:
2710 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2711 continue
2712 # Assume that a rule that ends in .h is a rule for a specific file.
2713 if added_dep.endswith('.h'):
2714 results.add(added_dep)
2715 else:
2716 results.add(os_path.join(added_dep, 'DEPS'))
2717 return results
[email protected]f32e2d1e2013-07-26 21:39:082718
2719
Saagar Sanghavifceeaae2020-08-12 16:40:362720def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502721 """When a dependency prefixed with + is added to a DEPS file, we
2722 want to make sure that the change is reviewed by an OWNER of the
2723 target file or directory, to avoid layering violations from being
2724 introduced. This check verifies that this happens.
2725 """
2726 # We rely on Gerrit's code-owners to check approvals.
2727 # input_api.gerrit is always set for Chromium, but other projects
2728 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102729 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502730 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302731 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502732 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302733 try:
2734 if (input_api.change.issue and
2735 input_api.gerrit.IsOwnersOverrideApproved(
2736 input_api.change.issue)):
2737 # Skip OWNERS check when Owners-Override label is approved. This is
2738 # intended for global owners, trusted bots, and on-call sheriffs.
2739 # Review is still required for these changes.
2740 return []
2741 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:242742 return [output_api.PresubmitPromptWarning(
2743 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232744
Sam Maiera6e76d72022-02-11 21:43:502745 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242746
Bruce Dawson40fece62022-09-16 19:58:312747 # Consistently use / as path separator to simplify the writing of regex
2748 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502749 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312750 r"^third_party/blink/.*",
2751 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502752 for f in input_api.AffectedFiles(include_deletes=False,
2753 file_filter=file_filter):
2754 filename = input_api.os_path.basename(f.LocalPath())
2755 if filename == 'DEPS':
2756 virtual_depended_on_files.update(
2757 _CalculateAddedDeps(input_api.os_path,
2758 '\n'.join(f.OldContents()),
2759 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552760
Sam Maiera6e76d72022-02-11 21:43:502761 if not virtual_depended_on_files:
2762 return []
[email protected]e871964c2013-05-13 14:14:552763
Sam Maiera6e76d72022-02-11 21:43:502764 if input_api.is_committing:
2765 if input_api.tbr:
2766 return [
2767 output_api.PresubmitNotifyResult(
2768 '--tbr was specified, skipping OWNERS check for DEPS additions'
2769 )
2770 ]
Daniel Cheng3008dc12022-05-13 04:02:112771 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2772 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502773 if input_api.dry_run:
2774 return [
2775 output_api.PresubmitNotifyResult(
2776 'This is a dry run, skipping OWNERS check for DEPS additions'
2777 )
2778 ]
2779 if not input_api.change.issue:
2780 return [
2781 output_api.PresubmitError(
2782 "DEPS approval by OWNERS check failed: this change has "
2783 "no change number, so we can't check it for approvals.")
2784 ]
2785 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412786 else:
Sam Maiera6e76d72022-02-11 21:43:502787 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552788
Sam Maiera6e76d72022-02-11 21:43:502789 owner_email, reviewers = (
2790 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2791 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552792
Sam Maiera6e76d72022-02-11 21:43:502793 owner_email = owner_email or input_api.change.author_email
2794
2795 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2796 virtual_depended_on_files, reviewers.union([owner_email]), [])
2797 missing_files = [
2798 f for f in virtual_depended_on_files
2799 if approval_status[f] != input_api.owners_client.APPROVED
2800 ]
2801
2802 # We strip the /DEPS part that was added by
2803 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2804 # directory.
2805 def StripDeps(path):
2806 start_deps = path.rfind('/DEPS')
2807 if start_deps != -1:
2808 return path[:start_deps]
2809 else:
2810 return path
2811
2812 unapproved_dependencies = [
2813 "'+%s'," % StripDeps(path) for path in missing_files
2814 ]
2815
2816 if unapproved_dependencies:
2817 output_list = [
2818 output(
2819 'You need LGTM from owners of depends-on paths in DEPS that were '
2820 'modified in this CL:\n %s' %
2821 '\n '.join(sorted(unapproved_dependencies)))
2822 ]
2823 suggested_owners = input_api.owners_client.SuggestOwners(
2824 missing_files, exclude=[owner_email])
2825 output_list.append(
2826 output('Suggested missing target path OWNERS:\n %s' %
2827 '\n '.join(suggested_owners or [])))
2828 return output_list
2829
2830 return []
[email protected]e871964c2013-05-13 14:14:552831
2832
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492833# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362834def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502835 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2836 files_to_skip = (
2837 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2838 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:012839 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312840 r"^base/logging\.h$",
2841 r"^base/logging\.cc$",
2842 r"^base/task/thread_pool/task_tracker\.cc$",
2843 r"^chrome/app/chrome_main_delegate\.cc$",
2844 r"^chrome/browser/chrome_browser_main\.cc$",
2845 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
2846 r"^chrome/browser/browser_switcher/bho/.*",
2847 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
2848 r"^chrome/chrome_cleaner/.*",
2849 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
2850 r"^chrome/installer/setup/.*",
2851 r"^chromecast/",
2852 r"^components/browser_watcher/dump_stability_report_main_win\.cc$",
2853 r"^components/media_control/renderer/media_playback_options\.cc$",
2854 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:502855 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312856 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:502857 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:312858 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:502859 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312860 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
2861 r"^courgette/courgette_minimal_tool\.cc$",
2862 r"^courgette/courgette_tool\.cc$",
2863 r"^extensions/renderer/logging_native_handler\.cc$",
2864 r"^fuchsia_web/common/init_logging\.cc$",
2865 r"^fuchsia_web/runners/common/web_component\.cc$",
2866 r"^fuchsia_web/shell/.*_shell\.cc$",
2867 r"^headless/app/headless_shell\.cc$",
2868 r"^ipc/ipc_logging\.cc$",
2869 r"^native_client_sdk/",
2870 r"^remoting/base/logging\.h$",
2871 r"^remoting/host/.*",
2872 r"^sandbox/linux/.*",
2873 r"^storage/browser/file_system/dump_file_system\.cc$",
2874 r"^tools/",
2875 r"^ui/base/resource/data_pack\.cc$",
2876 r"^ui/aura/bench/bench_main\.cc$",
2877 r"^ui/ozone/platform/cast/",
2878 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:502879 r"xwmstartupcheck\.cc$"))
2880 source_file_filter = lambda x: input_api.FilterSourceFile(
2881 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402882
Sam Maiera6e76d72022-02-11 21:43:502883 log_info = set([])
2884 printf = set([])
[email protected]85218562013-11-22 07:41:402885
Sam Maiera6e76d72022-02-11 21:43:502886 for f in input_api.AffectedSourceFiles(source_file_filter):
2887 for _, line in f.ChangedContents():
2888 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2889 log_info.add(f.LocalPath())
2890 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2891 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372892
Sam Maiera6e76d72022-02-11 21:43:502893 if input_api.re.search(r"\bprintf\(", line):
2894 printf.add(f.LocalPath())
2895 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2896 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402897
Sam Maiera6e76d72022-02-11 21:43:502898 if log_info:
2899 return [
2900 output_api.PresubmitError(
2901 'These files spam the console log with LOG(INFO):',
2902 items=log_info)
2903 ]
2904 if printf:
2905 return [
2906 output_api.PresubmitError(
2907 'These files spam the console log with printf/fprintf:',
2908 items=printf)
2909 ]
2910 return []
[email protected]85218562013-11-22 07:41:402911
2912
Saagar Sanghavifceeaae2020-08-12 16:40:362913def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502914 """These types are all expected to hold locks while in scope and
2915 so should never be anonymous (which causes them to be immediately
2916 destroyed)."""
2917 they_who_must_be_named = [
2918 'base::AutoLock',
2919 'base::AutoReset',
2920 'base::AutoUnlock',
2921 'SkAutoAlphaRestore',
2922 'SkAutoBitmapShaderInstall',
2923 'SkAutoBlitterChoose',
2924 'SkAutoBounderCommit',
2925 'SkAutoCallProc',
2926 'SkAutoCanvasRestore',
2927 'SkAutoCommentBlock',
2928 'SkAutoDescriptor',
2929 'SkAutoDisableDirectionCheck',
2930 'SkAutoDisableOvalCheck',
2931 'SkAutoFree',
2932 'SkAutoGlyphCache',
2933 'SkAutoHDC',
2934 'SkAutoLockColors',
2935 'SkAutoLockPixels',
2936 'SkAutoMalloc',
2937 'SkAutoMaskFreeImage',
2938 'SkAutoMutexAcquire',
2939 'SkAutoPathBoundsUpdate',
2940 'SkAutoPDFRelease',
2941 'SkAutoRasterClipValidate',
2942 'SkAutoRef',
2943 'SkAutoTime',
2944 'SkAutoTrace',
2945 'SkAutoUnref',
2946 ]
2947 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2948 # bad: base::AutoLock(lock.get());
2949 # not bad: base::AutoLock lock(lock.get());
2950 bad_pattern = input_api.re.compile(anonymous)
2951 # good: new base::AutoLock(lock.get())
2952 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2953 errors = []
[email protected]49aa76a2013-12-04 06:59:162954
Sam Maiera6e76d72022-02-11 21:43:502955 for f in input_api.AffectedFiles():
2956 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2957 continue
2958 for linenum, line in f.ChangedContents():
2959 if bad_pattern.search(line) and not good_pattern.search(line):
2960 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162961
Sam Maiera6e76d72022-02-11 21:43:502962 if errors:
2963 return [
2964 output_api.PresubmitError(
2965 'These lines create anonymous variables that need to be named:',
2966 items=errors)
2967 ]
2968 return []
[email protected]49aa76a2013-12-04 06:59:162969
2970
Saagar Sanghavifceeaae2020-08-12 16:40:362971def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502972 # Returns whether |template_str| is of the form <T, U...> for some types T
2973 # and U. Assumes that |template_str| is already in the form <...>.
2974 def HasMoreThanOneArg(template_str):
2975 # Level of <...> nesting.
2976 nesting = 0
2977 for c in template_str:
2978 if c == '<':
2979 nesting += 1
2980 elif c == '>':
2981 nesting -= 1
2982 elif c == ',' and nesting == 1:
2983 return True
2984 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532985
Sam Maiera6e76d72022-02-11 21:43:502986 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2987 sources = lambda affected_file: input_api.FilterSourceFile(
2988 affected_file,
2989 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2990 DEFAULT_FILES_TO_SKIP),
2991 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552992
Sam Maiera6e76d72022-02-11 21:43:502993 # Pattern to capture a single "<...>" block of template arguments. It can
2994 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2995 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2996 # latter would likely require counting that < and > match, which is not
2997 # expressible in regular languages. Should the need arise, one can introduce
2998 # limited counting (matching up to a total number of nesting depth), which
2999 # should cover all practical cases for already a low nesting limit.
3000 template_arg_pattern = (
3001 r'<[^>]*' # Opening block of <.
3002 r'>([^<]*>)?') # Closing block of >.
3003 # Prefix expressing that whatever follows is not already inside a <...>
3004 # block.
3005 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3006 null_construct_pattern = input_api.re.compile(
3007 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3008 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553009
Sam Maiera6e76d72022-02-11 21:43:503010 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3011 template_arg_no_array_pattern = (
3012 r'<[^>]*[^]]' # Opening block of <.
3013 r'>([^(<]*[^]]>)?') # Closing block of >.
3014 # Prefix saying that what follows is the start of an expression.
3015 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3016 # Suffix saying that what follows are call parentheses with a non-empty list
3017 # of arguments.
3018 nonempty_arg_list_pattern = r'\(([^)]|$)'
3019 # Put the template argument into a capture group for deeper examination later.
3020 return_construct_pattern = input_api.re.compile(
3021 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3022 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553023
Sam Maiera6e76d72022-02-11 21:43:503024 problems_constructor = []
3025 problems_nullptr = []
3026 for f in input_api.AffectedSourceFiles(sources):
3027 for line_number, line in f.ChangedContents():
3028 # Disallow:
3029 # return std::unique_ptr<T>(foo);
3030 # bar = std::unique_ptr<T>(foo);
3031 # But allow:
3032 # return std::unique_ptr<T[]>(foo);
3033 # bar = std::unique_ptr<T[]>(foo);
3034 # And also allow cases when the second template argument is present. Those
3035 # cases cannot be handled by std::make_unique:
3036 # return std::unique_ptr<T, U>(foo);
3037 # bar = std::unique_ptr<T, U>(foo);
3038 local_path = f.LocalPath()
3039 return_construct_result = return_construct_pattern.search(line)
3040 if return_construct_result and not HasMoreThanOneArg(
3041 return_construct_result.group('template_arg')):
3042 problems_constructor.append(
3043 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3044 # Disallow:
3045 # std::unique_ptr<T>()
3046 if null_construct_pattern.search(line):
3047 problems_nullptr.append(
3048 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053049
Sam Maiera6e76d72022-02-11 21:43:503050 errors = []
3051 if problems_nullptr:
3052 errors.append(
3053 output_api.PresubmitPromptWarning(
3054 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3055 problems_nullptr))
3056 if problems_constructor:
3057 errors.append(
3058 output_api.PresubmitError(
3059 'The following files use explicit std::unique_ptr constructor. '
3060 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3061 'std::make_unique is not an option.', problems_constructor))
3062 return errors
Peter Kasting4844e46e2018-02-23 07:27:103063
3064
Saagar Sanghavifceeaae2020-08-12 16:40:363065def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503066 """Checks if any new user action has been added."""
3067 if any('actions.xml' == input_api.os_path.basename(f)
3068 for f in input_api.LocalPaths()):
3069 # If actions.xml is already included in the changelist, the PRESUBMIT
3070 # for actions.xml will do a more complete presubmit check.
3071 return []
3072
3073 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3074 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3075 input_api.DEFAULT_FILES_TO_SKIP)
3076 file_filter = lambda f: input_api.FilterSourceFile(
3077 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3078
3079 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3080 current_actions = None
3081 for f in input_api.AffectedFiles(file_filter=file_filter):
3082 for line_num, line in f.ChangedContents():
3083 match = input_api.re.search(action_re, line)
3084 if match:
3085 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3086 # loaded only once.
3087 if not current_actions:
3088 with open(
3089 'tools/metrics/actions/actions.xml') as actions_f:
3090 current_actions = actions_f.read()
3091 # Search for the matched user action name in |current_actions|.
3092 for action_name in match.groups():
3093 action = 'name="{0}"'.format(action_name)
3094 if action not in current_actions:
3095 return [
3096 output_api.PresubmitPromptWarning(
3097 'File %s line %d: %s is missing in '
3098 'tools/metrics/actions/actions.xml. Please run '
3099 'tools/metrics/actions/extract_actions.py to update.'
3100 % (f.LocalPath(), line_num, action_name))
3101 ]
[email protected]999261d2014-03-03 20:08:083102 return []
3103
[email protected]999261d2014-03-03 20:08:083104
Daniel Cheng13ca61a882017-08-25 15:11:253105def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503106 import sys
3107 sys.path = sys.path + [
3108 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3109 'json_comment_eater')
3110 ]
3111 import json_comment_eater
3112 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:253113
3114
[email protected]99171a92014-06-03 08:44:473115def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:173116 try:
Sam Maiera6e76d72022-02-11 21:43:503117 contents = input_api.ReadFile(filename)
3118 if eat_comments:
3119 json_comment_eater = _ImportJSONCommentEater(input_api)
3120 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:173121
Sam Maiera6e76d72022-02-11 21:43:503122 input_api.json.loads(contents)
3123 except ValueError as e:
3124 return e
Andrew Grieve4deedb12022-02-03 21:34:503125 return None
3126
3127
Sam Maiera6e76d72022-02-11 21:43:503128def _GetIDLParseError(input_api, filename):
3129 try:
3130 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:283131 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:343132 if not char.isascii():
3133 return (
3134 'Non-ascii character "%s" (ord %d) found at offset %d.' %
3135 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:503136 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
3137 'tools', 'json_schema_compiler',
3138 'idl_schema.py')
3139 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:283140 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:503141 stdin=input_api.subprocess.PIPE,
3142 stdout=input_api.subprocess.PIPE,
3143 stderr=input_api.subprocess.PIPE,
3144 universal_newlines=True)
3145 (_, error) = process.communicate(input=contents)
3146 return error or None
3147 except ValueError as e:
3148 return e
agrievef32bcc72016-04-04 14:57:403149
agrievef32bcc72016-04-04 14:57:403150
Sam Maiera6e76d72022-02-11 21:43:503151def CheckParseErrors(input_api, output_api):
3152 """Check that IDL and JSON files do not contain syntax errors."""
3153 actions = {
3154 '.idl': _GetIDLParseError,
3155 '.json': _GetJSONParseError,
3156 }
3157 # Most JSON files are preprocessed and support comments, but these do not.
3158 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313159 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:503160 ]
3161 # Only run IDL checker on files in these directories.
3162 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313163 r'^chrome/common/extensions/api/',
3164 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:503165 ]
agrievef32bcc72016-04-04 14:57:403166
Sam Maiera6e76d72022-02-11 21:43:503167 def get_action(affected_file):
3168 filename = affected_file.LocalPath()
3169 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:403170
Sam Maiera6e76d72022-02-11 21:43:503171 def FilterFile(affected_file):
3172 action = get_action(affected_file)
3173 if not action:
3174 return False
3175 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403176
Sam Maiera6e76d72022-02-11 21:43:503177 if _MatchesFile(input_api,
3178 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3179 return False
3180
3181 if (action == _GetIDLParseError
3182 and not _MatchesFile(input_api, idl_included_patterns, path)):
3183 return False
3184 return True
3185
3186 results = []
3187 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3188 include_deletes=False):
3189 action = get_action(affected_file)
3190 kwargs = {}
3191 if (action == _GetJSONParseError
3192 and _MatchesFile(input_api, json_no_comments_patterns,
3193 affected_file.LocalPath())):
3194 kwargs['eat_comments'] = False
3195 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3196 **kwargs)
3197 if parse_error:
3198 results.append(
3199 output_api.PresubmitError(
3200 '%s could not be parsed: %s' %
3201 (affected_file.LocalPath(), parse_error)))
3202 return results
3203
3204
3205def CheckJavaStyle(input_api, output_api):
3206 """Runs checkstyle on changed java files and returns errors if any exist."""
3207
3208 # Return early if no java files were modified.
3209 if not any(
3210 _IsJavaFile(input_api, f.LocalPath())
3211 for f in input_api.AffectedFiles()):
3212 return []
3213
3214 import sys
3215 original_sys_path = sys.path
3216 try:
3217 sys.path = sys.path + [
3218 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3219 'android', 'checkstyle')
3220 ]
3221 import checkstyle
3222 finally:
3223 # Restore sys.path to what it was before.
3224 sys.path = original_sys_path
3225
Andrew Grieve4f88e3ca2022-11-22 19:09:203226 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:503227 input_api,
3228 output_api,
Sam Maiera6e76d72022-02-11 21:43:503229 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3230
3231
3232def CheckPythonDevilInit(input_api, output_api):
3233 """Checks to make sure devil is initialized correctly in python scripts."""
3234 script_common_initialize_pattern = input_api.re.compile(
3235 r'script_common\.InitializeEnvironment\(')
3236 devil_env_config_initialize = input_api.re.compile(
3237 r'devil_env\.config\.Initialize\(')
3238
3239 errors = []
3240
3241 sources = lambda affected_file: input_api.FilterSourceFile(
3242 affected_file,
3243 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313244 r'^build/android/devil_chromium\.py',
3245 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503246 )),
3247 files_to_check=[r'.*\.py$'])
3248
3249 for f in input_api.AffectedSourceFiles(sources):
3250 for line_num, line in f.ChangedContents():
3251 if (script_common_initialize_pattern.search(line)
3252 or devil_env_config_initialize.search(line)):
3253 errors.append("%s:%d" % (f.LocalPath(), line_num))
3254
3255 results = []
3256
3257 if errors:
3258 results.append(
3259 output_api.PresubmitError(
3260 'Devil initialization should always be done using '
3261 'devil_chromium.Initialize() in the chromium project, to use better '
3262 'defaults for dependencies (ex. up-to-date version of adb).',
3263 errors))
3264
3265 return results
3266
3267
3268def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313269 # Consistently use / as path separator to simplify the writing of regex
3270 # expressions.
3271 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503272 for pattern in patterns:
3273 if input_api.re.search(pattern, path):
3274 return True
3275 return False
3276
3277
Daniel Chenga37c03db2022-05-12 17:20:343278def _ChangeHasSecurityReviewer(input_api, owners_file):
3279 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503280
Daniel Chenga37c03db2022-05-12 17:20:343281 Args:
3282 input_api: The presubmit input API.
3283 owners_file: OWNERS file with required reviewers. Typically, this is
3284 something like ipc/SECURITY_OWNERS.
3285
3286 Note: if the presubmit is running for commit rather than for upload, this
3287 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503288 """
Daniel Chengd88244472022-05-16 09:08:473289 # Owners-Override should bypass all additional OWNERS enforcement checks.
3290 # A CR+1 vote will still be required to land this change.
3291 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3292 input_api.change.issue)):
3293 return True
3294
Daniel Chenga37c03db2022-05-12 17:20:343295 owner_email, reviewers = (
3296 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113297 input_api,
3298 None,
3299 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503300
Daniel Chenga37c03db2022-05-12 17:20:343301 security_owners = input_api.owners_client.ListOwners(owners_file)
3302 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503303
Daniel Chenga37c03db2022-05-12 17:20:343304
3305@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253306class _SecurityProblemWithItems:
3307 problem: str
3308 items: Sequence[str]
3309
3310
3311@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343312class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253313 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343314 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253315 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343316
3317
3318def _FindMissingSecurityOwners(input_api,
3319 output_api,
3320 file_patterns: Sequence[str],
3321 excluded_patterns: Sequence[str],
3322 required_owners_file: str,
3323 custom_rule_function: Optional[Callable] = None
3324 ) -> _MissingSecurityOwnersResult:
3325 """Find OWNERS files missing per-file rules for security-sensitive files.
3326
3327 Args:
3328 input_api: the PRESUBMIT input API object.
3329 output_api: the PRESUBMIT output API object.
3330 file_patterns: basename patterns that require a corresponding per-file
3331 security restriction.
3332 excluded_patterns: path patterns that should be exempted from
3333 requiring a security restriction.
3334 required_owners_file: path to the required OWNERS file, e.g.
3335 ipc/SECURITY_OWNERS
3336 cc_alias: If not None, email that will be CCed automatically if the
3337 change contains security-sensitive files, as determined by
3338 `file_patterns` and `excluded_patterns`.
3339 custom_rule_function: If not None, will be called with `input_api` and
3340 the current file under consideration. Returning True will add an
3341 exact match per-file rule check for the current file.
3342 """
3343
3344 # `to_check` is a mapping of an OWNERS file path to Patterns.
3345 #
3346 # Patterns is a dictionary mapping glob patterns (suitable for use in
3347 # per-file rules) to a PatternEntry.
3348 #
Sam Maiera6e76d72022-02-11 21:43:503349 # PatternEntry is a dictionary with two keys:
3350 # - 'files': the files that are matched by this pattern
3351 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343352 #
Sam Maiera6e76d72022-02-11 21:43:503353 # For example, if we expect OWNERS file to contain rules for *.mojom and
3354 # *_struct_traits*.*, Patterns might look like this:
3355 # {
3356 # '*.mojom': {
3357 # 'files': ...,
3358 # 'rules': [
3359 # 'per-file *.mojom=set noparent',
3360 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3361 # ],
3362 # },
3363 # '*_struct_traits*.*': {
3364 # 'files': ...,
3365 # 'rules': [
3366 # 'per-file *_struct_traits*.*=set noparent',
3367 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3368 # ],
3369 # },
3370 # }
3371 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343372 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503373
Daniel Chenga37c03db2022-05-12 17:20:343374 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503375 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473376 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503377 if owners_file not in to_check:
3378 to_check[owners_file] = {}
3379 if pattern not in to_check[owners_file]:
3380 to_check[owners_file][pattern] = {
3381 'files': [],
3382 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343383 f'per-file {pattern}=set noparent',
3384 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503385 ]
3386 }
Daniel Chenged57a162022-05-25 02:56:343387 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343388 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503389
Daniel Chenga37c03db2022-05-12 17:20:343390 # Only enforce security OWNERS rules for a directory if that directory has a
3391 # file that matches `file_patterns`. For example, if a directory only
3392 # contains *.mojom files and no *_messages*.h files, the check should only
3393 # ensure that rules for *.mojom files are present.
3394 for file in input_api.AffectedFiles(include_deletes=False):
3395 file_basename = input_api.os_path.basename(file.LocalPath())
3396 if custom_rule_function is not None and custom_rule_function(
3397 input_api, file):
3398 AddPatternToCheck(file, file_basename)
3399 continue
Sam Maiera6e76d72022-02-11 21:43:503400
Daniel Chenga37c03db2022-05-12 17:20:343401 if any(
3402 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3403 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503404 continue
3405
3406 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343407 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3408 # file's basename.
3409 if input_api.fnmatch.fnmatch(file_basename, pattern):
3410 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503411 break
3412
Daniel Chenga37c03db2022-05-12 17:20:343413 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253414
3415 # Check if any newly added lines in OWNERS files intersect with required
3416 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3417 # This is a hack, but is needed because the OWNERS check (by design) ignores
3418 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3419 # OWNER and have that newly-added OWNER self-approve their own addition.
3420 newly_covered_files = []
3421 for file in input_api.AffectedFiles(include_deletes=False):
3422 if not file.LocalPath() in to_check:
3423 continue
3424 for _, line in file.ChangedContents():
3425 for _, entry in to_check[file.LocalPath()].items():
3426 if line in entry['rules']:
3427 newly_covered_files.extend(entry['files'])
3428
3429 missing_reviewer_problems = None
3430 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343431 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253432 missing_reviewer_problems = _SecurityProblemWithItems(
3433 f'Review from an owner in {required_owners_file} is required for '
3434 'the following newly-added files:',
3435 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503436
3437 # Go through the OWNERS files to check, filtering out rules that are already
3438 # present in that OWNERS file.
3439 for owners_file, patterns in to_check.items():
3440 try:
Daniel Cheng171dad8d2022-05-21 00:40:253441 lines = set(
3442 input_api.ReadFile(
3443 input_api.os_path.join(input_api.change.RepositoryRoot(),
3444 owners_file)).splitlines())
3445 for entry in patterns.values():
3446 entry['rules'] = [
3447 rule for rule in entry['rules'] if rule not in lines
3448 ]
Sam Maiera6e76d72022-02-11 21:43:503449 except IOError:
3450 # No OWNERS file, so all the rules are definitely missing.
3451 continue
3452
3453 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253454 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343455
Sam Maiera6e76d72022-02-11 21:43:503456 for owners_file, patterns in to_check.items():
3457 missing_lines = []
3458 files = []
3459 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343460 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503461 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503462 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253463 joined_missing_lines = '\n'.join(line for line in missing_lines)
3464 owners_file_problems.append(
3465 _SecurityProblemWithItems(
3466 'Found missing OWNERS lines for security-sensitive files. '
3467 f'Please add the following lines to {owners_file}:\n'
3468 f'{joined_missing_lines}\n\nTo ensure security review for:',
3469 files))
Daniel Chenga37c03db2022-05-12 17:20:343470
Daniel Cheng171dad8d2022-05-21 00:40:253471 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343472 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253473 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343474
3475
3476def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3477 # Whether or not a file affects IPC is (mostly) determined by a simple list
3478 # of filename patterns.
3479 file_patterns = [
3480 # Legacy IPC:
3481 '*_messages.cc',
3482 '*_messages*.h',
3483 '*_param_traits*.*',
3484 # Mojo IPC:
3485 '*.mojom',
3486 '*_mojom_traits*.*',
3487 '*_type_converter*.*',
3488 # Android native IPC:
3489 '*.aidl',
3490 ]
3491
Daniel Chenga37c03db2022-05-12 17:20:343492 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463493 # These third_party directories do not contain IPCs, but contain files
3494 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343495 'third_party/crashpad/*',
3496 'third_party/blink/renderer/platform/bindings/*',
3497 'third_party/protobuf/benchmarks/python/*',
3498 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473499 # Enum-only mojoms used for web metrics, so no security review needed.
3500 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343501 # These files are just used to communicate between class loaders running
3502 # in the same process.
3503 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3504 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3505 ]
3506
3507 def IsMojoServiceManifestFile(input_api, file):
3508 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3509 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3510 if not manifest_pattern.search(file.LocalPath()):
3511 return False
3512
3513 if test_manifest_pattern.search(file.LocalPath()):
3514 return False
3515
3516 # All actual service manifest files should contain at least one
3517 # qualified reference to service_manager::Manifest.
3518 return any('service_manager::Manifest' in line
3519 for line in file.NewContents())
3520
3521 return _FindMissingSecurityOwners(
3522 input_api,
3523 output_api,
3524 file_patterns,
3525 excluded_patterns,
3526 'ipc/SECURITY_OWNERS',
3527 custom_rule_function=IsMojoServiceManifestFile)
3528
3529
3530def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3531 file_patterns = [
3532 # Component specifications.
3533 '*.cml', # Component Framework v2.
3534 '*.cmx', # Component Framework v1.
3535
3536 # Fuchsia IDL protocol specifications.
3537 '*.fidl',
3538 ]
3539
3540 # Don't check for owners files for changes in these directories.
3541 excluded_patterns = [
3542 'third_party/crashpad/*',
3543 ]
3544
3545 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3546 excluded_patterns,
3547 'build/fuchsia/SECURITY_OWNERS')
3548
3549
3550def CheckSecurityOwners(input_api, output_api):
3551 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3552 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3553 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3554 input_api, output_api)
3555
3556 if ipc_results.has_security_sensitive_files:
3557 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503558
3559 results = []
Daniel Chenga37c03db2022-05-12 17:20:343560
Daniel Cheng171dad8d2022-05-21 00:40:253561 missing_reviewer_problems = []
3562 if ipc_results.missing_reviewer_problem:
3563 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3564 if fuchsia_results.missing_reviewer_problem:
3565 missing_reviewer_problems.append(
3566 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343567
Daniel Cheng171dad8d2022-05-21 00:40:253568 # Missing reviewers are an error unless there's no issue number
3569 # associated with this branch; in that case, the presubmit is being run
3570 # with --all or --files.
3571 #
3572 # Note that upload should never be an error; otherwise, it would be
3573 # impossible to upload changes at all.
3574 if input_api.is_committing and input_api.change.issue:
3575 make_presubmit_message = output_api.PresubmitError
3576 else:
3577 make_presubmit_message = output_api.PresubmitNotifyResult
3578 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503579 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253580 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343581
Daniel Cheng171dad8d2022-05-21 00:40:253582 owners_file_problems = []
3583 owners_file_problems.extend(ipc_results.owners_file_problems)
3584 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343585
Daniel Cheng171dad8d2022-05-21 00:40:253586 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113587 # Missing per-file rules are always an error. While swarming and caching
3588 # means that uploading a patchset with updated OWNERS files and sending
3589 # it to the CQ again should not have a large incremental cost, it is
3590 # still frustrating to discover the error only after the change has
3591 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343592 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253593 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503594
3595 return results
3596
3597
3598def _GetFilesUsingSecurityCriticalFunctions(input_api):
3599 """Checks affected files for changes to security-critical calls. This
3600 function checks the full change diff, to catch both additions/changes
3601 and removals.
3602
3603 Returns a dict keyed by file name, and the value is a set of detected
3604 functions.
3605 """
3606 # Map of function pretty name (displayed in an error) to the pattern to
3607 # match it with.
3608 _PATTERNS_TO_CHECK = {
3609 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3610 }
3611 _PATTERNS_TO_CHECK = {
3612 k: input_api.re.compile(v)
3613 for k, v in _PATTERNS_TO_CHECK.items()
3614 }
3615
Sam Maiera6e76d72022-02-11 21:43:503616 # We don't want to trigger on strings within this file.
3617 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343618 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503619
3620 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3621 files_to_functions = {}
3622 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3623 diff = f.GenerateScmDiff()
3624 for line in diff.split('\n'):
3625 # Not using just RightHandSideLines() because removing a
3626 # call to a security-critical function can be just as important
3627 # as adding or changing the arguments.
3628 if line.startswith('-') or (line.startswith('+')
3629 and not line.startswith('++')):
3630 for name, pattern in _PATTERNS_TO_CHECK.items():
3631 if pattern.search(line):
3632 path = f.LocalPath()
3633 if not path in files_to_functions:
3634 files_to_functions[path] = set()
3635 files_to_functions[path].add(name)
3636 return files_to_functions
3637
3638
3639def CheckSecurityChanges(input_api, output_api):
3640 """Checks that changes involving security-critical functions are reviewed
3641 by the security team.
3642 """
3643 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3644 if not len(files_to_functions):
3645 return []
3646
Sam Maiera6e76d72022-02-11 21:43:503647 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343648 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503649 return []
3650
Daniel Chenga37c03db2022-05-12 17:20:343651 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503652 'that need to be reviewed by {}.\n'.format(owners_file)
3653 for path, names in files_to_functions.items():
3654 msg += ' {}\n'.format(path)
3655 for name in names:
3656 msg += ' {}\n'.format(name)
3657 msg += '\n'
3658
3659 if input_api.is_committing:
3660 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033661 else:
Sam Maiera6e76d72022-02-11 21:43:503662 output = output_api.PresubmitNotifyResult
3663 return [output(msg)]
3664
3665
3666def CheckSetNoParent(input_api, output_api):
3667 """Checks that set noparent is only used together with an OWNERS file in
3668 //build/OWNERS.setnoparent (see also
3669 //docs/code_reviews.md#owners-files-details)
3670 """
3671 # Return early if no OWNERS files were modified.
3672 if not any(f.LocalPath().endswith('OWNERS')
3673 for f in input_api.AffectedFiles(include_deletes=False)):
3674 return []
3675
3676 errors = []
3677
3678 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3679 allowed_owners_files = set()
3680 with open(allowed_owners_files_file, 'r') as f:
3681 for line in f:
3682 line = line.strip()
3683 if not line or line.startswith('#'):
3684 continue
3685 allowed_owners_files.add(line)
3686
3687 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3688
3689 for f in input_api.AffectedFiles(include_deletes=False):
3690 if not f.LocalPath().endswith('OWNERS'):
3691 continue
3692
3693 found_owners_files = set()
3694 found_set_noparent_lines = dict()
3695
3696 # Parse the OWNERS file.
3697 for lineno, line in enumerate(f.NewContents(), 1):
3698 line = line.strip()
3699 if line.startswith('set noparent'):
3700 found_set_noparent_lines[''] = lineno
3701 if line.startswith('file://'):
3702 if line in allowed_owners_files:
3703 found_owners_files.add('')
3704 if line.startswith('per-file'):
3705 match = per_file_pattern.match(line)
3706 if match:
3707 glob = match.group(1).strip()
3708 directive = match.group(2).strip()
3709 if directive == 'set noparent':
3710 found_set_noparent_lines[glob] = lineno
3711 if directive.startswith('file://'):
3712 if directive in allowed_owners_files:
3713 found_owners_files.add(glob)
3714
3715 # Check that every set noparent line has a corresponding file:// line
3716 # listed in build/OWNERS.setnoparent. An exception is made for top level
3717 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493718 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3719 if (linux_path.count('/') != 1
3720 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503721 for set_noparent_line in found_set_noparent_lines:
3722 if set_noparent_line in found_owners_files:
3723 continue
3724 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493725 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503726 found_set_noparent_lines[set_noparent_line]))
3727
3728 results = []
3729 if errors:
3730 if input_api.is_committing:
3731 output = output_api.PresubmitError
3732 else:
3733 output = output_api.PresubmitPromptWarning
3734 results.append(
3735 output(
3736 'Found the following "set noparent" restrictions in OWNERS files that '
3737 'do not include owners from build/OWNERS.setnoparent:',
3738 long_text='\n\n'.join(errors)))
3739 return results
3740
3741
3742def CheckUselessForwardDeclarations(input_api, output_api):
3743 """Checks that added or removed lines in non third party affected
3744 header files do not lead to new useless class or struct forward
3745 declaration.
3746 """
3747 results = []
3748 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3749 input_api.re.MULTILINE)
3750 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3751 input_api.re.MULTILINE)
3752 for f in input_api.AffectedFiles(include_deletes=False):
3753 if (f.LocalPath().startswith('third_party')
3754 and not f.LocalPath().startswith('third_party/blink')
3755 and not f.LocalPath().startswith('third_party\\blink')):
3756 continue
3757
3758 if not f.LocalPath().endswith('.h'):
3759 continue
3760
3761 contents = input_api.ReadFile(f)
3762 fwd_decls = input_api.re.findall(class_pattern, contents)
3763 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3764
3765 useless_fwd_decls = []
3766 for decl in fwd_decls:
3767 count = sum(1 for _ in input_api.re.finditer(
3768 r'\b%s\b' % input_api.re.escape(decl), contents))
3769 if count == 1:
3770 useless_fwd_decls.append(decl)
3771
3772 if not useless_fwd_decls:
3773 continue
3774
3775 for line in f.GenerateScmDiff().splitlines():
3776 if (line.startswith('-') and not line.startswith('--')
3777 or line.startswith('+') and not line.startswith('++')):
3778 for decl in useless_fwd_decls:
3779 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3780 results.append(
3781 output_api.PresubmitPromptWarning(
3782 '%s: %s forward declaration is no longer needed'
3783 % (f.LocalPath(), decl)))
3784 useless_fwd_decls.remove(decl)
3785
3786 return results
3787
3788
3789def _CheckAndroidDebuggableBuild(input_api, output_api):
3790 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3791 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3792 this is a debuggable build of Android.
3793 """
3794 build_type_check_pattern = input_api.re.compile(
3795 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3796
3797 errors = []
3798
3799 sources = lambda affected_file: input_api.FilterSourceFile(
3800 affected_file,
3801 files_to_skip=(
3802 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3803 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313804 r"^android_webview/support_library/boundary_interfaces/",
3805 r"^chrome/android/webapk/.*",
3806 r'^third_party/.*',
3807 r"tools/android/customtabs_benchmark/.*",
3808 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:503809 )),
3810 files_to_check=[r'.*\.java$'])
3811
3812 for f in input_api.AffectedSourceFiles(sources):
3813 for line_num, line in f.ChangedContents():
3814 if build_type_check_pattern.search(line):
3815 errors.append("%s:%d" % (f.LocalPath(), line_num))
3816
3817 results = []
3818
3819 if errors:
3820 results.append(
3821 output_api.PresubmitPromptWarning(
3822 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3823 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3824
3825 return results
3826
3827# TODO: add unit tests
3828def _CheckAndroidToastUsage(input_api, output_api):
3829 """Checks that code uses org.chromium.ui.widget.Toast instead of
3830 android.widget.Toast (Chromium Toast doesn't force hardware
3831 acceleration on low-end devices, saving memory).
3832 """
3833 toast_import_pattern = input_api.re.compile(
3834 r'^import android\.widget\.Toast;$')
3835
3836 errors = []
3837
3838 sources = lambda affected_file: input_api.FilterSourceFile(
3839 affected_file,
3840 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:313841 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
3842 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:503843 files_to_check=[r'.*\.java$'])
3844
3845 for f in input_api.AffectedSourceFiles(sources):
3846 for line_num, line in f.ChangedContents():
3847 if toast_import_pattern.search(line):
3848 errors.append("%s:%d" % (f.LocalPath(), line_num))
3849
3850 results = []
3851
3852 if errors:
3853 results.append(
3854 output_api.PresubmitError(
3855 'android.widget.Toast usage is detected. Android toasts use hardware'
3856 ' acceleration, and can be\ncostly on low-end devices. Please use'
3857 ' org.chromium.ui.widget.Toast instead.\n'
3858 'Contact [email protected] if you have any questions.',
3859 errors))
3860
3861 return results
3862
3863
3864def _CheckAndroidCrLogUsage(input_api, output_api):
3865 """Checks that new logs using org.chromium.base.Log:
3866 - Are using 'TAG' as variable name for the tags (warn)
3867 - Are using a tag that is shorter than 20 characters (error)
3868 """
3869
3870 # Do not check format of logs in the given files
3871 cr_log_check_excluded_paths = [
3872 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:313873 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:503874 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:313875 r"^android_webview/glue/java/src/com/android/"
3876 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:503877 # The customtabs_benchmark is a small app that does not depend on Chromium
3878 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:313879 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:503880 ]
3881
3882 cr_log_import_pattern = input_api.re.compile(
3883 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3884 class_in_base_pattern = input_api.re.compile(
3885 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3886 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3887 input_api.re.MULTILINE)
3888 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3889 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3890 log_decl_pattern = input_api.re.compile(
3891 r'static final String TAG = "(?P<name>(.*))"')
3892 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3893
3894 REF_MSG = ('See docs/android_logging.md for more info.')
3895 sources = lambda x: input_api.FilterSourceFile(
3896 x,
3897 files_to_check=[r'.*\.java$'],
3898 files_to_skip=cr_log_check_excluded_paths)
3899
3900 tag_decl_errors = []
3901 tag_length_errors = []
3902 tag_errors = []
3903 tag_with_dot_errors = []
3904 util_log_errors = []
3905
3906 for f in input_api.AffectedSourceFiles(sources):
3907 file_content = input_api.ReadFile(f)
3908 has_modified_logs = False
3909 # Per line checks
3910 if (cr_log_import_pattern.search(file_content)
3911 or (class_in_base_pattern.search(file_content)
3912 and not has_some_log_import_pattern.search(file_content))):
3913 # Checks to run for files using cr log
3914 for line_num, line in f.ChangedContents():
3915 if rough_log_decl_pattern.search(line):
3916 has_modified_logs = True
3917
3918 # Check if the new line is doing some logging
3919 match = log_call_pattern.search(line)
3920 if match:
3921 has_modified_logs = True
3922
3923 # Make sure it uses "TAG"
3924 if not match.group('tag') == 'TAG':
3925 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3926 else:
3927 # Report non cr Log function calls in changed lines
3928 for line_num, line in f.ChangedContents():
3929 if log_call_pattern.search(line):
3930 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3931
3932 # Per file checks
3933 if has_modified_logs:
3934 # Make sure the tag is using the "cr" prefix and is not too long
3935 match = log_decl_pattern.search(file_content)
3936 tag_name = match.group('name') if match else None
3937 if not tag_name:
3938 tag_decl_errors.append(f.LocalPath())
3939 elif len(tag_name) > 20:
3940 tag_length_errors.append(f.LocalPath())
3941 elif '.' in tag_name:
3942 tag_with_dot_errors.append(f.LocalPath())
3943
3944 results = []
3945 if tag_decl_errors:
3946 results.append(
3947 output_api.PresubmitPromptWarning(
3948 'Please define your tags using the suggested format: .\n'
3949 '"private static final String TAG = "<package tag>".\n'
3950 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3951 tag_decl_errors))
3952
3953 if tag_length_errors:
3954 results.append(
3955 output_api.PresubmitError(
3956 'The tag length is restricted by the system to be at most '
3957 '20 characters.\n' + REF_MSG, tag_length_errors))
3958
3959 if tag_errors:
3960 results.append(
3961 output_api.PresubmitPromptWarning(
3962 'Please use a variable named "TAG" for your log tags.\n' +
3963 REF_MSG, tag_errors))
3964
3965 if util_log_errors:
3966 results.append(
3967 output_api.PresubmitPromptWarning(
3968 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3969 util_log_errors))
3970
3971 if tag_with_dot_errors:
3972 results.append(
3973 output_api.PresubmitPromptWarning(
3974 'Dot in log tags cause them to be elided in crash reports.\n' +
3975 REF_MSG, tag_with_dot_errors))
3976
3977 return results
3978
3979
3980def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3981 """Checks that junit.framework.* is no longer used."""
3982 deprecated_junit_framework_pattern = input_api.re.compile(
3983 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3984 sources = lambda x: input_api.FilterSourceFile(
3985 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3986 errors = []
3987 for f in input_api.AffectedFiles(file_filter=sources):
3988 for line_num, line in f.ChangedContents():
3989 if deprecated_junit_framework_pattern.search(line):
3990 errors.append("%s:%d" % (f.LocalPath(), line_num))
3991
3992 results = []
3993 if errors:
3994 results.append(
3995 output_api.PresubmitError(
3996 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3997 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3998 ' if you have any question.', errors))
3999 return results
4000
4001
4002def _CheckAndroidTestJUnitInheritance(input_api, output_api):
4003 """Checks that if new Java test classes have inheritance.
4004 Either the new test class is JUnit3 test or it is a JUnit4 test class
4005 with a base class, either case is undesirable.
4006 """
4007 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
4008
4009 sources = lambda x: input_api.FilterSourceFile(
4010 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
4011 errors = []
4012 for f in input_api.AffectedFiles(file_filter=sources):
4013 if not f.OldContents():
4014 class_declaration_start_flag = False
4015 for line_num, line in f.ChangedContents():
4016 if class_declaration_pattern.search(line):
4017 class_declaration_start_flag = True
4018 if class_declaration_start_flag and ' extends ' in line:
4019 errors.append('%s:%d' % (f.LocalPath(), line_num))
4020 if '{' in line:
4021 class_declaration_start_flag = False
4022
4023 results = []
4024 if errors:
4025 results.append(
4026 output_api.PresubmitPromptWarning(
4027 'The newly created files include Test classes that inherits from base'
4028 ' class. Please do not use inheritance in JUnit4 tests or add new'
4029 ' JUnit3 tests. Contact [email protected] if you have any'
4030 ' questions.', errors))
4031 return results
4032
4033
4034def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4035 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4036 deprecated_annotation_import_pattern = input_api.re.compile(
4037 r'^import android\.test\.suitebuilder\.annotation\..*;',
4038 input_api.re.MULTILINE)
4039 sources = lambda x: input_api.FilterSourceFile(
4040 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4041 errors = []
4042 for f in input_api.AffectedFiles(file_filter=sources):
4043 for line_num, line in f.ChangedContents():
4044 if deprecated_annotation_import_pattern.search(line):
4045 errors.append("%s:%d" % (f.LocalPath(), line_num))
4046
4047 results = []
4048 if errors:
4049 results.append(
4050 output_api.PresubmitError(
4051 'Annotations in android.test.suitebuilder.annotation have been'
4052 ' deprecated since API level 24. Please use android.support.test.filters'
4053 ' from //third_party/android_support_test_runner:runner_java instead.'
4054 ' Contact [email protected] if you have any questions.',
4055 errors))
4056 return results
4057
4058
4059def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4060 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514061 file_filter = lambda f: (f.LocalPath().endswith(
4062 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4063 LocalPath() or '/res/drawable-ldrtl/'.replace(
4064 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504065 errors = []
4066 for f in input_api.AffectedFiles(include_deletes=False,
4067 file_filter=file_filter):
4068 errors.append(' %s' % f.LocalPath())
4069
4070 results = []
4071 if errors:
4072 results.append(
4073 output_api.PresubmitError(
4074 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4075 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4076 '/res/drawable-ldrtl/.\n'
4077 'Contact [email protected] if you have questions.', errors))
4078 return results
4079
4080
4081def _CheckAndroidWebkitImports(input_api, output_api):
4082 """Checks that code uses org.chromium.base.Callback instead of
4083 android.webview.ValueCallback except in the WebView glue layer
4084 and WebLayer.
4085 """
4086 valuecallback_import_pattern = input_api.re.compile(
4087 r'^import android\.webkit\.ValueCallback;$')
4088
4089 errors = []
4090
4091 sources = lambda affected_file: input_api.FilterSourceFile(
4092 affected_file,
4093 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4094 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314095 r'^android_webview/glue/.*',
4096 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504097 )),
4098 files_to_check=[r'.*\.java$'])
4099
4100 for f in input_api.AffectedSourceFiles(sources):
4101 for line_num, line in f.ChangedContents():
4102 if valuecallback_import_pattern.search(line):
4103 errors.append("%s:%d" % (f.LocalPath(), line_num))
4104
4105 results = []
4106
4107 if errors:
4108 results.append(
4109 output_api.PresubmitError(
4110 'android.webkit.ValueCallback usage is detected outside of the glue'
4111 ' layer. To stay compatible with the support library, android.webkit.*'
4112 ' classes should only be used inside the glue layer and'
4113 ' org.chromium.base.Callback should be used instead.', errors))
4114
4115 return results
4116
4117
4118def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4119 """Checks Android XML styles """
4120
4121 # Return early if no relevant files were modified.
4122 if not any(
4123 _IsXmlOrGrdFile(input_api, f.LocalPath())
4124 for f in input_api.AffectedFiles(include_deletes=False)):
4125 return []
4126
4127 import sys
4128 original_sys_path = sys.path
4129 try:
4130 sys.path = sys.path + [
4131 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4132 'android', 'checkxmlstyle')
4133 ]
4134 import checkxmlstyle
4135 finally:
4136 # Restore sys.path to what it was before.
4137 sys.path = original_sys_path
4138
4139 if is_check_on_upload:
4140 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4141 else:
4142 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4143
4144
4145def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4146 """Checks Android Infobar Deprecation """
4147
4148 import sys
4149 original_sys_path = sys.path
4150 try:
4151 sys.path = sys.path + [
4152 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4153 'android', 'infobar_deprecation')
4154 ]
4155 import infobar_deprecation
4156 finally:
4157 # Restore sys.path to what it was before.
4158 sys.path = original_sys_path
4159
4160 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4161
4162
4163class _PydepsCheckerResult:
4164 def __init__(self, cmd, pydeps_path, process, old_contents):
4165 self._cmd = cmd
4166 self._pydeps_path = pydeps_path
4167 self._process = process
4168 self._old_contents = old_contents
4169
4170 def GetError(self):
4171 """Returns an error message, or None."""
4172 import difflib
4173 if self._process.wait() != 0:
4174 # STDERR should already be printed.
4175 return 'Command failed: ' + self._cmd
4176 new_contents = self._process.stdout.read().splitlines()[2:]
4177 if self._old_contents != new_contents:
4178 diff = '\n'.join(
4179 difflib.context_diff(self._old_contents, new_contents))
4180 return ('File is stale: {}\n'
4181 'Diff (apply to fix):\n'
4182 '{}\n'
4183 'To regenerate, run:\n\n'
4184 ' {}').format(self._pydeps_path, diff, self._cmd)
4185 return None
4186
4187
4188class PydepsChecker:
4189 def __init__(self, input_api, pydeps_files):
4190 self._file_cache = {}
4191 self._input_api = input_api
4192 self._pydeps_files = pydeps_files
4193
4194 def _LoadFile(self, path):
4195 """Returns the list of paths within a .pydeps file relative to //."""
4196 if path not in self._file_cache:
4197 with open(path, encoding='utf-8') as f:
4198 self._file_cache[path] = f.read()
4199 return self._file_cache[path]
4200
4201 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594202 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504203 pydeps_data = self._LoadFile(pydeps_path)
4204 uses_gn_paths = '--gn-paths' in pydeps_data
4205 entries = (l for l in pydeps_data.splitlines()
4206 if not l.startswith('#'))
4207 if uses_gn_paths:
4208 # Paths look like: //foo/bar/baz
4209 return (e[2:] for e in entries)
4210 else:
4211 # Paths look like: path/relative/to/file.pydeps
4212 os_path = self._input_api.os_path
4213 pydeps_dir = os_path.dirname(pydeps_path)
4214 return (os_path.normpath(os_path.join(pydeps_dir, e))
4215 for e in entries)
4216
4217 def _CreateFilesToPydepsMap(self):
4218 """Returns a map of local_path -> list_of_pydeps."""
4219 ret = {}
4220 for pydep_local_path in self._pydeps_files:
4221 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4222 ret.setdefault(path, []).append(pydep_local_path)
4223 return ret
4224
4225 def ComputeAffectedPydeps(self):
4226 """Returns an iterable of .pydeps files that might need regenerating."""
4227 affected_pydeps = set()
4228 file_to_pydeps_map = None
4229 for f in self._input_api.AffectedFiles(include_deletes=True):
4230 local_path = f.LocalPath()
4231 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4232 # subrepositories. We can't figure out which files change, so re-check
4233 # all files.
4234 # Changes to print_python_deps.py affect all .pydeps.
4235 if local_path in ('DEPS', 'PRESUBMIT.py'
4236 ) or local_path.endswith('print_python_deps.py'):
4237 return self._pydeps_files
4238 elif local_path.endswith('.pydeps'):
4239 if local_path in self._pydeps_files:
4240 affected_pydeps.add(local_path)
4241 elif local_path.endswith('.py'):
4242 if file_to_pydeps_map is None:
4243 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4244 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4245 return affected_pydeps
4246
4247 def DetermineIfStaleAsync(self, pydeps_path):
4248 """Runs print_python_deps.py to see if the files is stale."""
4249 import os
4250
4251 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4252 if old_pydeps_data:
4253 cmd = old_pydeps_data[1][1:].strip()
4254 if '--output' not in cmd:
4255 cmd += ' --output ' + pydeps_path
4256 old_contents = old_pydeps_data[2:]
4257 else:
4258 # A default cmd that should work in most cases (as long as pydeps filename
4259 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4260 # file is empty/new.
4261 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4262 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4263 old_contents = []
4264 env = dict(os.environ)
4265 env['PYTHONDONTWRITEBYTECODE'] = '1'
4266 process = self._input_api.subprocess.Popen(
4267 cmd + ' --output ""',
4268 shell=True,
4269 env=env,
4270 stdout=self._input_api.subprocess.PIPE,
4271 encoding='utf-8')
4272 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404273
4274
Tibor Goldschwendt360793f72019-06-25 18:23:494275def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504276 args = {}
4277 with open('build/config/gclient_args.gni', 'r') as f:
4278 for line in f:
4279 line = line.strip()
4280 if not line or line.startswith('#'):
4281 continue
4282 attribute, value = line.split('=')
4283 args[attribute.strip()] = value.strip()
4284 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494285
4286
Saagar Sanghavifceeaae2020-08-12 16:40:364287def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504288 """Checks if a .pydeps file needs to be regenerated."""
4289 # This check is for Python dependency lists (.pydeps files), and involves
4290 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4291 # doesn't work on Windows and Mac, so skip it on other platforms.
4292 if not input_api.platform.startswith('linux'):
4293 return []
Erik Staabc734cd7a2021-11-23 03:11:524294
Sam Maiera6e76d72022-02-11 21:43:504295 results = []
4296 # First, check for new / deleted .pydeps.
4297 for f in input_api.AffectedFiles(include_deletes=True):
4298 # Check whether we are running the presubmit check for a file in src.
4299 # f.LocalPath is relative to repo (src, or internal repo).
4300 # os_path.exists is relative to src repo.
4301 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4302 # to src and we can conclude that the pydeps is in src.
4303 if f.LocalPath().endswith('.pydeps'):
4304 if input_api.os_path.exists(f.LocalPath()):
4305 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4306 results.append(
4307 output_api.PresubmitError(
4308 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4309 'remove %s' % f.LocalPath()))
4310 elif f.Action() != 'D' and f.LocalPath(
4311 ) not in _ALL_PYDEPS_FILES:
4312 results.append(
4313 output_api.PresubmitError(
4314 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4315 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404316
Sam Maiera6e76d72022-02-11 21:43:504317 if results:
4318 return results
4319
4320 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4321 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4322 affected_pydeps = set(checker.ComputeAffectedPydeps())
4323 affected_android_pydeps = affected_pydeps.intersection(
4324 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4325 if affected_android_pydeps and not is_android:
4326 results.append(
4327 output_api.PresubmitPromptOrNotify(
4328 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594329 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504330 'run because you are not using an Android checkout. To validate that\n'
4331 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4332 'use the android-internal-presubmit optional trybot.\n'
4333 'Possibly stale pydeps files:\n{}'.format(
4334 '\n'.join(affected_android_pydeps))))
4335
4336 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4337 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4338 # Process these concurrently, as each one takes 1-2 seconds.
4339 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4340 for result in pydep_results:
4341 error_msg = result.GetError()
4342 if error_msg:
4343 results.append(output_api.PresubmitError(error_msg))
4344
agrievef32bcc72016-04-04 14:57:404345 return results
4346
agrievef32bcc72016-04-04 14:57:404347
Saagar Sanghavifceeaae2020-08-12 16:40:364348def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504349 """Checks to make sure no header files have |Singleton<|."""
4350
4351 def FileFilter(affected_file):
4352 # It's ok for base/memory/singleton.h to have |Singleton<|.
4353 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314354 (r"^base/memory/singleton\.h$",
4355 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504356 return input_api.FilterSourceFile(affected_file,
4357 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434358
Sam Maiera6e76d72022-02-11 21:43:504359 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4360 files = []
4361 for f in input_api.AffectedSourceFiles(FileFilter):
4362 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4363 or f.LocalPath().endswith('.hpp')
4364 or f.LocalPath().endswith('.inl')):
4365 contents = input_api.ReadFile(f)
4366 for line in contents.splitlines(False):
4367 if (not line.lstrip().startswith('//')
4368 and # Strip C++ comment.
4369 pattern.search(line)):
4370 files.append(f)
4371 break
glidere61efad2015-02-18 17:39:434372
Sam Maiera6e76d72022-02-11 21:43:504373 if files:
4374 return [
4375 output_api.PresubmitError(
4376 'Found base::Singleton<T> in the following header files.\n' +
4377 'Please move them to an appropriate source file so that the ' +
4378 'template gets instantiated in a single compilation unit.',
4379 files)
4380 ]
4381 return []
glidere61efad2015-02-18 17:39:434382
4383
[email protected]fd20b902014-05-09 02:14:534384_DEPRECATED_CSS = [
4385 # Values
4386 ( "-webkit-box", "flex" ),
4387 ( "-webkit-inline-box", "inline-flex" ),
4388 ( "-webkit-flex", "flex" ),
4389 ( "-webkit-inline-flex", "inline-flex" ),
4390 ( "-webkit-min-content", "min-content" ),
4391 ( "-webkit-max-content", "max-content" ),
4392
4393 # Properties
4394 ( "-webkit-background-clip", "background-clip" ),
4395 ( "-webkit-background-origin", "background-origin" ),
4396 ( "-webkit-background-size", "background-size" ),
4397 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444398 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:534399
4400 # Functions
4401 ( "-webkit-gradient", "gradient" ),
4402 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4403 ( "-webkit-linear-gradient", "linear-gradient" ),
4404 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4405 ( "-webkit-radial-gradient", "radial-gradient" ),
4406 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4407]
4408
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204409
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494410# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364411def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504412 """ Make sure that we don't use deprecated CSS
4413 properties, functions or values. Our external
4414 documentation and iOS CSS for dom distiller
4415 (reader mode) are ignored by the hooks as it
4416 needs to be consumed by WebKit. """
4417 results = []
4418 file_inclusion_pattern = [r".+\.css$"]
4419 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4420 input_api.DEFAULT_FILES_TO_SKIP +
4421 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4422 r"^native_client_sdk"))
4423 file_filter = lambda f: input_api.FilterSourceFile(
4424 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4425 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4426 for line_num, line in fpath.ChangedContents():
4427 for (deprecated_value, value) in _DEPRECATED_CSS:
4428 if deprecated_value in line:
4429 results.append(
4430 output_api.PresubmitError(
4431 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4432 (fpath.LocalPath(), line_num, deprecated_value,
4433 value)))
4434 return results
[email protected]fd20b902014-05-09 02:14:534435
mohan.reddyf21db962014-10-16 12:26:474436
Saagar Sanghavifceeaae2020-08-12 16:40:364437def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504438 bad_files = {}
4439 for f in input_api.AffectedFiles(include_deletes=False):
4440 if (f.LocalPath().startswith('third_party')
4441 and not f.LocalPath().startswith('third_party/blink')
4442 and not f.LocalPath().startswith('third_party\\blink')):
4443 continue
rlanday6802cf632017-05-30 17:48:364444
Sam Maiera6e76d72022-02-11 21:43:504445 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4446 continue
rlanday6802cf632017-05-30 17:48:364447
Sam Maiera6e76d72022-02-11 21:43:504448 relative_includes = [
4449 line for _, line in f.ChangedContents()
4450 if "#include" in line and "../" in line
4451 ]
4452 if not relative_includes:
4453 continue
4454 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364455
Sam Maiera6e76d72022-02-11 21:43:504456 if not bad_files:
4457 return []
rlanday6802cf632017-05-30 17:48:364458
Sam Maiera6e76d72022-02-11 21:43:504459 error_descriptions = []
4460 for file_path, bad_lines in bad_files.items():
4461 error_description = file_path
4462 for line in bad_lines:
4463 error_description += '\n ' + line
4464 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364465
Sam Maiera6e76d72022-02-11 21:43:504466 results = []
4467 results.append(
4468 output_api.PresubmitError(
4469 'You added one or more relative #include paths (including "../").\n'
4470 'These shouldn\'t be used because they can be used to include headers\n'
4471 'from code that\'s not correctly specified as a dependency in the\n'
4472 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364473
Sam Maiera6e76d72022-02-11 21:43:504474 return results
rlanday6802cf632017-05-30 17:48:364475
Takeshi Yoshinoe387aa32017-08-02 13:16:134476
Saagar Sanghavifceeaae2020-08-12 16:40:364477def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504478 """Check that nobody tries to include a cc file. It's a relatively
4479 common error which results in duplicate symbols in object
4480 files. This may not always break the build until someone later gets
4481 very confusing linking errors."""
4482 results = []
4483 for f in input_api.AffectedFiles(include_deletes=False):
4484 # We let third_party code do whatever it wants
4485 if (f.LocalPath().startswith('third_party')
4486 and not f.LocalPath().startswith('third_party/blink')
4487 and not f.LocalPath().startswith('third_party\\blink')):
4488 continue
Daniel Bratell65b033262019-04-23 08:17:064489
Sam Maiera6e76d72022-02-11 21:43:504490 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4491 continue
Daniel Bratell65b033262019-04-23 08:17:064492
Sam Maiera6e76d72022-02-11 21:43:504493 for _, line in f.ChangedContents():
4494 if line.startswith('#include "'):
4495 included_file = line.split('"')[1]
4496 if _IsCPlusPlusFile(input_api, included_file):
4497 # The most common naming for external files with C++ code,
4498 # apart from standard headers, is to call them foo.inc, but
4499 # Chromium sometimes uses foo-inc.cc so allow that as well.
4500 if not included_file.endswith(('.h', '-inc.cc')):
4501 results.append(
4502 output_api.PresubmitError(
4503 'Only header files or .inc files should be included in other\n'
4504 'C++ files. Compiling the contents of a cc file more than once\n'
4505 'will cause duplicate information in the build which may later\n'
4506 'result in strange link_errors.\n' +
4507 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064508
Sam Maiera6e76d72022-02-11 21:43:504509 return results
Daniel Bratell65b033262019-04-23 08:17:064510
4511
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204512def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504513 if not isinstance(key, ast.Str):
4514 return 'Key at line %d must be a string literal' % key.lineno
4515 if not isinstance(value, ast.Dict):
4516 return 'Value at line %d must be a dict' % value.lineno
4517 if len(value.keys) != 1:
4518 return 'Dict at line %d must have single entry' % value.lineno
4519 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4520 return (
4521 'Entry at line %d must have a string literal \'filepath\' as key' %
4522 value.lineno)
4523 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134524
Takeshi Yoshinoe387aa32017-08-02 13:16:134525
Sergey Ulanov4af16052018-11-08 02:41:464526def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504527 if not isinstance(key, ast.Str):
4528 return 'Key at line %d must be a string literal' % key.lineno
4529 if not isinstance(value, ast.List):
4530 return 'Value at line %d must be a list' % value.lineno
4531 for element in value.elts:
4532 if not isinstance(element, ast.Str):
4533 return 'Watchlist elements on line %d is not a string' % key.lineno
4534 if not email_regex.match(element.s):
4535 return ('Watchlist element on line %d doesn\'t look like a valid '
4536 + 'email: %s') % (key.lineno, element.s)
4537 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134538
Takeshi Yoshinoe387aa32017-08-02 13:16:134539
Sergey Ulanov4af16052018-11-08 02:41:464540def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504541 mismatch_template = (
4542 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4543 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134544
Sam Maiera6e76d72022-02-11 21:43:504545 email_regex = input_api.re.compile(
4546 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464547
Sam Maiera6e76d72022-02-11 21:43:504548 ast = input_api.ast
4549 i = 0
4550 last_key = ''
4551 while True:
4552 if i >= len(wd_dict.keys):
4553 if i >= len(w_dict.keys):
4554 return None
4555 return mismatch_template % ('missing',
4556 'line %d' % w_dict.keys[i].lineno)
4557 elif i >= len(w_dict.keys):
4558 return (mismatch_template %
4559 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134560
Sam Maiera6e76d72022-02-11 21:43:504561 wd_key = wd_dict.keys[i]
4562 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134563
Sam Maiera6e76d72022-02-11 21:43:504564 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4565 wd_dict.values[i], ast)
4566 if result is not None:
4567 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134568
Sam Maiera6e76d72022-02-11 21:43:504569 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4570 email_regex)
4571 if result is not None:
4572 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204573
Sam Maiera6e76d72022-02-11 21:43:504574 if wd_key.s != w_key.s:
4575 return mismatch_template % ('%s at line %d' %
4576 (wd_key.s, wd_key.lineno),
4577 '%s at line %d' %
4578 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204579
Sam Maiera6e76d72022-02-11 21:43:504580 if wd_key.s < last_key:
4581 return (
4582 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4583 % (wd_key.lineno, w_key.lineno))
4584 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204585
Sam Maiera6e76d72022-02-11 21:43:504586 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204587
4588
Sergey Ulanov4af16052018-11-08 02:41:464589def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504590 ast = input_api.ast
4591 if not isinstance(expression, ast.Expression):
4592 return 'WATCHLISTS file must contain a valid expression'
4593 dictionary = expression.body
4594 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4595 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204596
Sam Maiera6e76d72022-02-11 21:43:504597 first_key = dictionary.keys[0]
4598 first_value = dictionary.values[0]
4599 second_key = dictionary.keys[1]
4600 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204601
Sam Maiera6e76d72022-02-11 21:43:504602 if (not isinstance(first_key, ast.Str)
4603 or first_key.s != 'WATCHLIST_DEFINITIONS'
4604 or not isinstance(first_value, ast.Dict)):
4605 return ('The first entry of the dict in WATCHLISTS file must be '
4606 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204607
Sam Maiera6e76d72022-02-11 21:43:504608 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4609 or not isinstance(second_value, ast.Dict)):
4610 return ('The second entry of the dict in WATCHLISTS file must be '
4611 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204612
Sam Maiera6e76d72022-02-11 21:43:504613 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134614
4615
Saagar Sanghavifceeaae2020-08-12 16:40:364616def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504617 for f in input_api.AffectedFiles(include_deletes=False):
4618 if f.LocalPath() == 'WATCHLISTS':
4619 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134620
Sam Maiera6e76d72022-02-11 21:43:504621 try:
4622 # First, make sure that it can be evaluated.
4623 input_api.ast.literal_eval(contents)
4624 # Get an AST tree for it and scan the tree for detailed style checking.
4625 expression = input_api.ast.parse(contents,
4626 filename='WATCHLISTS',
4627 mode='eval')
4628 except ValueError as e:
4629 return [
4630 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4631 long_text=repr(e))
4632 ]
4633 except SyntaxError as e:
4634 return [
4635 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4636 long_text=repr(e))
4637 ]
4638 except TypeError as e:
4639 return [
4640 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4641 long_text=repr(e))
4642 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134643
Sam Maiera6e76d72022-02-11 21:43:504644 result = _CheckWATCHLISTSSyntax(expression, input_api)
4645 if result is not None:
4646 return [output_api.PresubmitError(result)]
4647 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134648
Sam Maiera6e76d72022-02-11 21:43:504649 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134650
Sean Kaucb7c9b32022-10-25 21:25:524651def CheckGnRebasePath(input_api, output_api):
4652 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
4653
4654 Developers should use root_build_dir instead of "//" when using target_gen_dir because
4655 Chromium is sometimes built outside of the source tree.
4656 """
4657
4658 def gn_files(f):
4659 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
4660
4661 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
4662 problems = []
4663 for f in input_api.AffectedSourceFiles(gn_files):
4664 for line_num, line in f.ChangedContents():
4665 if rebase_path_regex.search(line):
4666 problems.append(
4667 'Absolute path in rebase_path() in %s:%d' %
4668 (f.LocalPath(), line_num))
4669
4670 if problems:
4671 return [
4672 output_api.PresubmitPromptWarning(
4673 'Using an absolute path in rebase_path()',
4674 items=sorted(problems),
4675 long_text=(
4676 'rebase_path() should use root_build_dir instead of "/" ',
4677 'since builds can be initiated from outside of the source ',
4678 'root.'))
4679 ]
4680 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134681
Andrew Grieve1b290e4a22020-11-24 20:07:014682def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504683 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014684
Sam Maiera6e76d72022-02-11 21:43:504685 As documented at //build/docs/writing_gn_templates.md
4686 """
Andrew Grieve1b290e4a22020-11-24 20:07:014687
Sam Maiera6e76d72022-02-11 21:43:504688 def gn_files(f):
4689 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014690
Sam Maiera6e76d72022-02-11 21:43:504691 problems = []
4692 for f in input_api.AffectedSourceFiles(gn_files):
4693 for line_num, line in f.ChangedContents():
4694 if 'forward_variables_from(invoker, "*")' in line:
4695 problems.append(
4696 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4697 (f.LocalPath(), line_num))
4698
4699 if problems:
4700 return [
4701 output_api.PresubmitPromptWarning(
4702 'forward_variables_from("*") without exclusions',
4703 items=sorted(problems),
4704 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594705 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504706 'explicitly listed in forward_variables_from(). For more '
4707 'details, see:\n'
4708 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4709 'build/docs/writing_gn_templates.md'
4710 '#Using-forward_variables_from'))
4711 ]
4712 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014713
Saagar Sanghavifceeaae2020-08-12 16:40:364714def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504715 """Checks that newly added header files have corresponding GN changes.
4716 Note that this is only a heuristic. To be precise, run script:
4717 build/check_gn_headers.py.
4718 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194719
Sam Maiera6e76d72022-02-11 21:43:504720 def headers(f):
4721 return input_api.FilterSourceFile(
4722 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194723
Sam Maiera6e76d72022-02-11 21:43:504724 new_headers = []
4725 for f in input_api.AffectedSourceFiles(headers):
4726 if f.Action() != 'A':
4727 continue
4728 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194729
Sam Maiera6e76d72022-02-11 21:43:504730 def gn_files(f):
4731 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194732
Sam Maiera6e76d72022-02-11 21:43:504733 all_gn_changed_contents = ''
4734 for f in input_api.AffectedSourceFiles(gn_files):
4735 for _, line in f.ChangedContents():
4736 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194737
Sam Maiera6e76d72022-02-11 21:43:504738 problems = []
4739 for header in new_headers:
4740 basename = input_api.os_path.basename(header)
4741 if basename not in all_gn_changed_contents:
4742 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194743
Sam Maiera6e76d72022-02-11 21:43:504744 if problems:
4745 return [
4746 output_api.PresubmitPromptWarning(
4747 'Missing GN changes for new header files',
4748 items=sorted(problems),
4749 long_text=
4750 'Please double check whether newly added header files need '
4751 'corresponding changes in gn or gni files.\nThis checking is only a '
4752 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4753 'Read https://crbug.com/661774 for more info.')
4754 ]
4755 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194756
4757
Saagar Sanghavifceeaae2020-08-12 16:40:364758def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504759 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024760
Sam Maiera6e76d72022-02-11 21:43:504761 This assumes we won't intentionally reference one product from the other
4762 product.
4763 """
4764 all_problems = []
4765 test_cases = [{
4766 "filename_postfix": "google_chrome_strings.grd",
4767 "correct_name": "Chrome",
4768 "incorrect_name": "Chromium",
4769 }, {
4770 "filename_postfix": "chromium_strings.grd",
4771 "correct_name": "Chromium",
4772 "incorrect_name": "Chrome",
4773 }]
Michael Giuffridad3bc8672018-10-25 22:48:024774
Sam Maiera6e76d72022-02-11 21:43:504775 for test_case in test_cases:
4776 problems = []
4777 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4778 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024779
Sam Maiera6e76d72022-02-11 21:43:504780 # Check each new line. Can yield false positives in multiline comments, but
4781 # easier than trying to parse the XML because messages can have nested
4782 # children, and associating message elements with affected lines is hard.
4783 for f in input_api.AffectedSourceFiles(filename_filter):
4784 for line_num, line in f.ChangedContents():
4785 if "<message" in line or "<!--" in line or "-->" in line:
4786 continue
4787 if test_case["incorrect_name"] in line:
4788 problems.append("Incorrect product name in %s:%d" %
4789 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024790
Sam Maiera6e76d72022-02-11 21:43:504791 if problems:
4792 message = (
4793 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4794 % (test_case["correct_name"], test_case["correct_name"],
4795 test_case["incorrect_name"]))
4796 all_problems.append(
4797 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024798
Sam Maiera6e76d72022-02-11 21:43:504799 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024800
4801
Saagar Sanghavifceeaae2020-08-12 16:40:364802def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504803 """Avoid large files, especially binary files, in the repository since
4804 git doesn't scale well for those. They will be in everyone's repo
4805 clones forever, forever making Chromium slower to clone and work
4806 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364807
Sam Maiera6e76d72022-02-11 21:43:504808 # Uploading files to cloud storage is not trivial so we don't want
4809 # to set the limit too low, but the upper limit for "normal" large
4810 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4811 # anything over 20 MB is exceptional.
4812 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364813
Sam Maiera6e76d72022-02-11 21:43:504814 too_large_files = []
4815 for f in input_api.AffectedFiles():
4816 # Check both added and modified files (but not deleted files).
4817 if f.Action() in ('A', 'M'):
4818 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4819 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4820 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364821
Sam Maiera6e76d72022-02-11 21:43:504822 if too_large_files:
4823 message = (
4824 'Do not commit large files to git since git scales badly for those.\n'
4825 +
4826 'Instead put the large files in cloud storage and use DEPS to\n' +
4827 'fetch them.\n' + '\n'.join(too_large_files))
4828 return [
4829 output_api.PresubmitError('Too large files found in commit',
4830 long_text=message + '\n')
4831 ]
4832 else:
4833 return []
Daniel Bratell93eb6c62019-04-29 20:13:364834
Max Morozb47503b2019-08-08 21:03:274835
Saagar Sanghavifceeaae2020-08-12 16:40:364836def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504837 """Checks specific for fuzz target sources."""
4838 EXPORTED_SYMBOLS = [
4839 'LLVMFuzzerInitialize',
4840 'LLVMFuzzerCustomMutator',
4841 'LLVMFuzzerCustomCrossOver',
4842 'LLVMFuzzerMutate',
4843 ]
Max Morozb47503b2019-08-08 21:03:274844
Sam Maiera6e76d72022-02-11 21:43:504845 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274846
Sam Maiera6e76d72022-02-11 21:43:504847 def FilterFile(affected_file):
4848 """Ignore libFuzzer source code."""
4849 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:314850 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:274851
Sam Maiera6e76d72022-02-11 21:43:504852 return input_api.FilterSourceFile(affected_file,
4853 files_to_check=[files_to_check],
4854 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274855
Sam Maiera6e76d72022-02-11 21:43:504856 files_with_missing_header = []
4857 for f in input_api.AffectedSourceFiles(FilterFile):
4858 contents = input_api.ReadFile(f, 'r')
4859 if REQUIRED_HEADER in contents:
4860 continue
Max Morozb47503b2019-08-08 21:03:274861
Sam Maiera6e76d72022-02-11 21:43:504862 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4863 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274864
Sam Maiera6e76d72022-02-11 21:43:504865 if not files_with_missing_header:
4866 return []
Max Morozb47503b2019-08-08 21:03:274867
Sam Maiera6e76d72022-02-11 21:43:504868 long_text = (
4869 'If you define any of the libFuzzer optional functions (%s), it is '
4870 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4871 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4872 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4873 'to access command line arguments passed to the fuzzer. Instead, prefer '
4874 'static initialization and shared resources as documented in '
4875 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4876 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4877 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274878
Sam Maiera6e76d72022-02-11 21:43:504879 return [
4880 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4881 REQUIRED_HEADER,
4882 items=files_with_missing_header,
4883 long_text=long_text)
4884 ]
Max Morozb47503b2019-08-08 21:03:274885
4886
Mohamed Heikald048240a2019-11-12 16:57:374887def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504888 """
4889 Warns authors who add images into the repo to make sure their images are
4890 optimized before committing.
4891 """
4892 images_added = False
4893 image_paths = []
4894 errors = []
4895 filter_lambda = lambda x: input_api.FilterSourceFile(
4896 x,
4897 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4898 DEFAULT_FILES_TO_SKIP),
4899 files_to_check=[r'.*\/(drawable|mipmap)'])
4900 for f in input_api.AffectedFiles(include_deletes=False,
4901 file_filter=filter_lambda):
4902 local_path = f.LocalPath().lower()
4903 if any(
4904 local_path.endswith(extension)
4905 for extension in _IMAGE_EXTENSIONS):
4906 images_added = True
4907 image_paths.append(f)
4908 if images_added:
4909 errors.append(
4910 output_api.PresubmitPromptWarning(
4911 'It looks like you are trying to commit some images. If these are '
4912 'non-test-only images, please make sure to read and apply the tips in '
4913 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4914 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4915 'FYI only and will not block your CL on the CQ.', image_paths))
4916 return errors
Mohamed Heikald048240a2019-11-12 16:57:374917
4918
Saagar Sanghavifceeaae2020-08-12 16:40:364919def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504920 """Groups upload checks that target android code."""
4921 results = []
4922 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4923 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4924 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4925 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4926 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4927 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4928 input_api, output_api))
4929 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4930 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4931 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4932 results.extend(_CheckNewImagesWarning(input_api, output_api))
4933 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4934 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4935 return results
4936
Becky Zhou7c69b50992018-12-10 19:37:574937
Saagar Sanghavifceeaae2020-08-12 16:40:364938def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504939 """Groups commit checks that target android code."""
4940 results = []
4941 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4942 return results
dgnaa68d5e2015-06-10 10:08:224943
Chris Hall59f8d0c72020-05-01 07:31:194944# TODO(chrishall): could we additionally match on any path owned by
4945# ui/accessibility/OWNERS ?
4946_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:314947 r"^chrome/browser.*/accessibility/",
4948 r"^chrome/browser/extensions/api/automation.*/",
4949 r"^chrome/renderer/extensions/accessibility_.*",
4950 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:174951 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:314952 r"^content/browser/accessibility/",
4953 r"^content/renderer/accessibility/",
4954 r"^content/tests/data/accessibility/",
4955 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:174956 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:314957 r"^ui/accessibility/",
4958 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:194959)
4960
Saagar Sanghavifceeaae2020-08-12 16:40:364961def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504962 """Checks that commits to accessibility code contain an AX-Relnotes field in
4963 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194964
Sam Maiera6e76d72022-02-11 21:43:504965 def FileFilter(affected_file):
4966 paths = _ACCESSIBILITY_PATHS
4967 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194968
Sam Maiera6e76d72022-02-11 21:43:504969 # Only consider changes affecting accessibility paths.
4970 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4971 return []
Akihiro Ota08108e542020-05-20 15:30:534972
Sam Maiera6e76d72022-02-11 21:43:504973 # AX-Relnotes can appear in either the description or the footer.
4974 # When searching the description, require 'AX-Relnotes:' to appear at the
4975 # beginning of a line.
4976 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4977 description_has_relnotes = any(
4978 ax_regex.match(line)
4979 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194980
Sam Maiera6e76d72022-02-11 21:43:504981 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4982 'AX-Relnotes', [])
4983 if description_has_relnotes or footer_relnotes:
4984 return []
Chris Hall59f8d0c72020-05-01 07:31:194985
Sam Maiera6e76d72022-02-11 21:43:504986 # TODO(chrishall): link to Relnotes documentation in message.
4987 message = (
4988 "Missing 'AX-Relnotes:' field required for accessibility changes"
4989 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4990 "user-facing changes"
4991 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4992 "user-facing effects"
4993 "\n if this is confusing or annoying then please contact members "
4994 "of ui/accessibility/OWNERS.")
4995
4996 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224997
Mark Schillacie5a0be22022-01-19 00:38:394998
4999_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315000 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395001)
5002
5003_ACCESSIBILITY_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315004 r"^content/test/data/accessibility/accname/.*\.html",
5005 r"^content/test/data/accessibility/aria/.*\.html",
5006 r"^content/test/data/accessibility/css/.*\.html",
5007 r"^content/test/data/accessibility/html/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395008)
5009
5010_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315011 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395012)
5013
5014_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315015 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395016)
5017
5018def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505019 """Checks that commits that include a newly added, renamed/moved, or deleted
5020 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5021 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395022
Sam Maiera6e76d72022-02-11 21:43:505023 def FilePathFilter(affected_file):
5024 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5025 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395026
Sam Maiera6e76d72022-02-11 21:43:505027 def AndroidFilePathFilter(affected_file):
5028 paths = _ACCESSIBILITY_ANDROID_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 # Only consider changes in the events test data path with html type.
5032 if not any(
5033 input_api.AffectedFiles(include_deletes=True,
5034 file_filter=FilePathFilter)):
5035 return []
Mark Schillacie5a0be22022-01-19 00:38:395036
Sam Maiera6e76d72022-02-11 21:43:505037 # If the commit contains any change to the Android test file, ignore.
5038 if any(
5039 input_api.AffectedFiles(include_deletes=True,
5040 file_filter=AndroidFilePathFilter)):
5041 return []
Mark Schillacie5a0be22022-01-19 00:38:395042
Sam Maiera6e76d72022-02-11 21:43:505043 # Only consider changes that are adding/renaming or deleting a file
5044 message = []
5045 for f in input_api.AffectedFiles(include_deletes=True,
5046 file_filter=FilePathFilter):
5047 if f.Action() == 'A' or f.Action() == 'D':
5048 message = (
5049 "It appears that you are adding, renaming or deleting"
5050 "\na dump_accessibility_events* test, but have not included"
5051 "\na corresponding change for Android."
5052 "\nPlease include (or remove) the test from:"
5053 "\n content/public/android/javatests/src/org/chromium/"
5054 "content/browser/accessibility/"
5055 "WebContentsAccessibilityEventsTest.java"
5056 "\nIf this message is confusing or annoying, please contact"
5057 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395058
Sam Maiera6e76d72022-02-11 21:43:505059 # If no message was set, return empty.
5060 if not len(message):
5061 return []
5062
5063 return [output_api.PresubmitPromptWarning(message)]
5064
Mark Schillacie5a0be22022-01-19 00:38:395065
5066def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505067 """Checks that commits that include a newly added, renamed/moved, or deleted
5068 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5069 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395070
Sam Maiera6e76d72022-02-11 21:43:505071 def FilePathFilter(affected_file):
5072 paths = _ACCESSIBILITY_TREE_TEST_PATH
5073 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395074
Sam Maiera6e76d72022-02-11 21:43:505075 def AndroidFilePathFilter(affected_file):
5076 paths = _ACCESSIBILITY_ANDROID_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 # Only consider changes in the various tree test data paths with html type.
5080 if not any(
5081 input_api.AffectedFiles(include_deletes=True,
5082 file_filter=FilePathFilter)):
5083 return []
Mark Schillacie5a0be22022-01-19 00:38:395084
Sam Maiera6e76d72022-02-11 21:43:505085 # If the commit contains any change to the Android test file, ignore.
5086 if any(
5087 input_api.AffectedFiles(include_deletes=True,
5088 file_filter=AndroidFilePathFilter)):
5089 return []
Mark Schillacie5a0be22022-01-19 00:38:395090
Sam Maiera6e76d72022-02-11 21:43:505091 # Only consider changes that are adding/renaming or deleting a file
5092 message = []
5093 for f in input_api.AffectedFiles(include_deletes=True,
5094 file_filter=FilePathFilter):
5095 if f.Action() == 'A' or f.Action() == 'D':
5096 message = (
5097 "It appears that you are adding, renaming or deleting"
5098 "\na dump_accessibility_tree* test, but have not included"
5099 "\na corresponding change for Android."
5100 "\nPlease include (or remove) the test from:"
5101 "\n content/public/android/javatests/src/org/chromium/"
5102 "content/browser/accessibility/"
5103 "WebContentsAccessibilityTreeTest.java"
5104 "\nIf this message is confusing or annoying, please contact"
5105 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395106
Sam Maiera6e76d72022-02-11 21:43:505107 # If no message was set, return empty.
5108 if not len(message):
5109 return []
5110
5111 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395112
5113
Bruce Dawson33806592022-11-16 01:44:515114def CheckEsLintConfigChanges(input_api, output_api):
5115 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
5116 modified. This is important because enabling an error in .eslintrc.js can
5117 trigger errors in any .js or .ts files in its directory, leading to hidden
5118 presubmit errors."""
5119 results = []
5120 eslint_filter = lambda f: input_api.FilterSourceFile(
5121 f, files_to_check=[r'.*\.eslintrc\.js$'])
5122 for f in input_api.AffectedFiles(include_deletes=False,
5123 file_filter=eslint_filter):
5124 local_dir = input_api.os_path.dirname(f.LocalPath())
5125 # Use / characters so that the commands printed work on any OS.
5126 local_dir = local_dir.replace(input_api.os_path.sep, '/')
5127 if local_dir:
5128 local_dir += '/'
5129 results.append(
5130 output_api.PresubmitNotifyResult(
5131 '%(file)s modified. Consider running \'git cl presubmit --files '
5132 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
5133 'files before landing this change.' %
5134 { 'file' : f.LocalPath(), 'dir' : local_dir}))
5135 return results
5136
5137
seanmccullough4a9356252021-04-08 19:54:095138# string pattern, sequence of strings to show when pattern matches,
5139# error flag. True if match is a presubmit error, otherwise it's a warning.
5140_NON_INCLUSIVE_TERMS = (
5141 (
5142 # Note that \b pattern in python re is pretty particular. In this
5143 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5144 # ...' will not. This may require some tweaking to catch these cases
5145 # without triggering a lot of false positives. Leaving it naive and
5146 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:325147 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:095148 (
5149 'Please don\'t use blacklist, whitelist, ' # nocheck
5150 'or slave in your', # nocheck
5151 'code and make every effort to use other terms. Using "// nocheck"',
5152 '"# nocheck" or "<!-- nocheck -->"',
5153 'at the end of the offending line will bypass this PRESUBMIT error',
5154 'but avoid using this whenever possible. Reach out to',
5155 '[email protected] if you have questions'),
5156 True),)
5157
Saagar Sanghavifceeaae2020-08-12 16:40:365158def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505159 """Checks common to both upload and commit."""
5160 results = []
Eric Boren6fd2b932018-01-25 15:05:085161 results.extend(
Sam Maiera6e76d72022-02-11 21:43:505162 input_api.canned_checks.PanProjectChecks(
5163 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:085164
Sam Maiera6e76d72022-02-11 21:43:505165 author = input_api.change.author_email
5166 if author and author not in _KNOWN_ROBOTS:
5167 results.extend(
5168 input_api.canned_checks.CheckAuthorizedAuthor(
5169 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:245170
Sam Maiera6e76d72022-02-11 21:43:505171 results.extend(
5172 input_api.canned_checks.CheckChangeHasNoTabs(
5173 input_api,
5174 output_api,
5175 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
5176 results.extend(
5177 input_api.RunTests(
5178 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:175179
Bruce Dawsonc8054482022-03-28 15:33:375180 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:505181 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:375182 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:505183 results.extend(
5184 input_api.RunTests(
5185 input_api.canned_checks.CheckDirMetadataFormat(
5186 input_api, output_api, dirmd_bin)))
5187 results.extend(
5188 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
5189 input_api, output_api))
5190 results.extend(
5191 input_api.canned_checks.CheckNoNewMetadataInOwners(
5192 input_api, output_api))
5193 results.extend(
5194 input_api.canned_checks.CheckInclusiveLanguage(
5195 input_api,
5196 output_api,
5197 excluded_directories_relative_path=[
5198 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
5199 ],
5200 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:595201
Aleksey Khoroshilov2978c942022-06-13 16:14:125202 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:475203 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:125204 for f in input_api.AffectedFiles(include_deletes=False,
5205 file_filter=presubmit_py_filter):
5206 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
5207 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
5208 # The PRESUBMIT.py file (and the directory containing it) might have
5209 # been affected by being moved or removed, so only try to run the tests
5210 # if they still exist.
5211 if not input_api.os_path.exists(test_file):
5212 continue
Sam Maiera6e76d72022-02-11 21:43:505213
Aleksey Khoroshilov2978c942022-06-13 16:14:125214 use_python3 = False
5215 with open(f.LocalPath()) as fp:
5216 use_python3 = any(
5217 line.startswith('USE_PYTHON3 = True')
5218 for line in fp.readlines())
5219
5220 results.extend(
5221 input_api.canned_checks.RunUnitTestsInDirectory(
5222 input_api,
5223 output_api,
5224 full_path,
5225 files_to_check=[r'^PRESUBMIT_test\.py$'],
5226 run_on_python2=not use_python3,
5227 run_on_python3=use_python3,
5228 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:505229 return results
[email protected]1f7b4172010-01-28 01:17:345230
[email protected]b337cb5b2011-01-23 21:24:055231
Saagar Sanghavifceeaae2020-08-12 16:40:365232def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505233 problems = [
5234 f.LocalPath() for f in input_api.AffectedFiles()
5235 if f.LocalPath().endswith(('.orig', '.rej'))
5236 ]
5237 # Cargo.toml.orig files are part of third-party crates downloaded from
5238 # crates.io and should be included.
5239 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5240 if problems:
5241 return [
5242 output_api.PresubmitError("Don't commit .rej and .orig files.",
5243 problems)
5244 ]
5245 else:
5246 return []
[email protected]b8079ae4a2012-12-05 19:56:495247
5248
Saagar Sanghavifceeaae2020-08-12 16:40:365249def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505250 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5251 macro_re = input_api.re.compile(
5252 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5253 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5254 input_api.re.MULTILINE)
5255 extension_re = input_api.re.compile(r'\.[a-z]+$')
5256 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005257 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505258 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005259 # The build-config macros are allowed to be used in build_config.h
5260 # without including itself.
5261 if f.LocalPath() == config_h_file:
5262 continue
Sam Maiera6e76d72022-02-11 21:43:505263 if not f.LocalPath().endswith(
5264 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5265 continue
5266 found_line_number = None
5267 found_macro = None
5268 all_lines = input_api.ReadFile(f, 'r').splitlines()
5269 for line_num, line in enumerate(all_lines):
5270 match = macro_re.search(line)
5271 if match:
5272 found_line_number = line_num
5273 found_macro = match.group(2)
5274 break
5275 if not found_line_number:
5276 continue
Kent Tamura5a8755d2017-06-29 23:37:075277
Sam Maiera6e76d72022-02-11 21:43:505278 found_include_line = -1
5279 for line_num, line in enumerate(all_lines):
5280 if include_re.search(line):
5281 found_include_line = line_num
5282 break
5283 if found_include_line >= 0 and found_include_line < found_line_number:
5284 continue
Kent Tamura5a8755d2017-06-29 23:37:075285
Sam Maiera6e76d72022-02-11 21:43:505286 if not f.LocalPath().endswith('.h'):
5287 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5288 try:
5289 content = input_api.ReadFile(primary_header_path, 'r')
5290 if include_re.search(content):
5291 continue
5292 except IOError:
5293 pass
5294 errors.append('%s:%d %s macro is used without first including build/'
5295 'build_config.h.' %
5296 (f.LocalPath(), found_line_number, found_macro))
5297 if errors:
5298 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5299 return []
Kent Tamura5a8755d2017-06-29 23:37:075300
5301
Lei Zhang1c12a22f2021-05-12 11:28:455302def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505303 stl_include_re = input_api.re.compile(r'^#include\s+<('
5304 r'algorithm|'
5305 r'array|'
5306 r'limits|'
5307 r'list|'
5308 r'map|'
5309 r'memory|'
5310 r'queue|'
5311 r'set|'
5312 r'string|'
5313 r'unordered_map|'
5314 r'unordered_set|'
5315 r'utility|'
5316 r'vector)>')
5317 std_namespace_re = input_api.re.compile(r'std::')
5318 errors = []
5319 for f in input_api.AffectedFiles():
5320 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5321 continue
Lei Zhang1c12a22f2021-05-12 11:28:455322
Sam Maiera6e76d72022-02-11 21:43:505323 uses_std_namespace = False
5324 has_stl_include = False
5325 for line in f.NewContents():
5326 if has_stl_include and uses_std_namespace:
5327 break
Lei Zhang1c12a22f2021-05-12 11:28:455328
Sam Maiera6e76d72022-02-11 21:43:505329 if not has_stl_include and stl_include_re.search(line):
5330 has_stl_include = True
5331 continue
Lei Zhang1c12a22f2021-05-12 11:28:455332
Bruce Dawson4a5579a2022-04-08 17:11:365333 if not uses_std_namespace and (std_namespace_re.search(line)
5334 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505335 uses_std_namespace = True
5336 continue
Lei Zhang1c12a22f2021-05-12 11:28:455337
Sam Maiera6e76d72022-02-11 21:43:505338 if has_stl_include and not uses_std_namespace:
5339 errors.append(
5340 '%s: Includes STL header(s) but does not reference std::' %
5341 f.LocalPath())
5342 if errors:
5343 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5344 return []
Lei Zhang1c12a22f2021-05-12 11:28:455345
5346
Xiaohan Wang42d96c22022-01-20 17:23:115347def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505348 """Check for sensible looking, totally invalid OS macros."""
5349 preprocessor_statement = input_api.re.compile(r'^\s*#')
5350 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5351 results = []
5352 for lnum, line in f.ChangedContents():
5353 if preprocessor_statement.search(line):
5354 for match in os_macro.finditer(line):
5355 results.append(
5356 ' %s:%d: %s' %
5357 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5358 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5359 return results
[email protected]b00342e7f2013-03-26 16:21:545360
5361
Xiaohan Wang42d96c22022-01-20 17:23:115362def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505363 """Check all affected files for invalid OS macros."""
5364 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005365 # The OS_ macros are allowed to be used in build/build_config.h.
5366 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505367 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005368 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5369 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505370 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:545371
Sam Maiera6e76d72022-02-11 21:43:505372 if not bad_macros:
5373 return []
[email protected]b00342e7f2013-03-26 16:21:545374
Sam Maiera6e76d72022-02-11 21:43:505375 return [
5376 output_api.PresubmitError(
5377 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5378 'defined in build_config.h):', bad_macros)
5379 ]
[email protected]b00342e7f2013-03-26 16:21:545380
lliabraa35bab3932014-10-01 12:16:445381
5382def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505383 """Check all affected files for invalid "if defined" macros."""
5384 ALWAYS_DEFINED_MACROS = (
5385 "TARGET_CPU_PPC",
5386 "TARGET_CPU_PPC64",
5387 "TARGET_CPU_68K",
5388 "TARGET_CPU_X86",
5389 "TARGET_CPU_ARM",
5390 "TARGET_CPU_MIPS",
5391 "TARGET_CPU_SPARC",
5392 "TARGET_CPU_ALPHA",
5393 "TARGET_IPHONE_SIMULATOR",
5394 "TARGET_OS_EMBEDDED",
5395 "TARGET_OS_IPHONE",
5396 "TARGET_OS_MAC",
5397 "TARGET_OS_UNIX",
5398 "TARGET_OS_WIN32",
5399 )
5400 ifdef_macro = input_api.re.compile(
5401 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5402 results = []
5403 for lnum, line in f.ChangedContents():
5404 for match in ifdef_macro.finditer(line):
5405 if match.group(1) in ALWAYS_DEFINED_MACROS:
5406 always_defined = ' %s is always defined. ' % match.group(1)
5407 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5408 results.append(
5409 ' %s:%d %s\n\t%s' %
5410 (f.LocalPath(), lnum, always_defined, did_you_mean))
5411 return results
lliabraa35bab3932014-10-01 12:16:445412
5413
Saagar Sanghavifceeaae2020-08-12 16:40:365414def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505415 """Check all affected files for invalid "if defined" macros."""
5416 bad_macros = []
5417 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5418 for f in input_api.AffectedFiles():
5419 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5420 continue
5421 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5422 bad_macros.extend(
5423 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445424
Sam Maiera6e76d72022-02-11 21:43:505425 if not bad_macros:
5426 return []
lliabraa35bab3932014-10-01 12:16:445427
Sam Maiera6e76d72022-02-11 21:43:505428 return [
5429 output_api.PresubmitError(
5430 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5431 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5432 bad_macros)
5433 ]
lliabraa35bab3932014-10-01 12:16:445434
5435
Saagar Sanghavifceeaae2020-08-12 16:40:365436def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505437 """Check for same IPC rules described in
5438 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5439 """
5440 base_pattern = r'IPC_ENUM_TRAITS\('
5441 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5442 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045443
Sam Maiera6e76d72022-02-11 21:43:505444 problems = []
5445 for f in input_api.AffectedSourceFiles(None):
5446 local_path = f.LocalPath()
5447 if not local_path.endswith('.h'):
5448 continue
5449 for line_number, line in f.ChangedContents():
5450 if inclusion_pattern.search(
5451 line) and not comment_pattern.search(line):
5452 problems.append('%s:%d\n %s' %
5453 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045454
Sam Maiera6e76d72022-02-11 21:43:505455 if problems:
5456 return [
5457 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5458 problems)
5459 ]
5460 else:
5461 return []
mlamouria82272622014-09-16 18:45:045462
[email protected]b00342e7f2013-03-26 16:21:545463
Saagar Sanghavifceeaae2020-08-12 16:40:365464def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505465 """Check to make sure no files being submitted have long paths.
5466 This causes issues on Windows.
5467 """
5468 problems = []
5469 for f in input_api.AffectedTestableFiles():
5470 local_path = f.LocalPath()
5471 # Windows has a path limit of 260 characters. Limit path length to 200 so
5472 # that we have some extra for the prefix on dev machines and the bots.
5473 if len(local_path) > 200:
5474 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055475
Sam Maiera6e76d72022-02-11 21:43:505476 if problems:
5477 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5478 else:
5479 return []
Stephen Martinis97a394142018-06-07 23:06:055480
5481
Saagar Sanghavifceeaae2020-08-12 16:40:365482def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505483 """Check that header files have proper guards against multiple inclusion.
5484 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365485 should include the string "no-include-guard-because-multiply-included" or
5486 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505487 """
Daniel Bratell8ba52722018-03-02 16:06:145488
Sam Maiera6e76d72022-02-11 21:43:505489 def is_chromium_header_file(f):
5490 # We only check header files under the control of the Chromium
5491 # project. That is, those outside third_party apart from
5492 # third_party/blink.
5493 # We also exclude *_message_generator.h headers as they use
5494 # include guards in a special, non-typical way.
5495 file_with_path = input_api.os_path.normpath(f.LocalPath())
5496 return (file_with_path.endswith('.h')
5497 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335498 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505499 and (not file_with_path.startswith('third_party')
5500 or file_with_path.startswith(
5501 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145502
Sam Maiera6e76d72022-02-11 21:43:505503 def replace_special_with_underscore(string):
5504 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145505
Sam Maiera6e76d72022-02-11 21:43:505506 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145507
Sam Maiera6e76d72022-02-11 21:43:505508 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5509 guard_name = None
5510 guard_line_number = None
5511 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145512
Sam Maiera6e76d72022-02-11 21:43:505513 file_with_path = input_api.os_path.normpath(f.LocalPath())
5514 base_file_name = input_api.os_path.splitext(
5515 input_api.os_path.basename(file_with_path))[0]
5516 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145517
Sam Maiera6e76d72022-02-11 21:43:505518 expected_guard = replace_special_with_underscore(
5519 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145520
Sam Maiera6e76d72022-02-11 21:43:505521 # For "path/elem/file_name.h" we should really only accept
5522 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5523 # are too many (1000+) files with slight deviations from the
5524 # coding style. The most important part is that the include guard
5525 # is there, and that it's unique, not the name so this check is
5526 # forgiving for existing files.
5527 #
5528 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145529
Sam Maiera6e76d72022-02-11 21:43:505530 guard_name_pattern_list = [
5531 # Anything with the right suffix (maybe with an extra _).
5532 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145533
Sam Maiera6e76d72022-02-11 21:43:505534 # To cover include guards with old Blink style.
5535 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145536
Sam Maiera6e76d72022-02-11 21:43:505537 # Anything including the uppercase name of the file.
5538 r'\w*' + input_api.re.escape(
5539 replace_special_with_underscore(upper_base_file_name)) +
5540 r'\w*',
5541 ]
5542 guard_name_pattern = '|'.join(guard_name_pattern_list)
5543 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5544 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145545
Sam Maiera6e76d72022-02-11 21:43:505546 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365547 if ('no-include-guard-because-multiply-included' in line
5548 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505549 guard_name = 'DUMMY' # To not trigger check outside the loop.
5550 break
Daniel Bratell8ba52722018-03-02 16:06:145551
Sam Maiera6e76d72022-02-11 21:43:505552 if guard_name is None:
5553 match = guard_pattern.match(line)
5554 if match:
5555 guard_name = match.group(1)
5556 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145557
Sam Maiera6e76d72022-02-11 21:43:505558 # We allow existing files to use include guards whose names
5559 # don't match the chromium style guide, but new files should
5560 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495561 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165562 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505563 errors.append(
5564 output_api.PresubmitPromptWarning(
5565 'Header using the wrong include guard name %s'
5566 % guard_name, [
5567 '%s:%d' %
5568 (f.LocalPath(), line_number + 1)
5569 ], 'Expected: %r\nFound: %r' %
5570 (expected_guard, guard_name)))
5571 else:
5572 # The line after #ifndef should have a #define of the same name.
5573 if line_number == guard_line_number + 1:
5574 expected_line = '#define %s' % guard_name
5575 if line != expected_line:
5576 errors.append(
5577 output_api.PresubmitPromptWarning(
5578 'Missing "%s" for include guard' %
5579 expected_line,
5580 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5581 'Expected: %r\nGot: %r' %
5582 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145583
Sam Maiera6e76d72022-02-11 21:43:505584 if not seen_guard_end and line == '#endif // %s' % guard_name:
5585 seen_guard_end = True
5586 elif seen_guard_end:
5587 if line.strip() != '':
5588 errors.append(
5589 output_api.PresubmitPromptWarning(
5590 'Include guard %s not covering the whole file'
5591 % (guard_name), [f.LocalPath()]))
5592 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145593
Sam Maiera6e76d72022-02-11 21:43:505594 if guard_name is None:
5595 errors.append(
5596 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495597 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505598 'Recommended name: %s\n'
5599 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365600 '"no-include-guard-because-multiply-included" or\n'
5601 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505602 % (f.LocalPath(), expected_guard)))
5603
5604 return errors
Daniel Bratell8ba52722018-03-02 16:06:145605
5606
Saagar Sanghavifceeaae2020-08-12 16:40:365607def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505608 """Check source code and known ascii text files for Windows style line
5609 endings.
5610 """
Bruce Dawson5efbdc652022-04-11 19:29:515611 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235612
Sam Maiera6e76d72022-02-11 21:43:505613 file_inclusion_pattern = (known_text_files,
5614 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5615 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235616
Sam Maiera6e76d72022-02-11 21:43:505617 problems = []
5618 source_file_filter = lambda f: input_api.FilterSourceFile(
5619 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5620 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515621 # Ignore test files that contain crlf intentionally.
5622 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345623 continue
Sam Maiera6e76d72022-02-11 21:43:505624 include_file = False
5625 for line in input_api.ReadFile(f, 'r').splitlines(True):
5626 if line.endswith('\r\n'):
5627 include_file = True
5628 if include_file:
5629 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235630
Sam Maiera6e76d72022-02-11 21:43:505631 if problems:
5632 return [
5633 output_api.PresubmitPromptWarning(
5634 'Are you sure that you want '
5635 'these files to contain Windows style line endings?\n' +
5636 '\n'.join(problems))
5637 ]
mostynbb639aca52015-01-07 20:31:235638
Sam Maiera6e76d72022-02-11 21:43:505639 return []
5640
mostynbb639aca52015-01-07 20:31:235641
Evan Stade6cfc964c12021-05-18 20:21:165642def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505643 """Check that .icon files (which are fragments of C++) have license headers.
5644 """
Evan Stade6cfc964c12021-05-18 20:21:165645
Sam Maiera6e76d72022-02-11 21:43:505646 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165647
Sam Maiera6e76d72022-02-11 21:43:505648 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5649 return input_api.canned_checks.CheckLicense(input_api,
5650 output_api,
5651 source_file_filter=icons)
5652
Evan Stade6cfc964c12021-05-18 20:21:165653
Jose Magana2b456f22021-03-09 23:26:405654def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505655 """Check source code for use of Chrome App technologies being
5656 deprecated.
5657 """
Jose Magana2b456f22021-03-09 23:26:405658
Sam Maiera6e76d72022-02-11 21:43:505659 def _CheckForDeprecatedTech(input_api,
5660 output_api,
5661 detection_list,
5662 files_to_check=None,
5663 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405664
Sam Maiera6e76d72022-02-11 21:43:505665 if (files_to_check or files_to_skip):
5666 source_file_filter = lambda f: input_api.FilterSourceFile(
5667 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5668 else:
5669 source_file_filter = None
5670
5671 problems = []
5672
5673 for f in input_api.AffectedSourceFiles(source_file_filter):
5674 if f.Action() == 'D':
5675 continue
5676 for _, line in f.ChangedContents():
5677 if any(detect in line for detect in detection_list):
5678 problems.append(f.LocalPath())
5679
5680 return problems
5681
5682 # to avoid this presubmit script triggering warnings
5683 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405684
5685 problems = []
5686
Sam Maiera6e76d72022-02-11 21:43:505687 # NMF: any files with extensions .nmf or NMF
5688 _NMF_FILES = r'\.(nmf|NMF)$'
5689 problems += _CheckForDeprecatedTech(
5690 input_api,
5691 output_api,
5692 detection_list=[''], # any change to the file will trigger warning
5693 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405694
Sam Maiera6e76d72022-02-11 21:43:505695 # MANIFEST: any manifest.json that in its diff includes "app":
5696 _MANIFEST_FILES = r'(manifest\.json)$'
5697 problems += _CheckForDeprecatedTech(
5698 input_api,
5699 output_api,
5700 detection_list=['"app":'],
5701 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405702
Sam Maiera6e76d72022-02-11 21:43:505703 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5704 problems += _CheckForDeprecatedTech(
5705 input_api,
5706 output_api,
5707 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:315708 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:405709
Gao Shenga79ebd42022-08-08 17:25:595710 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505711 problems += _CheckForDeprecatedTech(
5712 input_api,
5713 output_api,
5714 detection_list=['#include "ppapi', '#include <ppapi'],
5715 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5716 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:315717 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:405718
Sam Maiera6e76d72022-02-11 21:43:505719 if problems:
5720 return [
5721 output_api.PresubmitPromptWarning(
5722 'You are adding/modifying code'
5723 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5724 ' PNaCl, PPAPI). See this blog post for more details:\n'
5725 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5726 'and this documentation for options to replace these technologies:\n'
5727 'https://developer.chrome.com/docs/apps/migration/\n' +
5728 '\n'.join(problems))
5729 ]
Jose Magana2b456f22021-03-09 23:26:405730
Sam Maiera6e76d72022-02-11 21:43:505731 return []
Jose Magana2b456f22021-03-09 23:26:405732
mostynbb639aca52015-01-07 20:31:235733
Saagar Sanghavifceeaae2020-08-12 16:40:365734def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505735 """Checks that all source files use SYSLOG properly."""
5736 syslog_files = []
5737 for f in input_api.AffectedSourceFiles(src_file_filter):
5738 for line_number, line in f.ChangedContents():
5739 if 'SYSLOG' in line:
5740 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565741
Sam Maiera6e76d72022-02-11 21:43:505742 if syslog_files:
5743 return [
5744 output_api.PresubmitPromptWarning(
5745 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5746 ' calls.\nFiles to check:\n',
5747 items=syslog_files)
5748 ]
5749 return []
pastarmovj89f7ee12016-09-20 14:58:135750
5751
[email protected]1f7b4172010-01-28 01:17:345752def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505753 if input_api.version < [2, 0, 0]:
5754 return [
5755 output_api.PresubmitError(
5756 "Your depot_tools is out of date. "
5757 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5758 "but your version is %d.%d.%d" % tuple(input_api.version))
5759 ]
5760 results = []
5761 results.extend(
5762 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5763 return results
[email protected]ca8d1982009-02-19 16:33:125764
5765
5766def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505767 if input_api.version < [2, 0, 0]:
5768 return [
5769 output_api.PresubmitError(
5770 "Your depot_tools is out of date. "
5771 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5772 "but your version is %d.%d.%d" % tuple(input_api.version))
5773 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365774
Sam Maiera6e76d72022-02-11 21:43:505775 results = []
5776 # Make sure the tree is 'open'.
5777 results.extend(
5778 input_api.canned_checks.CheckTreeIsOpen(
5779 input_api,
5780 output_api,
5781 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275782
Sam Maiera6e76d72022-02-11 21:43:505783 results.extend(
5784 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5785 results.extend(
5786 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5787 results.extend(
5788 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5789 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505790 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145791
5792
Saagar Sanghavifceeaae2020-08-12 16:40:365793def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505794 """Check string ICU syntax validity and if translation screenshots exist."""
5795 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5796 # footer is set to true.
5797 git_footers = input_api.change.GitFootersFromDescription()
5798 skip_screenshot_check_footer = [
5799 footer.lower() for footer in git_footers.get(
5800 u'Skip-Translation-Screenshots-Check', [])
5801 ]
5802 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025803
Sam Maiera6e76d72022-02-11 21:43:505804 import os
5805 import re
5806 import sys
5807 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145808
Sam Maiera6e76d72022-02-11 21:43:505809 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5810 if (f.Action() == 'A' or f.Action() == 'M'))
5811 removed_paths = set(f.LocalPath()
5812 for f in input_api.AffectedFiles(include_deletes=True)
5813 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145814
Sam Maiera6e76d72022-02-11 21:43:505815 affected_grds = [
5816 f for f in input_api.AffectedFiles()
5817 if f.LocalPath().endswith(('.grd', '.grdp'))
5818 ]
5819 affected_grds = [
5820 f for f in affected_grds if not 'testdata' in f.LocalPath()
5821 ]
5822 if not affected_grds:
5823 return []
meacer8c0d3832019-12-26 21:46:165824
Sam Maiera6e76d72022-02-11 21:43:505825 affected_png_paths = [
5826 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5827 if (f.LocalPath().endswith('.png'))
5828 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145829
Sam Maiera6e76d72022-02-11 21:43:505830 # Check for screenshots. Developers can upload screenshots using
5831 # tools/translation/upload_screenshots.py which finds and uploads
5832 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5833 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5834 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5835 #
5836 # The logic here is as follows:
5837 #
5838 # - If the CL has a .png file under the screenshots directory for a grd
5839 # file, warn the developer. Actual images should never be checked into the
5840 # Chrome repo.
5841 #
5842 # - If the CL contains modified or new messages in grd files and doesn't
5843 # contain the corresponding .sha1 files, warn the developer to add images
5844 # and upload them via tools/translation/upload_screenshots.py.
5845 #
5846 # - If the CL contains modified or new messages in grd files and the
5847 # corresponding .sha1 files, everything looks good.
5848 #
5849 # - If the CL contains removed messages in grd files but the corresponding
5850 # .sha1 files aren't removed, warn the developer to remove them.
5851 unnecessary_screenshots = []
5852 missing_sha1 = []
5853 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145854
Sam Maiera6e76d72022-02-11 21:43:505855 # This checks verifies that the ICU syntax of messages this CL touched is
5856 # valid, and reports any found syntax errors.
5857 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5858 # without developers being aware of them. Later on, such ICU syntax errors
5859 # break message extraction for translation, hence would block Chromium
5860 # translations until they are fixed.
5861 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145862
Sam Maiera6e76d72022-02-11 21:43:505863 def _CheckScreenshotAdded(screenshots_dir, message_id):
5864 sha1_path = input_api.os_path.join(screenshots_dir,
5865 message_id + '.png.sha1')
5866 if sha1_path not in new_or_added_paths:
5867 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145868
Sam Maiera6e76d72022-02-11 21:43:505869 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5870 sha1_path = input_api.os_path.join(screenshots_dir,
5871 message_id + '.png.sha1')
5872 if input_api.os_path.exists(
5873 sha1_path) and sha1_path not in removed_paths:
5874 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145875
Sam Maiera6e76d72022-02-11 21:43:505876 def _ValidateIcuSyntax(text, level, signatures):
5877 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145878
Sam Maiera6e76d72022-02-11 21:43:505879 Check if text looks similar to ICU and checks for ICU syntax correctness
5880 in this case. Reports various issues with ICU syntax and values of
5881 variants. Supports checking of nested messages. Accumulate information of
5882 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265883
Sam Maiera6e76d72022-02-11 21:43:505884 Args:
5885 text: a string to check.
5886 level: a number of current nesting level.
5887 signatures: an accumulator, a list of tuple of (level, variable,
5888 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265889
Sam Maiera6e76d72022-02-11 21:43:505890 Returns:
5891 None if a string is not ICU or no issue detected.
5892 A tuple of (message, start index, end index) if an issue detected.
5893 """
5894 valid_types = {
5895 'plural': (frozenset(
5896 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5897 'other']), frozenset(['=1', 'other'])),
5898 'selectordinal': (frozenset(
5899 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5900 'other']), frozenset(['one', 'other'])),
5901 'select': (frozenset(), frozenset(['other'])),
5902 }
Rainhard Findlingfc31844c52020-05-15 09:58:265903
Sam Maiera6e76d72022-02-11 21:43:505904 # Check if the message looks like an attempt to use ICU
5905 # plural. If yes - check if its syntax strictly matches ICU format.
5906 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5907 text)
5908 if not like:
5909 signatures.append((level, None, None, None))
5910 return
Rainhard Findlingfc31844c52020-05-15 09:58:265911
Sam Maiera6e76d72022-02-11 21:43:505912 # Check for valid prefix and suffix
5913 m = re.match(
5914 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5915 r'(plural|selectordinal|select),\s*'
5916 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5917 if not m:
5918 return (('This message looks like an ICU plural, '
5919 'but does not follow ICU syntax.'), like.start(),
5920 like.end())
5921 starting, variable, kind, variant_pairs = m.groups()
5922 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5923 m.start(4))
5924 if depth:
5925 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5926 len(text))
5927 first = text[0]
5928 ending = text[last_pos:]
5929 if not starting:
5930 return ('Invalid ICU format. No initial opening bracket',
5931 last_pos - 1, last_pos)
5932 if not ending or '}' not in ending:
5933 return ('Invalid ICU format. No final closing bracket',
5934 last_pos - 1, last_pos)
5935 elif first != '{':
5936 return ((
5937 'Invalid ICU format. Extra characters at the start of a complex '
5938 'message (go/icu-message-migration): "%s"') % starting, 0,
5939 len(starting))
5940 elif ending != '}':
5941 return ((
5942 'Invalid ICU format. Extra characters at the end of a complex '
5943 'message (go/icu-message-migration): "%s"') % ending,
5944 last_pos - 1, len(text) - 1)
5945 if kind not in valid_types:
5946 return (('Unknown ICU message type %s. '
5947 'Valid types are: plural, select, selectordinal') % kind,
5948 0, 0)
5949 known, required = valid_types[kind]
5950 defined_variants = set()
5951 for variant, variant_range, value, value_range in variants:
5952 start, end = variant_range
5953 if variant in defined_variants:
5954 return ('Variant "%s" is defined more than once' % variant,
5955 start, end)
5956 elif known and variant not in known:
5957 return ('Variant "%s" is not valid for %s message' %
5958 (variant, kind), start, end)
5959 defined_variants.add(variant)
5960 # Check for nested structure
5961 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5962 if res:
5963 return (res[0], res[1] + value_range[0] + 1,
5964 res[2] + value_range[0] + 1)
5965 missing = required - defined_variants
5966 if missing:
5967 return ('Required variants missing: %s' % ', '.join(missing), 0,
5968 len(text))
5969 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265970
Sam Maiera6e76d72022-02-11 21:43:505971 def _ParseIcuVariants(text, offset=0):
5972 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265973
Sam Maiera6e76d72022-02-11 21:43:505974 Builds a tuple of variant names and values, as well as
5975 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265976
Sam Maiera6e76d72022-02-11 21:43:505977 Args:
5978 text: a string to parse
5979 offset: additional offset to add to positions in the text to get correct
5980 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265981
Sam Maiera6e76d72022-02-11 21:43:505982 Returns:
5983 List of tuples, each tuple consist of four fields: variant name,
5984 variant name span (tuple of two integers), variant value, value
5985 span (tuple of two integers).
5986 """
5987 depth, start, end = 0, -1, -1
5988 variants = []
5989 key = None
5990 for idx, char in enumerate(text):
5991 if char == '{':
5992 if not depth:
5993 start = idx
5994 chunk = text[end + 1:start]
5995 key = chunk.strip()
5996 pos = offset + end + 1 + chunk.find(key)
5997 span = (pos, pos + len(key))
5998 depth += 1
5999 elif char == '}':
6000 if not depth:
6001 return variants, depth, offset + idx
6002 depth -= 1
6003 if not depth:
6004 end = idx
6005 variants.append((key, span, text[start:end + 1],
6006 (offset + start, offset + end + 1)))
6007 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266008
Sam Maiera6e76d72022-02-11 21:43:506009 try:
6010 old_sys_path = sys.path
6011 sys.path = sys.path + [
6012 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6013 'translation')
6014 ]
6015 from helper import grd_helper
6016 finally:
6017 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266018
Sam Maiera6e76d72022-02-11 21:43:506019 for f in affected_grds:
6020 file_path = f.LocalPath()
6021 old_id_to_msg_map = {}
6022 new_id_to_msg_map = {}
6023 # Note that this code doesn't check if the file has been deleted. This is
6024 # OK because it only uses the old and new file contents and doesn't load
6025 # the file via its path.
6026 # It's also possible that a file's content refers to a renamed or deleted
6027 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6028 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6029 # .grdp files.
6030 if file_path.endswith('.grdp'):
6031 if f.OldContents():
6032 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6033 '\n'.join(f.OldContents()))
6034 if f.NewContents():
6035 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6036 '\n'.join(f.NewContents()))
6037 else:
6038 file_dir = input_api.os_path.dirname(file_path) or '.'
6039 if f.OldContents():
6040 old_id_to_msg_map = grd_helper.GetGrdMessages(
6041 StringIO('\n'.join(f.OldContents())), file_dir)
6042 if f.NewContents():
6043 new_id_to_msg_map = grd_helper.GetGrdMessages(
6044 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266045
Sam Maiera6e76d72022-02-11 21:43:506046 grd_name, ext = input_api.os_path.splitext(
6047 input_api.os_path.basename(file_path))
6048 screenshots_dir = input_api.os_path.join(
6049 input_api.os_path.dirname(file_path),
6050 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266051
Sam Maiera6e76d72022-02-11 21:43:506052 # Compute added, removed and modified message IDs.
6053 old_ids = set(old_id_to_msg_map)
6054 new_ids = set(new_id_to_msg_map)
6055 added_ids = new_ids - old_ids
6056 removed_ids = old_ids - new_ids
6057 modified_ids = set([])
6058 for key in old_ids.intersection(new_ids):
6059 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6060 new_id_to_msg_map[key].ContentsAsXml('', True)):
6061 # The message content itself changed. Require an updated screenshot.
6062 modified_ids.add(key)
6063 elif old_id_to_msg_map[key].attrs['meaning'] != \
6064 new_id_to_msg_map[key].attrs['meaning']:
6065 # The message meaning changed. Ensure there is a screenshot for it.
6066 sha1_path = input_api.os_path.join(screenshots_dir,
6067 key + '.png.sha1')
6068 if sha1_path not in new_or_added_paths and not \
6069 input_api.os_path.exists(sha1_path):
6070 # There is neither a previous screenshot nor is a new one added now.
6071 # Require a screenshot.
6072 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146073
Sam Maiera6e76d72022-02-11 21:43:506074 if run_screenshot_check:
6075 # Check the screenshot directory for .png files. Warn if there is any.
6076 for png_path in affected_png_paths:
6077 if png_path.startswith(screenshots_dir):
6078 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146079
Sam Maiera6e76d72022-02-11 21:43:506080 for added_id in added_ids:
6081 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096082
Sam Maiera6e76d72022-02-11 21:43:506083 for modified_id in modified_ids:
6084 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146085
Sam Maiera6e76d72022-02-11 21:43:506086 for removed_id in removed_ids:
6087 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6088
6089 # Check new and changed strings for ICU syntax errors.
6090 for key in added_ids.union(modified_ids):
6091 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6092 err = _ValidateIcuSyntax(msg, 0, [])
6093 if err is not None:
6094 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6095
6096 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266097 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506098 if unnecessary_screenshots:
6099 results.append(
6100 output_api.PresubmitError(
6101 'Do not include actual screenshots in the changelist. Run '
6102 'tools/translate/upload_screenshots.py to upload them instead:',
6103 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146104
Sam Maiera6e76d72022-02-11 21:43:506105 if missing_sha1:
6106 results.append(
6107 output_api.PresubmitError(
6108 'You are adding or modifying UI strings.\n'
6109 'To ensure the best translations, take screenshots of the relevant UI '
6110 '(https://g.co/chrome/translation) and add these files to your '
6111 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146112
Sam Maiera6e76d72022-02-11 21:43:506113 if unnecessary_sha1_files:
6114 results.append(
6115 output_api.PresubmitError(
6116 'You removed strings associated with these files. Remove:',
6117 sorted(unnecessary_sha1_files)))
6118 else:
6119 results.append(
6120 output_api.PresubmitPromptOrNotify('Skipping translation '
6121 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146122
Sam Maiera6e76d72022-02-11 21:43:506123 if icu_syntax_errors:
6124 results.append(
6125 output_api.PresubmitPromptWarning(
6126 'ICU syntax errors were found in the following strings (problems or '
6127 'feedback? Contact [email protected]):',
6128 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:266129
Sam Maiera6e76d72022-02-11 21:43:506130 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:126131
6132
Saagar Sanghavifceeaae2020-08-12 16:40:366133def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:126134 repo_root=None,
6135 translation_expectations_path=None,
6136 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:506137 import sys
6138 affected_grds = [
6139 f for f in input_api.AffectedFiles()
6140 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
6141 ]
6142 if not affected_grds:
6143 return []
6144
6145 try:
6146 old_sys_path = sys.path
6147 sys.path = sys.path + [
6148 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6149 'translation')
6150 ]
6151 from helper import git_helper
6152 from helper import translation_helper
6153 finally:
6154 sys.path = old_sys_path
6155
6156 # Check that translation expectations can be parsed and we can get a list of
6157 # translatable grd files. |repo_root| and |translation_expectations_path| are
6158 # only passed by tests.
6159 if not repo_root:
6160 repo_root = input_api.PresubmitLocalPath()
6161 if not translation_expectations_path:
6162 translation_expectations_path = input_api.os_path.join(
6163 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
6164 if not grd_files:
6165 grd_files = git_helper.list_grds_in_repository(repo_root)
6166
6167 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:596168 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:506169 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
6170 'tests')
6171 grd_files = [p for p in grd_files if ignore_path not in p]
6172
6173 try:
6174 translation_helper.get_translatable_grds(
6175 repo_root, grd_files, translation_expectations_path)
6176 except Exception as e:
6177 return [
6178 output_api.PresubmitNotifyResult(
6179 'Failed to get a list of translatable grd files. This happens when:\n'
6180 ' - One of the modified grd or grdp files cannot be parsed or\n'
6181 ' - %s is not updated.\n'
6182 'Stack:\n%s' % (translation_expectations_path, str(e)))
6183 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:126184 return []
6185
Ken Rockotc31f4832020-05-29 18:58:516186
Saagar Sanghavifceeaae2020-08-12 16:40:366187def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506188 """Changes to [Stable] mojom types must preserve backward-compatibility."""
6189 changed_mojoms = input_api.AffectedFiles(
6190 include_deletes=True,
6191 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:526192
Bruce Dawson344ab262022-06-04 11:35:106193 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:506194 return []
6195
6196 delta = []
6197 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:506198 delta.append({
6199 'filename': mojom.LocalPath(),
6200 'old': '\n'.join(mojom.OldContents()) or None,
6201 'new': '\n'.join(mojom.NewContents()) or None,
6202 })
6203
6204 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:216205 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:506206 input_api.os_path.join(
6207 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
6208 'check_stable_mojom_compatibility.py'), '--src-root',
6209 input_api.PresubmitLocalPath()
6210 ],
6211 stdin=input_api.subprocess.PIPE,
6212 stdout=input_api.subprocess.PIPE,
6213 stderr=input_api.subprocess.PIPE,
6214 universal_newlines=True)
6215 (x, error) = process.communicate(input=input_api.json.dumps(delta))
6216 if process.returncode:
6217 return [
6218 output_api.PresubmitError(
6219 'One or more [Stable] mojom definitions appears to have been changed '
6220 'in a way that is not backward-compatible.',
6221 long_text=error)
6222 ]
Erik Staabc734cd7a2021-11-23 03:11:526223 return []
6224
Dominic Battre645d42342020-12-04 16:14:106225def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506226 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106227
Sam Maiera6e76d72022-02-11 21:43:506228 def FilterFile(affected_file):
6229 """Accept only .cc files and the like."""
6230 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6231 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6232 input_api.DEFAULT_FILES_TO_SKIP)
6233 return input_api.FilterSourceFile(
6234 affected_file,
6235 files_to_check=file_inclusion_pattern,
6236 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106237
Sam Maiera6e76d72022-02-11 21:43:506238 def ModifiedLines(affected_file):
6239 """Returns a list of tuples (line number, line text) of added and removed
6240 lines.
Dominic Battre645d42342020-12-04 16:14:106241
Sam Maiera6e76d72022-02-11 21:43:506242 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106243
Sam Maiera6e76d72022-02-11 21:43:506244 This relies on the scm diff output describing each changed code section
6245 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106246
Sam Maiera6e76d72022-02-11 21:43:506247 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6248 """
6249 line_num = 0
6250 modified_lines = []
6251 for line in affected_file.GenerateScmDiff().splitlines():
6252 # Extract <new line num> of the patch fragment (see format above).
6253 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6254 line)
6255 if m:
6256 line_num = int(m.groups(1)[0])
6257 continue
6258 if ((line.startswith('+') and not line.startswith('++'))
6259 or (line.startswith('-') and not line.startswith('--'))):
6260 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106261
Sam Maiera6e76d72022-02-11 21:43:506262 if not line.startswith('-'):
6263 line_num += 1
6264 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106265
Sam Maiera6e76d72022-02-11 21:43:506266 def FindLineWith(lines, needle):
6267 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106268
Sam Maiera6e76d72022-02-11 21:43:506269 If 0 or >1 lines contain `needle`, -1 is returned.
6270 """
6271 matching_line_numbers = [
6272 # + 1 for 1-based counting of line numbers.
6273 i + 1 for i, line in enumerate(lines) if needle in line
6274 ]
6275 return matching_line_numbers[0] if len(
6276 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106277
Sam Maiera6e76d72022-02-11 21:43:506278 def ModifiedPrefMigration(affected_file):
6279 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6280 # Determine first and last lines of MigrateObsolete.*Pref functions.
6281 new_contents = affected_file.NewContents()
6282 range_1 = (FindLineWith(new_contents,
6283 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6284 FindLineWith(new_contents,
6285 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6286 range_2 = (FindLineWith(new_contents,
6287 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6288 FindLineWith(new_contents,
6289 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6290 if (-1 in range_1 + range_2):
6291 raise Exception(
6292 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6293 )
Dominic Battre645d42342020-12-04 16:14:106294
Sam Maiera6e76d72022-02-11 21:43:506295 # Check whether any of the modified lines are part of the
6296 # MigrateObsolete.*Pref functions.
6297 for line_nr, line in ModifiedLines(affected_file):
6298 if (range_1[0] <= line_nr <= range_1[1]
6299 or range_2[0] <= line_nr <= range_2[1]):
6300 return True
6301 return False
Dominic Battre645d42342020-12-04 16:14:106302
Sam Maiera6e76d72022-02-11 21:43:506303 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6304 browser_prefs_file_pattern = input_api.re.compile(
6305 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106306
Sam Maiera6e76d72022-02-11 21:43:506307 changes = input_api.AffectedFiles(include_deletes=True,
6308 file_filter=FilterFile)
6309 potential_problems = []
6310 for f in changes:
6311 for line in f.GenerateScmDiff().splitlines():
6312 # Check deleted lines for pref registrations.
6313 if (line.startswith('-') and not line.startswith('--')
6314 and register_pref_pattern.search(line)):
6315 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106316
Sam Maiera6e76d72022-02-11 21:43:506317 if browser_prefs_file_pattern.search(f.LocalPath()):
6318 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6319 # assume that they knew that they have to deprecate preferences and don't
6320 # warn.
6321 try:
6322 if ModifiedPrefMigration(f):
6323 return []
6324 except Exception as e:
6325 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106326
Sam Maiera6e76d72022-02-11 21:43:506327 if potential_problems:
6328 return [
6329 output_api.PresubmitPromptWarning(
6330 'Discovered possible removal of preference registrations.\n\n'
6331 'Please make sure to properly deprecate preferences by clearing their\n'
6332 'value for a couple of milestones before finally removing the code.\n'
6333 'Otherwise data may stay in the preferences files forever. See\n'
6334 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6335 'chrome/browser/prefs/README.md for examples.\n'
6336 'This may be a false positive warning (e.g. if you move preference\n'
6337 'registrations to a different place).\n', potential_problems)
6338 ]
6339 return []
6340
Matt Stark6ef08872021-07-29 01:21:466341
6342def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506343 """Changes to GRD files must be consistent for tools to read them."""
6344 changed_grds = input_api.AffectedFiles(
6345 include_deletes=False,
6346 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6347 errors = []
6348 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6349 for matcher, msg in _INVALID_GRD_FILE_LINE]
6350 for grd in changed_grds:
6351 for i, line in enumerate(grd.NewContents()):
6352 for matcher, msg in invalid_file_regexes:
6353 if matcher.search(line):
6354 errors.append(
6355 output_api.PresubmitError(
6356 'Problem on {grd}:{i} - {msg}'.format(
6357 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6358 return errors
6359
Kevin McNee967dd2d22021-11-15 16:09:296360
6361def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506362 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
6363 presence of MPArch features such as bfcache, prerendering, and fenced frames.
6364 """
Kevin McNee967dd2d22021-11-15 16:09:296365
Ian Vollickdba956c2022-04-20 23:53:456366 # Only consider top-level directories that (1) can use content APIs or
6367 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
6368 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:506369 files_to_check = (
Bruce Dawson40fece62022-09-16 19:58:316370 r'^(chrome|components|content|extensions|third_party/blink/renderer)/.+%s' %
Kevin McNee967dd2d22021-11-15 16:09:296371 _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:316372 r'^(chrome|components|content|extensions|third_party/blink/renderer)/.+%s' %
Sam Maiera6e76d72022-02-11 21:43:506373 _HEADER_EXTENSIONS,
6374 )
6375 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6376 input_api.DEFAULT_FILES_TO_SKIP)
6377 source_file_filter = lambda f: input_api.FilterSourceFile(
6378 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:296379
Kevin McNee29c0e8232022-08-05 15:36:096380 # Here we list the classes/methods we're monitoring. For the "fyi" cases,
6381 # we add the CL to the watchlist, but we don't omit a warning or have it be
6382 # included in the triage rotation.
Sam Maiera6e76d72022-02-11 21:43:506383 # Note that since these are are just regular expressions and we don't have
6384 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
6385 # could have a method named IsInMainFrame).
Kevin McNee29c0e8232022-08-05 15:36:096386 fyi_concerning_class_pattern = input_api.re.compile(
Sam Maiera6e76d72022-02-11 21:43:506387 r'WebContentsObserver|WebContentsUserData')
6388 # A subset of WebContentsObserver overrides where there's particular risk for
6389 # confusing tab and page level operations and data (e.g. incorrectly
6390 # resetting page state in DidFinishNavigation).
Kevin McNee29c0e8232022-08-05 15:36:096391 fyi_concerning_wco_methods = [
Sam Maiera6e76d72022-02-11 21:43:506392 'DidStartNavigation',
6393 'ReadyToCommitNavigation',
6394 'DidFinishNavigation',
6395 'RenderViewReady',
6396 'RenderViewDeleted',
6397 'RenderViewHostChanged',
Sam Maiera6e76d72022-02-11 21:43:506398 'DOMContentLoaded',
6399 'DidFinishLoad',
6400 ]
6401 concerning_nav_handle_methods = [
6402 'IsInMainFrame',
6403 ]
6404 concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:506405 'FromRenderFrameHost',
6406 'FromRenderViewHost',
Kevin McNee29c0e8232022-08-05 15:36:096407 ]
6408 fyi_concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:506409 'GetRenderViewHost',
6410 ]
6411 concerning_rfh_methods = [
6412 'GetParent',
6413 'GetMainFrame',
Kevin McNee29c0e8232022-08-05 15:36:096414 ]
6415 fyi_concerning_rfh_methods = [
Sam Maiera6e76d72022-02-11 21:43:506416 'GetFrameTreeNodeId',
6417 ]
Ian Vollickc825b1f2022-04-19 14:30:156418 concerning_rfhi_methods = [
6419 'is_main_frame',
6420 ]
Ian Vollicka77a73ea2022-04-06 18:08:016421 concerning_ftn_methods = [
6422 'IsMainFrame',
6423 ]
Ian Vollickdba956c2022-04-20 23:53:456424 concerning_blink_frame_methods = [
Ian Vollick4d785d22022-06-18 00:10:026425 'IsCrossOriginToNearestMainFrame',
Ian Vollickdba956c2022-04-20 23:53:456426 ]
Sam Maiera6e76d72022-02-11 21:43:506427 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
6428 item for sublist in [
Kevin McNee29c0e8232022-08-05 15:36:096429 concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:016430 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:156431 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:456432 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:506433 ] for item in sublist) + r')\(')
Kevin McNee29c0e8232022-08-05 15:36:096434 fyi_concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
6435 item for sublist in [
6436 fyi_concerning_wco_methods, fyi_concerning_web_contents_methods,
6437 fyi_concerning_rfh_methods,
6438 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:296439
Kevin McNee4eeec792022-02-14 20:02:046440 used_apis = set()
Kevin McNee29c0e8232022-08-05 15:36:096441 used_fyi_methods = False
Sam Maiera6e76d72022-02-11 21:43:506442 for f in input_api.AffectedFiles(include_deletes=False,
6443 file_filter=source_file_filter):
6444 for line_num, line in f.ChangedContents():
Kevin McNee29c0e8232022-08-05 15:36:096445 fyi_class_match = fyi_concerning_class_pattern.search(line)
6446 if fyi_class_match:
6447 used_fyi_methods = True
6448 fyi_method_match = fyi_concerning_method_pattern.search(line)
6449 if fyi_method_match:
6450 used_fyi_methods = True
Kevin McNee4eeec792022-02-14 20:02:046451 method_match = concerning_method_pattern.search(line)
6452 if method_match:
6453 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:506454
Kevin McNee4eeec792022-02-14 20:02:046455 if not used_apis:
Kevin McNee29c0e8232022-08-05 15:36:096456 if used_fyi_methods:
6457 output_api.AppendCC('[email protected]')
6458
Kevin McNee4eeec792022-02-14 20:02:046459 return []
Kevin McNee967dd2d22021-11-15 16:09:296460
Kevin McNee4eeec792022-02-14 20:02:046461 output_api.AppendCC('[email protected]')
6462 message = ('This change uses API(s) that are ambiguous in the presence of '
6463 'MPArch features such as bfcache, prerendering, and fenced '
6464 'frames.')
Kevin McNee29c0e8232022-08-05 15:36:096465 explanation = (
Kevin McNee4eeec792022-02-14 20:02:046466 'Please double check whether new code assumes that a WebContents only '
Kevin McNee29c0e8232022-08-05 15:36:096467 'contains a single page at a time. Notably, checking whether a frame '
6468 'is the \"main frame\" is not specific enough to determine whether it '
6469 'corresponds to the document reflected in the omnibox. A WebContents '
6470 'may have additional main frames for prerendered pages, bfcached '
6471 'pages, fenced frames, etc. '
6472 'See this doc [1] and the comments on the individual APIs '
Kevin McNee4eeec792022-02-14 20:02:046473 'for guidance and this doc [2] for context. The MPArch review '
6474 'watchlist has been CC\'d on this change to help identify any issues.\n'
6475 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
6476 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
6477 )
6478 return [
6479 output_api.PresubmitNotifyResult(message,
6480 items=list(used_apis),
Kevin McNee29c0e8232022-08-05 15:36:096481 long_text=explanation)
Kevin McNee4eeec792022-02-14 20:02:046482 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:366483
6484
6485def CheckAssertAshOnlyCode(input_api, output_api):
6486 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6487 assert(is_chromeos_ash).
6488 """
6489
6490 def FileFilter(affected_file):
6491 """Includes directories known to be Ash only."""
6492 return input_api.FilterSourceFile(
6493 affected_file,
6494 files_to_check=(
6495 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6496 r'.*/ash/.*BUILD\.gn'), # Any path component.
6497 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6498
6499 errors = []
6500 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566501 for f in input_api.AffectedFiles(include_deletes=False,
6502 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366503 if (not pattern.search(input_api.ReadFile(f))):
6504 errors.append(
6505 output_api.PresubmitError(
6506 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6507 'possible, please create and issue and add a comment such '
6508 'as:\n # TODO(https://crbug.com/XXX): add '
6509 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6510 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276511
6512
6513def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506514 path = affected_file.LocalPath()
6515 if not _IsCPlusPlusFile(input_api, path):
6516 return False
6517
6518 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6519 if "/renderer/" in path:
6520 return True
6521
6522 # Blink's public/web API is only used/included by Renderer-only code. Note
6523 # that public/platform API may be used in non-Renderer processes (e.g. there
6524 # are some includes in code used by Utility, PDF, or Plugin processes).
6525 if "/blink/public/web/" in path:
6526 return True
6527
6528 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276529 return False
6530
Lukasz Anforowicz7016d05e2021-11-30 03:56:276531# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6532# by the Chromium Clang Plugin (which will be preferable because it will
6533# 1) report errors earlier - at compile-time and 2) cover more rules).
6534def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506535 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6536 errors = []
6537 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6538 # C++ comment.
6539 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6540 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6541 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6542 if raw_ptr_matcher.search(line):
6543 errors.append(
6544 output_api.PresubmitError(
6545 'Problem on {path}:{line} - '\
6546 'raw_ptr<T> should not be used in Renderer-only code '\
6547 '(as documented in the "Pointers to unprotected memory" '\
6548 'section in //base/memory/raw_ptr.md)'.format(
6549 path=f.LocalPath(), line=line_num)))
6550 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566551
6552
6553def CheckPythonShebang(input_api, output_api):
6554 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6555 system-wide python.
6556 """
6557 errors = []
6558 sources = lambda affected_file: input_api.FilterSourceFile(
6559 affected_file,
6560 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6561 r'third_party/blink/web_tests/external/') + input_api.
6562 DEFAULT_FILES_TO_SKIP),
6563 files_to_check=[r'.*\.py$'])
6564 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276565 for line_num, line in f.ChangedContents():
6566 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6567 errors.append(f.LocalPath())
6568 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566569
6570 result = []
6571 for file in errors:
6572 result.append(
6573 output_api.PresubmitError(
6574 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6575 file))
6576 return result
James Shen81cc0e22022-06-15 21:10:456577
6578
6579def CheckBatchAnnotation(input_api, output_api):
6580 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6581 is not an instrumentation test, disregard."""
6582
6583 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6584 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6585 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6586 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6587 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6588
ckitagawae8fd23b2022-06-17 15:29:386589 missing_annotation_errors = []
6590 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456591
6592 def _FilterFile(affected_file):
6593 return input_api.FilterSourceFile(
6594 affected_file,
6595 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6596 files_to_check=[r'.*Test\.java$'])
6597
6598 for f in input_api.AffectedSourceFiles(_FilterFile):
6599 batch_matched = None
6600 do_not_batch_matched = None
6601 is_instrumentation_test = True
6602 for line in f.NewContents():
6603 if robolectric_test.search(line) or uiautomator_test.search(line):
6604 # Skip Robolectric and UiAutomator tests.
6605 is_instrumentation_test = False
6606 break
6607 if not batch_matched:
6608 batch_matched = batch_annotation.search(line)
6609 if not do_not_batch_matched:
6610 do_not_batch_matched = do_not_batch_annotation.search(line)
6611 test_class_declaration_matched = test_class_declaration.search(
6612 line)
6613 if test_class_declaration_matched:
6614 break
6615 if (is_instrumentation_test and
6616 not batch_matched and
6617 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246618 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386619 if (not is_instrumentation_test and
6620 (batch_matched or
6621 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246622 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456623
6624 results = []
6625
ckitagawae8fd23b2022-06-17 15:29:386626 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456627 results.append(
6628 output_api.PresubmitPromptWarning(
6629 """
6630Instrumentation tests should use either @Batch or @DoNotBatch. If tests are not
6631safe to run in batch, please use @DoNotBatch with reasons.
ckitagawae8fd23b2022-06-17 15:29:386632""", missing_annotation_errors))
6633 if extra_annotation_errors:
6634 results.append(
6635 output_api.PresubmitPromptWarning(
6636 """
6637Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6638""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456639
6640 return results
Sam Maier4cef9242022-10-03 14:21:246641
6642
6643def CheckMockAnnotation(input_api, output_api):
6644 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6645 classes with @Mock or @Spy. If this is not an instrumentation test,
6646 disregard."""
6647
6648 # This is just trying to be approximately correct. We are not writing a
6649 # Java parser, so special cases like statically importing mock() then
6650 # calling an unrelated non-mockito spy() function will cause a false
6651 # positive.
6652 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6653 mock_static_import = input_api.re.compile(
6654 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6655 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6656 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6657 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6658 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6659 fully_qualified_mock_function = input_api.re.compile(
6660 r'Mockito\.' + mock_or_spy_function_call)
6661 statically_imported_mock_function = input_api.re.compile(
6662 r'\W' + mock_or_spy_function_call)
6663 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6664 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6665
6666 def _DoClassLookup(class_name, class_name_map, package):
6667 found = class_name_map.get(class_name)
6668 if found is not None:
6669 return found
6670 else:
6671 return package + '.' + class_name
6672
6673 def _FilterFile(affected_file):
6674 return input_api.FilterSourceFile(
6675 affected_file,
6676 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6677 files_to_check=[r'.*Test\.java$'])
6678
6679 mocked_by_function_classes = set()
6680 mocked_by_annotation_classes = set()
6681 class_to_filename = {}
6682 for f in input_api.AffectedSourceFiles(_FilterFile):
6683 mock_function_regex = fully_qualified_mock_function
6684 next_line_is_annotated = False
6685 fully_qualified_class_map = {}
6686 package = None
6687
6688 for line in f.NewContents():
6689 if robolectric_test.search(line) or uiautomator_test.search(line):
6690 # Skip Robolectric and UiAutomator tests.
6691 break
6692
6693 m = package_name.search(line)
6694 if m:
6695 package = m.group(1)
6696 continue
6697
6698 if mock_static_import.search(line):
6699 mock_function_regex = statically_imported_mock_function
6700 continue
6701
6702 m = import_class.search(line)
6703 if m:
6704 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
6705 continue
6706
6707 if next_line_is_annotated:
6708 next_line_is_annotated = False
6709 fully_qualified_class = _DoClassLookup(
6710 field_type.search(line).group(1), fully_qualified_class_map,
6711 package)
6712 mocked_by_annotation_classes.add(fully_qualified_class)
6713 continue
6714
6715 if mock_annotation.search(line):
6716 next_line_is_annotated = True
6717 continue
6718
6719 m = mock_function_regex.search(line)
6720 if m:
6721 fully_qualified_class = _DoClassLookup(m.group(1),
6722 fully_qualified_class_map, package)
6723 # Skipping builtin classes, since they don't get optimized.
6724 if fully_qualified_class.startswith(
6725 'android.') or fully_qualified_class.startswith(
6726 'java.'):
6727 continue
6728 class_to_filename[fully_qualified_class] = str(f.LocalPath())
6729 mocked_by_function_classes.add(fully_qualified_class)
6730
6731 results = []
6732 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
6733 if missed_classes:
6734 error_locations = []
6735 for c in missed_classes:
6736 error_locations.append(c + ' in ' + class_to_filename[c])
6737 results.append(
6738 output_api.PresubmitPromptWarning(
6739 """
6740Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
67411) If the mocked variable can be a class member, annotate the member with
6742 @Mock/@Spy.
67432) If the mocked variable cannot be a class member, create a dummy member
6744 variable of that type, annotated with @Mock/@Spy. This dummy does not need
6745 to be used or initialized in any way.
67463) If the mocked type is definitely not going to be optimized, whether it's a
6747 builtin type which we don't ship, or a class you know R8 will treat
6748 specially, you can ignore this warning.
6749""", error_locations))
6750
6751 return results
Mike Dougherty1b8be712022-10-20 00:15:136752
6753def CheckNoJsInIos(input_api, output_api):
6754 """Checks to make sure that JavaScript files are not used on iOS."""
6755
6756 def _FilterFile(affected_file):
6757 return input_api.FilterSourceFile(
6758 affected_file,
6759 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
6760 (r'^ios/third_party/*', r'^third_party/*'),
6761 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
6762
6763 error_paths = []
6764 warning_paths = []
6765
6766 for f in input_api.AffectedSourceFiles(_FilterFile):
6767 local_path = f.LocalPath()
6768
6769 if input_api.os_path.splitext(local_path)[1] == '.js':
6770 if f.Action() == 'A':
6771 error_paths.append(local_path)
6772 elif f.Action() != 'D':
6773 warning_paths.append(local_path)
6774
6775 results = []
6776
6777 if warning_paths:
6778 results.append(output_api.PresubmitPromptWarning(
6779 'TypeScript is now fully supported for iOS feature scripts. '
6780 'Consider converting JavaScript files to TypeScript. See '
6781 '//ios/web/public/js_messaging/README.md for more details.',
6782 warning_paths))
6783
6784 if error_paths:
6785 results.append(output_api.PresubmitError(
6786 'Do not use JavaScript on iOS as TypeScript is fully supported. '
6787 'See //ios/web/public/js_messaging/README.md for help using '
6788 'scripts on iOS.', error_paths))
6789
6790 return results