blob: 4d066d7bbd147f76fabceb2fd86b9f7c65f3f066 [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 ),
Min Qinbc44383c2023-02-22 17:25:26188 BanRule(
189 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
190 (
191 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
192 'avoid extra indirections. Please also add trace event as the call '
193 'might take more than 20 ms to complete.',
194 ),
195 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15196)
wnwenbdc444e2016-05-25 13:44:15197
Daniel Cheng917ce542022-03-15 20:46:57198_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15199 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41200 'StrictMode.allowThreadDiskReads()',
201 (
202 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
203 'directly.',
204 ),
205 False,
206 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15207 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41208 'StrictMode.allowThreadDiskWrites()',
209 (
210 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
211 'directly.',
212 ),
213 False,
214 ),
Daniel Cheng917ce542022-03-15 20:46:57215 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36216 '.waitForIdleSync()',
217 (
218 'Do not use waitForIdleSync as it masks underlying issues. There is '
219 'almost always something else you should wait on instead.',
220 ),
221 False,
222 ),
Ashley Newson09cbd602022-10-26 11:40:14223 BanRule(
Ashley Newsoneb6f5ce2022-10-26 14:45:42224 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14225 (
226 'Do not call android.content.Context.registerReceiver (or an override) '
227 'directly. Use one of the wrapper methods defined in '
228 'org.chromium.base.ContextUtils, such as '
229 'registerProtectedBroadcastReceiver, '
230 'registerExportedBroadcastReceiver, or '
231 'registerNonExportedBroadcastReceiver. See their documentation for '
232 'which one to use.',
233 ),
234 True,
235 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57236 r'.*Test[^a-z]',
237 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14238 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38239 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14240 ),
241 ),
Ted Chocd5b327b12022-11-05 02:13:22242 BanRule(
243 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
244 (
245 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
246 'IntProperty because it will avoid unnecessary autoboxing of '
247 'primitives.',
248 ),
249 ),
Peilin Wangbba4a8652022-11-10 16:33:57250 BanRule(
251 'requestLayout()',
252 (
253 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
254 'which emits a trace event with additional information to help with '
255 'scroll jank investigations. See http://crbug.com/1354176.',
256 ),
257 False,
258 excluded_paths=(
259 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
260 ),
261 ),
Ted Chocf40ea9152023-02-14 19:02:39262 BanRule(
263 'Profile.getLastUsedRegularProfile()',
264 (
265 'Prefer passing in the Profile reference instead of relying on the '
266 'static getLastUsedRegularProfile() call. Only top level entry points '
267 '(e.g. Activities) should call this method. Otherwise, the Profile '
268 'should either be passed in explicitly or retreived from an existing '
269 'entity with a reference to the Profile (e.g. WebContents).',
270 ),
271 False,
272 excluded_paths=(
273 r'.*Test[A-Z]?.*\.java',
274 ),
275 ),
Min Qinbc44383c2023-02-22 17:25:26276 BanRule(
277 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
278 (
279 'getDrawable() can be expensive. If you have a lot of calls to '
280 'GetDrawable() or your code may introduce janks, please put your calls '
281 'inside a trace().',
282 ),
283 False,
284 excluded_paths=(
285 r'.*Test[A-Z]?.*\.java',
286 ),
287 ),
Eric Stevensona9a980972017-09-23 00:04:41288)
289
Clement Yan9b330cb2022-11-17 05:25:29290_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
291 BanRule(
292 r'/\bchrome\.send\b',
293 (
294 '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).',
295 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
296 ),
297 True,
298 (
299 r'^(?!ash\/webui).+',
300 # TODO(crbug.com/1385601): pre-existing violations still need to be
301 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58302 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29303 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
304 'ash/webui/common/resources/quick_unlock/lock_screen_constants.js',
305 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
306 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.js',
307 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
308 'ash/webui/multidevice_debug/resources/logs.js',
309 'ash/webui/multidevice_debug/resources/webui.js',
310 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
311 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
312 'ash/webui/scanning/resources/scanning_browser_proxy.js',
313 ),
314 ),
315)
316
Daniel Cheng917ce542022-03-15 20:46:57317_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15318 BanRule(
[email protected]127f18ec2012-06-16 05:05:59319 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20320 (
321 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59322 'prohibited. Please use CrTrackingArea instead.',
323 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
324 ),
325 False,
326 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15327 BanRule(
[email protected]eaae1972014-04-16 04:17:26328 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20329 (
330 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59331 'instead.',
332 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
333 ),
334 False,
335 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15336 BanRule(
[email protected]127f18ec2012-06-16 05:05:59337 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20338 (
339 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59340 'Please use |convertPoint:(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 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20347 (
348 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59349 'Please use |convertPoint:(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(
[email protected]127f18ec2012-06-16 05:05:59355 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20356 (
357 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59358 'Please use |convertRect:(point) fromView:nil| instead.',
359 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
360 ),
361 True,
362 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15363 BanRule(
[email protected]127f18ec2012-06-16 05:05:59364 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20365 (
366 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59367 'Please use |convertRect:(point) toView:nil| instead.',
368 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
369 ),
370 True,
371 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15372 BanRule(
[email protected]127f18ec2012-06-16 05:05:59373 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20374 (
375 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59376 'Please use |convertSize:(point) fromView:nil| instead.',
377 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
378 ),
379 True,
380 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15381 BanRule(
[email protected]127f18ec2012-06-16 05:05:59382 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20383 (
384 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59385 'Please use |convertSize:(point) toView:nil| instead.',
386 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
387 ),
388 True,
389 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15390 BanRule(
jif65398702016-10-27 10:19:48391 r"/\s+UTF8String\s*]",
392 (
393 'The use of -[NSString UTF8String] is dangerous as it can return null',
394 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
395 'Please use |SysNSStringToUTF8| instead.',
396 ),
397 True,
398 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15399 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34400 r'__unsafe_unretained',
401 (
402 'The use of __unsafe_unretained is almost certainly wrong, unless',
403 'when interacting with NSFastEnumeration or NSInvocation.',
404 'Please use __weak in files build with ARC, nothing otherwise.',
405 ),
406 False,
407 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15408 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13409 'freeWhenDone:NO',
410 (
411 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
412 'Foundation types is prohibited.',
413 ),
414 True,
415 ),
[email protected]127f18ec2012-06-16 05:05:59416)
417
Sylvain Defresnea8b73d252018-02-28 15:45:54418_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15419 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54420 r'/\bTEST[(]',
421 (
422 'TEST() macro should not be used in Objective-C++ code as it does not ',
423 'drain the autorelease pool at the end of the test. Use TEST_F() ',
424 'macro instead with a fixture inheriting from PlatformTest (or a ',
425 'typedef).'
426 ),
427 True,
428 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15429 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54430 r'/\btesting::Test\b',
431 (
432 'testing::Test should not be used in Objective-C++ code as it does ',
433 'not drain the autorelease pool at the end of the test. Use ',
434 'PlatformTest instead.'
435 ),
436 True,
437 ),
Ewann2ecc8d72022-07-18 07:41:23438 BanRule(
439 ' systemImageNamed:',
440 (
441 '+[UIImage systemImageNamed:] should not be used to create symbols.',
442 'Instead use a wrapper defined in:',
Victor Vianna77a40f62023-01-31 19:04:53443 'ios/chrome/browser/ui/icons/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23444 ),
445 True,
Ewann450a2ef2022-07-19 14:38:23446 excluded_paths=(
Victor Vianna77a40f62023-01-31 19:04:53447 'ios/chrome/browser/ui/icons/symbol_helpers.mm',
Ewann450a2ef2022-07-19 14:38:23448 ),
Ewann2ecc8d72022-07-18 07:41:23449 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54450)
451
Daniel Cheng917ce542022-03-15 20:46:57452_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15453 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05454 r'/\bEXPECT_OCMOCK_VERIFY\b',
455 (
456 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
457 'it is meant for GTests. Use [mock verify] instead.'
458 ),
459 True,
460 ),
461)
462
Daniel Cheng917ce542022-03-15 20:46:57463_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15464 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04465 r'/\busing namespace ',
466 (
467 'Using directives ("using namespace x") are banned by the Google Style',
468 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
469 'Explicitly qualify symbols or use using declarations ("using x::foo").',
470 ),
471 True,
472 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
473 ),
Antonio Gomes07300d02019-03-13 20:59:57474 # Make sure that gtest's FRIEND_TEST() macro is not used; the
475 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
476 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15477 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20478 'FRIEND_TEST(',
479 (
[email protected]e3c945502012-06-26 20:01:49480 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20481 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
482 ),
483 False,
[email protected]7345da02012-11-27 14:31:49484 (),
[email protected]23e6cbc2012-06-16 18:51:20485 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15486 BanRule(
tomhudsone2c14d552016-05-26 17:07:46487 'setMatrixClip',
488 (
489 'Overriding setMatrixClip() is prohibited; ',
490 'the base function is deprecated. ',
491 ),
492 True,
493 (),
494 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15495 BanRule(
[email protected]52657f62013-05-20 05:30:31496 'SkRefPtr',
497 (
498 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22499 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31500 ),
501 True,
502 (),
503 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15504 BanRule(
[email protected]52657f62013-05-20 05:30:31505 'SkAutoRef',
506 (
507 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22508 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31509 ),
510 True,
511 (),
512 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15513 BanRule(
[email protected]52657f62013-05-20 05:30:31514 'SkAutoTUnref',
515 (
516 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22517 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31518 ),
519 True,
520 (),
521 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15522 BanRule(
[email protected]52657f62013-05-20 05:30:31523 'SkAutoUnref',
524 (
525 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
526 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22527 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31528 ),
529 True,
530 (),
531 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15532 BanRule(
[email protected]d89eec82013-12-03 14:10:59533 r'/HANDLE_EINTR\(.*close',
534 (
535 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
536 'descriptor will be closed, and it is incorrect to retry the close.',
537 'Either call close directly and ignore its return value, or wrap close',
538 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
539 ),
540 True,
541 (),
542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15543 BanRule(
[email protected]d89eec82013-12-03 14:10:59544 r'/IGNORE_EINTR\((?!.*close)',
545 (
546 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
547 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
548 ),
549 True,
550 (
551 # Files that #define IGNORE_EINTR.
Bruce Dawson40fece62022-09-16 19:58:31552 r'^base/posix/eintr_wrapper\.h$',
553 r'^ppapi/tests/test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59554 ),
555 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15556 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43557 r'/v8::Extension\(',
558 (
559 'Do not introduce new v8::Extensions into the code base, use',
560 'gin::Wrappable instead. See http://crbug.com/334679',
561 ),
562 True,
[email protected]f55c90ee62014-04-12 00:50:03563 (
Bruce Dawson40fece62022-09-16 19:58:31564 r'extensions/renderer/safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03565 ),
[email protected]ec5b3f02014-04-04 18:43:43566 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15567 BanRule(
jame2d1a952016-04-02 00:27:10568 '#pragma comment(lib,',
569 (
570 'Specify libraries to link with in build files and not in the source.',
571 ),
572 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41573 (
Bruce Dawson40fece62022-09-16 19:58:31574 r'^base/third_party/symbolize/.*',
575 r'^third_party/abseil-cpp/.*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41576 ),
jame2d1a952016-04-02 00:27:10577 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15578 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02579 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59580 (
581 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
582 ),
583 False,
584 (),
585 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15586 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02587 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59588 (
589 'Consider using THREAD_CHECKER macros instead of the class directly.',
590 ),
591 False,
592 (),
593 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15594 BanRule(
Sean Maher03efef12022-09-23 22:43:13595 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
596 (
597 'It is not allowed to call these methods from the subclasses ',
598 'of Sequenced or SingleThread task runners.',
599 ),
600 True,
601 (),
602 ),
603 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06604 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
605 (
606 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
607 'deprecated (http://crbug.com/634507). Please avoid converting away',
608 'from the Time types in Chromium code, especially if any math is',
609 'being done on time values. For interfacing with platform/library',
610 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
611 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48612 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06613 'other use cases, please contact base/time/OWNERS.',
614 ),
615 False,
616 (),
617 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15618 BanRule(
dbeamb6f4fde2017-06-15 04:03:06619 'CallJavascriptFunctionUnsafe',
620 (
621 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
622 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
623 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
624 ),
625 False,
626 (
Bruce Dawson40fece62022-09-16 19:58:31627 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
628 r'^content/public/browser/web_ui\.h$',
629 r'^content/public/test/test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06630 ),
631 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15632 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24633 'leveldb::DB::Open',
634 (
635 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
636 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
637 "Chrome's tracing, making their memory usage visible.",
638 ),
639 True,
640 (
641 r'^third_party/leveldatabase/.*\.(cc|h)$',
642 ),
Gabriel Charette0592c3a2017-07-26 12:02:04643 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15644 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08645 'leveldb::NewMemEnv',
646 (
647 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58648 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
649 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08650 ),
651 True,
652 (
653 r'^third_party/leveldatabase/.*\.(cc|h)$',
654 ),
655 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15656 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47657 'RunLoop::QuitCurrent',
658 (
Robert Liao64b7ab22017-08-04 23:03:43659 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
660 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47661 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41662 False,
Gabriel Charetted9839bc2017-07-29 14:17:47663 (),
Gabriel Charettea44975052017-08-21 23:14:04664 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15665 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04666 'base::ScopedMockTimeMessageLoopTaskRunner',
667 (
Gabriel Charette87cc1af2018-04-25 20:52:51668 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11669 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51670 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
671 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
672 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04673 ),
Gabriel Charette87cc1af2018-04-25 20:52:51674 False,
Gabriel Charettea44975052017-08-21 23:14:04675 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57676 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15677 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44678 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57679 (
680 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02681 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57682 ),
683 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16684 # Abseil's benchmarks never linked into chrome.
685 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38686 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15687 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08688 r'/\bstd::sto(i|l|ul|ll|ull)\b',
Peter Kasting991618a62019-06-17 22:00:09689 (
Peter Kastinge2c5ee82023-02-15 17:23:08690 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
691 'Use base::StringTo[U]Int[64]() instead.',
Peter Kasting991618a62019-06-17 22:00:09692 ),
693 True,
694 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
695 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15696 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08697 r'/\bstd::sto(f|d|ld)\b',
Peter Kasting991618a62019-06-17 22:00:09698 (
Peter Kastinge2c5ee82023-02-15 17:23:08699 'std::sto{f,d,ld}() use exceptions to communicate results. ',
Peter Kasting991618a62019-06-17 22:00:09700 '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(
Daniel Bratell69334cc2019-03-26 11:07:45708 r'/\bstd::to_string\b',
709 (
Peter Kastinge2c5ee82023-02-15 17:23:08710 'std::to_string() is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09711 'For locale-independent strings, e.g. writing numbers to disk',
712 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45713 'For user-visible strings, use base::FormatNumber() and',
714 'the related functions in base/i18n/number_formatting.h.',
715 ),
Peter Kasting991618a62019-06-17 22:00:09716 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21717 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45718 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15719 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45720 r'/\bstd::shared_ptr\b',
721 (
Peter Kastinge2c5ee82023-02-15 17:23:08722 'std::shared_ptr is banned. Use scoped_refptr instead.',
Daniel Bratell69334cc2019-03-26 11:07:45723 ),
724 True,
Ulan Degenbaev947043882021-02-10 14:02:31725 [
726 # Needed for interop with third-party library.
727 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57728 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58729 '^third_party/blink/renderer/bindings/core/v8/' +
730 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58731 '^gin/array_buffer\.(cc|h)',
732 '^chrome/services/sharing/nearby/',
Stephen Nuskoe09c8ef22022-09-29 00:47:28733 # Needed for interop with third-party library libunwindstack.
Stephen Nuskoe51c1382022-09-26 15:49:03734 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
Bob Beck03509d282022-12-07 21:49:05735 # Needed for interop with third-party boringssl cert verifier
736 '^third_party/boringssl/',
737 '^net/cert/',
738 '^net/tools/cert_verify_tool/',
739 '^services/cert_verifier/',
740 '^components/certificate_transparency/',
741 '^components/media_router/common/providers/cast/certificate/',
Meilin Wang00efc7c2021-05-13 01:12:42742 # gRPC provides some C++ libraries that use std::shared_ptr<>.
Yeunjoo Choi1b644402022-08-25 02:36:10743 '^chromeos/ash/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59744 '^chromecast/cast_core/grpc',
745 '^chromecast/cast_core/runtime/browser',
Yue Shef83d95202022-09-26 20:23:45746 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Wez5f56be52021-05-04 09:30:58747 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Wez6da2e412022-11-23 11:28:48748 '^base/fuchsia/.*\.(cc|h)',
Wez5f56be52021-05-04 09:30:58749 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57750 # Needed for clang plugin tests
751 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57752 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21753 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15754 BanRule(
Peter Kasting991618a62019-06-17 22:00:09755 r'/\bstd::weak_ptr\b',
756 (
Peter Kastinge2c5ee82023-02-15 17:23:08757 'std::weak_ptr is banned. Use base::WeakPtr instead.',
Peter Kasting991618a62019-06-17 22:00:09758 ),
759 True,
760 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
761 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15762 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21763 r'/\blong long\b',
764 (
Peter Kastinge2c5ee82023-02-15 17:23:08765 'long long is banned. Use [u]int64_t instead.',
Daniel Bratell609102be2019-03-27 20:53:21766 ),
767 False, # Only a warning since it is already used.
768 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
769 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15770 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44771 r'/\b(absl|std)::any\b',
Daniel Chengc05fcc62022-01-12 16:54:29772 (
Peter Kastinge2c5ee82023-02-15 17:23:08773 '{absl,std}::any are banned due to incompatibility with the component ',
774 'build.',
Daniel Chengc05fcc62022-01-12 16:54:29775 ),
776 True,
777 # Not an error in third party folders, though it probably should be :)
778 [_THIRD_PARTY_EXCEPT_BLINK],
779 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15780 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21781 r'/\bstd::bind\b',
782 (
Peter Kastinge2c5ee82023-02-15 17:23:08783 'std::bind() is banned because of lifetime risks. Use ',
784 'base::Bind{Once,Repeating}() instead.',
Daniel Bratell609102be2019-03-27 20:53:21785 ),
786 True,
787 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
788 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15789 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44790 (
791 r'/\b(?:'
792 r'std::linear_congruential_engine|std::mersenne_twister_engine|'
793 r'std::subtract_with_carry_engine|std::discard_block_engine|'
794 r'std::independent_bits_engine|std::shuffle_order_engine|'
795 r'std::minstd_rand0|std::minstd_rand|'
796 r'std::mt19937|std::mt19937_64|'
797 r'std::ranlux24_base|std::ranlux48_base|std::ranlux24|std::ranlux48|'
798 r'std::knuth_b|'
799 r'std::default_random_engine|'
800 r'std::random_device'
801 r')\b'
802 ),
803 (
804 'STL random number engines and generators are banned. Use the ',
805 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
806 'base::RandomBitGenerator.'
807 ),
808 True,
809 [
810 # Not an error in third_party folders.
811 _THIRD_PARTY_EXCEPT_BLINK,
812 # Various tools which build outside of Chrome.
813 r'testing/libfuzzer',
814 r'tools/android/io_benchmark/',
815 # Fuzzers are allowed to use standard library random number generators
816 # since fuzzing speed + reproducibility is important.
817 r'tools/ipc_fuzzer/',
818 r'.+_fuzzer\.cc$',
819 r'.+_fuzzertest\.cc$',
820 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
821 # the standard library's random number generators, and should be
822 # migrated to the //base equivalent.
823 r'ash/ambient/model/ambient_topic_queue\.cc',
824 r'base/allocator/partition_allocator/partition_alloc_unittest\.cc',
825 r'base/ranges/algorithm_unittest\.cc',
826 r'base/test/launcher/test_launcher\.cc',
827 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
828 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
829 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
830 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
831 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
832 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
833 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
834 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
835 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
836 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
837 r'chrome/chrome_cleaner/logging/detailed_info_sampler\.cc',
838 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
839 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
840 r'components/metrics/metrics_state_manager\.cc',
841 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
842 r'components/zucchini/disassembler_elf_unittest\.cc',
843 r'content/browser/webid/federated_auth_request_impl\.cc',
844 r'content/browser/webid/federated_auth_request_impl\.cc',
845 r'media/cast/test/utility/udp_proxy\.h',
846 r'sql/recover_module/module_unittest\.cc',
847 ],
848 ),
849 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08850 r'/\b(absl,std)::bind_front\b',
Peter Kasting4f35bfc2022-10-18 18:39:12851 (
Peter Kastinge2c5ee82023-02-15 17:23:08852 '{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
853 'instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12854 ),
855 True,
856 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
857 ),
858 BanRule(
859 r'/\bABSL_FLAG\b',
860 (
861 'ABSL_FLAG is banned. Use base::CommandLine instead.',
862 ),
863 True,
864 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
865 ),
866 BanRule(
867 r'/\babsl::c_',
868 (
Peter Kastinge2c5ee82023-02-15 17:23:08869 'Abseil container utilities are banned. Use base/ranges/algorithm.h ',
Peter Kasting4f35bfc2022-10-18 18:39:12870 'instead.',
871 ),
872 True,
873 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
874 ),
875 BanRule(
876 r'/\babsl::FunctionRef\b',
877 (
878 'absl::FunctionRef is banned. Use base::FunctionRef instead.',
879 ),
880 True,
881 [
882 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
883 # interoperability.
884 r'^base/functional/bind_internal\.h',
885 # base::FunctionRef is implemented on top of absl::FunctionRef.
886 r'^base/functional/function_ref.*\..+',
887 # Not an error in third_party folders.
888 _THIRD_PARTY_EXCEPT_BLINK,
889 ],
890 ),
891 BanRule(
892 r'/\babsl::(Insecure)?BitGen\b',
893 (
Daniel Cheng192683f2022-11-01 20:52:44894 'absl random number generators are banned. Use the helpers in '
895 'base/rand_util.h instead, e.g. base::RandBytes() or ',
896 'base::RandomBitGenerator.'
Peter Kasting4f35bfc2022-10-18 18:39:12897 ),
898 True,
899 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
900 ),
901 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08902 r'/(\babsl::Span\b|#include <span>)',
Peter Kasting4f35bfc2022-10-18 18:39:12903 (
Peter Kastinge2c5ee82023-02-15 17:23:08904 'absl::Span is banned and <span> is not allowed yet ',
905 '(https://crbug.com/1414652). Use base::span instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12906 ),
907 True,
Victor Vasiliev23b9ea6a2023-01-05 19:42:29908 [
909 # Needed to use QUICHE API.
910 r'services/network/web_transport\.cc',
911 # Not an error in third_party folders.
912 _THIRD_PARTY_EXCEPT_BLINK
913 ],
Peter Kasting4f35bfc2022-10-18 18:39:12914 ),
915 BanRule(
916 r'/\babsl::StatusOr\b',
917 (
918 'absl::StatusOr is banned. Use base::expected instead.',
919 ),
920 True,
Adithya Srinivasanb2041882022-10-21 19:34:20921 [
922 # Needed to use liburlpattern API.
923 r'third_party/blink/renderer/core/url_pattern/.*',
924 # Not an error in third_party folders.
925 _THIRD_PARTY_EXCEPT_BLINK
926 ],
Peter Kasting4f35bfc2022-10-18 18:39:12927 ),
928 BanRule(
929 r'/\babsl::StrFormat\b',
930 (
Peter Kastinge2c5ee82023-02-15 17:23:08931 'absl::StrFormat() is not allowed yet (https://crbug.com/1371963). ',
932 'Use base::StringPrintf() instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12933 ),
934 True,
935 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
936 ),
937 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08938 r'/\b(absl|std)::(u16)?string_view\b',
Peter Kasting4f35bfc2022-10-18 18:39:12939 (
Peter Kastinge2c5ee82023-02-15 17:23:08940 'absl::string_view is banned and std::[u16]string_view are not allowed',
941 ' yet (https://crbug.com/691162). Use base::StringPiece[16] instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12942 ),
943 True,
Adithya Srinivasanb2041882022-10-21 19:34:20944 [
945 # Needed to use liburlpattern API.
946 r'third_party/blink/renderer/core/url_pattern/.*',
David Benjamin3a305f12022-11-19 00:10:03947 # Needed to use QUICHE API.
Victor Vasilieva13f1932022-12-02 15:27:24948 r'net/quic/.*',
949 r'net/spdy/.*',
David Benjamin3a305f12022-11-19 00:10:03950 r'net/test/embedded_test_server/.*',
Victor Vasilieva13f1932022-12-02 15:27:24951 r'net/third_party/quiche/.*',
952 r'services/network/web_transport\.cc',
Adithya Srinivasanb2041882022-10-21 19:34:20953 # Not an error in third_party folders.
954 _THIRD_PARTY_EXCEPT_BLINK
955 ],
Peter Kasting4f35bfc2022-10-18 18:39:12956 ),
957 BanRule(
958 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
959 (
960 'Abseil string utilities are banned. Use base/strings instead.',
961 ),
962 True,
963 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
964 ),
965 BanRule(
966 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
967 (
968 'Abseil synchronization primitives are banned. Use',
969 'base/synchronization instead.',
970 ),
971 True,
972 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
973 ),
974 BanRule(
975 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
976 (
977 'Abseil\'s time library is banned. Use base/time instead.',
978 ),
979 True,
980 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
981 ),
982 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:03983 r'/\bstd::optional\b',
984 (
Peter Kastinge2c5ee82023-02-15 17:23:08985 'std::optional is not allowed yet (https://crbug.com/1373619). Use ',
986 'absl::optional instead.',
Avi Drissman48ee39e2022-02-16 16:31:03987 ),
988 True,
989 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
990 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15991 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08992 r'/#include <chrono>',
Daniel Bratell609102be2019-03-27 20:53:21993 (
Peter Kastinge2c5ee82023-02-15 17:23:08994 '<chrono> is banned. Use base/time instead.',
Daniel Bratell609102be2019-03-27 20:53:21995 ),
996 True,
997 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
998 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15999 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081000 r'/#include <exception>',
Daniel Bratell609102be2019-03-27 20:53:211001 (
1002 'Exceptions are banned and disabled in Chromium.',
1003 ),
1004 True,
1005 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1006 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151007 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211008 r'/\bstd::function\b',
1009 (
Peter Kastinge2c5ee82023-02-15 17:23:081010 'std::function is banned. Use base::{Once,Repeating}Callback instead.',
Daniel Bratell609102be2019-03-27 20:53:211011 ),
Daniel Chenge5583e3c2022-09-22 00:19:411012 True,
Daniel Chengcd23b8b2022-09-16 17:16:241013 [
1014 # Has tests that template trait helpers don't unintentionally match
1015 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:411016 r'base/functional/callback_helpers_unittest\.cc',
1017 # Required to implement interfaces from the third-party perfetto
1018 # library.
1019 r'base/tracing/perfetto_task_runner\.cc',
1020 r'base/tracing/perfetto_task_runner\.h',
1021 # Needed for interop with the third-party nearby library type
1022 # location::nearby::connections::ResultCallback.
1023 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1024 # Needed for interop with the internal libassistant library.
1025 'chromeos/ash/services/libassistant/callback_utils\.h',
1026 # Needed for interop with Fuchsia fidl APIs.
1027 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1028 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1029 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1030 # Required to interop with interfaces from the third-party perfetto
1031 # library.
1032 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1033 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1034 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1035 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1036 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1037 'services/tracing/public/cpp/perfetto/producer_client\.h',
1038 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1039 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1040 # Required for interop with the third-party webrtc library.
1041 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1042 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Bob Beck5fc0be82022-12-12 23:32:521043 # This code is in the process of being extracted into a third-party library.
1044 # See https://crbug.com/1322914
1045 '^net/cert/pki/path_builder_unittest\.cc',
Daniel Chenge5583e3c2022-09-22 00:19:411046 # TODO(https://crbug.com/1364577): Various uses that should be
1047 # migrated to something else.
1048 # Should use base::OnceCallback or base::RepeatingCallback.
1049 'base/allocator/dispatcher/initializer_unittest\.cc',
1050 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1051 'chrome/browser/ash/accessibility/speech_monitor\.h',
1052 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1053 'chromecast/base/observer_unittest\.cc',
1054 'chromecast/browser/cast_web_view\.h',
1055 'chromecast/public/cast_media_shlib\.h',
1056 'device/bluetooth/floss/exported_callback_manager\.h',
1057 'device/bluetooth/floss/floss_dbus_client\.h',
1058 'device/fido/cable/v2_handshake_unittest\.cc',
1059 'device/fido/pin\.cc',
1060 'services/tracing/perfetto/test_utils\.h',
1061 # Should use base::FunctionRef.
1062 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1063 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1064 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1065 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1066 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1067 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1068 # Does not need std::function at all.
1069 'components/omnibox/browser/autocomplete_result\.cc',
1070 'device/fido/win/webauthn_api\.cc',
1071 'media/audio/alsa/alsa_util\.cc',
1072 'media/remoting/stream_provider\.h',
1073 'sql/vfs_wrapper\.cc',
1074 # TODO(https://crbug.com/1364585): Remove usage and exception list
1075 # entries.
1076 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1077 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1078 # TODO(https://crbug.com/1364579): Remove usage and exception list
1079 # entry.
1080 'ui/views/controls/focus_ring\.h',
1081
1082 # Various pre-existing uses in //tools that is low-priority to fix.
1083 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1084 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1085 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1086 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1087 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
1088
Daniel Chengcd23b8b2022-09-16 17:16:241089 # Not an error in third_party folders.
1090 _THIRD_PARTY_EXCEPT_BLINK
1091 ],
Daniel Bratell609102be2019-03-27 20:53:211092 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151093 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081094 r'/#include <random>',
Daniel Bratell609102be2019-03-27 20:53:211095 (
Peter Kastinge2c5ee82023-02-15 17:23:081096 '<random> is banned. Use base::RandomBitGenerator instead.',
Daniel Bratell609102be2019-03-27 20:53:211097 ),
1098 True,
1099 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1100 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151101 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081102 r'/#include <X11/',
Tom Andersona95e12042020-09-09 23:08:001103 (
1104 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
1105 ),
1106 True,
1107 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1108 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151109 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211110 r'/\bstd::ratio\b',
1111 (
1112 'std::ratio is banned by the Google Style Guide.',
1113 ),
1114 True,
1115 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451116 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151117 BanRule(
Peter Kasting6d77e9d2023-02-09 21:58:181118 r'/\bstd::aligned_alloc\b',
1119 (
Peter Kastinge2c5ee82023-02-15 17:23:081120 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1121 'base::AlignedAlloc() instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181122 ),
1123 True,
1124 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1125 ),
1126 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081127 r'/\bstd::(u16)?string_view\b',
Peter Kasting6d77e9d2023-02-09 21:58:181128 (
Peter Kastinge2c5ee82023-02-15 17:23:081129 'std::[u16]string_view is not yet allowed (crbug.com/691162). Use ',
1130 'base::StringPiece[16] instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181131 ),
1132 True,
1133 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1134 ),
1135 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081136 r'/#include <(barrier|latch|semaphore|stop_token)>',
Peter Kasting6d77e9d2023-02-09 21:58:181137 (
Peter Kastinge2c5ee82023-02-15 17:23:081138 'The thread support library is banned. Use base/synchronization '
1139 'instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181140 ),
1141 True,
1142 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1143 ),
1144 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081145 r'/\bstd::(c8rtomb|mbrtoc8)\b',
Peter Kasting6d77e9d2023-02-09 21:58:181146 (
Peter Kastinge2c5ee82023-02-15 17:23:081147 'std::c8rtomb() and std::mbrtoc8() are banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181148 ),
1149 True,
1150 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1151 ),
1152 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081153 r'/\bchar8_t|std::u8string\b',
Peter Kasting6d77e9d2023-02-09 21:58:181154 (
Peter Kastinge2c5ee82023-02-15 17:23:081155 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1156 ' char and std::string instead?',
1157 ),
1158 True,
1159 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1160 ),
1161 BanRule(
1162 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1163 (
1164 'Coroutines are not yet allowed (https://crbug.com/1403840).',
1165 ),
1166 True,
1167 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1168 ),
1169 BanRule(
1170 r'/\[\[(un)?likely\]\]',
1171 (
1172 '[[likely]] and [[unlikely]] are not yet allowed ',
1173 '(https://crbug.com/1414620). Use [UN]LIKELY instead.',
1174 ),
1175 True,
1176 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1177 ),
1178 BanRule(
1179 r'/#include <format>',
1180 (
1181 '<format> is not yet allowed. Use base::StringPrintf() instead.',
1182 ),
1183 True,
1184 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1185 ),
1186 BanRule(
1187 r'/#include <ranges>',
1188 (
1189 '<ranges> is not yet allowed. Use base/ranges/algorithm.h instead.',
1190 ),
1191 True,
1192 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1193 ),
1194 BanRule(
1195 r'/#include <source_location>',
1196 (
1197 '<source_location> is not yet allowed. Use base/location.h instead.',
1198 ),
1199 True,
1200 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1201 ),
1202 BanRule(
1203 r'/#include <syncstream>',
1204 (
1205 '<syncstream> is banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181206 ),
1207 True,
1208 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1209 ),
1210 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:581211 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:191212 (
1213 'RunMessageLoop is deprecated, use RunLoop instead.',
1214 ),
1215 False,
1216 (),
1217 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151218 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441219 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191220 (
1221 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1222 "if you're convinced you need this.",
1223 ),
1224 False,
1225 (),
1226 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151227 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441228 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191229 (
1230 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041231 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191232 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1233 'async events instead of flushing threads.',
1234 ),
1235 False,
1236 (),
1237 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151238 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191239 r'MessageLoopRunner',
1240 (
1241 'MessageLoopRunner is deprecated, use RunLoop instead.',
1242 ),
1243 False,
1244 (),
1245 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151246 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441247 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191248 (
1249 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1250 "gab@ if you found a use case where this is the only solution.",
1251 ),
1252 False,
1253 (),
1254 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151255 BanRule(
Victor Costane48a2e82019-03-15 22:02:341256 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161257 (
Victor Costane48a2e82019-03-15 22:02:341258 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161259 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1260 ),
1261 True,
1262 (
1263 r'^sql/initialization\.(cc|h)$',
1264 r'^third_party/sqlite/.*\.(c|cc|h)$',
1265 ),
1266 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151267 BanRule(
Austin Sullivand661ab52022-11-16 08:55:151268 'CREATE VIEW',
1269 (
1270 'SQL views are disabled in Chromium feature code',
1271 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1272 ),
1273 True,
1274 (
1275 _THIRD_PARTY_EXCEPT_BLINK,
1276 # sql/ itself uses views when using memory-mapped IO.
1277 r'^sql/.*',
1278 # Various performance tools that do not build as part of Chrome.
1279 r'^infra/.*',
1280 r'^tools/perf.*',
1281 r'.*perfetto.*',
1282 ),
1283 ),
1284 BanRule(
1285 'CREATE VIRTUAL TABLE',
1286 (
1287 'SQL virtual tables are disabled in Chromium feature code',
1288 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1289 ),
1290 True,
1291 (
1292 _THIRD_PARTY_EXCEPT_BLINK,
1293 # sql/ itself uses virtual tables in the recovery module and tests.
1294 r'^sql/.*',
1295 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1296 r'third_party/blink/web_tests/storage/websql/.*'
1297 # Various performance tools that do not build as part of Chrome.
1298 r'^tools/perf.*',
1299 r'.*perfetto.*',
1300 ),
1301 ),
1302 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441303 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471304 (
1305 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1306 'base::RandomShuffle instead.'
1307 ),
1308 True,
1309 (),
1310 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151311 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241312 'ios/web/public/test/http_server',
1313 (
1314 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1315 ),
1316 False,
1317 (),
1318 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151319 BanRule(
Robert Liao764c9492019-01-24 18:46:281320 'GetAddressOf',
1321 (
1322 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531323 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111324 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531325 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281326 ),
1327 True,
1328 (),
1329 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151330 BanRule(
Ben Lewisa9514602019-04-29 17:53:051331 'SHFileOperation',
1332 (
1333 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1334 'complex functions to achieve the same goals. Use IFileOperation for ',
1335 'any esoteric actions instead.'
1336 ),
1337 True,
1338 (),
1339 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151340 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511341 'StringFromGUID2',
1342 (
1343 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241344 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511345 ),
1346 True,
1347 (
Daniel Chenga44a1bcd2022-03-15 20:00:151348 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511349 ),
1350 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151351 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511352 'StringFromCLSID',
1353 (
1354 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241355 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511356 ),
1357 True,
1358 (
Daniel Chenga44a1bcd2022-03-15 20:00:151359 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511360 ),
1361 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151362 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131363 'kCFAllocatorNull',
1364 (
1365 'The use of kCFAllocatorNull with the NoCopy creation of ',
1366 'CoreFoundation types is prohibited.',
1367 ),
1368 True,
1369 (),
1370 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151371 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291372 'mojo::ConvertTo',
1373 (
1374 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1375 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1376 'StringTraits if you would like to convert between custom types and',
1377 'the wire format of mojom types.'
1378 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221379 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291380 (
David Dorwin13dc48b2022-06-03 21:18:421381 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1382 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291383 r'^third_party/blink/.*\.(cc|h)$',
1384 r'^content/renderer/.*\.(cc|h)$',
1385 ),
1386 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151387 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161388 'GetInterfaceProvider',
1389 (
1390 'InterfaceProvider is deprecated.',
1391 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1392 'or Platform::GetBrowserInterfaceBroker.'
1393 ),
1394 False,
1395 (),
1396 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151397 BanRule(
Robert Liao1d78df52019-11-11 20:02:011398 'CComPtr',
1399 (
1400 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1401 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1402 'details.'
1403 ),
1404 False,
1405 (),
1406 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151407 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201408 r'/\b(IFACE|STD)METHOD_?\(',
1409 (
1410 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1411 'Instead, always use IFACEMETHODIMP in the declaration.'
1412 ),
1413 False,
1414 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1415 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151416 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471417 'set_owned_by_client',
1418 (
1419 'set_owned_by_client is deprecated.',
1420 'views::View already owns the child views by default. This introduces ',
1421 'a competing ownership model which makes the code difficult to reason ',
1422 'about. See http://crbug.com/1044687 for more details.'
1423 ),
1424 False,
1425 (),
1426 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151427 BanRule(
Peter Boström7ff41522021-07-29 03:43:271428 'RemoveAllChildViewsWithoutDeleting',
1429 (
1430 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1431 'This method is deemed dangerous as, unless raw pointers are re-added,',
1432 'calls to this method introduce memory leaks.'
1433 ),
1434 False,
1435 (),
1436 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151437 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121438 r'/\bTRACE_EVENT_ASYNC_',
1439 (
1440 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1441 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1442 ),
1443 False,
1444 (
1445 r'^base/trace_event/.*',
1446 r'^base/tracing/.*',
1447 ),
1448 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151449 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431450 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1451 (
1452 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1453 'dumps and may spam crash reports. Consider if the throttled',
1454 'variants suffice instead.',
1455 ),
1456 False,
1457 (),
1458 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151459 BanRule(
Robert Liao22f66a52021-04-10 00:57:521460 'RoInitialize',
1461 (
Robert Liao48018922021-04-16 23:03:021462 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521463 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1464 'instead. See http://crbug.com/1197722 for more information.'
1465 ),
1466 True,
Robert Liao48018922021-04-16 23:03:021467 (
Bruce Dawson40fece62022-09-16 19:58:311468 r'^base/win/scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021469 ),
Robert Liao22f66a52021-04-10 00:57:521470 ),
Patrick Monettec343bb982022-06-01 17:18:451471 BanRule(
1472 r'base::Watchdog',
1473 (
1474 'base::Watchdog is deprecated because it creates its own thread.',
1475 'Instead, manually start a timer on a SequencedTaskRunner.',
1476 ),
1477 False,
1478 (),
1479 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091480 BanRule(
1481 'base::Passed',
1482 (
1483 'Do not use base::Passed. It is a legacy helper for capturing ',
1484 'move-only types with base::BindRepeating, but invoking the ',
1485 'resulting RepeatingCallback moves the captured value out of ',
1486 'the callback storage, and subsequent invocations may pass the ',
1487 'value in a valid but undefined state. Prefer base::BindOnce().',
1488 'See http://crbug.com/1326449 for context.'
1489 ),
1490 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481491 (
1492 # False positive, but it is also fine to let bind internals reference
1493 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241494 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481495 r'^base[\\/]functional[\\/]bind_internal\.h',
1496 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091497 ),
Daniel Cheng2248b332022-07-27 06:16:591498 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431499 r'base::Feature k',
1500 (
1501 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1502 'directly declaring/defining features.'
1503 ),
1504 True,
1505 [
1506 _THIRD_PARTY_EXCEPT_BLINK,
1507 ],
1508 ),
Robert Ogden92101dcb2022-10-19 23:49:361509 BanRule(
1510 r'\bchartorune\b',
1511 (
1512 'chartorune is not memory-safe, unless you can guarantee the input ',
1513 'string is always null-terminated. Otherwise, please use charntorune ',
1514 'from libphonenumber instead.'
1515 ),
1516 True,
1517 [
1518 _THIRD_PARTY_EXCEPT_BLINK,
1519 # Exceptions to this rule should have a fuzzer.
1520 ],
1521 ),
Benoit Lize79cf0592023-01-27 10:01:571522 BanRule(
1523 r'/\b#include "base/atomicops\.h"\b',
1524 (
1525 'Do not use base::subtle atomics, but std::atomic, which are simpler to '
1526 'use, have better understood, clearer and richer semantics, and are '
1527 'harder to mis-use. See details in base/atomicops.h.'
1528 ),
1529 False,
1530 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1531 ),
[email protected]127f18ec2012-06-16 05:05:591532)
1533
Daniel Cheng92c15e32022-03-16 17:48:221534_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1535 BanRule(
1536 'handle<shared_buffer>',
1537 (
1538 'Please use one of the more specific shared memory types instead:',
1539 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1540 ' mojo_base.mojom.WritableSharedMemoryRegion',
1541 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1542 ),
1543 True,
1544 ),
1545)
1546
mlamouria82272622014-09-16 18:45:041547_IPC_ENUM_TRAITS_DEPRECATED = (
1548 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501549 'See http://www.chromium.org/Home/chromium-security/education/'
1550 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041551
Stephen Martinis97a394142018-06-07 23:06:051552_LONG_PATH_ERROR = (
1553 'Some files included in this CL have file names that are too long (> 200'
1554 ' characters). If committed, these files will cause issues on Windows. See'
1555 ' https://crbug.com/612667 for more details.'
1556)
1557
Shenghua Zhangbfaa38b82017-11-16 21:58:021558_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:311559 r".*/AppHooksImpl\.java",
1560 r".*/BuildHooksAndroidImpl\.java",
1561 r".*/LicenseContentProvider\.java",
1562 r".*/PlatformServiceBridgeImpl.java",
1563 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021564]
[email protected]127f18ec2012-06-16 05:05:591565
Mohamed Heikald048240a2019-11-12 16:57:371566# List of image extensions that are used as resources in chromium.
1567_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1568
Sean Kau46e29bc2017-08-28 16:31:161569# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401570_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:311571 r'test/data/',
1572 r'testing/buildbot/',
1573 r'^components/policy/resources/policy_templates\.json$',
1574 r'^third_party/protobuf/',
1575 r'^third_party/blink/perf_tests/speedometer/resources/todomvc/learn.json',
1576 r'^third_party/blink/renderer/devtools/protocol\.json$',
1577 r'^third_party/blink/web_tests/external/wpt/',
1578 r'^tools/perf/',
1579 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311580 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:311581 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:161582]
1583
Andrew Grieveb773bad2020-06-05 18:00:381584# These are not checked on the public chromium-presubmit trybot.
1585# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041586# checkouts.
agrievef32bcc72016-04-04 14:57:401587_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381588 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381589]
1590
1591
1592_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101593 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041594 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361595 'base/android/jni_generator/jni_generator.pydeps',
1596 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361597 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041598 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361599 'build/android/gyp/aar.pydeps',
1600 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271601 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361602 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381603 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361604 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021605 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221606 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111607 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:301608 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361609 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361610 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361611 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111612 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041613 'build/android/gyp/create_app_bundle_apks.pydeps',
1614 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361615 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121616 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091617 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221618 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401619 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001620 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361621 'build/android/gyp/dex.pydeps',
1622 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361623 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211624 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361625 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361626 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361627 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581628 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361629 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141630 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261631 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471632 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041633 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361634 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361635 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101636 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361637 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221638 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361639 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221640 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101641 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461642 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301643 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241644 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361645 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461646 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561647 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361648 'build/android/incremental_install/generate_android_manifest.pydeps',
1649 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321650 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041651 'build/android/resource_sizes.pydeps',
1652 'build/android/test_runner.pydeps',
1653 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361654 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361655 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321656 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271657 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1658 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041659 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001660 'components/cronet/tools/generate_javadoc.pydeps',
1661 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381662 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001663 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381664 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181665 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411666 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1667 'testing/merge_scripts/standard_gtest_merge.pydeps',
1668 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1669 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041670 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421671 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251672 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421673 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131674 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501675 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411676 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1677 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061678 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221679 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451680 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401681]
1682
wnwenbdc444e2016-05-25 13:44:151683
agrievef32bcc72016-04-04 14:57:401684_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1685
1686
Eric Boren6fd2b932018-01-25 15:05:081687# Bypass the AUTHORS check for these accounts.
1688_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591689 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451690 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591691 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521692 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231693 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471694 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461695 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:181696 'lacros-sdk-version-roller', 'chrome-automated-expectation',
Keybo Qianec7dcb12023-01-27 18:38:561697 'chromium-automated-expectation', 'chrome-branch-day')
Eric Boren835d71f2018-09-07 21:09:041698 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271699 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041700 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161701 for s in ('chromium-internal-autoroll',)
1702 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:551703 for s in ('swarming-tasks',)
1704 ) | set('%[email protected]' % s
1705 for s in ('global-integration-try-builder',
1706 'global-integration-ci-builder'))
Eric Boren6fd2b932018-01-25 15:05:081707
Matt Stark6ef08872021-07-29 01:21:461708_INVALID_GRD_FILE_LINE = [
1709 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1710]
Eric Boren6fd2b932018-01-25 15:05:081711
Daniel Bratell65b033262019-04-23 08:17:061712def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501713 """Returns True if this file contains C++-like code (and not Python,
1714 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061715
Sam Maiera6e76d72022-02-11 21:43:501716 ext = input_api.os_path.splitext(file_path)[1]
1717 # This list is compatible with CppChecker.IsCppFile but we should
1718 # consider adding ".c" to it. If we do that we can use this function
1719 # at more places in the code.
1720 return ext in (
1721 '.h',
1722 '.cc',
1723 '.cpp',
1724 '.m',
1725 '.mm',
1726 )
1727
Daniel Bratell65b033262019-04-23 08:17:061728
1729def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501730 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061731
1732
1733def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501734 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061735
1736
1737def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501738 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061739
Mohamed Heikal5e5b7922020-10-29 18:57:591740
Erik Staabc734cd7a2021-11-23 03:11:521741def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501742 ext = input_api.os_path.splitext(file_path)[1]
1743 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521744
1745
Sven Zheng76a79ea2022-12-21 21:25:241746def _IsMojomFile(input_api, file_path):
1747 return input_api.os_path.splitext(file_path)[1] == ".mojom"
1748
1749
Mohamed Heikal5e5b7922020-10-29 18:57:591750def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501751 """Prevent additions of dependencies from the upstream repo on //clank."""
1752 # clank can depend on clank
1753 if input_api.change.RepositoryRoot().endswith('clank'):
1754 return []
1755 build_file_patterns = [
1756 r'(.+/)?BUILD\.gn',
1757 r'.+\.gni',
1758 ]
1759 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1760 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591761
Sam Maiera6e76d72022-02-11 21:43:501762 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591763
Sam Maiera6e76d72022-02-11 21:43:501764 def FilterFile(affected_file):
1765 return input_api.FilterSourceFile(affected_file,
1766 files_to_check=build_file_patterns,
1767 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591768
Sam Maiera6e76d72022-02-11 21:43:501769 problems = []
1770 for f in input_api.AffectedSourceFiles(FilterFile):
1771 local_path = f.LocalPath()
1772 for line_number, line in f.ChangedContents():
1773 if (bad_pattern.search(line)):
1774 problems.append('%s:%d\n %s' %
1775 (local_path, line_number, line.strip()))
1776 if problems:
1777 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1778 else:
1779 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591780
1781
Saagar Sanghavifceeaae2020-08-12 16:40:361782def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501783 """Attempts to prevent use of functions intended only for testing in
1784 non-testing code. For now this is just a best-effort implementation
1785 that ignores header files and may have some false positives. A
1786 better implementation would probably need a proper C++ parser.
1787 """
1788 # We only scan .cc files and the like, as the declaration of
1789 # for-testing functions in header files are hard to distinguish from
1790 # calls to such functions without a proper C++ parser.
1791 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191792
Sam Maiera6e76d72022-02-11 21:43:501793 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1794 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1795 base_function_pattern)
1796 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1797 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1798 exclusion_pattern = input_api.re.compile(
1799 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1800 (base_function_pattern, base_function_pattern))
1801 # Avoid a false positive in this case, where the method name, the ::, and
1802 # the closing { are all on different lines due to line wrapping.
1803 # HelperClassForTesting::
1804 # HelperClassForTesting(
1805 # args)
1806 # : member(0) {}
1807 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191808
Sam Maiera6e76d72022-02-11 21:43:501809 def FilterFile(affected_file):
1810 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1811 input_api.DEFAULT_FILES_TO_SKIP)
1812 return input_api.FilterSourceFile(
1813 affected_file,
1814 files_to_check=file_inclusion_pattern,
1815 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191816
Sam Maiera6e76d72022-02-11 21:43:501817 problems = []
1818 for f in input_api.AffectedSourceFiles(FilterFile):
1819 local_path = f.LocalPath()
1820 in_method_defn = False
1821 for line_number, line in f.ChangedContents():
1822 if (inclusion_pattern.search(line)
1823 and not comment_pattern.search(line)
1824 and not exclusion_pattern.search(line)
1825 and not allowlist_pattern.search(line)
1826 and not in_method_defn):
1827 problems.append('%s:%d\n %s' %
1828 (local_path, line_number, line.strip()))
1829 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191830
Sam Maiera6e76d72022-02-11 21:43:501831 if problems:
1832 return [
1833 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1834 ]
1835 else:
1836 return []
[email protected]55459852011-08-10 15:17:191837
1838
Saagar Sanghavifceeaae2020-08-12 16:40:361839def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501840 """This is a simplified version of
1841 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1842 """
1843 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1844 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1845 name_pattern = r'ForTest(s|ing)?'
1846 # Describes an occurrence of "ForTest*" inside a // comment.
1847 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1848 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1849 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1850 # Catch calls.
1851 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1852 # Ignore definitions. (Comments are ignored separately.)
1853 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231854
Sam Maiera6e76d72022-02-11 21:43:501855 problems = []
1856 sources = lambda x: input_api.FilterSourceFile(
1857 x,
1858 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1859 DEFAULT_FILES_TO_SKIP),
1860 files_to_check=[r'.*\.java$'])
1861 for f in input_api.AffectedFiles(include_deletes=False,
1862 file_filter=sources):
1863 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231864 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501865 for line_number, line in f.ChangedContents():
1866 if is_inside_javadoc and javadoc_end_re.search(line):
1867 is_inside_javadoc = False
1868 if not is_inside_javadoc and javadoc_start_re.search(line):
1869 is_inside_javadoc = True
1870 if is_inside_javadoc:
1871 continue
1872 if (inclusion_re.search(line) and not comment_re.search(line)
1873 and not annotation_re.search(line)
1874 and not exclusion_re.search(line)):
1875 problems.append('%s:%d\n %s' %
1876 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231877
Sam Maiera6e76d72022-02-11 21:43:501878 if problems:
1879 return [
1880 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1881 ]
1882 else:
1883 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231884
1885
Saagar Sanghavifceeaae2020-08-12 16:40:361886def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501887 """Checks to make sure no .h files include <iostream>."""
1888 files = []
1889 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1890 input_api.re.MULTILINE)
1891 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1892 if not f.LocalPath().endswith('.h'):
1893 continue
1894 contents = input_api.ReadFile(f)
1895 if pattern.search(contents):
1896 files.append(f)
[email protected]10689ca2011-09-02 02:31:541897
Sam Maiera6e76d72022-02-11 21:43:501898 if len(files):
1899 return [
1900 output_api.PresubmitError(
1901 'Do not #include <iostream> in header files, since it inserts static '
1902 'initialization into every file including the header. Instead, '
1903 '#include <ostream>. See http://crbug.com/94794', files)
1904 ]
1905 return []
1906
[email protected]10689ca2011-09-02 02:31:541907
Aleksey Khoroshilov9b28c032022-06-03 16:35:321908def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501909 """Checks no windows headers with StrCat redefined are included directly."""
1910 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:321911 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
1912 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
1913 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
1914 _NON_BASE_DEPENDENT_PATHS)
1915 sources_filter = lambda f: input_api.FilterSourceFile(
1916 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
1917
Sam Maiera6e76d72022-02-11 21:43:501918 pattern_deny = input_api.re.compile(
1919 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1920 input_api.re.MULTILINE)
1921 pattern_allow = input_api.re.compile(
1922 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:321923 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:501924 contents = input_api.ReadFile(f)
1925 if pattern_deny.search(
1926 contents) and not pattern_allow.search(contents):
1927 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431928
Sam Maiera6e76d72022-02-11 21:43:501929 if len(files):
1930 return [
1931 output_api.PresubmitError(
1932 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1933 'directly since they pollute code with StrCat macro. Instead, '
1934 'include matching header from base/win. See http://crbug.com/856536',
1935 files)
1936 ]
1937 return []
Danil Chapovalov3518f362018-08-11 16:13:431938
[email protected]10689ca2011-09-02 02:31:541939
Saagar Sanghavifceeaae2020-08-12 16:40:361940def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501941 """Checks to make sure no source files use UNIT_TEST."""
1942 problems = []
1943 for f in input_api.AffectedFiles():
1944 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1945 continue
[email protected]72df4e782012-06-21 16:28:181946
Sam Maiera6e76d72022-02-11 21:43:501947 for line_num, line in f.ChangedContents():
1948 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1949 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181950
Sam Maiera6e76d72022-02-11 21:43:501951 if not problems:
1952 return []
1953 return [
1954 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1955 '\n'.join(problems))
1956 ]
1957
[email protected]72df4e782012-06-21 16:28:181958
Saagar Sanghavifceeaae2020-08-12 16:40:361959def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501960 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341961
Sam Maiera6e76d72022-02-11 21:43:501962 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1963 instead of DISABLED_. To filter false positives, reports are only generated
1964 if a corresponding MAYBE_ line exists.
1965 """
1966 problems = []
Dominic Battre033531052018-09-24 15:45:341967
Sam Maiera6e76d72022-02-11 21:43:501968 # The following two patterns are looked for in tandem - is a test labeled
1969 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1970 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1971 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341972
Sam Maiera6e76d72022-02-11 21:43:501973 # This is for the case that a test is disabled on all platforms.
1974 full_disable_pattern = input_api.re.compile(
1975 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1976 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341977
Sam Maiera6e76d72022-02-11 21:43:501978 for f in input_api.AffectedFiles(False):
1979 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1980 continue
Dominic Battre033531052018-09-24 15:45:341981
Sam Maiera6e76d72022-02-11 21:43:501982 # Search for MABYE_, DISABLE_ pairs.
1983 disable_lines = {} # Maps of test name to line number.
1984 maybe_lines = {}
1985 for line_num, line in f.ChangedContents():
1986 disable_match = disable_pattern.search(line)
1987 if disable_match:
1988 disable_lines[disable_match.group(1)] = line_num
1989 maybe_match = maybe_pattern.search(line)
1990 if maybe_match:
1991 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341992
Sam Maiera6e76d72022-02-11 21:43:501993 # Search for DISABLE_ occurrences within a TEST() macro.
1994 disable_tests = set(disable_lines.keys())
1995 maybe_tests = set(maybe_lines.keys())
1996 for test in disable_tests.intersection(maybe_tests):
1997 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341998
Sam Maiera6e76d72022-02-11 21:43:501999 contents = input_api.ReadFile(f)
2000 full_disable_match = full_disable_pattern.search(contents)
2001 if full_disable_match:
2002 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342003
Sam Maiera6e76d72022-02-11 21:43:502004 if not problems:
2005 return []
2006 return [
2007 output_api.PresubmitPromptWarning(
2008 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2009 '\n'.join(problems))
2010 ]
2011
Dominic Battre033531052018-09-24 15:45:342012
Nina Satragnof7660532021-09-20 18:03:352013def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502014 """Checks to make sure tests disabled conditionally are not missing a
2015 corresponding MAYBE_ prefix.
2016 """
2017 # Expect at least a lowercase character in the test name. This helps rule out
2018 # false positives with macros wrapping the actual tests name.
2019 define_maybe_pattern = input_api.re.compile(
2020 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192021 # The test_maybe_pattern needs to handle all of these forms. The standard:
2022 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2023 # With a wrapper macro around the test name:
2024 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2025 # And the odd-ball NACL_BROWSER_TEST_f format:
2026 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2027 # The optional E2E_ENABLED-style is handled with (\w*\()?
2028 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2029 # trailing ')'.
2030 test_maybe_pattern = (
2031 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502032 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2033 warnings = []
Nina Satragnof7660532021-09-20 18:03:352034
Sam Maiera6e76d72022-02-11 21:43:502035 # Read the entire files. We can't just read the affected lines, forgetting to
2036 # add MAYBE_ on a change would not show up otherwise.
2037 for f in input_api.AffectedFiles(False):
2038 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2039 continue
2040 contents = input_api.ReadFile(f)
2041 lines = contents.splitlines(True)
2042 current_position = 0
2043 warning_test_names = set()
2044 for line_num, line in enumerate(lines, start=1):
2045 current_position += len(line)
2046 maybe_match = define_maybe_pattern.search(line)
2047 if maybe_match:
2048 test_name = maybe_match.group('test_name')
2049 # Do not warn twice for the same test.
2050 if (test_name in warning_test_names):
2051 continue
2052 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352053
Sam Maiera6e76d72022-02-11 21:43:502054 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2055 # the current position.
2056 test_match = input_api.re.compile(
2057 test_maybe_pattern.format(test_name=test_name),
2058 input_api.re.MULTILINE).search(contents, current_position)
2059 suite_match = input_api.re.compile(
2060 suite_maybe_pattern.format(test_name=test_name),
2061 input_api.re.MULTILINE).search(contents, current_position)
2062 if not test_match and not suite_match:
2063 warnings.append(
2064 output_api.PresubmitPromptWarning(
2065 '%s:%d found MAYBE_ defined without corresponding test %s'
2066 % (f.LocalPath(), line_num, test_name)))
2067 return warnings
2068
[email protected]72df4e782012-06-21 16:28:182069
Saagar Sanghavifceeaae2020-08-12 16:40:362070def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502071 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2072 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162073 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502074 input_api.re.MULTILINE)
2075 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2076 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2077 continue
2078 for lnum, line in f.ChangedContents():
2079 if input_api.re.search(pattern, line):
2080 errors.append(
2081 output_api.PresubmitError((
2082 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2083 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2084 (f.LocalPath(), lnum)))
2085 return errors
danakj61c1aa22015-10-26 19:55:522086
2087
Weilun Shia487fad2020-10-28 00:10:342088# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2089# more reliable way. See
2090# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192091
wnwenbdc444e2016-05-25 13:44:152092
Saagar Sanghavifceeaae2020-08-12 16:40:362093def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502094 """Check that FlakyTest annotation is our own instead of the android one"""
2095 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2096 files = []
2097 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2098 if f.LocalPath().endswith('Test.java'):
2099 if pattern.search(input_api.ReadFile(f)):
2100 files.append(f)
2101 if len(files):
2102 return [
2103 output_api.PresubmitError(
2104 'Use org.chromium.base.test.util.FlakyTest instead of '
2105 'android.test.FlakyTest', files)
2106 ]
2107 return []
mcasasb7440c282015-02-04 14:52:192108
wnwenbdc444e2016-05-25 13:44:152109
Saagar Sanghavifceeaae2020-08-12 16:40:362110def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502111 """Make sure .DEPS.git is never modified manually."""
2112 if any(f.LocalPath().endswith('.DEPS.git')
2113 for f in input_api.AffectedFiles()):
2114 return [
2115 output_api.PresubmitError(
2116 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2117 'automated system based on what\'s in DEPS and your changes will be\n'
2118 'overwritten.\n'
2119 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2120 'get-the-code#Rolling_DEPS\n'
2121 'for more information')
2122 ]
2123 return []
[email protected]2a8ac9c2011-10-19 17:20:442124
2125
Sven Zheng76a79ea2022-12-21 21:25:242126def CheckCrosApiNeedBrowserTest(input_api, output_api):
2127 """Check new crosapi should add browser test."""
2128 has_new_crosapi = False
2129 has_browser_test = False
2130 for f in input_api.AffectedFiles():
2131 path = f.LocalPath()
2132 if (path.startswith('chromeos/crosapi/mojom') and
2133 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2134 has_new_crosapi = True
2135 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2136 has_browser_test = True
2137 if has_new_crosapi and not has_browser_test:
2138 return [
2139 output_api.PresubmitPromptWarning(
2140 'You are adding a new crosapi, but there is no file ends with '
2141 'browsertest.cc file being added or modified. It is important '
2142 'to add crosapi browser test coverage to avoid version '
2143 ' skew issues.\n'
2144 'Check //docs/lacros/test_instructions.md for more information.'
2145 )
2146 ]
2147 return []
2148
2149
Saagar Sanghavifceeaae2020-08-12 16:40:362150def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502151 """Checks that DEPS file deps are from allowed_hosts."""
2152 # Run only if DEPS file has been modified to annoy fewer bystanders.
2153 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2154 return []
2155 # Outsource work to gclient verify
2156 try:
2157 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2158 'third_party', 'depot_tools',
2159 'gclient.py')
2160 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322161 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502162 stderr=input_api.subprocess.STDOUT)
2163 return []
2164 except input_api.subprocess.CalledProcessError as error:
2165 return [
2166 output_api.PresubmitError(
2167 'DEPS file must have only git dependencies.',
2168 long_text=error.output)
2169 ]
tandriief664692014-09-23 14:51:472170
2171
Mario Sanchez Prada2472cab2019-09-18 10:58:312172def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152173 ban_rule):
Allen Bauer84778682022-09-22 16:28:562174 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312175
Sam Maiera6e76d72022-02-11 21:43:502176 Returns an string composed of the name of the file, the line number where the
2177 match has been found and the additional text passed as |message| in case the
2178 target type name matches the text inside the line passed as parameter.
2179 """
2180 result = []
Peng Huang9c5949a02020-06-11 19:20:542181
Daniel Chenga44a1bcd2022-03-15 20:00:152182 # Ignore comments about banned types.
2183 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502184 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152185 # A // nocheck comment will bypass this error.
2186 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502187 return result
2188
2189 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152190 if ban_rule.pattern[0:1] == '/':
2191 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502192 if input_api.re.search(regex, line):
2193 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152194 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502195 matched = True
2196
2197 if matched:
2198 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152199 for line in ban_rule.explanation:
2200 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502201
danakjd18e8892020-12-17 17:42:012202 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312203
2204
Saagar Sanghavifceeaae2020-08-12 16:40:362205def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502206 """Make sure that banned functions are not used."""
2207 warnings = []
2208 errors = []
[email protected]127f18ec2012-06-16 05:05:592209
Sam Maiera6e76d72022-02-11 21:43:502210 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152211 if not excluded_paths:
2212 return False
2213
Sam Maiera6e76d72022-02-11 21:43:502214 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312215 # Consistently use / as path separator to simplify the writing of regex
2216 # expressions.
2217 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502218 for item in excluded_paths:
2219 if input_api.re.match(item, local_path):
2220 return True
2221 return False
wnwenbdc444e2016-05-25 13:44:152222
Sam Maiera6e76d72022-02-11 21:43:502223 def IsIosObjcFile(affected_file):
2224 local_path = affected_file.LocalPath()
2225 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2226 '.h'):
2227 return False
2228 basename = input_api.os_path.basename(local_path)
2229 if 'ios' in basename.split('_'):
2230 return True
2231 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2232 if sep and 'ios' in local_path.split(sep):
2233 return True
2234 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542235
Daniel Chenga44a1bcd2022-03-15 20:00:152236 def CheckForMatch(affected_file, line_num: int, line: str,
2237 ban_rule: BanRule):
2238 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2239 return
2240
Sam Maiera6e76d72022-02-11 21:43:502241 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152242 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502243 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152244 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502245 errors.extend(problems)
2246 else:
2247 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152248
Sam Maiera6e76d72022-02-11 21:43:502249 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2250 for f in input_api.AffectedFiles(file_filter=file_filter):
2251 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152252 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2253 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412254
Clement Yan9b330cb2022-11-17 05:25:292255 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2256 for f in input_api.AffectedFiles(file_filter=file_filter):
2257 for line_num, line in f.ChangedContents():
2258 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2259 CheckForMatch(f, line_num, line, ban_rule)
2260
Sam Maiera6e76d72022-02-11 21:43:502261 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2262 for f in input_api.AffectedFiles(file_filter=file_filter):
2263 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152264 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2265 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592266
Sam Maiera6e76d72022-02-11 21:43:502267 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2268 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152269 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2270 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542271
Sam Maiera6e76d72022-02-11 21:43:502272 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2273 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2274 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152275 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2276 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052277
Sam Maiera6e76d72022-02-11 21:43:502278 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2279 for f in input_api.AffectedFiles(file_filter=file_filter):
2280 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152281 for ban_rule in _BANNED_CPP_FUNCTIONS:
2282 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592283
Daniel Cheng92c15e32022-03-16 17:48:222284 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2285 for f in input_api.AffectedFiles(file_filter=file_filter):
2286 for line_num, line in f.ChangedContents():
2287 for ban_rule in _BANNED_MOJOM_PATTERNS:
2288 CheckForMatch(f, line_num, line, ban_rule)
2289
2290
Sam Maiera6e76d72022-02-11 21:43:502291 result = []
2292 if (warnings):
2293 result.append(
2294 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2295 '\n'.join(warnings)))
2296 if (errors):
2297 result.append(
2298 output_api.PresubmitError('Banned functions were used.\n' +
2299 '\n'.join(errors)))
2300 return result
[email protected]127f18ec2012-06-16 05:05:592301
Allen Bauer84778682022-09-22 16:28:562302def CheckNoLayoutCallsInTests(input_api, output_api):
2303 """Make sure there are no explicit calls to View::Layout() in tests"""
2304 warnings = []
2305 ban_rule = BanRule(
2306 r'/(\.|->)Layout\(\);',
2307 (
2308 'Direct calls to View::Layout() are not allowed in tests. '
2309 'If the view must be laid out here, use RunScheduledLayout(view). It '
2310 'is found in //ui/views/test/views_test_utils.h. '
2311 'See http://crbug.com/1350521 for more details.',
2312 ),
2313 False,
2314 )
2315 file_filter = lambda f: input_api.re.search(
2316 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2317 for f in input_api.AffectedFiles(file_filter = file_filter):
2318 for line_num, line in f.ChangedContents():
2319 problems = _GetMessageForMatchingType(input_api, f,
2320 line_num, line,
2321 ban_rule)
2322 if problems:
2323 warnings.extend(problems)
2324 result = []
2325 if (warnings):
2326 result.append(
2327 output_api.PresubmitPromptWarning(
2328 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2329 return result
[email protected]127f18ec2012-06-16 05:05:592330
Michael Thiessen44457642020-02-06 00:24:152331def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502332 """Make sure that banned java imports are not used."""
2333 errors = []
Michael Thiessen44457642020-02-06 00:24:152334
Sam Maiera6e76d72022-02-11 21:43:502335 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2336 for f in input_api.AffectedFiles(file_filter=file_filter):
2337 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152338 for ban_rule in _BANNED_JAVA_IMPORTS:
2339 # Consider merging this into the above function. There is no
2340 # real difference anymore other than helping with a little
2341 # bit of boilerplate text. Doing so means things like
2342 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502343 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152344 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502345 if problems:
2346 errors.extend(problems)
2347 result = []
2348 if (errors):
2349 result.append(
2350 output_api.PresubmitError('Banned imports were used.\n' +
2351 '\n'.join(errors)))
2352 return result
Michael Thiessen44457642020-02-06 00:24:152353
2354
Saagar Sanghavifceeaae2020-08-12 16:40:362355def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502356 """Make sure that banned functions are not used."""
2357 files = []
2358 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2359 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2360 if not f.LocalPath().endswith('.h'):
2361 continue
Bruce Dawson4c4c2922022-05-02 18:07:332362 if f.LocalPath().endswith('com_imported_mstscax.h'):
2363 continue
Sam Maiera6e76d72022-02-11 21:43:502364 contents = input_api.ReadFile(f)
2365 if pattern.search(contents):
2366 files.append(f)
[email protected]6c063c62012-07-11 19:11:062367
Sam Maiera6e76d72022-02-11 21:43:502368 if files:
2369 return [
2370 output_api.PresubmitError(
2371 'Do not use #pragma once in header files.\n'
2372 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2373 files)
2374 ]
2375 return []
[email protected]6c063c62012-07-11 19:11:062376
[email protected]127f18ec2012-06-16 05:05:592377
Saagar Sanghavifceeaae2020-08-12 16:40:362378def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502379 """Checks to make sure we don't introduce use of foo ? true : false."""
2380 problems = []
2381 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2382 for f in input_api.AffectedFiles():
2383 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2384 continue
[email protected]e7479052012-09-19 00:26:122385
Sam Maiera6e76d72022-02-11 21:43:502386 for line_num, line in f.ChangedContents():
2387 if pattern.match(line):
2388 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:122389
Sam Maiera6e76d72022-02-11 21:43:502390 if not problems:
2391 return []
2392 return [
2393 output_api.PresubmitPromptWarning(
2394 'Please consider avoiding the "? true : false" pattern if possible.\n'
2395 + '\n'.join(problems))
2396 ]
[email protected]e7479052012-09-19 00:26:122397
2398
Saagar Sanghavifceeaae2020-08-12 16:40:362399def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502400 """Runs checkdeps on #include and import statements added in this
2401 change. Breaking - rules is an error, breaking ! rules is a
2402 warning.
2403 """
2404 # Return early if no relevant file types were modified.
2405 for f in input_api.AffectedFiles():
2406 path = f.LocalPath()
2407 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2408 or _IsJavaFile(input_api, path)):
2409 break
[email protected]55f9f382012-07-31 11:02:182410 else:
Sam Maiera6e76d72022-02-11 21:43:502411 return []
rhalavati08acd232017-04-03 07:23:282412
Sam Maiera6e76d72022-02-11 21:43:502413 import sys
2414 # We need to wait until we have an input_api object and use this
2415 # roundabout construct to import checkdeps because this file is
2416 # eval-ed and thus doesn't have __file__.
2417 original_sys_path = sys.path
2418 try:
2419 sys.path = sys.path + [
2420 input_api.os_path.join(input_api.PresubmitLocalPath(),
2421 'buildtools', 'checkdeps')
2422 ]
2423 import checkdeps
2424 from rules import Rule
2425 finally:
2426 # Restore sys.path to what it was before.
2427 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:182428
Sam Maiera6e76d72022-02-11 21:43:502429 added_includes = []
2430 added_imports = []
2431 added_java_imports = []
2432 for f in input_api.AffectedFiles():
2433 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2434 changed_lines = [line for _, line in f.ChangedContents()]
2435 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2436 elif _IsProtoFile(input_api, f.LocalPath()):
2437 changed_lines = [line for _, line in f.ChangedContents()]
2438 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2439 elif _IsJavaFile(input_api, f.LocalPath()):
2440 changed_lines = [line for _, line in f.ChangedContents()]
2441 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242442
Sam Maiera6e76d72022-02-11 21:43:502443 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2444
2445 error_descriptions = []
2446 warning_descriptions = []
2447 error_subjects = set()
2448 warning_subjects = set()
2449
2450 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2451 added_includes):
2452 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2453 description_with_path = '%s\n %s' % (path, rule_description)
2454 if rule_type == Rule.DISALLOW:
2455 error_descriptions.append(description_with_path)
2456 error_subjects.add("#includes")
2457 else:
2458 warning_descriptions.append(description_with_path)
2459 warning_subjects.add("#includes")
2460
2461 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2462 added_imports):
2463 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2464 description_with_path = '%s\n %s' % (path, rule_description)
2465 if rule_type == Rule.DISALLOW:
2466 error_descriptions.append(description_with_path)
2467 error_subjects.add("imports")
2468 else:
2469 warning_descriptions.append(description_with_path)
2470 warning_subjects.add("imports")
2471
2472 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2473 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2474 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2475 description_with_path = '%s\n %s' % (path, rule_description)
2476 if rule_type == Rule.DISALLOW:
2477 error_descriptions.append(description_with_path)
2478 error_subjects.add("imports")
2479 else:
2480 warning_descriptions.append(description_with_path)
2481 warning_subjects.add("imports")
2482
2483 results = []
2484 if error_descriptions:
2485 results.append(
2486 output_api.PresubmitError(
2487 'You added one or more %s that violate checkdeps rules.' %
2488 " and ".join(error_subjects), error_descriptions))
2489 if warning_descriptions:
2490 results.append(
2491 output_api.PresubmitPromptOrNotify(
2492 'You added one or more %s of files that are temporarily\n'
2493 'allowed but being removed. Can you avoid introducing the\n'
2494 '%s? See relevant DEPS file(s) for details and contacts.' %
2495 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2496 warning_descriptions))
2497 return results
[email protected]55f9f382012-07-31 11:02:182498
2499
Saagar Sanghavifceeaae2020-08-12 16:40:362500def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502501 """Check that all files have their permissions properly set."""
2502 if input_api.platform == 'win32':
2503 return []
2504 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2505 'tools', 'checkperms',
2506 'checkperms.py')
2507 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322508 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502509 input_api.change.RepositoryRoot()
2510 ]
2511 with input_api.CreateTemporaryFile() as file_list:
2512 for f in input_api.AffectedFiles():
2513 # checkperms.py file/directory arguments must be relative to the
2514 # repository.
2515 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2516 file_list.close()
2517 args += ['--file-list', file_list.name]
2518 try:
2519 input_api.subprocess.check_output(args)
2520 return []
2521 except input_api.subprocess.CalledProcessError as error:
2522 return [
2523 output_api.PresubmitError('checkperms.py failed:',
2524 long_text=error.output.decode(
2525 'utf-8', 'ignore'))
2526 ]
[email protected]fbcafe5a2012-08-08 15:31:222527
2528
Saagar Sanghavifceeaae2020-08-12 16:40:362529def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502530 """Makes sure we don't include ui/aura/window_property.h
2531 in header files.
2532 """
2533 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2534 errors = []
2535 for f in input_api.AffectedFiles():
2536 if not f.LocalPath().endswith('.h'):
2537 continue
2538 for line_num, line in f.ChangedContents():
2539 if pattern.match(line):
2540 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:492541
Sam Maiera6e76d72022-02-11 21:43:502542 results = []
2543 if errors:
2544 results.append(
2545 output_api.PresubmitError(
2546 'Header files should not include ui/aura/window_property.h',
2547 errors))
2548 return results
[email protected]c8278b32012-10-30 20:35:492549
2550
Omer Katzcc77ea92021-04-26 10:23:282551def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502552 """Makes sure we don't include any headers from
2553 third_party/blink/renderer/platform/heap/impl or
2554 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2555 third_party/blink/renderer/platform/heap
2556 """
2557 impl_pattern = input_api.re.compile(
2558 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2559 v8_wrapper_pattern = input_api.re.compile(
2560 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2561 )
Bruce Dawson40fece62022-09-16 19:58:312562 # Consistently use / as path separator to simplify the writing of regex
2563 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502564 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312565 r"^third_party/blink/renderer/platform/heap/.*",
2566 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502567 errors = []
Omer Katzcc77ea92021-04-26 10:23:282568
Sam Maiera6e76d72022-02-11 21:43:502569 for f in input_api.AffectedFiles(file_filter=file_filter):
2570 for line_num, line in f.ChangedContents():
2571 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2572 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282573
Sam Maiera6e76d72022-02-11 21:43:502574 results = []
2575 if errors:
2576 results.append(
2577 output_api.PresubmitError(
2578 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2579 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2580 'relevant counterparts from third_party/blink/renderer/platform/heap',
2581 errors))
2582 return results
Omer Katzcc77ea92021-04-26 10:23:282583
2584
[email protected]70ca77752012-11-20 03:45:032585def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502586 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2587 errors = []
2588 for line_num, line in f.ChangedContents():
2589 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2590 # First-level headers in markdown look a lot like version control
2591 # conflict markers. http://daringfireball.net/projects/markdown/basics
2592 continue
2593 if pattern.match(line):
2594 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2595 return errors
[email protected]70ca77752012-11-20 03:45:032596
2597
Saagar Sanghavifceeaae2020-08-12 16:40:362598def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502599 """Usually this is not intentional and will cause a compile failure."""
2600 errors = []
2601 for f in input_api.AffectedFiles():
2602 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032603
Sam Maiera6e76d72022-02-11 21:43:502604 results = []
2605 if errors:
2606 results.append(
2607 output_api.PresubmitError(
2608 'Version control conflict markers found, please resolve.',
2609 errors))
2610 return results
[email protected]70ca77752012-11-20 03:45:032611
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202612
Saagar Sanghavifceeaae2020-08-12 16:40:362613def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502614 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2615 errors = []
2616 for f in input_api.AffectedFiles():
2617 for line_num, line in f.ChangedContents():
2618 if pattern.search(line):
2619 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162620
Sam Maiera6e76d72022-02-11 21:43:502621 results = []
2622 if errors:
2623 results.append(
2624 output_api.PresubmitPromptWarning(
2625 'Found Google support URL addressed by answer number. Please replace '
2626 'with a p= identifier instead. See crbug.com/679462\n',
2627 errors))
2628 return results
estadee17314a02017-01-12 16:22:162629
[email protected]70ca77752012-11-20 03:45:032630
Saagar Sanghavifceeaae2020-08-12 16:40:362631def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502632 def FilterFile(affected_file):
2633 """Filter function for use with input_api.AffectedSourceFiles,
2634 below. This filters out everything except non-test files from
2635 top-level directories that generally speaking should not hard-code
2636 service URLs (e.g. src/android_webview/, src/content/ and others).
2637 """
2638 return input_api.FilterSourceFile(
2639 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312640 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502641 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2642 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442643
Sam Maiera6e76d72022-02-11 21:43:502644 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2645 '\.(com|net)[^"]*"')
2646 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2647 pattern = input_api.re.compile(base_pattern)
2648 problems = [] # items are (filename, line_number, line)
2649 for f in input_api.AffectedSourceFiles(FilterFile):
2650 for line_num, line in f.ChangedContents():
2651 if not comment_pattern.search(line) and pattern.search(line):
2652 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442653
Sam Maiera6e76d72022-02-11 21:43:502654 if problems:
2655 return [
2656 output_api.PresubmitPromptOrNotify(
2657 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2658 'Are you sure this is correct?', [
2659 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2660 for problem in problems
2661 ])
2662 ]
2663 else:
2664 return []
[email protected]06e6d0ff2012-12-11 01:36:442665
2666
Saagar Sanghavifceeaae2020-08-12 16:40:362667def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502668 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292669
Sam Maiera6e76d72022-02-11 21:43:502670 def FileFilter(affected_file):
2671 """Includes directories known to be Chrome OS only."""
2672 return input_api.FilterSourceFile(
2673 affected_file,
2674 files_to_check=(
2675 '^ash/',
2676 '^chromeos/', # Top-level src/chromeos.
2677 '.*/chromeos/', # Any path component.
2678 '^components/arc',
2679 '^components/exo'),
2680 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292681
Sam Maiera6e76d72022-02-11 21:43:502682 prefs = []
2683 priority_prefs = []
2684 for f in input_api.AffectedFiles(file_filter=FileFilter):
2685 for line_num, line in f.ChangedContents():
2686 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2687 line):
2688 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2689 prefs.append(' %s' % line)
2690 if input_api.re.search(
2691 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2692 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2693 priority_prefs.append(' %s' % line)
2694
2695 results = []
2696 if (prefs):
2697 results.append(
2698 output_api.PresubmitPromptWarning(
2699 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2700 'by browser sync settings. If these prefs should be controlled by OS '
2701 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2702 '\n'.join(prefs)))
2703 if (priority_prefs):
2704 results.append(
2705 output_api.PresubmitPromptWarning(
2706 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2707 'controlled by browser sync settings. If these prefs should be '
2708 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2709 'instead.\n' + '\n'.join(prefs)))
2710 return results
James Cook6b6597c2019-11-06 22:05:292711
2712
Saagar Sanghavifceeaae2020-08-12 16:40:362713def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502714 """Makes sure there are no abbreviations in the name of PNG files.
2715 The native_client_sdk directory is excluded because it has auto-generated PNG
2716 files for documentation.
2717 """
2718 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:172719 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:312720 files_to_skip = [r'^native_client_sdk/',
2721 r'^services/test/',
2722 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182723 ]
Sam Maiera6e76d72022-02-11 21:43:502724 file_filter = lambda f: input_api.FilterSourceFile(
2725 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:172726 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:502727 for f in input_api.AffectedFiles(include_deletes=False,
2728 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:172729 file_name = input_api.os_path.split(f.LocalPath())[1]
2730 if abbreviation.search(file_name):
2731 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272732
Sam Maiera6e76d72022-02-11 21:43:502733 results = []
2734 if errors:
2735 results.append(
2736 output_api.PresubmitError(
2737 'The name of PNG files should not have abbreviations. \n'
2738 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2739 'Contact [email protected] if you have questions.', errors))
2740 return results
[email protected]d2530012013-01-25 16:39:272741
Evan Stade7cd4a2c2022-08-04 23:37:252742def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2743 """Heuristically identifies product icons based on their file name and reminds
2744 contributors not to add them to the Chromium repository.
2745 """
2746 errors = []
2747 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2748 file_filter = lambda f: input_api.FilterSourceFile(
2749 f, files_to_check=files_to_check)
2750 for f in input_api.AffectedFiles(include_deletes=False,
2751 file_filter=file_filter):
2752 errors.append(' %s' % f.LocalPath())
2753
2754 results = []
2755 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082756 # Give warnings instead of errors on presubmit --all and presubmit
2757 # --files.
2758 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2759 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252760 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082761 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252762 'Trademarked images should not be added to the public repo. '
2763 'See crbug.com/944754', errors))
2764 return results
2765
[email protected]d2530012013-01-25 16:39:272766
Daniel Cheng4dcdb6b2017-04-13 08:30:172767def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502768 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172769
Sam Maiera6e76d72022-02-11 21:43:502770 Args:
2771 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2772 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172773 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502774 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172775 if rule.startswith('+') or rule.startswith('!')
2776 ])
Sam Maiera6e76d72022-02-11 21:43:502777 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2778 add_rules.update([
2779 rule[1:] for rule in rules
2780 if rule.startswith('+') or rule.startswith('!')
2781 ])
2782 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172783
2784
2785def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502786 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172787
Sam Maiera6e76d72022-02-11 21:43:502788 # Stubs for handling special syntax in the root DEPS file.
2789 class _VarImpl:
2790 def __init__(self, local_scope):
2791 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172792
Sam Maiera6e76d72022-02-11 21:43:502793 def Lookup(self, var_name):
2794 """Implements the Var syntax."""
2795 try:
2796 return self._local_scope['vars'][var_name]
2797 except KeyError:
2798 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172799
Sam Maiera6e76d72022-02-11 21:43:502800 local_scope = {}
2801 global_scope = {
2802 'Var': _VarImpl(local_scope).Lookup,
2803 'Str': str,
2804 }
Dirk Pranke1b9e06382021-05-14 01:16:222805
Sam Maiera6e76d72022-02-11 21:43:502806 exec(contents, global_scope, local_scope)
2807 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172808
2809
2810def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502811 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2812 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412813
Sam Maiera6e76d72022-02-11 21:43:502814 For a directory (rather than a specific filename) we fake a path to
2815 a specific filename by adding /DEPS. This is chosen as a file that
2816 will seldom or never be subject to per-file include_rules.
2817 """
2818 # We ignore deps entries on auto-generated directories.
2819 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082820
Sam Maiera6e76d72022-02-11 21:43:502821 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2822 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172823
Sam Maiera6e76d72022-02-11 21:43:502824 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172825
Sam Maiera6e76d72022-02-11 21:43:502826 results = set()
2827 for added_dep in added_deps:
2828 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2829 continue
2830 # Assume that a rule that ends in .h is a rule for a specific file.
2831 if added_dep.endswith('.h'):
2832 results.add(added_dep)
2833 else:
2834 results.add(os_path.join(added_dep, 'DEPS'))
2835 return results
[email protected]f32e2d1e2013-07-26 21:39:082836
2837
Saagar Sanghavifceeaae2020-08-12 16:40:362838def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502839 """When a dependency prefixed with + is added to a DEPS file, we
2840 want to make sure that the change is reviewed by an OWNER of the
2841 target file or directory, to avoid layering violations from being
2842 introduced. This check verifies that this happens.
2843 """
2844 # We rely on Gerrit's code-owners to check approvals.
2845 # input_api.gerrit is always set for Chromium, but other projects
2846 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102847 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502848 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302849 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502850 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302851 try:
2852 if (input_api.change.issue and
2853 input_api.gerrit.IsOwnersOverrideApproved(
2854 input_api.change.issue)):
2855 # Skip OWNERS check when Owners-Override label is approved. This is
2856 # intended for global owners, trusted bots, and on-call sheriffs.
2857 # Review is still required for these changes.
2858 return []
2859 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:242860 return [output_api.PresubmitPromptWarning(
2861 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232862
Sam Maiera6e76d72022-02-11 21:43:502863 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242864
Bruce Dawson40fece62022-09-16 19:58:312865 # Consistently use / as path separator to simplify the writing of regex
2866 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502867 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312868 r"^third_party/blink/.*",
2869 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502870 for f in input_api.AffectedFiles(include_deletes=False,
2871 file_filter=file_filter):
2872 filename = input_api.os_path.basename(f.LocalPath())
2873 if filename == 'DEPS':
2874 virtual_depended_on_files.update(
2875 _CalculateAddedDeps(input_api.os_path,
2876 '\n'.join(f.OldContents()),
2877 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552878
Sam Maiera6e76d72022-02-11 21:43:502879 if not virtual_depended_on_files:
2880 return []
[email protected]e871964c2013-05-13 14:14:552881
Sam Maiera6e76d72022-02-11 21:43:502882 if input_api.is_committing:
2883 if input_api.tbr:
2884 return [
2885 output_api.PresubmitNotifyResult(
2886 '--tbr was specified, skipping OWNERS check for DEPS additions'
2887 )
2888 ]
Daniel Cheng3008dc12022-05-13 04:02:112889 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2890 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502891 if input_api.dry_run:
2892 return [
2893 output_api.PresubmitNotifyResult(
2894 'This is a dry run, skipping OWNERS check for DEPS additions'
2895 )
2896 ]
2897 if not input_api.change.issue:
2898 return [
2899 output_api.PresubmitError(
2900 "DEPS approval by OWNERS check failed: this change has "
2901 "no change number, so we can't check it for approvals.")
2902 ]
2903 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412904 else:
Sam Maiera6e76d72022-02-11 21:43:502905 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552906
Sam Maiera6e76d72022-02-11 21:43:502907 owner_email, reviewers = (
2908 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2909 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552910
Sam Maiera6e76d72022-02-11 21:43:502911 owner_email = owner_email or input_api.change.author_email
2912
2913 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2914 virtual_depended_on_files, reviewers.union([owner_email]), [])
2915 missing_files = [
2916 f for f in virtual_depended_on_files
2917 if approval_status[f] != input_api.owners_client.APPROVED
2918 ]
2919
2920 # We strip the /DEPS part that was added by
2921 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2922 # directory.
2923 def StripDeps(path):
2924 start_deps = path.rfind('/DEPS')
2925 if start_deps != -1:
2926 return path[:start_deps]
2927 else:
2928 return path
2929
2930 unapproved_dependencies = [
2931 "'+%s'," % StripDeps(path) for path in missing_files
2932 ]
2933
2934 if unapproved_dependencies:
2935 output_list = [
2936 output(
2937 'You need LGTM from owners of depends-on paths in DEPS that were '
2938 'modified in this CL:\n %s' %
2939 '\n '.join(sorted(unapproved_dependencies)))
2940 ]
2941 suggested_owners = input_api.owners_client.SuggestOwners(
2942 missing_files, exclude=[owner_email])
2943 output_list.append(
2944 output('Suggested missing target path OWNERS:\n %s' %
2945 '\n '.join(suggested_owners or [])))
2946 return output_list
2947
2948 return []
[email protected]e871964c2013-05-13 14:14:552949
2950
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492951# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362952def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502953 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2954 files_to_skip = (
2955 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2956 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:012957 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312958 r"^base/logging\.h$",
2959 r"^base/logging\.cc$",
2960 r"^base/task/thread_pool/task_tracker\.cc$",
2961 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:032962 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
2963 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312964 r"^chrome/browser/chrome_browser_main\.cc$",
2965 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
2966 r"^chrome/browser/browser_switcher/bho/.*",
2967 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
2968 r"^chrome/chrome_cleaner/.*",
2969 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
2970 r"^chrome/installer/setup/.*",
2971 r"^chromecast/",
Bruce Dawson40fece62022-09-16 19:58:312972 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:492973 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312974 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:502975 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312976 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:502977 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:312978 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:502979 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312980 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
2981 r"^courgette/courgette_minimal_tool\.cc$",
2982 r"^courgette/courgette_tool\.cc$",
2983 r"^extensions/renderer/logging_native_handler\.cc$",
2984 r"^fuchsia_web/common/init_logging\.cc$",
2985 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:152986 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312987 r"^headless/app/headless_shell\.cc$",
2988 r"^ipc/ipc_logging\.cc$",
2989 r"^native_client_sdk/",
2990 r"^remoting/base/logging\.h$",
2991 r"^remoting/host/.*",
2992 r"^sandbox/linux/.*",
2993 r"^storage/browser/file_system/dump_file_system\.cc$",
2994 r"^tools/",
2995 r"^ui/base/resource/data_pack\.cc$",
2996 r"^ui/aura/bench/bench_main\.cc$",
2997 r"^ui/ozone/platform/cast/",
2998 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:502999 r"xwmstartupcheck\.cc$"))
3000 source_file_filter = lambda x: input_api.FilterSourceFile(
3001 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403002
Sam Maiera6e76d72022-02-11 21:43:503003 log_info = set([])
3004 printf = set([])
[email protected]85218562013-11-22 07:41:403005
Sam Maiera6e76d72022-02-11 21:43:503006 for f in input_api.AffectedSourceFiles(source_file_filter):
3007 for _, line in f.ChangedContents():
3008 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3009 log_info.add(f.LocalPath())
3010 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3011 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373012
Sam Maiera6e76d72022-02-11 21:43:503013 if input_api.re.search(r"\bprintf\(", line):
3014 printf.add(f.LocalPath())
3015 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3016 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403017
Sam Maiera6e76d72022-02-11 21:43:503018 if log_info:
3019 return [
3020 output_api.PresubmitError(
3021 'These files spam the console log with LOG(INFO):',
3022 items=log_info)
3023 ]
3024 if printf:
3025 return [
3026 output_api.PresubmitError(
3027 'These files spam the console log with printf/fprintf:',
3028 items=printf)
3029 ]
3030 return []
[email protected]85218562013-11-22 07:41:403031
3032
Saagar Sanghavifceeaae2020-08-12 16:40:363033def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503034 """These types are all expected to hold locks while in scope and
3035 so should never be anonymous (which causes them to be immediately
3036 destroyed)."""
3037 they_who_must_be_named = [
3038 'base::AutoLock',
3039 'base::AutoReset',
3040 'base::AutoUnlock',
3041 'SkAutoAlphaRestore',
3042 'SkAutoBitmapShaderInstall',
3043 'SkAutoBlitterChoose',
3044 'SkAutoBounderCommit',
3045 'SkAutoCallProc',
3046 'SkAutoCanvasRestore',
3047 'SkAutoCommentBlock',
3048 'SkAutoDescriptor',
3049 'SkAutoDisableDirectionCheck',
3050 'SkAutoDisableOvalCheck',
3051 'SkAutoFree',
3052 'SkAutoGlyphCache',
3053 'SkAutoHDC',
3054 'SkAutoLockColors',
3055 'SkAutoLockPixels',
3056 'SkAutoMalloc',
3057 'SkAutoMaskFreeImage',
3058 'SkAutoMutexAcquire',
3059 'SkAutoPathBoundsUpdate',
3060 'SkAutoPDFRelease',
3061 'SkAutoRasterClipValidate',
3062 'SkAutoRef',
3063 'SkAutoTime',
3064 'SkAutoTrace',
3065 'SkAutoUnref',
3066 ]
3067 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3068 # bad: base::AutoLock(lock.get());
3069 # not bad: base::AutoLock lock(lock.get());
3070 bad_pattern = input_api.re.compile(anonymous)
3071 # good: new base::AutoLock(lock.get())
3072 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3073 errors = []
[email protected]49aa76a2013-12-04 06:59:163074
Sam Maiera6e76d72022-02-11 21:43:503075 for f in input_api.AffectedFiles():
3076 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3077 continue
3078 for linenum, line in f.ChangedContents():
3079 if bad_pattern.search(line) and not good_pattern.search(line):
3080 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163081
Sam Maiera6e76d72022-02-11 21:43:503082 if errors:
3083 return [
3084 output_api.PresubmitError(
3085 'These lines create anonymous variables that need to be named:',
3086 items=errors)
3087 ]
3088 return []
[email protected]49aa76a2013-12-04 06:59:163089
3090
Saagar Sanghavifceeaae2020-08-12 16:40:363091def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503092 # Returns whether |template_str| is of the form <T, U...> for some types T
3093 # and U. Assumes that |template_str| is already in the form <...>.
3094 def HasMoreThanOneArg(template_str):
3095 # Level of <...> nesting.
3096 nesting = 0
3097 for c in template_str:
3098 if c == '<':
3099 nesting += 1
3100 elif c == '>':
3101 nesting -= 1
3102 elif c == ',' and nesting == 1:
3103 return True
3104 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533105
Sam Maiera6e76d72022-02-11 21:43:503106 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3107 sources = lambda affected_file: input_api.FilterSourceFile(
3108 affected_file,
3109 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3110 DEFAULT_FILES_TO_SKIP),
3111 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553112
Sam Maiera6e76d72022-02-11 21:43:503113 # Pattern to capture a single "<...>" block of template arguments. It can
3114 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3115 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3116 # latter would likely require counting that < and > match, which is not
3117 # expressible in regular languages. Should the need arise, one can introduce
3118 # limited counting (matching up to a total number of nesting depth), which
3119 # should cover all practical cases for already a low nesting limit.
3120 template_arg_pattern = (
3121 r'<[^>]*' # Opening block of <.
3122 r'>([^<]*>)?') # Closing block of >.
3123 # Prefix expressing that whatever follows is not already inside a <...>
3124 # block.
3125 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3126 null_construct_pattern = input_api.re.compile(
3127 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3128 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553129
Sam Maiera6e76d72022-02-11 21:43:503130 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3131 template_arg_no_array_pattern = (
3132 r'<[^>]*[^]]' # Opening block of <.
3133 r'>([^(<]*[^]]>)?') # Closing block of >.
3134 # Prefix saying that what follows is the start of an expression.
3135 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3136 # Suffix saying that what follows are call parentheses with a non-empty list
3137 # of arguments.
3138 nonempty_arg_list_pattern = r'\(([^)]|$)'
3139 # Put the template argument into a capture group for deeper examination later.
3140 return_construct_pattern = input_api.re.compile(
3141 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3142 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553143
Sam Maiera6e76d72022-02-11 21:43:503144 problems_constructor = []
3145 problems_nullptr = []
3146 for f in input_api.AffectedSourceFiles(sources):
3147 for line_number, line in f.ChangedContents():
3148 # Disallow:
3149 # return std::unique_ptr<T>(foo);
3150 # bar = std::unique_ptr<T>(foo);
3151 # But allow:
3152 # return std::unique_ptr<T[]>(foo);
3153 # bar = std::unique_ptr<T[]>(foo);
3154 # And also allow cases when the second template argument is present. Those
3155 # cases cannot be handled by std::make_unique:
3156 # return std::unique_ptr<T, U>(foo);
3157 # bar = std::unique_ptr<T, U>(foo);
3158 local_path = f.LocalPath()
3159 return_construct_result = return_construct_pattern.search(line)
3160 if return_construct_result and not HasMoreThanOneArg(
3161 return_construct_result.group('template_arg')):
3162 problems_constructor.append(
3163 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3164 # Disallow:
3165 # std::unique_ptr<T>()
3166 if null_construct_pattern.search(line):
3167 problems_nullptr.append(
3168 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053169
Sam Maiera6e76d72022-02-11 21:43:503170 errors = []
3171 if problems_nullptr:
3172 errors.append(
3173 output_api.PresubmitPromptWarning(
3174 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3175 problems_nullptr))
3176 if problems_constructor:
3177 errors.append(
3178 output_api.PresubmitError(
3179 'The following files use explicit std::unique_ptr constructor. '
3180 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3181 'std::make_unique is not an option.', problems_constructor))
3182 return errors
Peter Kasting4844e46e2018-02-23 07:27:103183
3184
Saagar Sanghavifceeaae2020-08-12 16:40:363185def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503186 """Checks if any new user action has been added."""
3187 if any('actions.xml' == input_api.os_path.basename(f)
3188 for f in input_api.LocalPaths()):
3189 # If actions.xml is already included in the changelist, the PRESUBMIT
3190 # for actions.xml will do a more complete presubmit check.
3191 return []
3192
3193 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3194 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3195 input_api.DEFAULT_FILES_TO_SKIP)
3196 file_filter = lambda f: input_api.FilterSourceFile(
3197 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3198
3199 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3200 current_actions = None
3201 for f in input_api.AffectedFiles(file_filter=file_filter):
3202 for line_num, line in f.ChangedContents():
3203 match = input_api.re.search(action_re, line)
3204 if match:
3205 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3206 # loaded only once.
3207 if not current_actions:
3208 with open(
3209 'tools/metrics/actions/actions.xml') as actions_f:
3210 current_actions = actions_f.read()
3211 # Search for the matched user action name in |current_actions|.
3212 for action_name in match.groups():
3213 action = 'name="{0}"'.format(action_name)
3214 if action not in current_actions:
3215 return [
3216 output_api.PresubmitPromptWarning(
3217 'File %s line %d: %s is missing in '
3218 'tools/metrics/actions/actions.xml. Please run '
3219 'tools/metrics/actions/extract_actions.py to update.'
3220 % (f.LocalPath(), line_num, action_name))
3221 ]
[email protected]999261d2014-03-03 20:08:083222 return []
3223
[email protected]999261d2014-03-03 20:08:083224
Daniel Cheng13ca61a882017-08-25 15:11:253225def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503226 import sys
3227 sys.path = sys.path + [
3228 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3229 'json_comment_eater')
3230 ]
3231 import json_comment_eater
3232 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:253233
3234
[email protected]99171a92014-06-03 08:44:473235def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:173236 try:
Sam Maiera6e76d72022-02-11 21:43:503237 contents = input_api.ReadFile(filename)
3238 if eat_comments:
3239 json_comment_eater = _ImportJSONCommentEater(input_api)
3240 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:173241
Sam Maiera6e76d72022-02-11 21:43:503242 input_api.json.loads(contents)
3243 except ValueError as e:
3244 return e
Andrew Grieve4deedb12022-02-03 21:34:503245 return None
3246
3247
Sam Maiera6e76d72022-02-11 21:43:503248def _GetIDLParseError(input_api, filename):
3249 try:
3250 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:283251 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:343252 if not char.isascii():
3253 return (
3254 'Non-ascii character "%s" (ord %d) found at offset %d.' %
3255 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:503256 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
3257 'tools', 'json_schema_compiler',
3258 'idl_schema.py')
3259 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:283260 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:503261 stdin=input_api.subprocess.PIPE,
3262 stdout=input_api.subprocess.PIPE,
3263 stderr=input_api.subprocess.PIPE,
3264 universal_newlines=True)
3265 (_, error) = process.communicate(input=contents)
3266 return error or None
3267 except ValueError as e:
3268 return e
agrievef32bcc72016-04-04 14:57:403269
agrievef32bcc72016-04-04 14:57:403270
Sam Maiera6e76d72022-02-11 21:43:503271def CheckParseErrors(input_api, output_api):
3272 """Check that IDL and JSON files do not contain syntax errors."""
3273 actions = {
3274 '.idl': _GetIDLParseError,
3275 '.json': _GetJSONParseError,
3276 }
3277 # Most JSON files are preprocessed and support comments, but these do not.
3278 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313279 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:503280 ]
3281 # Only run IDL checker on files in these directories.
3282 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313283 r'^chrome/common/extensions/api/',
3284 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:503285 ]
agrievef32bcc72016-04-04 14:57:403286
Sam Maiera6e76d72022-02-11 21:43:503287 def get_action(affected_file):
3288 filename = affected_file.LocalPath()
3289 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:403290
Sam Maiera6e76d72022-02-11 21:43:503291 def FilterFile(affected_file):
3292 action = get_action(affected_file)
3293 if not action:
3294 return False
3295 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403296
Sam Maiera6e76d72022-02-11 21:43:503297 if _MatchesFile(input_api,
3298 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3299 return False
3300
3301 if (action == _GetIDLParseError
3302 and not _MatchesFile(input_api, idl_included_patterns, path)):
3303 return False
3304 return True
3305
3306 results = []
3307 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3308 include_deletes=False):
3309 action = get_action(affected_file)
3310 kwargs = {}
3311 if (action == _GetJSONParseError
3312 and _MatchesFile(input_api, json_no_comments_patterns,
3313 affected_file.LocalPath())):
3314 kwargs['eat_comments'] = False
3315 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3316 **kwargs)
3317 if parse_error:
3318 results.append(
3319 output_api.PresubmitError(
3320 '%s could not be parsed: %s' %
3321 (affected_file.LocalPath(), parse_error)))
3322 return results
3323
3324
3325def CheckJavaStyle(input_api, output_api):
3326 """Runs checkstyle on changed java files and returns errors if any exist."""
3327
3328 # Return early if no java files were modified.
3329 if not any(
3330 _IsJavaFile(input_api, f.LocalPath())
3331 for f in input_api.AffectedFiles()):
3332 return []
3333
3334 import sys
3335 original_sys_path = sys.path
3336 try:
3337 sys.path = sys.path + [
3338 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3339 'android', 'checkstyle')
3340 ]
3341 import checkstyle
3342 finally:
3343 # Restore sys.path to what it was before.
3344 sys.path = original_sys_path
3345
Andrew Grieve4f88e3ca2022-11-22 19:09:203346 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:503347 input_api,
3348 output_api,
Sam Maiera6e76d72022-02-11 21:43:503349 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3350
3351
3352def CheckPythonDevilInit(input_api, output_api):
3353 """Checks to make sure devil is initialized correctly in python scripts."""
3354 script_common_initialize_pattern = input_api.re.compile(
3355 r'script_common\.InitializeEnvironment\(')
3356 devil_env_config_initialize = input_api.re.compile(
3357 r'devil_env\.config\.Initialize\(')
3358
3359 errors = []
3360
3361 sources = lambda affected_file: input_api.FilterSourceFile(
3362 affected_file,
3363 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313364 r'^build/android/devil_chromium\.py',
3365 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503366 )),
3367 files_to_check=[r'.*\.py$'])
3368
3369 for f in input_api.AffectedSourceFiles(sources):
3370 for line_num, line in f.ChangedContents():
3371 if (script_common_initialize_pattern.search(line)
3372 or devil_env_config_initialize.search(line)):
3373 errors.append("%s:%d" % (f.LocalPath(), line_num))
3374
3375 results = []
3376
3377 if errors:
3378 results.append(
3379 output_api.PresubmitError(
3380 'Devil initialization should always be done using '
3381 'devil_chromium.Initialize() in the chromium project, to use better '
3382 'defaults for dependencies (ex. up-to-date version of adb).',
3383 errors))
3384
3385 return results
3386
3387
3388def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313389 # Consistently use / as path separator to simplify the writing of regex
3390 # expressions.
3391 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503392 for pattern in patterns:
3393 if input_api.re.search(pattern, path):
3394 return True
3395 return False
3396
3397
Daniel Chenga37c03db2022-05-12 17:20:343398def _ChangeHasSecurityReviewer(input_api, owners_file):
3399 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503400
Daniel Chenga37c03db2022-05-12 17:20:343401 Args:
3402 input_api: The presubmit input API.
3403 owners_file: OWNERS file with required reviewers. Typically, this is
3404 something like ipc/SECURITY_OWNERS.
3405
3406 Note: if the presubmit is running for commit rather than for upload, this
3407 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503408 """
Daniel Chengd88244472022-05-16 09:08:473409 # Owners-Override should bypass all additional OWNERS enforcement checks.
3410 # A CR+1 vote will still be required to land this change.
3411 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3412 input_api.change.issue)):
3413 return True
3414
Daniel Chenga37c03db2022-05-12 17:20:343415 owner_email, reviewers = (
3416 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113417 input_api,
3418 None,
3419 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503420
Daniel Chenga37c03db2022-05-12 17:20:343421 security_owners = input_api.owners_client.ListOwners(owners_file)
3422 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503423
Daniel Chenga37c03db2022-05-12 17:20:343424
3425@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253426class _SecurityProblemWithItems:
3427 problem: str
3428 items: Sequence[str]
3429
3430
3431@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343432class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253433 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343434 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253435 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343436
3437
3438def _FindMissingSecurityOwners(input_api,
3439 output_api,
3440 file_patterns: Sequence[str],
3441 excluded_patterns: Sequence[str],
3442 required_owners_file: str,
3443 custom_rule_function: Optional[Callable] = None
3444 ) -> _MissingSecurityOwnersResult:
3445 """Find OWNERS files missing per-file rules for security-sensitive files.
3446
3447 Args:
3448 input_api: the PRESUBMIT input API object.
3449 output_api: the PRESUBMIT output API object.
3450 file_patterns: basename patterns that require a corresponding per-file
3451 security restriction.
3452 excluded_patterns: path patterns that should be exempted from
3453 requiring a security restriction.
3454 required_owners_file: path to the required OWNERS file, e.g.
3455 ipc/SECURITY_OWNERS
3456 cc_alias: If not None, email that will be CCed automatically if the
3457 change contains security-sensitive files, as determined by
3458 `file_patterns` and `excluded_patterns`.
3459 custom_rule_function: If not None, will be called with `input_api` and
3460 the current file under consideration. Returning True will add an
3461 exact match per-file rule check for the current file.
3462 """
3463
3464 # `to_check` is a mapping of an OWNERS file path to Patterns.
3465 #
3466 # Patterns is a dictionary mapping glob patterns (suitable for use in
3467 # per-file rules) to a PatternEntry.
3468 #
Sam Maiera6e76d72022-02-11 21:43:503469 # PatternEntry is a dictionary with two keys:
3470 # - 'files': the files that are matched by this pattern
3471 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343472 #
Sam Maiera6e76d72022-02-11 21:43:503473 # For example, if we expect OWNERS file to contain rules for *.mojom and
3474 # *_struct_traits*.*, Patterns might look like this:
3475 # {
3476 # '*.mojom': {
3477 # 'files': ...,
3478 # 'rules': [
3479 # 'per-file *.mojom=set noparent',
3480 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3481 # ],
3482 # },
3483 # '*_struct_traits*.*': {
3484 # 'files': ...,
3485 # 'rules': [
3486 # 'per-file *_struct_traits*.*=set noparent',
3487 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3488 # ],
3489 # },
3490 # }
3491 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343492 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503493
Daniel Chenga37c03db2022-05-12 17:20:343494 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503495 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473496 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503497 if owners_file not in to_check:
3498 to_check[owners_file] = {}
3499 if pattern not in to_check[owners_file]:
3500 to_check[owners_file][pattern] = {
3501 'files': [],
3502 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343503 f'per-file {pattern}=set noparent',
3504 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503505 ]
3506 }
Daniel Chenged57a162022-05-25 02:56:343507 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343508 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503509
Daniel Chenga37c03db2022-05-12 17:20:343510 # Only enforce security OWNERS rules for a directory if that directory has a
3511 # file that matches `file_patterns`. For example, if a directory only
3512 # contains *.mojom files and no *_messages*.h files, the check should only
3513 # ensure that rules for *.mojom files are present.
3514 for file in input_api.AffectedFiles(include_deletes=False):
3515 file_basename = input_api.os_path.basename(file.LocalPath())
3516 if custom_rule_function is not None and custom_rule_function(
3517 input_api, file):
3518 AddPatternToCheck(file, file_basename)
3519 continue
Sam Maiera6e76d72022-02-11 21:43:503520
Daniel Chenga37c03db2022-05-12 17:20:343521 if any(
3522 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3523 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503524 continue
3525
3526 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343527 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3528 # file's basename.
3529 if input_api.fnmatch.fnmatch(file_basename, pattern):
3530 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503531 break
3532
Daniel Chenga37c03db2022-05-12 17:20:343533 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253534
3535 # Check if any newly added lines in OWNERS files intersect with required
3536 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3537 # This is a hack, but is needed because the OWNERS check (by design) ignores
3538 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3539 # OWNER and have that newly-added OWNER self-approve their own addition.
3540 newly_covered_files = []
3541 for file in input_api.AffectedFiles(include_deletes=False):
3542 if not file.LocalPath() in to_check:
3543 continue
3544 for _, line in file.ChangedContents():
3545 for _, entry in to_check[file.LocalPath()].items():
3546 if line in entry['rules']:
3547 newly_covered_files.extend(entry['files'])
3548
3549 missing_reviewer_problems = None
3550 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343551 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253552 missing_reviewer_problems = _SecurityProblemWithItems(
3553 f'Review from an owner in {required_owners_file} is required for '
3554 'the following newly-added files:',
3555 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503556
3557 # Go through the OWNERS files to check, filtering out rules that are already
3558 # present in that OWNERS file.
3559 for owners_file, patterns in to_check.items():
3560 try:
Daniel Cheng171dad8d2022-05-21 00:40:253561 lines = set(
3562 input_api.ReadFile(
3563 input_api.os_path.join(input_api.change.RepositoryRoot(),
3564 owners_file)).splitlines())
3565 for entry in patterns.values():
3566 entry['rules'] = [
3567 rule for rule in entry['rules'] if rule not in lines
3568 ]
Sam Maiera6e76d72022-02-11 21:43:503569 except IOError:
3570 # No OWNERS file, so all the rules are definitely missing.
3571 continue
3572
3573 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253574 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343575
Sam Maiera6e76d72022-02-11 21:43:503576 for owners_file, patterns in to_check.items():
3577 missing_lines = []
3578 files = []
3579 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343580 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503581 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503582 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253583 joined_missing_lines = '\n'.join(line for line in missing_lines)
3584 owners_file_problems.append(
3585 _SecurityProblemWithItems(
3586 'Found missing OWNERS lines for security-sensitive files. '
3587 f'Please add the following lines to {owners_file}:\n'
3588 f'{joined_missing_lines}\n\nTo ensure security review for:',
3589 files))
Daniel Chenga37c03db2022-05-12 17:20:343590
Daniel Cheng171dad8d2022-05-21 00:40:253591 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343592 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253593 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343594
3595
3596def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3597 # Whether or not a file affects IPC is (mostly) determined by a simple list
3598 # of filename patterns.
3599 file_patterns = [
3600 # Legacy IPC:
3601 '*_messages.cc',
3602 '*_messages*.h',
3603 '*_param_traits*.*',
3604 # Mojo IPC:
3605 '*.mojom',
3606 '*_mojom_traits*.*',
3607 '*_type_converter*.*',
3608 # Android native IPC:
3609 '*.aidl',
3610 ]
3611
Daniel Chenga37c03db2022-05-12 17:20:343612 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463613 # These third_party directories do not contain IPCs, but contain files
3614 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343615 'third_party/crashpad/*',
3616 'third_party/blink/renderer/platform/bindings/*',
3617 'third_party/protobuf/benchmarks/python/*',
3618 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473619 # Enum-only mojoms used for web metrics, so no security review needed.
3620 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343621 # These files are just used to communicate between class loaders running
3622 # in the same process.
3623 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3624 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3625 ]
3626
3627 def IsMojoServiceManifestFile(input_api, file):
3628 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3629 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3630 if not manifest_pattern.search(file.LocalPath()):
3631 return False
3632
3633 if test_manifest_pattern.search(file.LocalPath()):
3634 return False
3635
3636 # All actual service manifest files should contain at least one
3637 # qualified reference to service_manager::Manifest.
3638 return any('service_manager::Manifest' in line
3639 for line in file.NewContents())
3640
3641 return _FindMissingSecurityOwners(
3642 input_api,
3643 output_api,
3644 file_patterns,
3645 excluded_patterns,
3646 'ipc/SECURITY_OWNERS',
3647 custom_rule_function=IsMojoServiceManifestFile)
3648
3649
3650def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3651 file_patterns = [
3652 # Component specifications.
3653 '*.cml', # Component Framework v2.
3654 '*.cmx', # Component Framework v1.
3655
3656 # Fuchsia IDL protocol specifications.
3657 '*.fidl',
3658 ]
3659
3660 # Don't check for owners files for changes in these directories.
3661 excluded_patterns = [
3662 'third_party/crashpad/*',
3663 ]
3664
3665 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3666 excluded_patterns,
3667 'build/fuchsia/SECURITY_OWNERS')
3668
3669
3670def CheckSecurityOwners(input_api, output_api):
3671 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3672 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3673 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3674 input_api, output_api)
3675
3676 if ipc_results.has_security_sensitive_files:
3677 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503678
3679 results = []
Daniel Chenga37c03db2022-05-12 17:20:343680
Daniel Cheng171dad8d2022-05-21 00:40:253681 missing_reviewer_problems = []
3682 if ipc_results.missing_reviewer_problem:
3683 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3684 if fuchsia_results.missing_reviewer_problem:
3685 missing_reviewer_problems.append(
3686 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343687
Daniel Cheng171dad8d2022-05-21 00:40:253688 # Missing reviewers are an error unless there's no issue number
3689 # associated with this branch; in that case, the presubmit is being run
3690 # with --all or --files.
3691 #
3692 # Note that upload should never be an error; otherwise, it would be
3693 # impossible to upload changes at all.
3694 if input_api.is_committing and input_api.change.issue:
3695 make_presubmit_message = output_api.PresubmitError
3696 else:
3697 make_presubmit_message = output_api.PresubmitNotifyResult
3698 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503699 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253700 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343701
Daniel Cheng171dad8d2022-05-21 00:40:253702 owners_file_problems = []
3703 owners_file_problems.extend(ipc_results.owners_file_problems)
3704 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343705
Daniel Cheng171dad8d2022-05-21 00:40:253706 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113707 # Missing per-file rules are always an error. While swarming and caching
3708 # means that uploading a patchset with updated OWNERS files and sending
3709 # it to the CQ again should not have a large incremental cost, it is
3710 # still frustrating to discover the error only after the change has
3711 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343712 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253713 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503714
3715 return results
3716
3717
3718def _GetFilesUsingSecurityCriticalFunctions(input_api):
3719 """Checks affected files for changes to security-critical calls. This
3720 function checks the full change diff, to catch both additions/changes
3721 and removals.
3722
3723 Returns a dict keyed by file name, and the value is a set of detected
3724 functions.
3725 """
3726 # Map of function pretty name (displayed in an error) to the pattern to
3727 # match it with.
3728 _PATTERNS_TO_CHECK = {
3729 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3730 }
3731 _PATTERNS_TO_CHECK = {
3732 k: input_api.re.compile(v)
3733 for k, v in _PATTERNS_TO_CHECK.items()
3734 }
3735
Sam Maiera6e76d72022-02-11 21:43:503736 # We don't want to trigger on strings within this file.
3737 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343738 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503739
3740 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3741 files_to_functions = {}
3742 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3743 diff = f.GenerateScmDiff()
3744 for line in diff.split('\n'):
3745 # Not using just RightHandSideLines() because removing a
3746 # call to a security-critical function can be just as important
3747 # as adding or changing the arguments.
3748 if line.startswith('-') or (line.startswith('+')
3749 and not line.startswith('++')):
3750 for name, pattern in _PATTERNS_TO_CHECK.items():
3751 if pattern.search(line):
3752 path = f.LocalPath()
3753 if not path in files_to_functions:
3754 files_to_functions[path] = set()
3755 files_to_functions[path].add(name)
3756 return files_to_functions
3757
3758
3759def CheckSecurityChanges(input_api, output_api):
3760 """Checks that changes involving security-critical functions are reviewed
3761 by the security team.
3762 """
3763 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3764 if not len(files_to_functions):
3765 return []
3766
Sam Maiera6e76d72022-02-11 21:43:503767 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343768 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503769 return []
3770
Daniel Chenga37c03db2022-05-12 17:20:343771 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503772 'that need to be reviewed by {}.\n'.format(owners_file)
3773 for path, names in files_to_functions.items():
3774 msg += ' {}\n'.format(path)
3775 for name in names:
3776 msg += ' {}\n'.format(name)
3777 msg += '\n'
3778
3779 if input_api.is_committing:
3780 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033781 else:
Sam Maiera6e76d72022-02-11 21:43:503782 output = output_api.PresubmitNotifyResult
3783 return [output(msg)]
3784
3785
3786def CheckSetNoParent(input_api, output_api):
3787 """Checks that set noparent is only used together with an OWNERS file in
3788 //build/OWNERS.setnoparent (see also
3789 //docs/code_reviews.md#owners-files-details)
3790 """
3791 # Return early if no OWNERS files were modified.
3792 if not any(f.LocalPath().endswith('OWNERS')
3793 for f in input_api.AffectedFiles(include_deletes=False)):
3794 return []
3795
3796 errors = []
3797
3798 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3799 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:163800 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:503801 for line in f:
3802 line = line.strip()
3803 if not line or line.startswith('#'):
3804 continue
3805 allowed_owners_files.add(line)
3806
3807 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3808
3809 for f in input_api.AffectedFiles(include_deletes=False):
3810 if not f.LocalPath().endswith('OWNERS'):
3811 continue
3812
3813 found_owners_files = set()
3814 found_set_noparent_lines = dict()
3815
3816 # Parse the OWNERS file.
3817 for lineno, line in enumerate(f.NewContents(), 1):
3818 line = line.strip()
3819 if line.startswith('set noparent'):
3820 found_set_noparent_lines[''] = lineno
3821 if line.startswith('file://'):
3822 if line in allowed_owners_files:
3823 found_owners_files.add('')
3824 if line.startswith('per-file'):
3825 match = per_file_pattern.match(line)
3826 if match:
3827 glob = match.group(1).strip()
3828 directive = match.group(2).strip()
3829 if directive == 'set noparent':
3830 found_set_noparent_lines[glob] = lineno
3831 if directive.startswith('file://'):
3832 if directive in allowed_owners_files:
3833 found_owners_files.add(glob)
3834
3835 # Check that every set noparent line has a corresponding file:// line
3836 # listed in build/OWNERS.setnoparent. An exception is made for top level
3837 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493838 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3839 if (linux_path.count('/') != 1
3840 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503841 for set_noparent_line in found_set_noparent_lines:
3842 if set_noparent_line in found_owners_files:
3843 continue
3844 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493845 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503846 found_set_noparent_lines[set_noparent_line]))
3847
3848 results = []
3849 if errors:
3850 if input_api.is_committing:
3851 output = output_api.PresubmitError
3852 else:
3853 output = output_api.PresubmitPromptWarning
3854 results.append(
3855 output(
3856 'Found the following "set noparent" restrictions in OWNERS files that '
3857 'do not include owners from build/OWNERS.setnoparent:',
3858 long_text='\n\n'.join(errors)))
3859 return results
3860
3861
3862def CheckUselessForwardDeclarations(input_api, output_api):
3863 """Checks that added or removed lines in non third party affected
3864 header files do not lead to new useless class or struct forward
3865 declaration.
3866 """
3867 results = []
3868 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3869 input_api.re.MULTILINE)
3870 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3871 input_api.re.MULTILINE)
3872 for f in input_api.AffectedFiles(include_deletes=False):
3873 if (f.LocalPath().startswith('third_party')
3874 and not f.LocalPath().startswith('third_party/blink')
3875 and not f.LocalPath().startswith('third_party\\blink')):
3876 continue
3877
3878 if not f.LocalPath().endswith('.h'):
3879 continue
3880
3881 contents = input_api.ReadFile(f)
3882 fwd_decls = input_api.re.findall(class_pattern, contents)
3883 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3884
3885 useless_fwd_decls = []
3886 for decl in fwd_decls:
3887 count = sum(1 for _ in input_api.re.finditer(
3888 r'\b%s\b' % input_api.re.escape(decl), contents))
3889 if count == 1:
3890 useless_fwd_decls.append(decl)
3891
3892 if not useless_fwd_decls:
3893 continue
3894
3895 for line in f.GenerateScmDiff().splitlines():
3896 if (line.startswith('-') and not line.startswith('--')
3897 or line.startswith('+') and not line.startswith('++')):
3898 for decl in useless_fwd_decls:
3899 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3900 results.append(
3901 output_api.PresubmitPromptWarning(
3902 '%s: %s forward declaration is no longer needed'
3903 % (f.LocalPath(), decl)))
3904 useless_fwd_decls.remove(decl)
3905
3906 return results
3907
3908
3909def _CheckAndroidDebuggableBuild(input_api, output_api):
3910 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3911 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3912 this is a debuggable build of Android.
3913 """
3914 build_type_check_pattern = input_api.re.compile(
3915 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3916
3917 errors = []
3918
3919 sources = lambda affected_file: input_api.FilterSourceFile(
3920 affected_file,
3921 files_to_skip=(
3922 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3923 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313924 r"^android_webview/support_library/boundary_interfaces/",
3925 r"^chrome/android/webapk/.*",
3926 r'^third_party/.*',
3927 r"tools/android/customtabs_benchmark/.*",
3928 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:503929 )),
3930 files_to_check=[r'.*\.java$'])
3931
3932 for f in input_api.AffectedSourceFiles(sources):
3933 for line_num, line in f.ChangedContents():
3934 if build_type_check_pattern.search(line):
3935 errors.append("%s:%d" % (f.LocalPath(), line_num))
3936
3937 results = []
3938
3939 if errors:
3940 results.append(
3941 output_api.PresubmitPromptWarning(
3942 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3943 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3944
3945 return results
3946
3947# TODO: add unit tests
3948def _CheckAndroidToastUsage(input_api, output_api):
3949 """Checks that code uses org.chromium.ui.widget.Toast instead of
3950 android.widget.Toast (Chromium Toast doesn't force hardware
3951 acceleration on low-end devices, saving memory).
3952 """
3953 toast_import_pattern = input_api.re.compile(
3954 r'^import android\.widget\.Toast;$')
3955
3956 errors = []
3957
3958 sources = lambda affected_file: input_api.FilterSourceFile(
3959 affected_file,
3960 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:313961 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
3962 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:503963 files_to_check=[r'.*\.java$'])
3964
3965 for f in input_api.AffectedSourceFiles(sources):
3966 for line_num, line in f.ChangedContents():
3967 if toast_import_pattern.search(line):
3968 errors.append("%s:%d" % (f.LocalPath(), line_num))
3969
3970 results = []
3971
3972 if errors:
3973 results.append(
3974 output_api.PresubmitError(
3975 'android.widget.Toast usage is detected. Android toasts use hardware'
3976 ' acceleration, and can be\ncostly on low-end devices. Please use'
3977 ' org.chromium.ui.widget.Toast instead.\n'
3978 'Contact [email protected] if you have any questions.',
3979 errors))
3980
3981 return results
3982
3983
3984def _CheckAndroidCrLogUsage(input_api, output_api):
3985 """Checks that new logs using org.chromium.base.Log:
3986 - Are using 'TAG' as variable name for the tags (warn)
3987 - Are using a tag that is shorter than 20 characters (error)
3988 """
3989
3990 # Do not check format of logs in the given files
3991 cr_log_check_excluded_paths = [
3992 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:313993 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:503994 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:313995 r"^android_webview/glue/java/src/com/android/"
3996 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:503997 # The customtabs_benchmark is a small app that does not depend on Chromium
3998 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:313999 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504000 ]
4001
4002 cr_log_import_pattern = input_api.re.compile(
4003 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4004 class_in_base_pattern = input_api.re.compile(
4005 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4006 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4007 input_api.re.MULTILINE)
4008 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4009 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4010 log_decl_pattern = input_api.re.compile(
4011 r'static final String TAG = "(?P<name>(.*))"')
4012 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4013
4014 REF_MSG = ('See docs/android_logging.md for more info.')
4015 sources = lambda x: input_api.FilterSourceFile(
4016 x,
4017 files_to_check=[r'.*\.java$'],
4018 files_to_skip=cr_log_check_excluded_paths)
4019
4020 tag_decl_errors = []
4021 tag_length_errors = []
4022 tag_errors = []
4023 tag_with_dot_errors = []
4024 util_log_errors = []
4025
4026 for f in input_api.AffectedSourceFiles(sources):
4027 file_content = input_api.ReadFile(f)
4028 has_modified_logs = False
4029 # Per line checks
4030 if (cr_log_import_pattern.search(file_content)
4031 or (class_in_base_pattern.search(file_content)
4032 and not has_some_log_import_pattern.search(file_content))):
4033 # Checks to run for files using cr log
4034 for line_num, line in f.ChangedContents():
4035 if rough_log_decl_pattern.search(line):
4036 has_modified_logs = True
4037
4038 # Check if the new line is doing some logging
4039 match = log_call_pattern.search(line)
4040 if match:
4041 has_modified_logs = True
4042
4043 # Make sure it uses "TAG"
4044 if not match.group('tag') == 'TAG':
4045 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4046 else:
4047 # Report non cr Log function calls in changed lines
4048 for line_num, line in f.ChangedContents():
4049 if log_call_pattern.search(line):
4050 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4051
4052 # Per file checks
4053 if has_modified_logs:
4054 # Make sure the tag is using the "cr" prefix and is not too long
4055 match = log_decl_pattern.search(file_content)
4056 tag_name = match.group('name') if match else None
4057 if not tag_name:
4058 tag_decl_errors.append(f.LocalPath())
4059 elif len(tag_name) > 20:
4060 tag_length_errors.append(f.LocalPath())
4061 elif '.' in tag_name:
4062 tag_with_dot_errors.append(f.LocalPath())
4063
4064 results = []
4065 if tag_decl_errors:
4066 results.append(
4067 output_api.PresubmitPromptWarning(
4068 'Please define your tags using the suggested format: .\n'
4069 '"private static final String TAG = "<package tag>".\n'
4070 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4071 tag_decl_errors))
4072
4073 if tag_length_errors:
4074 results.append(
4075 output_api.PresubmitError(
4076 'The tag length is restricted by the system to be at most '
4077 '20 characters.\n' + REF_MSG, tag_length_errors))
4078
4079 if tag_errors:
4080 results.append(
4081 output_api.PresubmitPromptWarning(
4082 'Please use a variable named "TAG" for your log tags.\n' +
4083 REF_MSG, tag_errors))
4084
4085 if util_log_errors:
4086 results.append(
4087 output_api.PresubmitPromptWarning(
4088 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4089 util_log_errors))
4090
4091 if tag_with_dot_errors:
4092 results.append(
4093 output_api.PresubmitPromptWarning(
4094 'Dot in log tags cause them to be elided in crash reports.\n' +
4095 REF_MSG, tag_with_dot_errors))
4096
4097 return results
4098
4099
4100def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
4101 """Checks that junit.framework.* is no longer used."""
4102 deprecated_junit_framework_pattern = input_api.re.compile(
4103 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
4104 sources = lambda x: input_api.FilterSourceFile(
4105 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4106 errors = []
4107 for f in input_api.AffectedFiles(file_filter=sources):
4108 for line_num, line in f.ChangedContents():
4109 if deprecated_junit_framework_pattern.search(line):
4110 errors.append("%s:%d" % (f.LocalPath(), line_num))
4111
4112 results = []
4113 if errors:
4114 results.append(
4115 output_api.PresubmitError(
4116 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
4117 '(org.junit.*) from //third_party/junit. Contact [email protected]'
4118 ' if you have any question.', errors))
4119 return results
4120
4121
4122def _CheckAndroidTestJUnitInheritance(input_api, output_api):
4123 """Checks that if new Java test classes have inheritance.
4124 Either the new test class is JUnit3 test or it is a JUnit4 test class
4125 with a base class, either case is undesirable.
4126 """
4127 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
4128
4129 sources = lambda x: input_api.FilterSourceFile(
4130 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
4131 errors = []
4132 for f in input_api.AffectedFiles(file_filter=sources):
4133 if not f.OldContents():
4134 class_declaration_start_flag = False
4135 for line_num, line in f.ChangedContents():
4136 if class_declaration_pattern.search(line):
4137 class_declaration_start_flag = True
4138 if class_declaration_start_flag and ' extends ' in line:
4139 errors.append('%s:%d' % (f.LocalPath(), line_num))
4140 if '{' in line:
4141 class_declaration_start_flag = False
4142
4143 results = []
4144 if errors:
4145 results.append(
4146 output_api.PresubmitPromptWarning(
4147 'The newly created files include Test classes that inherits from base'
4148 ' class. Please do not use inheritance in JUnit4 tests or add new'
4149 ' JUnit3 tests. Contact [email protected] if you have any'
4150 ' questions.', errors))
4151 return results
4152
4153
4154def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4155 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4156 deprecated_annotation_import_pattern = input_api.re.compile(
4157 r'^import android\.test\.suitebuilder\.annotation\..*;',
4158 input_api.re.MULTILINE)
4159 sources = lambda x: input_api.FilterSourceFile(
4160 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4161 errors = []
4162 for f in input_api.AffectedFiles(file_filter=sources):
4163 for line_num, line in f.ChangedContents():
4164 if deprecated_annotation_import_pattern.search(line):
4165 errors.append("%s:%d" % (f.LocalPath(), line_num))
4166
4167 results = []
4168 if errors:
4169 results.append(
4170 output_api.PresubmitError(
4171 'Annotations in android.test.suitebuilder.annotation have been'
4172 ' deprecated since API level 24. Please use android.support.test.filters'
4173 ' from //third_party/android_support_test_runner:runner_java instead.'
4174 ' Contact [email protected] if you have any questions.',
4175 errors))
4176 return results
4177
4178
4179def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4180 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514181 file_filter = lambda f: (f.LocalPath().endswith(
4182 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4183 LocalPath() or '/res/drawable-ldrtl/'.replace(
4184 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504185 errors = []
4186 for f in input_api.AffectedFiles(include_deletes=False,
4187 file_filter=file_filter):
4188 errors.append(' %s' % f.LocalPath())
4189
4190 results = []
4191 if errors:
4192 results.append(
4193 output_api.PresubmitError(
4194 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4195 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4196 '/res/drawable-ldrtl/.\n'
4197 'Contact [email protected] if you have questions.', errors))
4198 return results
4199
4200
4201def _CheckAndroidWebkitImports(input_api, output_api):
4202 """Checks that code uses org.chromium.base.Callback instead of
4203 android.webview.ValueCallback except in the WebView glue layer
4204 and WebLayer.
4205 """
4206 valuecallback_import_pattern = input_api.re.compile(
4207 r'^import android\.webkit\.ValueCallback;$')
4208
4209 errors = []
4210
4211 sources = lambda affected_file: input_api.FilterSourceFile(
4212 affected_file,
4213 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4214 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314215 r'^android_webview/glue/.*',
4216 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504217 )),
4218 files_to_check=[r'.*\.java$'])
4219
4220 for f in input_api.AffectedSourceFiles(sources):
4221 for line_num, line in f.ChangedContents():
4222 if valuecallback_import_pattern.search(line):
4223 errors.append("%s:%d" % (f.LocalPath(), line_num))
4224
4225 results = []
4226
4227 if errors:
4228 results.append(
4229 output_api.PresubmitError(
4230 'android.webkit.ValueCallback usage is detected outside of the glue'
4231 ' layer. To stay compatible with the support library, android.webkit.*'
4232 ' classes should only be used inside the glue layer and'
4233 ' org.chromium.base.Callback should be used instead.', errors))
4234
4235 return results
4236
4237
4238def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4239 """Checks Android XML styles """
4240
4241 # Return early if no relevant files were modified.
4242 if not any(
4243 _IsXmlOrGrdFile(input_api, f.LocalPath())
4244 for f in input_api.AffectedFiles(include_deletes=False)):
4245 return []
4246
4247 import sys
4248 original_sys_path = sys.path
4249 try:
4250 sys.path = sys.path + [
4251 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4252 'android', 'checkxmlstyle')
4253 ]
4254 import checkxmlstyle
4255 finally:
4256 # Restore sys.path to what it was before.
4257 sys.path = original_sys_path
4258
4259 if is_check_on_upload:
4260 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4261 else:
4262 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4263
4264
4265def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4266 """Checks Android Infobar Deprecation """
4267
4268 import sys
4269 original_sys_path = sys.path
4270 try:
4271 sys.path = sys.path + [
4272 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4273 'android', 'infobar_deprecation')
4274 ]
4275 import infobar_deprecation
4276 finally:
4277 # Restore sys.path to what it was before.
4278 sys.path = original_sys_path
4279
4280 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4281
4282
4283class _PydepsCheckerResult:
4284 def __init__(self, cmd, pydeps_path, process, old_contents):
4285 self._cmd = cmd
4286 self._pydeps_path = pydeps_path
4287 self._process = process
4288 self._old_contents = old_contents
4289
4290 def GetError(self):
4291 """Returns an error message, or None."""
4292 import difflib
4293 if self._process.wait() != 0:
4294 # STDERR should already be printed.
4295 return 'Command failed: ' + self._cmd
4296 new_contents = self._process.stdout.read().splitlines()[2:]
4297 if self._old_contents != new_contents:
4298 diff = '\n'.join(
4299 difflib.context_diff(self._old_contents, new_contents))
4300 return ('File is stale: {}\n'
4301 'Diff (apply to fix):\n'
4302 '{}\n'
4303 'To regenerate, run:\n\n'
4304 ' {}').format(self._pydeps_path, diff, self._cmd)
4305 return None
4306
4307
4308class PydepsChecker:
4309 def __init__(self, input_api, pydeps_files):
4310 self._file_cache = {}
4311 self._input_api = input_api
4312 self._pydeps_files = pydeps_files
4313
4314 def _LoadFile(self, path):
4315 """Returns the list of paths within a .pydeps file relative to //."""
4316 if path not in self._file_cache:
4317 with open(path, encoding='utf-8') as f:
4318 self._file_cache[path] = f.read()
4319 return self._file_cache[path]
4320
4321 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594322 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504323 pydeps_data = self._LoadFile(pydeps_path)
4324 uses_gn_paths = '--gn-paths' in pydeps_data
4325 entries = (l for l in pydeps_data.splitlines()
4326 if not l.startswith('#'))
4327 if uses_gn_paths:
4328 # Paths look like: //foo/bar/baz
4329 return (e[2:] for e in entries)
4330 else:
4331 # Paths look like: path/relative/to/file.pydeps
4332 os_path = self._input_api.os_path
4333 pydeps_dir = os_path.dirname(pydeps_path)
4334 return (os_path.normpath(os_path.join(pydeps_dir, e))
4335 for e in entries)
4336
4337 def _CreateFilesToPydepsMap(self):
4338 """Returns a map of local_path -> list_of_pydeps."""
4339 ret = {}
4340 for pydep_local_path in self._pydeps_files:
4341 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4342 ret.setdefault(path, []).append(pydep_local_path)
4343 return ret
4344
4345 def ComputeAffectedPydeps(self):
4346 """Returns an iterable of .pydeps files that might need regenerating."""
4347 affected_pydeps = set()
4348 file_to_pydeps_map = None
4349 for f in self._input_api.AffectedFiles(include_deletes=True):
4350 local_path = f.LocalPath()
4351 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4352 # subrepositories. We can't figure out which files change, so re-check
4353 # all files.
4354 # Changes to print_python_deps.py affect all .pydeps.
4355 if local_path in ('DEPS', 'PRESUBMIT.py'
4356 ) or local_path.endswith('print_python_deps.py'):
4357 return self._pydeps_files
4358 elif local_path.endswith('.pydeps'):
4359 if local_path in self._pydeps_files:
4360 affected_pydeps.add(local_path)
4361 elif local_path.endswith('.py'):
4362 if file_to_pydeps_map is None:
4363 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4364 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4365 return affected_pydeps
4366
4367 def DetermineIfStaleAsync(self, pydeps_path):
4368 """Runs print_python_deps.py to see if the files is stale."""
4369 import os
4370
4371 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4372 if old_pydeps_data:
4373 cmd = old_pydeps_data[1][1:].strip()
4374 if '--output' not in cmd:
4375 cmd += ' --output ' + pydeps_path
4376 old_contents = old_pydeps_data[2:]
4377 else:
4378 # A default cmd that should work in most cases (as long as pydeps filename
4379 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4380 # file is empty/new.
4381 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4382 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4383 old_contents = []
4384 env = dict(os.environ)
4385 env['PYTHONDONTWRITEBYTECODE'] = '1'
4386 process = self._input_api.subprocess.Popen(
4387 cmd + ' --output ""',
4388 shell=True,
4389 env=env,
4390 stdout=self._input_api.subprocess.PIPE,
4391 encoding='utf-8')
4392 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404393
4394
Tibor Goldschwendt360793f72019-06-25 18:23:494395def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504396 args = {}
4397 with open('build/config/gclient_args.gni', 'r') as f:
4398 for line in f:
4399 line = line.strip()
4400 if not line or line.startswith('#'):
4401 continue
4402 attribute, value = line.split('=')
4403 args[attribute.strip()] = value.strip()
4404 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494405
4406
Saagar Sanghavifceeaae2020-08-12 16:40:364407def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504408 """Checks if a .pydeps file needs to be regenerated."""
4409 # This check is for Python dependency lists (.pydeps files), and involves
4410 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4411 # doesn't work on Windows and Mac, so skip it on other platforms.
4412 if not input_api.platform.startswith('linux'):
4413 return []
Erik Staabc734cd7a2021-11-23 03:11:524414
Sam Maiera6e76d72022-02-11 21:43:504415 results = []
4416 # First, check for new / deleted .pydeps.
4417 for f in input_api.AffectedFiles(include_deletes=True):
4418 # Check whether we are running the presubmit check for a file in src.
4419 # f.LocalPath is relative to repo (src, or internal repo).
4420 # os_path.exists is relative to src repo.
4421 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4422 # to src and we can conclude that the pydeps is in src.
4423 if f.LocalPath().endswith('.pydeps'):
4424 if input_api.os_path.exists(f.LocalPath()):
4425 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4426 results.append(
4427 output_api.PresubmitError(
4428 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4429 'remove %s' % f.LocalPath()))
4430 elif f.Action() != 'D' and f.LocalPath(
4431 ) not in _ALL_PYDEPS_FILES:
4432 results.append(
4433 output_api.PresubmitError(
4434 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4435 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404436
Sam Maiera6e76d72022-02-11 21:43:504437 if results:
4438 return results
4439
4440 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4441 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4442 affected_pydeps = set(checker.ComputeAffectedPydeps())
4443 affected_android_pydeps = affected_pydeps.intersection(
4444 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4445 if affected_android_pydeps and not is_android:
4446 results.append(
4447 output_api.PresubmitPromptOrNotify(
4448 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594449 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504450 'run because you are not using an Android checkout. To validate that\n'
4451 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4452 'use the android-internal-presubmit optional trybot.\n'
4453 'Possibly stale pydeps files:\n{}'.format(
4454 '\n'.join(affected_android_pydeps))))
4455
4456 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4457 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4458 # Process these concurrently, as each one takes 1-2 seconds.
4459 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4460 for result in pydep_results:
4461 error_msg = result.GetError()
4462 if error_msg:
4463 results.append(output_api.PresubmitError(error_msg))
4464
agrievef32bcc72016-04-04 14:57:404465 return results
4466
agrievef32bcc72016-04-04 14:57:404467
Saagar Sanghavifceeaae2020-08-12 16:40:364468def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504469 """Checks to make sure no header files have |Singleton<|."""
4470
4471 def FileFilter(affected_file):
4472 # It's ok for base/memory/singleton.h to have |Singleton<|.
4473 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314474 (r"^base/memory/singleton\.h$",
4475 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504476 return input_api.FilterSourceFile(affected_file,
4477 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434478
Sam Maiera6e76d72022-02-11 21:43:504479 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4480 files = []
4481 for f in input_api.AffectedSourceFiles(FileFilter):
4482 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4483 or f.LocalPath().endswith('.hpp')
4484 or f.LocalPath().endswith('.inl')):
4485 contents = input_api.ReadFile(f)
4486 for line in contents.splitlines(False):
4487 if (not line.lstrip().startswith('//')
4488 and # Strip C++ comment.
4489 pattern.search(line)):
4490 files.append(f)
4491 break
glidere61efad2015-02-18 17:39:434492
Sam Maiera6e76d72022-02-11 21:43:504493 if files:
4494 return [
4495 output_api.PresubmitError(
4496 'Found base::Singleton<T> in the following header files.\n' +
4497 'Please move them to an appropriate source file so that the ' +
4498 'template gets instantiated in a single compilation unit.',
4499 files)
4500 ]
4501 return []
glidere61efad2015-02-18 17:39:434502
4503
[email protected]fd20b902014-05-09 02:14:534504_DEPRECATED_CSS = [
4505 # Values
4506 ( "-webkit-box", "flex" ),
4507 ( "-webkit-inline-box", "inline-flex" ),
4508 ( "-webkit-flex", "flex" ),
4509 ( "-webkit-inline-flex", "inline-flex" ),
4510 ( "-webkit-min-content", "min-content" ),
4511 ( "-webkit-max-content", "max-content" ),
4512
4513 # Properties
4514 ( "-webkit-background-clip", "background-clip" ),
4515 ( "-webkit-background-origin", "background-origin" ),
4516 ( "-webkit-background-size", "background-size" ),
4517 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444518 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:534519
4520 # Functions
4521 ( "-webkit-gradient", "gradient" ),
4522 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4523 ( "-webkit-linear-gradient", "linear-gradient" ),
4524 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4525 ( "-webkit-radial-gradient", "radial-gradient" ),
4526 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4527]
4528
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204529
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494530# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364531def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504532 """ Make sure that we don't use deprecated CSS
4533 properties, functions or values. Our external
4534 documentation and iOS CSS for dom distiller
4535 (reader mode) are ignored by the hooks as it
4536 needs to be consumed by WebKit. """
4537 results = []
4538 file_inclusion_pattern = [r".+\.css$"]
4539 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4540 input_api.DEFAULT_FILES_TO_SKIP +
4541 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4542 r"^native_client_sdk"))
4543 file_filter = lambda f: input_api.FilterSourceFile(
4544 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4545 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4546 for line_num, line in fpath.ChangedContents():
4547 for (deprecated_value, value) in _DEPRECATED_CSS:
4548 if deprecated_value in line:
4549 results.append(
4550 output_api.PresubmitError(
4551 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4552 (fpath.LocalPath(), line_num, deprecated_value,
4553 value)))
4554 return results
[email protected]fd20b902014-05-09 02:14:534555
mohan.reddyf21db962014-10-16 12:26:474556
Saagar Sanghavifceeaae2020-08-12 16:40:364557def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504558 bad_files = {}
4559 for f in input_api.AffectedFiles(include_deletes=False):
4560 if (f.LocalPath().startswith('third_party')
4561 and not f.LocalPath().startswith('third_party/blink')
4562 and not f.LocalPath().startswith('third_party\\blink')):
4563 continue
rlanday6802cf632017-05-30 17:48:364564
Sam Maiera6e76d72022-02-11 21:43:504565 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4566 continue
rlanday6802cf632017-05-30 17:48:364567
Sam Maiera6e76d72022-02-11 21:43:504568 relative_includes = [
4569 line for _, line in f.ChangedContents()
4570 if "#include" in line and "../" in line
4571 ]
4572 if not relative_includes:
4573 continue
4574 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364575
Sam Maiera6e76d72022-02-11 21:43:504576 if not bad_files:
4577 return []
rlanday6802cf632017-05-30 17:48:364578
Sam Maiera6e76d72022-02-11 21:43:504579 error_descriptions = []
4580 for file_path, bad_lines in bad_files.items():
4581 error_description = file_path
4582 for line in bad_lines:
4583 error_description += '\n ' + line
4584 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364585
Sam Maiera6e76d72022-02-11 21:43:504586 results = []
4587 results.append(
4588 output_api.PresubmitError(
4589 'You added one or more relative #include paths (including "../").\n'
4590 'These shouldn\'t be used because they can be used to include headers\n'
4591 'from code that\'s not correctly specified as a dependency in the\n'
4592 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364593
Sam Maiera6e76d72022-02-11 21:43:504594 return results
rlanday6802cf632017-05-30 17:48:364595
Takeshi Yoshinoe387aa32017-08-02 13:16:134596
Saagar Sanghavifceeaae2020-08-12 16:40:364597def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504598 """Check that nobody tries to include a cc file. It's a relatively
4599 common error which results in duplicate symbols in object
4600 files. This may not always break the build until someone later gets
4601 very confusing linking errors."""
4602 results = []
4603 for f in input_api.AffectedFiles(include_deletes=False):
4604 # We let third_party code do whatever it wants
4605 if (f.LocalPath().startswith('third_party')
4606 and not f.LocalPath().startswith('third_party/blink')
4607 and not f.LocalPath().startswith('third_party\\blink')):
4608 continue
Daniel Bratell65b033262019-04-23 08:17:064609
Sam Maiera6e76d72022-02-11 21:43:504610 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4611 continue
Daniel Bratell65b033262019-04-23 08:17:064612
Sam Maiera6e76d72022-02-11 21:43:504613 for _, line in f.ChangedContents():
4614 if line.startswith('#include "'):
4615 included_file = line.split('"')[1]
4616 if _IsCPlusPlusFile(input_api, included_file):
4617 # The most common naming for external files with C++ code,
4618 # apart from standard headers, is to call them foo.inc, but
4619 # Chromium sometimes uses foo-inc.cc so allow that as well.
4620 if not included_file.endswith(('.h', '-inc.cc')):
4621 results.append(
4622 output_api.PresubmitError(
4623 'Only header files or .inc files should be included in other\n'
4624 'C++ files. Compiling the contents of a cc file more than once\n'
4625 'will cause duplicate information in the build which may later\n'
4626 'result in strange link_errors.\n' +
4627 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064628
Sam Maiera6e76d72022-02-11 21:43:504629 return results
Daniel Bratell65b033262019-04-23 08:17:064630
4631
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204632def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504633 if not isinstance(key, ast.Str):
4634 return 'Key at line %d must be a string literal' % key.lineno
4635 if not isinstance(value, ast.Dict):
4636 return 'Value at line %d must be a dict' % value.lineno
4637 if len(value.keys) != 1:
4638 return 'Dict at line %d must have single entry' % value.lineno
4639 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4640 return (
4641 'Entry at line %d must have a string literal \'filepath\' as key' %
4642 value.lineno)
4643 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134644
Takeshi Yoshinoe387aa32017-08-02 13:16:134645
Sergey Ulanov4af16052018-11-08 02:41:464646def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504647 if not isinstance(key, ast.Str):
4648 return 'Key at line %d must be a string literal' % key.lineno
4649 if not isinstance(value, ast.List):
4650 return 'Value at line %d must be a list' % value.lineno
4651 for element in value.elts:
4652 if not isinstance(element, ast.Str):
4653 return 'Watchlist elements on line %d is not a string' % key.lineno
4654 if not email_regex.match(element.s):
4655 return ('Watchlist element on line %d doesn\'t look like a valid '
4656 + 'email: %s') % (key.lineno, element.s)
4657 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134658
Takeshi Yoshinoe387aa32017-08-02 13:16:134659
Sergey Ulanov4af16052018-11-08 02:41:464660def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504661 mismatch_template = (
4662 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4663 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134664
Sam Maiera6e76d72022-02-11 21:43:504665 email_regex = input_api.re.compile(
4666 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464667
Sam Maiera6e76d72022-02-11 21:43:504668 ast = input_api.ast
4669 i = 0
4670 last_key = ''
4671 while True:
4672 if i >= len(wd_dict.keys):
4673 if i >= len(w_dict.keys):
4674 return None
4675 return mismatch_template % ('missing',
4676 'line %d' % w_dict.keys[i].lineno)
4677 elif i >= len(w_dict.keys):
4678 return (mismatch_template %
4679 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134680
Sam Maiera6e76d72022-02-11 21:43:504681 wd_key = wd_dict.keys[i]
4682 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134683
Sam Maiera6e76d72022-02-11 21:43:504684 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4685 wd_dict.values[i], ast)
4686 if result is not None:
4687 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134688
Sam Maiera6e76d72022-02-11 21:43:504689 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4690 email_regex)
4691 if result is not None:
4692 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204693
Sam Maiera6e76d72022-02-11 21:43:504694 if wd_key.s != w_key.s:
4695 return mismatch_template % ('%s at line %d' %
4696 (wd_key.s, wd_key.lineno),
4697 '%s at line %d' %
4698 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204699
Sam Maiera6e76d72022-02-11 21:43:504700 if wd_key.s < last_key:
4701 return (
4702 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4703 % (wd_key.lineno, w_key.lineno))
4704 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204705
Sam Maiera6e76d72022-02-11 21:43:504706 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204707
4708
Sergey Ulanov4af16052018-11-08 02:41:464709def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504710 ast = input_api.ast
4711 if not isinstance(expression, ast.Expression):
4712 return 'WATCHLISTS file must contain a valid expression'
4713 dictionary = expression.body
4714 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4715 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204716
Sam Maiera6e76d72022-02-11 21:43:504717 first_key = dictionary.keys[0]
4718 first_value = dictionary.values[0]
4719 second_key = dictionary.keys[1]
4720 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204721
Sam Maiera6e76d72022-02-11 21:43:504722 if (not isinstance(first_key, ast.Str)
4723 or first_key.s != 'WATCHLIST_DEFINITIONS'
4724 or not isinstance(first_value, ast.Dict)):
4725 return ('The first entry of the dict in WATCHLISTS file must be '
4726 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204727
Sam Maiera6e76d72022-02-11 21:43:504728 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4729 or not isinstance(second_value, ast.Dict)):
4730 return ('The second entry of the dict in WATCHLISTS file must be '
4731 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204732
Sam Maiera6e76d72022-02-11 21:43:504733 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134734
4735
Saagar Sanghavifceeaae2020-08-12 16:40:364736def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504737 for f in input_api.AffectedFiles(include_deletes=False):
4738 if f.LocalPath() == 'WATCHLISTS':
4739 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134740
Sam Maiera6e76d72022-02-11 21:43:504741 try:
4742 # First, make sure that it can be evaluated.
4743 input_api.ast.literal_eval(contents)
4744 # Get an AST tree for it and scan the tree for detailed style checking.
4745 expression = input_api.ast.parse(contents,
4746 filename='WATCHLISTS',
4747 mode='eval')
4748 except ValueError as e:
4749 return [
4750 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4751 long_text=repr(e))
4752 ]
4753 except SyntaxError as e:
4754 return [
4755 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4756 long_text=repr(e))
4757 ]
4758 except TypeError as e:
4759 return [
4760 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4761 long_text=repr(e))
4762 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134763
Sam Maiera6e76d72022-02-11 21:43:504764 result = _CheckWATCHLISTSSyntax(expression, input_api)
4765 if result is not None:
4766 return [output_api.PresubmitError(result)]
4767 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134768
Sam Maiera6e76d72022-02-11 21:43:504769 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134770
Sean Kaucb7c9b32022-10-25 21:25:524771def CheckGnRebasePath(input_api, output_api):
4772 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
4773
4774 Developers should use root_build_dir instead of "//" when using target_gen_dir because
4775 Chromium is sometimes built outside of the source tree.
4776 """
4777
4778 def gn_files(f):
4779 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
4780
4781 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
4782 problems = []
4783 for f in input_api.AffectedSourceFiles(gn_files):
4784 for line_num, line in f.ChangedContents():
4785 if rebase_path_regex.search(line):
4786 problems.append(
4787 'Absolute path in rebase_path() in %s:%d' %
4788 (f.LocalPath(), line_num))
4789
4790 if problems:
4791 return [
4792 output_api.PresubmitPromptWarning(
4793 'Using an absolute path in rebase_path()',
4794 items=sorted(problems),
4795 long_text=(
4796 'rebase_path() should use root_build_dir instead of "/" ',
4797 'since builds can be initiated from outside of the source ',
4798 'root.'))
4799 ]
4800 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134801
Andrew Grieve1b290e4a22020-11-24 20:07:014802def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504803 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014804
Sam Maiera6e76d72022-02-11 21:43:504805 As documented at //build/docs/writing_gn_templates.md
4806 """
Andrew Grieve1b290e4a22020-11-24 20:07:014807
Sam Maiera6e76d72022-02-11 21:43:504808 def gn_files(f):
4809 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014810
Sam Maiera6e76d72022-02-11 21:43:504811 problems = []
4812 for f in input_api.AffectedSourceFiles(gn_files):
4813 for line_num, line in f.ChangedContents():
4814 if 'forward_variables_from(invoker, "*")' in line:
4815 problems.append(
4816 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4817 (f.LocalPath(), line_num))
4818
4819 if problems:
4820 return [
4821 output_api.PresubmitPromptWarning(
4822 'forward_variables_from("*") without exclusions',
4823 items=sorted(problems),
4824 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594825 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504826 'explicitly listed in forward_variables_from(). For more '
4827 'details, see:\n'
4828 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4829 'build/docs/writing_gn_templates.md'
4830 '#Using-forward_variables_from'))
4831 ]
4832 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014833
Saagar Sanghavifceeaae2020-08-12 16:40:364834def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504835 """Checks that newly added header files have corresponding GN changes.
4836 Note that this is only a heuristic. To be precise, run script:
4837 build/check_gn_headers.py.
4838 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194839
Sam Maiera6e76d72022-02-11 21:43:504840 def headers(f):
4841 return input_api.FilterSourceFile(
4842 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194843
Sam Maiera6e76d72022-02-11 21:43:504844 new_headers = []
4845 for f in input_api.AffectedSourceFiles(headers):
4846 if f.Action() != 'A':
4847 continue
4848 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194849
Sam Maiera6e76d72022-02-11 21:43:504850 def gn_files(f):
4851 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194852
Sam Maiera6e76d72022-02-11 21:43:504853 all_gn_changed_contents = ''
4854 for f in input_api.AffectedSourceFiles(gn_files):
4855 for _, line in f.ChangedContents():
4856 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194857
Sam Maiera6e76d72022-02-11 21:43:504858 problems = []
4859 for header in new_headers:
4860 basename = input_api.os_path.basename(header)
4861 if basename not in all_gn_changed_contents:
4862 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194863
Sam Maiera6e76d72022-02-11 21:43:504864 if problems:
4865 return [
4866 output_api.PresubmitPromptWarning(
4867 'Missing GN changes for new header files',
4868 items=sorted(problems),
4869 long_text=
4870 'Please double check whether newly added header files need '
4871 'corresponding changes in gn or gni files.\nThis checking is only a '
4872 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4873 'Read https://crbug.com/661774 for more info.')
4874 ]
4875 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194876
4877
Saagar Sanghavifceeaae2020-08-12 16:40:364878def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504879 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024880
Sam Maiera6e76d72022-02-11 21:43:504881 This assumes we won't intentionally reference one product from the other
4882 product.
4883 """
4884 all_problems = []
4885 test_cases = [{
4886 "filename_postfix": "google_chrome_strings.grd",
4887 "correct_name": "Chrome",
4888 "incorrect_name": "Chromium",
4889 }, {
4890 "filename_postfix": "chromium_strings.grd",
4891 "correct_name": "Chromium",
4892 "incorrect_name": "Chrome",
4893 }]
Michael Giuffridad3bc8672018-10-25 22:48:024894
Sam Maiera6e76d72022-02-11 21:43:504895 for test_case in test_cases:
4896 problems = []
4897 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4898 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024899
Sam Maiera6e76d72022-02-11 21:43:504900 # Check each new line. Can yield false positives in multiline comments, but
4901 # easier than trying to parse the XML because messages can have nested
4902 # children, and associating message elements with affected lines is hard.
4903 for f in input_api.AffectedSourceFiles(filename_filter):
4904 for line_num, line in f.ChangedContents():
4905 if "<message" in line or "<!--" in line or "-->" in line:
4906 continue
4907 if test_case["incorrect_name"] in line:
4908 problems.append("Incorrect product name in %s:%d" %
4909 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024910
Sam Maiera6e76d72022-02-11 21:43:504911 if problems:
4912 message = (
4913 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4914 % (test_case["correct_name"], test_case["correct_name"],
4915 test_case["incorrect_name"]))
4916 all_problems.append(
4917 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024918
Sam Maiera6e76d72022-02-11 21:43:504919 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024920
4921
Saagar Sanghavifceeaae2020-08-12 16:40:364922def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504923 """Avoid large files, especially binary files, in the repository since
4924 git doesn't scale well for those. They will be in everyone's repo
4925 clones forever, forever making Chromium slower to clone and work
4926 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364927
Sam Maiera6e76d72022-02-11 21:43:504928 # Uploading files to cloud storage is not trivial so we don't want
4929 # to set the limit too low, but the upper limit for "normal" large
4930 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4931 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:254932 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
4933 # Special exemption for a file that is slightly over the limit.
4934 SPECIAL_FILE_SIZE_LIMIT = 25 * 1024 * 1024
4935 SPECIAL_FILE_NAME = 'transport_security_state_static.json'
Daniel Bratell93eb6c62019-04-29 20:13:364936
Sam Maiera6e76d72022-02-11 21:43:504937 too_large_files = []
4938 for f in input_api.AffectedFiles():
4939 # Check both added and modified files (but not deleted files).
4940 if f.Action() in ('A', 'M'):
4941 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Bruce Dawsonbb414db2022-12-27 20:21:254942 limit = (SPECIAL_FILE_SIZE_LIMIT if
4943 f.AbsoluteLocalPath().endswith(SPECIAL_FILE_NAME) else
4944 TOO_LARGE_FILE_SIZE_LIMIT)
4945 if size > limit:
Sam Maiera6e76d72022-02-11 21:43:504946 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364947
Sam Maiera6e76d72022-02-11 21:43:504948 if too_large_files:
4949 message = (
4950 'Do not commit large files to git since git scales badly for those.\n'
4951 +
4952 'Instead put the large files in cloud storage and use DEPS to\n' +
4953 'fetch them.\n' + '\n'.join(too_large_files))
4954 return [
4955 output_api.PresubmitError('Too large files found in commit',
4956 long_text=message + '\n')
4957 ]
4958 else:
4959 return []
Daniel Bratell93eb6c62019-04-29 20:13:364960
Max Morozb47503b2019-08-08 21:03:274961
Saagar Sanghavifceeaae2020-08-12 16:40:364962def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504963 """Checks specific for fuzz target sources."""
4964 EXPORTED_SYMBOLS = [
4965 'LLVMFuzzerInitialize',
4966 'LLVMFuzzerCustomMutator',
4967 'LLVMFuzzerCustomCrossOver',
4968 'LLVMFuzzerMutate',
4969 ]
Max Morozb47503b2019-08-08 21:03:274970
Sam Maiera6e76d72022-02-11 21:43:504971 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274972
Sam Maiera6e76d72022-02-11 21:43:504973 def FilterFile(affected_file):
4974 """Ignore libFuzzer source code."""
4975 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:314976 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:274977
Sam Maiera6e76d72022-02-11 21:43:504978 return input_api.FilterSourceFile(affected_file,
4979 files_to_check=[files_to_check],
4980 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274981
Sam Maiera6e76d72022-02-11 21:43:504982 files_with_missing_header = []
4983 for f in input_api.AffectedSourceFiles(FilterFile):
4984 contents = input_api.ReadFile(f, 'r')
4985 if REQUIRED_HEADER in contents:
4986 continue
Max Morozb47503b2019-08-08 21:03:274987
Sam Maiera6e76d72022-02-11 21:43:504988 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4989 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274990
Sam Maiera6e76d72022-02-11 21:43:504991 if not files_with_missing_header:
4992 return []
Max Morozb47503b2019-08-08 21:03:274993
Sam Maiera6e76d72022-02-11 21:43:504994 long_text = (
4995 'If you define any of the libFuzzer optional functions (%s), it is '
4996 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4997 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4998 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4999 'to access command line arguments passed to the fuzzer. Instead, prefer '
5000 'static initialization and shared resources as documented in '
5001 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5002 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5003 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275004
Sam Maiera6e76d72022-02-11 21:43:505005 return [
5006 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5007 REQUIRED_HEADER,
5008 items=files_with_missing_header,
5009 long_text=long_text)
5010 ]
Max Morozb47503b2019-08-08 21:03:275011
5012
Mohamed Heikald048240a2019-11-12 16:57:375013def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505014 """
5015 Warns authors who add images into the repo to make sure their images are
5016 optimized before committing.
5017 """
5018 images_added = False
5019 image_paths = []
5020 errors = []
5021 filter_lambda = lambda x: input_api.FilterSourceFile(
5022 x,
5023 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5024 DEFAULT_FILES_TO_SKIP),
5025 files_to_check=[r'.*\/(drawable|mipmap)'])
5026 for f in input_api.AffectedFiles(include_deletes=False,
5027 file_filter=filter_lambda):
5028 local_path = f.LocalPath().lower()
5029 if any(
5030 local_path.endswith(extension)
5031 for extension in _IMAGE_EXTENSIONS):
5032 images_added = True
5033 image_paths.append(f)
5034 if images_added:
5035 errors.append(
5036 output_api.PresubmitPromptWarning(
5037 'It looks like you are trying to commit some images. If these are '
5038 'non-test-only images, please make sure to read and apply the tips in '
5039 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5040 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5041 'FYI only and will not block your CL on the CQ.', image_paths))
5042 return errors
Mohamed Heikald048240a2019-11-12 16:57:375043
5044
Saagar Sanghavifceeaae2020-08-12 16:40:365045def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505046 """Groups upload checks that target android code."""
5047 results = []
5048 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5049 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5050 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5051 results.extend(_CheckAndroidToastUsage(input_api, output_api))
5052 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
5053 results.extend(_CheckAndroidTestJUnitFrameworkImport(
5054 input_api, output_api))
5055 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5056 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5057 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5058 results.extend(_CheckNewImagesWarning(input_api, output_api))
5059 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5060 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5061 return results
5062
Becky Zhou7c69b50992018-12-10 19:37:575063
Saagar Sanghavifceeaae2020-08-12 16:40:365064def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505065 """Groups commit checks that target android code."""
5066 results = []
5067 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5068 return results
dgnaa68d5e2015-06-10 10:08:225069
Chris Hall59f8d0c72020-05-01 07:31:195070# TODO(chrishall): could we additionally match on any path owned by
5071# ui/accessibility/OWNERS ?
5072_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315073 r"^chrome/browser.*/accessibility/",
5074 r"^chrome/browser/extensions/api/automation.*/",
5075 r"^chrome/renderer/extensions/accessibility_.*",
5076 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:175077 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315078 r"^content/browser/accessibility/",
5079 r"^content/renderer/accessibility/",
5080 r"^content/tests/data/accessibility/",
5081 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175082 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:315083 r"^ui/accessibility/",
5084 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195085)
5086
Saagar Sanghavifceeaae2020-08-12 16:40:365087def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505088 """Checks that commits to accessibility code contain an AX-Relnotes field in
5089 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195090
Sam Maiera6e76d72022-02-11 21:43:505091 def FileFilter(affected_file):
5092 paths = _ACCESSIBILITY_PATHS
5093 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195094
Sam Maiera6e76d72022-02-11 21:43:505095 # Only consider changes affecting accessibility paths.
5096 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5097 return []
Akihiro Ota08108e542020-05-20 15:30:535098
Sam Maiera6e76d72022-02-11 21:43:505099 # AX-Relnotes can appear in either the description or the footer.
5100 # When searching the description, require 'AX-Relnotes:' to appear at the
5101 # beginning of a line.
5102 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5103 description_has_relnotes = any(
5104 ax_regex.match(line)
5105 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195106
Sam Maiera6e76d72022-02-11 21:43:505107 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5108 'AX-Relnotes', [])
5109 if description_has_relnotes or footer_relnotes:
5110 return []
Chris Hall59f8d0c72020-05-01 07:31:195111
Sam Maiera6e76d72022-02-11 21:43:505112 # TODO(chrishall): link to Relnotes documentation in message.
5113 message = (
5114 "Missing 'AX-Relnotes:' field required for accessibility changes"
5115 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5116 "user-facing changes"
5117 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5118 "user-facing effects"
5119 "\n if this is confusing or annoying then please contact members "
5120 "of ui/accessibility/OWNERS.")
5121
5122 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225123
Mark Schillacie5a0be22022-01-19 00:38:395124
5125_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315126 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395127)
5128
5129_ACCESSIBILITY_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315130 r"^content/test/data/accessibility/accname/.*\.html",
5131 r"^content/test/data/accessibility/aria/.*\.html",
5132 r"^content/test/data/accessibility/css/.*\.html",
5133 r"^content/test/data/accessibility/html/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395134)
5135
5136_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315137 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395138)
5139
5140_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315141 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395142)
5143
5144def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505145 """Checks that commits that include a newly added, renamed/moved, or deleted
5146 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5147 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395148
Sam Maiera6e76d72022-02-11 21:43:505149 def FilePathFilter(affected_file):
5150 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5151 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395152
Sam Maiera6e76d72022-02-11 21:43:505153 def AndroidFilePathFilter(affected_file):
5154 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5155 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395156
Sam Maiera6e76d72022-02-11 21:43:505157 # Only consider changes in the events test data path with html type.
5158 if not any(
5159 input_api.AffectedFiles(include_deletes=True,
5160 file_filter=FilePathFilter)):
5161 return []
Mark Schillacie5a0be22022-01-19 00:38:395162
Sam Maiera6e76d72022-02-11 21:43:505163 # If the commit contains any change to the Android test file, ignore.
5164 if any(
5165 input_api.AffectedFiles(include_deletes=True,
5166 file_filter=AndroidFilePathFilter)):
5167 return []
Mark Schillacie5a0be22022-01-19 00:38:395168
Sam Maiera6e76d72022-02-11 21:43:505169 # Only consider changes that are adding/renaming or deleting a file
5170 message = []
5171 for f in input_api.AffectedFiles(include_deletes=True,
5172 file_filter=FilePathFilter):
5173 if f.Action() == 'A' or f.Action() == 'D':
5174 message = (
5175 "It appears that you are adding, renaming or deleting"
5176 "\na dump_accessibility_events* test, but have not included"
5177 "\na corresponding change for Android."
5178 "\nPlease include (or remove) the test from:"
5179 "\n content/public/android/javatests/src/org/chromium/"
5180 "content/browser/accessibility/"
5181 "WebContentsAccessibilityEventsTest.java"
5182 "\nIf this message is confusing or annoying, please contact"
5183 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395184
Sam Maiera6e76d72022-02-11 21:43:505185 # If no message was set, return empty.
5186 if not len(message):
5187 return []
5188
5189 return [output_api.PresubmitPromptWarning(message)]
5190
Mark Schillacie5a0be22022-01-19 00:38:395191
5192def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505193 """Checks that commits that include a newly added, renamed/moved, or deleted
5194 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5195 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395196
Sam Maiera6e76d72022-02-11 21:43:505197 def FilePathFilter(affected_file):
5198 paths = _ACCESSIBILITY_TREE_TEST_PATH
5199 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395200
Sam Maiera6e76d72022-02-11 21:43:505201 def AndroidFilePathFilter(affected_file):
5202 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5203 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395204
Sam Maiera6e76d72022-02-11 21:43:505205 # Only consider changes in the various tree test data paths with html type.
5206 if not any(
5207 input_api.AffectedFiles(include_deletes=True,
5208 file_filter=FilePathFilter)):
5209 return []
Mark Schillacie5a0be22022-01-19 00:38:395210
Sam Maiera6e76d72022-02-11 21:43:505211 # If the commit contains any change to the Android test file, ignore.
5212 if any(
5213 input_api.AffectedFiles(include_deletes=True,
5214 file_filter=AndroidFilePathFilter)):
5215 return []
Mark Schillacie5a0be22022-01-19 00:38:395216
Sam Maiera6e76d72022-02-11 21:43:505217 # Only consider changes that are adding/renaming or deleting a file
5218 message = []
5219 for f in input_api.AffectedFiles(include_deletes=True,
5220 file_filter=FilePathFilter):
5221 if f.Action() == 'A' or f.Action() == 'D':
5222 message = (
5223 "It appears that you are adding, renaming or deleting"
5224 "\na dump_accessibility_tree* test, but have not included"
5225 "\na corresponding change for Android."
5226 "\nPlease include (or remove) the test from:"
5227 "\n content/public/android/javatests/src/org/chromium/"
5228 "content/browser/accessibility/"
5229 "WebContentsAccessibilityTreeTest.java"
5230 "\nIf this message is confusing or annoying, please contact"
5231 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395232
Sam Maiera6e76d72022-02-11 21:43:505233 # If no message was set, return empty.
5234 if not len(message):
5235 return []
5236
5237 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395238
5239
Bruce Dawson33806592022-11-16 01:44:515240def CheckEsLintConfigChanges(input_api, output_api):
5241 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
5242 modified. This is important because enabling an error in .eslintrc.js can
5243 trigger errors in any .js or .ts files in its directory, leading to hidden
5244 presubmit errors."""
5245 results = []
5246 eslint_filter = lambda f: input_api.FilterSourceFile(
5247 f, files_to_check=[r'.*\.eslintrc\.js$'])
5248 for f in input_api.AffectedFiles(include_deletes=False,
5249 file_filter=eslint_filter):
5250 local_dir = input_api.os_path.dirname(f.LocalPath())
5251 # Use / characters so that the commands printed work on any OS.
5252 local_dir = local_dir.replace(input_api.os_path.sep, '/')
5253 if local_dir:
5254 local_dir += '/'
5255 results.append(
5256 output_api.PresubmitNotifyResult(
5257 '%(file)s modified. Consider running \'git cl presubmit --files '
5258 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
5259 'files before landing this change.' %
5260 { 'file' : f.LocalPath(), 'dir' : local_dir}))
5261 return results
5262
5263
seanmccullough4a9356252021-04-08 19:54:095264# string pattern, sequence of strings to show when pattern matches,
5265# error flag. True if match is a presubmit error, otherwise it's a warning.
5266_NON_INCLUSIVE_TERMS = (
5267 (
5268 # Note that \b pattern in python re is pretty particular. In this
5269 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5270 # ...' will not. This may require some tweaking to catch these cases
5271 # without triggering a lot of false positives. Leaving it naive and
5272 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:325273 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:095274 (
5275 'Please don\'t use blacklist, whitelist, ' # nocheck
5276 'or slave in your', # nocheck
5277 'code and make every effort to use other terms. Using "// nocheck"',
5278 '"# nocheck" or "<!-- nocheck -->"',
5279 'at the end of the offending line will bypass this PRESUBMIT error',
5280 'but avoid using this whenever possible. Reach out to',
5281 '[email protected] if you have questions'),
5282 True),)
5283
Saagar Sanghavifceeaae2020-08-12 16:40:365284def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505285 """Checks common to both upload and commit."""
5286 results = []
Eric Boren6fd2b932018-01-25 15:05:085287 results.extend(
Sam Maiera6e76d72022-02-11 21:43:505288 input_api.canned_checks.PanProjectChecks(
5289 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:085290
Sam Maiera6e76d72022-02-11 21:43:505291 author = input_api.change.author_email
5292 if author and author not in _KNOWN_ROBOTS:
5293 results.extend(
5294 input_api.canned_checks.CheckAuthorizedAuthor(
5295 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:245296
Sam Maiera6e76d72022-02-11 21:43:505297 results.extend(
5298 input_api.canned_checks.CheckChangeHasNoTabs(
5299 input_api,
5300 output_api,
5301 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
5302 results.extend(
5303 input_api.RunTests(
5304 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:175305
Bruce Dawsonc8054482022-03-28 15:33:375306 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:505307 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:375308 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:505309 results.extend(
5310 input_api.RunTests(
5311 input_api.canned_checks.CheckDirMetadataFormat(
5312 input_api, output_api, dirmd_bin)))
5313 results.extend(
5314 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
5315 input_api, output_api))
5316 results.extend(
5317 input_api.canned_checks.CheckNoNewMetadataInOwners(
5318 input_api, output_api))
5319 results.extend(
5320 input_api.canned_checks.CheckInclusiveLanguage(
5321 input_api,
5322 output_api,
5323 excluded_directories_relative_path=[
5324 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
5325 ],
5326 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:595327
Aleksey Khoroshilov2978c942022-06-13 16:14:125328 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:475329 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:125330 for f in input_api.AffectedFiles(include_deletes=False,
5331 file_filter=presubmit_py_filter):
5332 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
5333 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
5334 # The PRESUBMIT.py file (and the directory containing it) might have
5335 # been affected by being moved or removed, so only try to run the tests
5336 # if they still exist.
5337 if not input_api.os_path.exists(test_file):
5338 continue
Sam Maiera6e76d72022-02-11 21:43:505339
Aleksey Khoroshilov2978c942022-06-13 16:14:125340 use_python3 = False
Bruce Dawson58a45d22023-02-27 11:24:165341 with open(f.LocalPath(), encoding='utf-8') as fp:
Aleksey Khoroshilov2978c942022-06-13 16:14:125342 use_python3 = any(
5343 line.startswith('USE_PYTHON3 = True')
5344 for line in fp.readlines())
5345
5346 results.extend(
5347 input_api.canned_checks.RunUnitTestsInDirectory(
5348 input_api,
5349 output_api,
5350 full_path,
5351 files_to_check=[r'^PRESUBMIT_test\.py$'],
5352 run_on_python2=not use_python3,
5353 run_on_python3=use_python3,
5354 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:505355 return results
[email protected]1f7b4172010-01-28 01:17:345356
[email protected]b337cb5b2011-01-23 21:24:055357
Saagar Sanghavifceeaae2020-08-12 16:40:365358def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505359 problems = [
5360 f.LocalPath() for f in input_api.AffectedFiles()
5361 if f.LocalPath().endswith(('.orig', '.rej'))
5362 ]
5363 # Cargo.toml.orig files are part of third-party crates downloaded from
5364 # crates.io and should be included.
5365 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5366 if problems:
5367 return [
5368 output_api.PresubmitError("Don't commit .rej and .orig files.",
5369 problems)
5370 ]
5371 else:
5372 return []
[email protected]b8079ae4a2012-12-05 19:56:495373
5374
Saagar Sanghavifceeaae2020-08-12 16:40:365375def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505376 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5377 macro_re = input_api.re.compile(
5378 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5379 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5380 input_api.re.MULTILINE)
5381 extension_re = input_api.re.compile(r'\.[a-z]+$')
5382 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005383 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505384 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005385 # The build-config macros are allowed to be used in build_config.h
5386 # without including itself.
5387 if f.LocalPath() == config_h_file:
5388 continue
Sam Maiera6e76d72022-02-11 21:43:505389 if not f.LocalPath().endswith(
5390 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5391 continue
5392 found_line_number = None
5393 found_macro = None
5394 all_lines = input_api.ReadFile(f, 'r').splitlines()
5395 for line_num, line in enumerate(all_lines):
5396 match = macro_re.search(line)
5397 if match:
5398 found_line_number = line_num
5399 found_macro = match.group(2)
5400 break
5401 if not found_line_number:
5402 continue
Kent Tamura5a8755d2017-06-29 23:37:075403
Sam Maiera6e76d72022-02-11 21:43:505404 found_include_line = -1
5405 for line_num, line in enumerate(all_lines):
5406 if include_re.search(line):
5407 found_include_line = line_num
5408 break
5409 if found_include_line >= 0 and found_include_line < found_line_number:
5410 continue
Kent Tamura5a8755d2017-06-29 23:37:075411
Sam Maiera6e76d72022-02-11 21:43:505412 if not f.LocalPath().endswith('.h'):
5413 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5414 try:
5415 content = input_api.ReadFile(primary_header_path, 'r')
5416 if include_re.search(content):
5417 continue
5418 except IOError:
5419 pass
5420 errors.append('%s:%d %s macro is used without first including build/'
5421 'build_config.h.' %
5422 (f.LocalPath(), found_line_number, found_macro))
5423 if errors:
5424 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5425 return []
Kent Tamura5a8755d2017-06-29 23:37:075426
5427
Lei Zhang1c12a22f2021-05-12 11:28:455428def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505429 stl_include_re = input_api.re.compile(r'^#include\s+<('
5430 r'algorithm|'
5431 r'array|'
5432 r'limits|'
5433 r'list|'
5434 r'map|'
5435 r'memory|'
5436 r'queue|'
5437 r'set|'
5438 r'string|'
5439 r'unordered_map|'
5440 r'unordered_set|'
5441 r'utility|'
5442 r'vector)>')
5443 std_namespace_re = input_api.re.compile(r'std::')
5444 errors = []
5445 for f in input_api.AffectedFiles():
5446 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5447 continue
Lei Zhang1c12a22f2021-05-12 11:28:455448
Sam Maiera6e76d72022-02-11 21:43:505449 uses_std_namespace = False
5450 has_stl_include = False
5451 for line in f.NewContents():
5452 if has_stl_include and uses_std_namespace:
5453 break
Lei Zhang1c12a22f2021-05-12 11:28:455454
Sam Maiera6e76d72022-02-11 21:43:505455 if not has_stl_include and stl_include_re.search(line):
5456 has_stl_include = True
5457 continue
Lei Zhang1c12a22f2021-05-12 11:28:455458
Bruce Dawson4a5579a2022-04-08 17:11:365459 if not uses_std_namespace and (std_namespace_re.search(line)
5460 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505461 uses_std_namespace = True
5462 continue
Lei Zhang1c12a22f2021-05-12 11:28:455463
Sam Maiera6e76d72022-02-11 21:43:505464 if has_stl_include and not uses_std_namespace:
5465 errors.append(
5466 '%s: Includes STL header(s) but does not reference std::' %
5467 f.LocalPath())
5468 if errors:
5469 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5470 return []
Lei Zhang1c12a22f2021-05-12 11:28:455471
5472
Xiaohan Wang42d96c22022-01-20 17:23:115473def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505474 """Check for sensible looking, totally invalid OS macros."""
5475 preprocessor_statement = input_api.re.compile(r'^\s*#')
5476 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5477 results = []
5478 for lnum, line in f.ChangedContents():
5479 if preprocessor_statement.search(line):
5480 for match in os_macro.finditer(line):
5481 results.append(
5482 ' %s:%d: %s' %
5483 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5484 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5485 return results
[email protected]b00342e7f2013-03-26 16:21:545486
5487
Xiaohan Wang42d96c22022-01-20 17:23:115488def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505489 """Check all affected files for invalid OS macros."""
5490 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005491 # The OS_ macros are allowed to be used in build/build_config.h.
5492 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505493 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005494 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5495 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505496 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:545497
Sam Maiera6e76d72022-02-11 21:43:505498 if not bad_macros:
5499 return []
[email protected]b00342e7f2013-03-26 16:21:545500
Sam Maiera6e76d72022-02-11 21:43:505501 return [
5502 output_api.PresubmitError(
5503 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5504 'defined in build_config.h):', bad_macros)
5505 ]
[email protected]b00342e7f2013-03-26 16:21:545506
lliabraa35bab3932014-10-01 12:16:445507
5508def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505509 """Check all affected files for invalid "if defined" macros."""
5510 ALWAYS_DEFINED_MACROS = (
5511 "TARGET_CPU_PPC",
5512 "TARGET_CPU_PPC64",
5513 "TARGET_CPU_68K",
5514 "TARGET_CPU_X86",
5515 "TARGET_CPU_ARM",
5516 "TARGET_CPU_MIPS",
5517 "TARGET_CPU_SPARC",
5518 "TARGET_CPU_ALPHA",
5519 "TARGET_IPHONE_SIMULATOR",
5520 "TARGET_OS_EMBEDDED",
5521 "TARGET_OS_IPHONE",
5522 "TARGET_OS_MAC",
5523 "TARGET_OS_UNIX",
5524 "TARGET_OS_WIN32",
5525 )
5526 ifdef_macro = input_api.re.compile(
5527 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5528 results = []
5529 for lnum, line in f.ChangedContents():
5530 for match in ifdef_macro.finditer(line):
5531 if match.group(1) in ALWAYS_DEFINED_MACROS:
5532 always_defined = ' %s is always defined. ' % match.group(1)
5533 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5534 results.append(
5535 ' %s:%d %s\n\t%s' %
5536 (f.LocalPath(), lnum, always_defined, did_you_mean))
5537 return results
lliabraa35bab3932014-10-01 12:16:445538
5539
Saagar Sanghavifceeaae2020-08-12 16:40:365540def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505541 """Check all affected files for invalid "if defined" macros."""
5542 bad_macros = []
5543 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5544 for f in input_api.AffectedFiles():
5545 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5546 continue
5547 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5548 bad_macros.extend(
5549 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445550
Sam Maiera6e76d72022-02-11 21:43:505551 if not bad_macros:
5552 return []
lliabraa35bab3932014-10-01 12:16:445553
Sam Maiera6e76d72022-02-11 21:43:505554 return [
5555 output_api.PresubmitError(
5556 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5557 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5558 bad_macros)
5559 ]
lliabraa35bab3932014-10-01 12:16:445560
5561
Saagar Sanghavifceeaae2020-08-12 16:40:365562def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505563 """Check for same IPC rules described in
5564 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5565 """
5566 base_pattern = r'IPC_ENUM_TRAITS\('
5567 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5568 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045569
Sam Maiera6e76d72022-02-11 21:43:505570 problems = []
5571 for f in input_api.AffectedSourceFiles(None):
5572 local_path = f.LocalPath()
5573 if not local_path.endswith('.h'):
5574 continue
5575 for line_number, line in f.ChangedContents():
5576 if inclusion_pattern.search(
5577 line) and not comment_pattern.search(line):
5578 problems.append('%s:%d\n %s' %
5579 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045580
Sam Maiera6e76d72022-02-11 21:43:505581 if problems:
5582 return [
5583 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5584 problems)
5585 ]
5586 else:
5587 return []
mlamouria82272622014-09-16 18:45:045588
[email protected]b00342e7f2013-03-26 16:21:545589
Saagar Sanghavifceeaae2020-08-12 16:40:365590def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505591 """Check to make sure no files being submitted have long paths.
5592 This causes issues on Windows.
5593 """
5594 problems = []
5595 for f in input_api.AffectedTestableFiles():
5596 local_path = f.LocalPath()
5597 # Windows has a path limit of 260 characters. Limit path length to 200 so
5598 # that we have some extra for the prefix on dev machines and the bots.
5599 if len(local_path) > 200:
5600 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055601
Sam Maiera6e76d72022-02-11 21:43:505602 if problems:
5603 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5604 else:
5605 return []
Stephen Martinis97a394142018-06-07 23:06:055606
5607
Saagar Sanghavifceeaae2020-08-12 16:40:365608def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505609 """Check that header files have proper guards against multiple inclusion.
5610 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365611 should include the string "no-include-guard-because-multiply-included" or
5612 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505613 """
Daniel Bratell8ba52722018-03-02 16:06:145614
Sam Maiera6e76d72022-02-11 21:43:505615 def is_chromium_header_file(f):
5616 # We only check header files under the control of the Chromium
5617 # project. That is, those outside third_party apart from
5618 # third_party/blink.
5619 # We also exclude *_message_generator.h headers as they use
5620 # include guards in a special, non-typical way.
5621 file_with_path = input_api.os_path.normpath(f.LocalPath())
5622 return (file_with_path.endswith('.h')
5623 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335624 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505625 and (not file_with_path.startswith('third_party')
5626 or file_with_path.startswith(
5627 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145628
Sam Maiera6e76d72022-02-11 21:43:505629 def replace_special_with_underscore(string):
5630 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145631
Sam Maiera6e76d72022-02-11 21:43:505632 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145633
Sam Maiera6e76d72022-02-11 21:43:505634 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5635 guard_name = None
5636 guard_line_number = None
5637 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145638
Sam Maiera6e76d72022-02-11 21:43:505639 file_with_path = input_api.os_path.normpath(f.LocalPath())
5640 base_file_name = input_api.os_path.splitext(
5641 input_api.os_path.basename(file_with_path))[0]
5642 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145643
Sam Maiera6e76d72022-02-11 21:43:505644 expected_guard = replace_special_with_underscore(
5645 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145646
Sam Maiera6e76d72022-02-11 21:43:505647 # For "path/elem/file_name.h" we should really only accept
5648 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5649 # are too many (1000+) files with slight deviations from the
5650 # coding style. The most important part is that the include guard
5651 # is there, and that it's unique, not the name so this check is
5652 # forgiving for existing files.
5653 #
5654 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145655
Sam Maiera6e76d72022-02-11 21:43:505656 guard_name_pattern_list = [
5657 # Anything with the right suffix (maybe with an extra _).
5658 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145659
Sam Maiera6e76d72022-02-11 21:43:505660 # To cover include guards with old Blink style.
5661 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145662
Sam Maiera6e76d72022-02-11 21:43:505663 # Anything including the uppercase name of the file.
5664 r'\w*' + input_api.re.escape(
5665 replace_special_with_underscore(upper_base_file_name)) +
5666 r'\w*',
5667 ]
5668 guard_name_pattern = '|'.join(guard_name_pattern_list)
5669 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5670 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145671
Sam Maiera6e76d72022-02-11 21:43:505672 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365673 if ('no-include-guard-because-multiply-included' in line
5674 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505675 guard_name = 'DUMMY' # To not trigger check outside the loop.
5676 break
Daniel Bratell8ba52722018-03-02 16:06:145677
Sam Maiera6e76d72022-02-11 21:43:505678 if guard_name is None:
5679 match = guard_pattern.match(line)
5680 if match:
5681 guard_name = match.group(1)
5682 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145683
Sam Maiera6e76d72022-02-11 21:43:505684 # We allow existing files to use include guards whose names
5685 # don't match the chromium style guide, but new files should
5686 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495687 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165688 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505689 errors.append(
5690 output_api.PresubmitPromptWarning(
5691 'Header using the wrong include guard name %s'
5692 % guard_name, [
5693 '%s:%d' %
5694 (f.LocalPath(), line_number + 1)
5695 ], 'Expected: %r\nFound: %r' %
5696 (expected_guard, guard_name)))
5697 else:
5698 # The line after #ifndef should have a #define of the same name.
5699 if line_number == guard_line_number + 1:
5700 expected_line = '#define %s' % guard_name
5701 if line != expected_line:
5702 errors.append(
5703 output_api.PresubmitPromptWarning(
5704 'Missing "%s" for include guard' %
5705 expected_line,
5706 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5707 'Expected: %r\nGot: %r' %
5708 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145709
Sam Maiera6e76d72022-02-11 21:43:505710 if not seen_guard_end and line == '#endif // %s' % guard_name:
5711 seen_guard_end = True
5712 elif seen_guard_end:
5713 if line.strip() != '':
5714 errors.append(
5715 output_api.PresubmitPromptWarning(
5716 'Include guard %s not covering the whole file'
5717 % (guard_name), [f.LocalPath()]))
5718 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145719
Sam Maiera6e76d72022-02-11 21:43:505720 if guard_name is None:
5721 errors.append(
5722 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495723 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505724 'Recommended name: %s\n'
5725 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365726 '"no-include-guard-because-multiply-included" or\n'
5727 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505728 % (f.LocalPath(), expected_guard)))
5729
5730 return errors
Daniel Bratell8ba52722018-03-02 16:06:145731
5732
Saagar Sanghavifceeaae2020-08-12 16:40:365733def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505734 """Check source code and known ascii text files for Windows style line
5735 endings.
5736 """
Bruce Dawson5efbdc652022-04-11 19:29:515737 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235738
Sam Maiera6e76d72022-02-11 21:43:505739 file_inclusion_pattern = (known_text_files,
5740 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5741 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235742
Sam Maiera6e76d72022-02-11 21:43:505743 problems = []
5744 source_file_filter = lambda f: input_api.FilterSourceFile(
5745 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5746 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515747 # Ignore test files that contain crlf intentionally.
5748 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345749 continue
Sam Maiera6e76d72022-02-11 21:43:505750 include_file = False
5751 for line in input_api.ReadFile(f, 'r').splitlines(True):
5752 if line.endswith('\r\n'):
5753 include_file = True
5754 if include_file:
5755 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235756
Sam Maiera6e76d72022-02-11 21:43:505757 if problems:
5758 return [
5759 output_api.PresubmitPromptWarning(
5760 'Are you sure that you want '
5761 'these files to contain Windows style line endings?\n' +
5762 '\n'.join(problems))
5763 ]
mostynbb639aca52015-01-07 20:31:235764
Sam Maiera6e76d72022-02-11 21:43:505765 return []
5766
mostynbb639aca52015-01-07 20:31:235767
Evan Stade6cfc964c12021-05-18 20:21:165768def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505769 """Check that .icon files (which are fragments of C++) have license headers.
5770 """
Evan Stade6cfc964c12021-05-18 20:21:165771
Sam Maiera6e76d72022-02-11 21:43:505772 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165773
Sam Maiera6e76d72022-02-11 21:43:505774 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5775 return input_api.canned_checks.CheckLicense(input_api,
5776 output_api,
5777 source_file_filter=icons)
5778
Evan Stade6cfc964c12021-05-18 20:21:165779
Jose Magana2b456f22021-03-09 23:26:405780def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505781 """Check source code for use of Chrome App technologies being
5782 deprecated.
5783 """
Jose Magana2b456f22021-03-09 23:26:405784
Sam Maiera6e76d72022-02-11 21:43:505785 def _CheckForDeprecatedTech(input_api,
5786 output_api,
5787 detection_list,
5788 files_to_check=None,
5789 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405790
Sam Maiera6e76d72022-02-11 21:43:505791 if (files_to_check or files_to_skip):
5792 source_file_filter = lambda f: input_api.FilterSourceFile(
5793 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5794 else:
5795 source_file_filter = None
5796
5797 problems = []
5798
5799 for f in input_api.AffectedSourceFiles(source_file_filter):
5800 if f.Action() == 'D':
5801 continue
5802 for _, line in f.ChangedContents():
5803 if any(detect in line for detect in detection_list):
5804 problems.append(f.LocalPath())
5805
5806 return problems
5807
5808 # to avoid this presubmit script triggering warnings
5809 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405810
5811 problems = []
5812
Sam Maiera6e76d72022-02-11 21:43:505813 # NMF: any files with extensions .nmf or NMF
5814 _NMF_FILES = r'\.(nmf|NMF)$'
5815 problems += _CheckForDeprecatedTech(
5816 input_api,
5817 output_api,
5818 detection_list=[''], # any change to the file will trigger warning
5819 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405820
Sam Maiera6e76d72022-02-11 21:43:505821 # MANIFEST: any manifest.json that in its diff includes "app":
5822 _MANIFEST_FILES = r'(manifest\.json)$'
5823 problems += _CheckForDeprecatedTech(
5824 input_api,
5825 output_api,
5826 detection_list=['"app":'],
5827 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405828
Sam Maiera6e76d72022-02-11 21:43:505829 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5830 problems += _CheckForDeprecatedTech(
5831 input_api,
5832 output_api,
5833 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:315834 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:405835
Gao Shenga79ebd42022-08-08 17:25:595836 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505837 problems += _CheckForDeprecatedTech(
5838 input_api,
5839 output_api,
5840 detection_list=['#include "ppapi', '#include <ppapi'],
5841 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5842 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:315843 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:405844
Sam Maiera6e76d72022-02-11 21:43:505845 if problems:
5846 return [
5847 output_api.PresubmitPromptWarning(
5848 'You are adding/modifying code'
5849 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5850 ' PNaCl, PPAPI). See this blog post for more details:\n'
5851 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5852 'and this documentation for options to replace these technologies:\n'
5853 'https://developer.chrome.com/docs/apps/migration/\n' +
5854 '\n'.join(problems))
5855 ]
Jose Magana2b456f22021-03-09 23:26:405856
Sam Maiera6e76d72022-02-11 21:43:505857 return []
Jose Magana2b456f22021-03-09 23:26:405858
mostynbb639aca52015-01-07 20:31:235859
Saagar Sanghavifceeaae2020-08-12 16:40:365860def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505861 """Checks that all source files use SYSLOG properly."""
5862 syslog_files = []
5863 for f in input_api.AffectedSourceFiles(src_file_filter):
5864 for line_number, line in f.ChangedContents():
5865 if 'SYSLOG' in line:
5866 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565867
Sam Maiera6e76d72022-02-11 21:43:505868 if syslog_files:
5869 return [
5870 output_api.PresubmitPromptWarning(
5871 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5872 ' calls.\nFiles to check:\n',
5873 items=syslog_files)
5874 ]
5875 return []
pastarmovj89f7ee12016-09-20 14:58:135876
5877
[email protected]1f7b4172010-01-28 01:17:345878def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505879 if input_api.version < [2, 0, 0]:
5880 return [
5881 output_api.PresubmitError(
5882 "Your depot_tools is out of date. "
5883 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5884 "but your version is %d.%d.%d" % tuple(input_api.version))
5885 ]
5886 results = []
5887 results.extend(
5888 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5889 return results
[email protected]ca8d1982009-02-19 16:33:125890
5891
5892def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505893 if input_api.version < [2, 0, 0]:
5894 return [
5895 output_api.PresubmitError(
5896 "Your depot_tools is out of date. "
5897 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5898 "but your version is %d.%d.%d" % tuple(input_api.version))
5899 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365900
Sam Maiera6e76d72022-02-11 21:43:505901 results = []
5902 # Make sure the tree is 'open'.
5903 results.extend(
5904 input_api.canned_checks.CheckTreeIsOpen(
5905 input_api,
5906 output_api,
5907 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275908
Sam Maiera6e76d72022-02-11 21:43:505909 results.extend(
5910 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5911 results.extend(
5912 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5913 results.extend(
5914 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5915 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505916 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145917
5918
Saagar Sanghavifceeaae2020-08-12 16:40:365919def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505920 """Check string ICU syntax validity and if translation screenshots exist."""
5921 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5922 # footer is set to true.
5923 git_footers = input_api.change.GitFootersFromDescription()
5924 skip_screenshot_check_footer = [
5925 footer.lower() for footer in git_footers.get(
5926 u'Skip-Translation-Screenshots-Check', [])
5927 ]
5928 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025929
Sam Maiera6e76d72022-02-11 21:43:505930 import os
5931 import re
5932 import sys
5933 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145934
Sam Maiera6e76d72022-02-11 21:43:505935 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5936 if (f.Action() == 'A' or f.Action() == 'M'))
5937 removed_paths = set(f.LocalPath()
5938 for f in input_api.AffectedFiles(include_deletes=True)
5939 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145940
Sam Maiera6e76d72022-02-11 21:43:505941 affected_grds = [
5942 f for f in input_api.AffectedFiles()
5943 if f.LocalPath().endswith(('.grd', '.grdp'))
5944 ]
5945 affected_grds = [
5946 f for f in affected_grds if not 'testdata' in f.LocalPath()
5947 ]
5948 if not affected_grds:
5949 return []
meacer8c0d3832019-12-26 21:46:165950
Sam Maiera6e76d72022-02-11 21:43:505951 affected_png_paths = [
5952 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5953 if (f.LocalPath().endswith('.png'))
5954 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145955
Sam Maiera6e76d72022-02-11 21:43:505956 # Check for screenshots. Developers can upload screenshots using
5957 # tools/translation/upload_screenshots.py which finds and uploads
5958 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5959 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5960 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5961 #
5962 # The logic here is as follows:
5963 #
5964 # - If the CL has a .png file under the screenshots directory for a grd
5965 # file, warn the developer. Actual images should never be checked into the
5966 # Chrome repo.
5967 #
5968 # - If the CL contains modified or new messages in grd files and doesn't
5969 # contain the corresponding .sha1 files, warn the developer to add images
5970 # and upload them via tools/translation/upload_screenshots.py.
5971 #
5972 # - If the CL contains modified or new messages in grd files and the
5973 # corresponding .sha1 files, everything looks good.
5974 #
5975 # - If the CL contains removed messages in grd files but the corresponding
5976 # .sha1 files aren't removed, warn the developer to remove them.
5977 unnecessary_screenshots = []
5978 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:475979 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:505980 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145981
Sam Maiera6e76d72022-02-11 21:43:505982 # This checks verifies that the ICU syntax of messages this CL touched is
5983 # valid, and reports any found syntax errors.
5984 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5985 # without developers being aware of them. Later on, such ICU syntax errors
5986 # break message extraction for translation, hence would block Chromium
5987 # translations until they are fixed.
5988 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145989
Sam Maiera6e76d72022-02-11 21:43:505990 def _CheckScreenshotAdded(screenshots_dir, message_id):
5991 sha1_path = input_api.os_path.join(screenshots_dir,
5992 message_id + '.png.sha1')
5993 if sha1_path not in new_or_added_paths:
5994 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145995
Bruce Dawson55776c42022-12-09 17:23:475996 def _CheckScreenshotModified(screenshots_dir, message_id):
5997 sha1_path = input_api.os_path.join(screenshots_dir,
5998 message_id + '.png.sha1')
5999 if sha1_path not in new_or_added_paths:
6000 missing_sha1_modified.append(sha1_path)
6001
Sam Maiera6e76d72022-02-11 21:43:506002 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6003 sha1_path = input_api.os_path.join(screenshots_dir,
6004 message_id + '.png.sha1')
6005 if input_api.os_path.exists(
6006 sha1_path) and sha1_path not in removed_paths:
6007 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146008
Sam Maiera6e76d72022-02-11 21:43:506009 def _ValidateIcuSyntax(text, level, signatures):
6010 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146011
Sam Maiera6e76d72022-02-11 21:43:506012 Check if text looks similar to ICU and checks for ICU syntax correctness
6013 in this case. Reports various issues with ICU syntax and values of
6014 variants. Supports checking of nested messages. Accumulate information of
6015 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266016
Sam Maiera6e76d72022-02-11 21:43:506017 Args:
6018 text: a string to check.
6019 level: a number of current nesting level.
6020 signatures: an accumulator, a list of tuple of (level, variable,
6021 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266022
Sam Maiera6e76d72022-02-11 21:43:506023 Returns:
6024 None if a string is not ICU or no issue detected.
6025 A tuple of (message, start index, end index) if an issue detected.
6026 """
6027 valid_types = {
6028 'plural': (frozenset(
6029 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6030 'other']), frozenset(['=1', 'other'])),
6031 'selectordinal': (frozenset(
6032 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6033 'other']), frozenset(['one', 'other'])),
6034 'select': (frozenset(), frozenset(['other'])),
6035 }
Rainhard Findlingfc31844c52020-05-15 09:58:266036
Sam Maiera6e76d72022-02-11 21:43:506037 # Check if the message looks like an attempt to use ICU
6038 # plural. If yes - check if its syntax strictly matches ICU format.
6039 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6040 text)
6041 if not like:
6042 signatures.append((level, None, None, None))
6043 return
Rainhard Findlingfc31844c52020-05-15 09:58:266044
Sam Maiera6e76d72022-02-11 21:43:506045 # Check for valid prefix and suffix
6046 m = re.match(
6047 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6048 r'(plural|selectordinal|select),\s*'
6049 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6050 if not m:
6051 return (('This message looks like an ICU plural, '
6052 'but does not follow ICU syntax.'), like.start(),
6053 like.end())
6054 starting, variable, kind, variant_pairs = m.groups()
6055 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6056 m.start(4))
6057 if depth:
6058 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6059 len(text))
6060 first = text[0]
6061 ending = text[last_pos:]
6062 if not starting:
6063 return ('Invalid ICU format. No initial opening bracket',
6064 last_pos - 1, last_pos)
6065 if not ending or '}' not in ending:
6066 return ('Invalid ICU format. No final closing bracket',
6067 last_pos - 1, last_pos)
6068 elif first != '{':
6069 return ((
6070 'Invalid ICU format. Extra characters at the start of a complex '
6071 'message (go/icu-message-migration): "%s"') % starting, 0,
6072 len(starting))
6073 elif ending != '}':
6074 return ((
6075 'Invalid ICU format. Extra characters at the end of a complex '
6076 'message (go/icu-message-migration): "%s"') % ending,
6077 last_pos - 1, len(text) - 1)
6078 if kind not in valid_types:
6079 return (('Unknown ICU message type %s. '
6080 'Valid types are: plural, select, selectordinal') % kind,
6081 0, 0)
6082 known, required = valid_types[kind]
6083 defined_variants = set()
6084 for variant, variant_range, value, value_range in variants:
6085 start, end = variant_range
6086 if variant in defined_variants:
6087 return ('Variant "%s" is defined more than once' % variant,
6088 start, end)
6089 elif known and variant not in known:
6090 return ('Variant "%s" is not valid for %s message' %
6091 (variant, kind), start, end)
6092 defined_variants.add(variant)
6093 # Check for nested structure
6094 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6095 if res:
6096 return (res[0], res[1] + value_range[0] + 1,
6097 res[2] + value_range[0] + 1)
6098 missing = required - defined_variants
6099 if missing:
6100 return ('Required variants missing: %s' % ', '.join(missing), 0,
6101 len(text))
6102 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266103
Sam Maiera6e76d72022-02-11 21:43:506104 def _ParseIcuVariants(text, offset=0):
6105 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266106
Sam Maiera6e76d72022-02-11 21:43:506107 Builds a tuple of variant names and values, as well as
6108 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266109
Sam Maiera6e76d72022-02-11 21:43:506110 Args:
6111 text: a string to parse
6112 offset: additional offset to add to positions in the text to get correct
6113 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266114
Sam Maiera6e76d72022-02-11 21:43:506115 Returns:
6116 List of tuples, each tuple consist of four fields: variant name,
6117 variant name span (tuple of two integers), variant value, value
6118 span (tuple of two integers).
6119 """
6120 depth, start, end = 0, -1, -1
6121 variants = []
6122 key = None
6123 for idx, char in enumerate(text):
6124 if char == '{':
6125 if not depth:
6126 start = idx
6127 chunk = text[end + 1:start]
6128 key = chunk.strip()
6129 pos = offset + end + 1 + chunk.find(key)
6130 span = (pos, pos + len(key))
6131 depth += 1
6132 elif char == '}':
6133 if not depth:
6134 return variants, depth, offset + idx
6135 depth -= 1
6136 if not depth:
6137 end = idx
6138 variants.append((key, span, text[start:end + 1],
6139 (offset + start, offset + end + 1)))
6140 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266141
Sam Maiera6e76d72022-02-11 21:43:506142 try:
6143 old_sys_path = sys.path
6144 sys.path = sys.path + [
6145 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6146 'translation')
6147 ]
6148 from helper import grd_helper
6149 finally:
6150 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266151
Sam Maiera6e76d72022-02-11 21:43:506152 for f in affected_grds:
6153 file_path = f.LocalPath()
6154 old_id_to_msg_map = {}
6155 new_id_to_msg_map = {}
6156 # Note that this code doesn't check if the file has been deleted. This is
6157 # OK because it only uses the old and new file contents and doesn't load
6158 # the file via its path.
6159 # It's also possible that a file's content refers to a renamed or deleted
6160 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6161 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6162 # .grdp files.
6163 if file_path.endswith('.grdp'):
6164 if f.OldContents():
6165 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6166 '\n'.join(f.OldContents()))
6167 if f.NewContents():
6168 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6169 '\n'.join(f.NewContents()))
6170 else:
6171 file_dir = input_api.os_path.dirname(file_path) or '.'
6172 if f.OldContents():
6173 old_id_to_msg_map = grd_helper.GetGrdMessages(
6174 StringIO('\n'.join(f.OldContents())), file_dir)
6175 if f.NewContents():
6176 new_id_to_msg_map = grd_helper.GetGrdMessages(
6177 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266178
Sam Maiera6e76d72022-02-11 21:43:506179 grd_name, ext = input_api.os_path.splitext(
6180 input_api.os_path.basename(file_path))
6181 screenshots_dir = input_api.os_path.join(
6182 input_api.os_path.dirname(file_path),
6183 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266184
Sam Maiera6e76d72022-02-11 21:43:506185 # Compute added, removed and modified message IDs.
6186 old_ids = set(old_id_to_msg_map)
6187 new_ids = set(new_id_to_msg_map)
6188 added_ids = new_ids - old_ids
6189 removed_ids = old_ids - new_ids
6190 modified_ids = set([])
6191 for key in old_ids.intersection(new_ids):
6192 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6193 new_id_to_msg_map[key].ContentsAsXml('', True)):
6194 # The message content itself changed. Require an updated screenshot.
6195 modified_ids.add(key)
6196 elif old_id_to_msg_map[key].attrs['meaning'] != \
6197 new_id_to_msg_map[key].attrs['meaning']:
6198 # The message meaning changed. Ensure there is a screenshot for it.
6199 sha1_path = input_api.os_path.join(screenshots_dir,
6200 key + '.png.sha1')
6201 if sha1_path not in new_or_added_paths and not \
6202 input_api.os_path.exists(sha1_path):
6203 # There is neither a previous screenshot nor is a new one added now.
6204 # Require a screenshot.
6205 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146206
Sam Maiera6e76d72022-02-11 21:43:506207 if run_screenshot_check:
6208 # Check the screenshot directory for .png files. Warn if there is any.
6209 for png_path in affected_png_paths:
6210 if png_path.startswith(screenshots_dir):
6211 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146212
Sam Maiera6e76d72022-02-11 21:43:506213 for added_id in added_ids:
6214 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096215
Sam Maiera6e76d72022-02-11 21:43:506216 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476217 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146218
Sam Maiera6e76d72022-02-11 21:43:506219 for removed_id in removed_ids:
6220 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6221
6222 # Check new and changed strings for ICU syntax errors.
6223 for key in added_ids.union(modified_ids):
6224 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6225 err = _ValidateIcuSyntax(msg, 0, [])
6226 if err is not None:
6227 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6228
6229 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266230 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506231 if unnecessary_screenshots:
6232 results.append(
6233 output_api.PresubmitError(
6234 'Do not include actual screenshots in the changelist. Run '
6235 'tools/translate/upload_screenshots.py to upload them instead:',
6236 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146237
Sam Maiera6e76d72022-02-11 21:43:506238 if missing_sha1:
6239 results.append(
6240 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:476241 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:506242 'To ensure the best translations, take screenshots of the relevant UI '
6243 '(https://g.co/chrome/translation) and add these files to your '
6244 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146245
Bruce Dawson55776c42022-12-09 17:23:476246 if missing_sha1_modified:
6247 results.append(
6248 output_api.PresubmitError(
6249 'You are modifying UI strings or their meanings.\n'
6250 'To ensure the best translations, take screenshots of the relevant UI '
6251 '(https://g.co/chrome/translation) and add these files to your '
6252 'changelist:', sorted(missing_sha1_modified)))
6253
Sam Maiera6e76d72022-02-11 21:43:506254 if unnecessary_sha1_files:
6255 results.append(
6256 output_api.PresubmitError(
6257 'You removed strings associated with these files. Remove:',
6258 sorted(unnecessary_sha1_files)))
6259 else:
6260 results.append(
6261 output_api.PresubmitPromptOrNotify('Skipping translation '
6262 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146263
Sam Maiera6e76d72022-02-11 21:43:506264 if icu_syntax_errors:
6265 results.append(
6266 output_api.PresubmitPromptWarning(
6267 'ICU syntax errors were found in the following strings (problems or '
6268 'feedback? Contact [email protected]):',
6269 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:266270
Sam Maiera6e76d72022-02-11 21:43:506271 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:126272
6273
Saagar Sanghavifceeaae2020-08-12 16:40:366274def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:126275 repo_root=None,
6276 translation_expectations_path=None,
6277 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:506278 import sys
6279 affected_grds = [
6280 f for f in input_api.AffectedFiles()
6281 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
6282 ]
6283 if not affected_grds:
6284 return []
6285
6286 try:
6287 old_sys_path = sys.path
6288 sys.path = sys.path + [
6289 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6290 'translation')
6291 ]
6292 from helper import git_helper
6293 from helper import translation_helper
6294 finally:
6295 sys.path = old_sys_path
6296
6297 # Check that translation expectations can be parsed and we can get a list of
6298 # translatable grd files. |repo_root| and |translation_expectations_path| are
6299 # only passed by tests.
6300 if not repo_root:
6301 repo_root = input_api.PresubmitLocalPath()
6302 if not translation_expectations_path:
6303 translation_expectations_path = input_api.os_path.join(
6304 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
6305 if not grd_files:
6306 grd_files = git_helper.list_grds_in_repository(repo_root)
6307
6308 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:596309 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:506310 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
6311 'tests')
6312 grd_files = [p for p in grd_files if ignore_path not in p]
6313
6314 try:
6315 translation_helper.get_translatable_grds(
6316 repo_root, grd_files, translation_expectations_path)
6317 except Exception as e:
6318 return [
6319 output_api.PresubmitNotifyResult(
6320 'Failed to get a list of translatable grd files. This happens when:\n'
6321 ' - One of the modified grd or grdp files cannot be parsed or\n'
6322 ' - %s is not updated.\n'
6323 'Stack:\n%s' % (translation_expectations_path, str(e)))
6324 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:126325 return []
6326
Ken Rockotc31f4832020-05-29 18:58:516327
Saagar Sanghavifceeaae2020-08-12 16:40:366328def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506329 """Changes to [Stable] mojom types must preserve backward-compatibility."""
6330 changed_mojoms = input_api.AffectedFiles(
6331 include_deletes=True,
6332 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:526333
Bruce Dawson344ab262022-06-04 11:35:106334 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:506335 return []
6336
6337 delta = []
6338 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:506339 delta.append({
6340 'filename': mojom.LocalPath(),
6341 'old': '\n'.join(mojom.OldContents()) or None,
6342 'new': '\n'.join(mojom.NewContents()) or None,
6343 })
6344
6345 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:216346 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:506347 input_api.os_path.join(
6348 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
6349 'check_stable_mojom_compatibility.py'), '--src-root',
6350 input_api.PresubmitLocalPath()
6351 ],
6352 stdin=input_api.subprocess.PIPE,
6353 stdout=input_api.subprocess.PIPE,
6354 stderr=input_api.subprocess.PIPE,
6355 universal_newlines=True)
6356 (x, error) = process.communicate(input=input_api.json.dumps(delta))
6357 if process.returncode:
6358 return [
6359 output_api.PresubmitError(
6360 'One or more [Stable] mojom definitions appears to have been changed '
6361 'in a way that is not backward-compatible.',
6362 long_text=error)
6363 ]
Erik Staabc734cd7a2021-11-23 03:11:526364 return []
6365
Dominic Battre645d42342020-12-04 16:14:106366def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506367 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106368
Sam Maiera6e76d72022-02-11 21:43:506369 def FilterFile(affected_file):
6370 """Accept only .cc files and the like."""
6371 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6372 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6373 input_api.DEFAULT_FILES_TO_SKIP)
6374 return input_api.FilterSourceFile(
6375 affected_file,
6376 files_to_check=file_inclusion_pattern,
6377 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106378
Sam Maiera6e76d72022-02-11 21:43:506379 def ModifiedLines(affected_file):
6380 """Returns a list of tuples (line number, line text) of added and removed
6381 lines.
Dominic Battre645d42342020-12-04 16:14:106382
Sam Maiera6e76d72022-02-11 21:43:506383 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106384
Sam Maiera6e76d72022-02-11 21:43:506385 This relies on the scm diff output describing each changed code section
6386 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106387
Sam Maiera6e76d72022-02-11 21:43:506388 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6389 """
6390 line_num = 0
6391 modified_lines = []
6392 for line in affected_file.GenerateScmDiff().splitlines():
6393 # Extract <new line num> of the patch fragment (see format above).
6394 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6395 line)
6396 if m:
6397 line_num = int(m.groups(1)[0])
6398 continue
6399 if ((line.startswith('+') and not line.startswith('++'))
6400 or (line.startswith('-') and not line.startswith('--'))):
6401 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106402
Sam Maiera6e76d72022-02-11 21:43:506403 if not line.startswith('-'):
6404 line_num += 1
6405 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106406
Sam Maiera6e76d72022-02-11 21:43:506407 def FindLineWith(lines, needle):
6408 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106409
Sam Maiera6e76d72022-02-11 21:43:506410 If 0 or >1 lines contain `needle`, -1 is returned.
6411 """
6412 matching_line_numbers = [
6413 # + 1 for 1-based counting of line numbers.
6414 i + 1 for i, line in enumerate(lines) if needle in line
6415 ]
6416 return matching_line_numbers[0] if len(
6417 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106418
Sam Maiera6e76d72022-02-11 21:43:506419 def ModifiedPrefMigration(affected_file):
6420 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6421 # Determine first and last lines of MigrateObsolete.*Pref functions.
6422 new_contents = affected_file.NewContents()
6423 range_1 = (FindLineWith(new_contents,
6424 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6425 FindLineWith(new_contents,
6426 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6427 range_2 = (FindLineWith(new_contents,
6428 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6429 FindLineWith(new_contents,
6430 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6431 if (-1 in range_1 + range_2):
6432 raise Exception(
6433 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6434 )
Dominic Battre645d42342020-12-04 16:14:106435
Sam Maiera6e76d72022-02-11 21:43:506436 # Check whether any of the modified lines are part of the
6437 # MigrateObsolete.*Pref functions.
6438 for line_nr, line in ModifiedLines(affected_file):
6439 if (range_1[0] <= line_nr <= range_1[1]
6440 or range_2[0] <= line_nr <= range_2[1]):
6441 return True
6442 return False
Dominic Battre645d42342020-12-04 16:14:106443
Sam Maiera6e76d72022-02-11 21:43:506444 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6445 browser_prefs_file_pattern = input_api.re.compile(
6446 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106447
Sam Maiera6e76d72022-02-11 21:43:506448 changes = input_api.AffectedFiles(include_deletes=True,
6449 file_filter=FilterFile)
6450 potential_problems = []
6451 for f in changes:
6452 for line in f.GenerateScmDiff().splitlines():
6453 # Check deleted lines for pref registrations.
6454 if (line.startswith('-') and not line.startswith('--')
6455 and register_pref_pattern.search(line)):
6456 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106457
Sam Maiera6e76d72022-02-11 21:43:506458 if browser_prefs_file_pattern.search(f.LocalPath()):
6459 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6460 # assume that they knew that they have to deprecate preferences and don't
6461 # warn.
6462 try:
6463 if ModifiedPrefMigration(f):
6464 return []
6465 except Exception as e:
6466 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106467
Sam Maiera6e76d72022-02-11 21:43:506468 if potential_problems:
6469 return [
6470 output_api.PresubmitPromptWarning(
6471 'Discovered possible removal of preference registrations.\n\n'
6472 'Please make sure to properly deprecate preferences by clearing their\n'
6473 'value for a couple of milestones before finally removing the code.\n'
6474 'Otherwise data may stay in the preferences files forever. See\n'
6475 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6476 'chrome/browser/prefs/README.md for examples.\n'
6477 'This may be a false positive warning (e.g. if you move preference\n'
6478 'registrations to a different place).\n', potential_problems)
6479 ]
6480 return []
6481
Matt Stark6ef08872021-07-29 01:21:466482
6483def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506484 """Changes to GRD files must be consistent for tools to read them."""
6485 changed_grds = input_api.AffectedFiles(
6486 include_deletes=False,
6487 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6488 errors = []
6489 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6490 for matcher, msg in _INVALID_GRD_FILE_LINE]
6491 for grd in changed_grds:
6492 for i, line in enumerate(grd.NewContents()):
6493 for matcher, msg in invalid_file_regexes:
6494 if matcher.search(line):
6495 errors.append(
6496 output_api.PresubmitError(
6497 'Problem on {grd}:{i} - {msg}'.format(
6498 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6499 return errors
6500
Kevin McNee967dd2d22021-11-15 16:09:296501
Henrique Ferreiro2a4b55942021-11-29 23:45:366502def CheckAssertAshOnlyCode(input_api, output_api):
6503 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6504 assert(is_chromeos_ash).
6505 """
6506
6507 def FileFilter(affected_file):
6508 """Includes directories known to be Ash only."""
6509 return input_api.FilterSourceFile(
6510 affected_file,
6511 files_to_check=(
6512 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6513 r'.*/ash/.*BUILD\.gn'), # Any path component.
6514 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6515
6516 errors = []
6517 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566518 for f in input_api.AffectedFiles(include_deletes=False,
6519 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366520 if (not pattern.search(input_api.ReadFile(f))):
6521 errors.append(
6522 output_api.PresubmitError(
6523 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6524 'possible, please create and issue and add a comment such '
6525 'as:\n # TODO(https://crbug.com/XXX): add '
6526 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6527 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276528
6529
6530def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506531 path = affected_file.LocalPath()
6532 if not _IsCPlusPlusFile(input_api, path):
6533 return False
6534
6535 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6536 if "/renderer/" in path:
6537 return True
6538
6539 # Blink's public/web API is only used/included by Renderer-only code. Note
6540 # that public/platform API may be used in non-Renderer processes (e.g. there
6541 # are some includes in code used by Utility, PDF, or Plugin processes).
6542 if "/blink/public/web/" in path:
6543 return True
6544
6545 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276546 return False
6547
Lukasz Anforowicz7016d05e2021-11-30 03:56:276548# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6549# by the Chromium Clang Plugin (which will be preferable because it will
6550# 1) report errors earlier - at compile-time and 2) cover more rules).
6551def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506552 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6553 errors = []
6554 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6555 # C++ comment.
6556 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6557 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6558 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6559 if raw_ptr_matcher.search(line):
6560 errors.append(
6561 output_api.PresubmitError(
6562 'Problem on {path}:{line} - '\
6563 'raw_ptr<T> should not be used in Renderer-only code '\
6564 '(as documented in the "Pointers to unprotected memory" '\
6565 'section in //base/memory/raw_ptr.md)'.format(
6566 path=f.LocalPath(), line=line_num)))
6567 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566568
6569
6570def CheckPythonShebang(input_api, output_api):
6571 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6572 system-wide python.
6573 """
6574 errors = []
6575 sources = lambda affected_file: input_api.FilterSourceFile(
6576 affected_file,
6577 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6578 r'third_party/blink/web_tests/external/') + input_api.
6579 DEFAULT_FILES_TO_SKIP),
6580 files_to_check=[r'.*\.py$'])
6581 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276582 for line_num, line in f.ChangedContents():
6583 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6584 errors.append(f.LocalPath())
6585 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566586
6587 result = []
6588 for file in errors:
6589 result.append(
6590 output_api.PresubmitError(
6591 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6592 file))
6593 return result
James Shen81cc0e22022-06-15 21:10:456594
6595
6596def CheckBatchAnnotation(input_api, output_api):
6597 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6598 is not an instrumentation test, disregard."""
6599
6600 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6601 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6602 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6603 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6604 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6605
ckitagawae8fd23b2022-06-17 15:29:386606 missing_annotation_errors = []
6607 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456608
6609 def _FilterFile(affected_file):
6610 return input_api.FilterSourceFile(
6611 affected_file,
6612 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6613 files_to_check=[r'.*Test\.java$'])
6614
6615 for f in input_api.AffectedSourceFiles(_FilterFile):
6616 batch_matched = None
6617 do_not_batch_matched = None
6618 is_instrumentation_test = True
6619 for line in f.NewContents():
6620 if robolectric_test.search(line) or uiautomator_test.search(line):
6621 # Skip Robolectric and UiAutomator tests.
6622 is_instrumentation_test = False
6623 break
6624 if not batch_matched:
6625 batch_matched = batch_annotation.search(line)
6626 if not do_not_batch_matched:
6627 do_not_batch_matched = do_not_batch_annotation.search(line)
6628 test_class_declaration_matched = test_class_declaration.search(
6629 line)
6630 if test_class_declaration_matched:
6631 break
6632 if (is_instrumentation_test and
6633 not batch_matched and
6634 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246635 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386636 if (not is_instrumentation_test and
6637 (batch_matched or
6638 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246639 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456640
6641 results = []
6642
ckitagawae8fd23b2022-06-17 15:29:386643 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456644 results.append(
6645 output_api.PresubmitPromptWarning(
6646 """
Henrique Nakashimacb4c55a2023-01-30 20:09:096647Instrumentation tests should use either @Batch or @DoNotBatch. Use
6648@Batch(Batch.PER_CLASS) in most cases. Use @Batch(Batch.UNIT_TESTS) when tests
6649have no side-effects. If the tests are not safe to run in batch, please use
6650@DoNotBatch with reasons.
Jens Mueller2085ff82023-02-27 11:54:496651See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:386652""", missing_annotation_errors))
6653 if extra_annotation_errors:
6654 results.append(
6655 output_api.PresubmitPromptWarning(
6656 """
6657Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6658""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456659
6660 return results
Sam Maier4cef9242022-10-03 14:21:246661
6662
6663def CheckMockAnnotation(input_api, output_api):
6664 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6665 classes with @Mock or @Spy. If this is not an instrumentation test,
6666 disregard."""
6667
6668 # This is just trying to be approximately correct. We are not writing a
6669 # Java parser, so special cases like statically importing mock() then
6670 # calling an unrelated non-mockito spy() function will cause a false
6671 # positive.
6672 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6673 mock_static_import = input_api.re.compile(
6674 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6675 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6676 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6677 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6678 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6679 fully_qualified_mock_function = input_api.re.compile(
6680 r'Mockito\.' + mock_or_spy_function_call)
6681 statically_imported_mock_function = input_api.re.compile(
6682 r'\W' + mock_or_spy_function_call)
6683 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6684 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6685
6686 def _DoClassLookup(class_name, class_name_map, package):
6687 found = class_name_map.get(class_name)
6688 if found is not None:
6689 return found
6690 else:
6691 return package + '.' + class_name
6692
6693 def _FilterFile(affected_file):
6694 return input_api.FilterSourceFile(
6695 affected_file,
6696 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6697 files_to_check=[r'.*Test\.java$'])
6698
6699 mocked_by_function_classes = set()
6700 mocked_by_annotation_classes = set()
6701 class_to_filename = {}
6702 for f in input_api.AffectedSourceFiles(_FilterFile):
6703 mock_function_regex = fully_qualified_mock_function
6704 next_line_is_annotated = False
6705 fully_qualified_class_map = {}
6706 package = None
6707
6708 for line in f.NewContents():
6709 if robolectric_test.search(line) or uiautomator_test.search(line):
6710 # Skip Robolectric and UiAutomator tests.
6711 break
6712
6713 m = package_name.search(line)
6714 if m:
6715 package = m.group(1)
6716 continue
6717
6718 if mock_static_import.search(line):
6719 mock_function_regex = statically_imported_mock_function
6720 continue
6721
6722 m = import_class.search(line)
6723 if m:
6724 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
6725 continue
6726
6727 if next_line_is_annotated:
6728 next_line_is_annotated = False
6729 fully_qualified_class = _DoClassLookup(
6730 field_type.search(line).group(1), fully_qualified_class_map,
6731 package)
6732 mocked_by_annotation_classes.add(fully_qualified_class)
6733 continue
6734
6735 if mock_annotation.search(line):
6736 next_line_is_annotated = True
6737 continue
6738
6739 m = mock_function_regex.search(line)
6740 if m:
6741 fully_qualified_class = _DoClassLookup(m.group(1),
6742 fully_qualified_class_map, package)
6743 # Skipping builtin classes, since they don't get optimized.
6744 if fully_qualified_class.startswith(
6745 'android.') or fully_qualified_class.startswith(
6746 'java.'):
6747 continue
6748 class_to_filename[fully_qualified_class] = str(f.LocalPath())
6749 mocked_by_function_classes.add(fully_qualified_class)
6750
6751 results = []
6752 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
6753 if missed_classes:
6754 error_locations = []
6755 for c in missed_classes:
6756 error_locations.append(c + ' in ' + class_to_filename[c])
6757 results.append(
6758 output_api.PresubmitPromptWarning(
6759 """
6760Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
67611) If the mocked variable can be a class member, annotate the member with
6762 @Mock/@Spy.
67632) If the mocked variable cannot be a class member, create a dummy member
6764 variable of that type, annotated with @Mock/@Spy. This dummy does not need
6765 to be used or initialized in any way.
67663) If the mocked type is definitely not going to be optimized, whether it's a
6767 builtin type which we don't ship, or a class you know R8 will treat
6768 specially, you can ignore this warning.
6769""", error_locations))
6770
6771 return results
Mike Dougherty1b8be712022-10-20 00:15:136772
6773def CheckNoJsInIos(input_api, output_api):
6774 """Checks to make sure that JavaScript files are not used on iOS."""
6775
6776 def _FilterFile(affected_file):
6777 return input_api.FilterSourceFile(
6778 affected_file,
6779 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
6780 (r'^ios/third_party/*', r'^third_party/*'),
6781 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
6782
6783 error_paths = []
6784 warning_paths = []
6785
6786 for f in input_api.AffectedSourceFiles(_FilterFile):
6787 local_path = f.LocalPath()
6788
6789 if input_api.os_path.splitext(local_path)[1] == '.js':
6790 if f.Action() == 'A':
6791 error_paths.append(local_path)
6792 elif f.Action() != 'D':
6793 warning_paths.append(local_path)
6794
6795 results = []
6796
6797 if warning_paths:
6798 results.append(output_api.PresubmitPromptWarning(
6799 'TypeScript is now fully supported for iOS feature scripts. '
6800 'Consider converting JavaScript files to TypeScript. See '
6801 '//ios/web/public/js_messaging/README.md for more details.',
6802 warning_paths))
6803
6804 if error_paths:
6805 results.append(output_api.PresubmitError(
6806 'Do not use JavaScript on iOS as TypeScript is fully supported. '
6807 'See //ios/web/public/js_messaging/README.md for help using '
6808 'scripts on iOS.', error_paths))
6809
6810 return results