blob: 1dfba1a8b3293554b8834ee71984d6b7e9d9942f [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-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]ca8d19842009-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 Dawson3bd976c2022-05-06 22:47:5224 (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.
Mila Greend3fc6a42021-09-10 17:38:2327 r"chrome[\\/]updater[\\/]mac[\\/]keystone[\\/]ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4728 # Generated file.
29 (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.
32 r"^media[\\/]test[\\/]data[\\/].*.ts",
Mila Greene3aa7222021-09-07 16:34:0833 r"^native_client_sdksrc[\\/]build_tools[\\/]make_rules.py",
Egor Paskoce145c42018-09-28 19:31:0434 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[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4938 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0439 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4640 # sqlite is an imported third party dependency.
41 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0442 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5443 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5344 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1245 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0446 r".+[\\/]pnacl_shim\.c$",
47 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0448 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1449 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0450 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5451 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0452 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4053)
[email protected]ca8d19842009-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 = (
75 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/]",
76 r"^tools[\\/]win[\\/]",
77)
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 = (
Egor Paskoce145c42018-09-28 19:31:0483 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,
Egor Paskoce145c42018-09-28 19:31:0493 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4394 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0495 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4396 # Web test harness.
97 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4798 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0499 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:08100 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:04101 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41102 # EarlGrey app side code for tests.
103 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17104 # Views Examples code
105 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:41106 # Chromium Codelab
107 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:44108)
[email protected]ca8d19842009-02-19 16:33:12109
Daniel Bratell609102be2019-03-27 20:53:21110_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15111
[email protected]eea609a2011-11-18 13:10:12112_TEST_ONLY_WARNING = (
113 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55114 'production code. If you are doing this from inside another method\n'
115 'named as *ForTesting(), then consider exposing things to have tests\n'
116 'make that same call directly.\n'
117 'If that is not possible, you may put a comment on the same line with\n'
118 ' // IN-TEST \n'
119 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
120 'method and can be ignored. Do not do this inside production code.\n'
121 'The android-binary-size trybot will block if the method exists in the\n'
122 'release apk.')
[email protected]eea609a2011-11-18 13:10:12123
124
Daniel Chenga44a1bcd2022-03-15 20:00:15125@dataclass
126class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34127 # String pattern. If the pattern begins with a slash, the pattern will be
128 # treated as a regular expression instead.
129 pattern: str
130 # Explanation as a sequence of strings. Each string in the sequence will be
131 # printed on its own line.
132 explanation: Sequence[str]
133 # Whether or not to treat this ban as a fatal error. If unspecified,
134 # defaults to true.
135 treat_as_error: Optional[bool] = None
136 # Paths that should be excluded from the ban check. Each string is a regular
137 # expression that will be matched against the path of the file being checked
138 # relative to the root of the source tree.
139 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28140
Daniel Chenga44a1bcd2022-03-15 20:00:15141
Daniel Cheng917ce542022-03-15 20:46:57142_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15143 BanRule(
144 'import java.net.URI;',
145 (
146 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
147 ),
148 excluded_paths=(
149 (r'net/android/javatests/src/org/chromium/net/'
150 'AndroidProxySelectorTest\.java'),
151 r'components/cronet/',
152 r'third_party/robolectric/local/',
153 ),
Michael Thiessen44457642020-02-06 00:24:15154 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15155 BanRule(
156 'import android.annotation.TargetApi;',
157 (
158 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
159 'RequiresApi ensures that any calls are guarded by the appropriate '
160 'SDK_INT check. See https://crbug.com/1116486.',
161 ),
162 ),
163 BanRule(
164 'import android.support.test.rule.UiThreadTestRule;',
165 (
166 'Do not use UiThreadTestRule, just use '
167 '@org.chromium.base.test.UiThreadTest on test methods that should run '
168 'on the UI thread. See https://crbug.com/1111893.',
169 ),
170 ),
171 BanRule(
172 'import android.support.test.annotation.UiThreadTest;',
173 ('Do not use android.support.test.annotation.UiThreadTest, use '
174 'org.chromium.base.test.UiThreadTest instead. See '
175 'https://crbug.com/1111893.',
176 ),
177 ),
178 BanRule(
179 'import android.support.test.rule.ActivityTestRule;',
180 (
181 'Do not use ActivityTestRule, use '
182 'org.chromium.base.test.BaseActivityTestRule instead.',
183 ),
184 excluded_paths=(
185 'components/cronet/',
186 ),
187 ),
188)
wnwenbdc444e2016-05-25 13:44:15189
Daniel Cheng917ce542022-03-15 20:46:57190_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15191 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41192 'StrictMode.allowThreadDiskReads()',
193 (
194 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
195 'directly.',
196 ),
197 False,
198 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15199 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41200 'StrictMode.allowThreadDiskWrites()',
201 (
202 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
203 'directly.',
204 ),
205 False,
206 ),
Daniel Cheng917ce542022-03-15 20:46:57207 BanRule(
Michael Thiessen0f2547e32020-07-27 21:55:36208 '.waitForIdleSync()',
209 (
210 'Do not use waitForIdleSync as it masks underlying issues. There is '
211 'almost always something else you should wait on instead.',
212 ),
213 False,
214 ),
Eric Stevensona9a980972017-09-23 00:04:41215)
216
Daniel Cheng917ce542022-03-15 20:46:57217_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15218 BanRule(
[email protected]127f18ec2012-06-16 05:05:59219 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20220 (
221 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59222 'prohibited. Please use CrTrackingArea instead.',
223 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
224 ),
225 False,
226 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15227 BanRule(
[email protected]eaae1972014-04-16 04:17:26228 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20229 (
230 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59231 'instead.',
232 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
233 ),
234 False,
235 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15236 BanRule(
[email protected]127f18ec2012-06-16 05:05:59237 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20238 (
239 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59240 'Please use |convertPoint:(point) fromView:nil| instead.',
241 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
242 ),
243 True,
244 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15245 BanRule(
[email protected]127f18ec2012-06-16 05:05:59246 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20247 (
248 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59249 'Please use |convertPoint:(point) toView:nil| instead.',
250 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
251 ),
252 True,
253 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15254 BanRule(
[email protected]127f18ec2012-06-16 05:05:59255 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20256 (
257 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59258 'Please use |convertRect:(point) fromView:nil| instead.',
259 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
260 ),
261 True,
262 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15263 BanRule(
[email protected]127f18ec2012-06-16 05:05:59264 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20265 (
266 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59267 'Please use |convertRect:(point) toView:nil| instead.',
268 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
269 ),
270 True,
271 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15272 BanRule(
[email protected]127f18ec2012-06-16 05:05:59273 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20274 (
275 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59276 'Please use |convertSize:(point) fromView:nil| instead.',
277 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
278 ),
279 True,
280 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15281 BanRule(
[email protected]127f18ec2012-06-16 05:05:59282 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20283 (
284 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59285 'Please use |convertSize:(point) toView:nil| instead.',
286 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
287 ),
288 True,
289 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15290 BanRule(
jif65398702016-10-27 10:19:48291 r"/\s+UTF8String\s*]",
292 (
293 'The use of -[NSString UTF8String] is dangerous as it can return null',
294 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
295 'Please use |SysNSStringToUTF8| instead.',
296 ),
297 True,
298 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15299 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34300 r'__unsafe_unretained',
301 (
302 'The use of __unsafe_unretained is almost certainly wrong, unless',
303 'when interacting with NSFastEnumeration or NSInvocation.',
304 'Please use __weak in files build with ARC, nothing otherwise.',
305 ),
306 False,
307 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15308 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13309 'freeWhenDone:NO',
310 (
311 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
312 'Foundation types is prohibited.',
313 ),
314 True,
315 ),
[email protected]127f18ec2012-06-16 05:05:59316)
317
Sylvain Defresnea8b73d252018-02-28 15:45:54318_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15319 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54320 r'/\bTEST[(]',
321 (
322 'TEST() macro should not be used in Objective-C++ code as it does not ',
323 'drain the autorelease pool at the end of the test. Use TEST_F() ',
324 'macro instead with a fixture inheriting from PlatformTest (or a ',
325 'typedef).'
326 ),
327 True,
328 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15329 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54330 r'/\btesting::Test\b',
331 (
332 'testing::Test should not be used in Objective-C++ code as it does ',
333 'not drain the autorelease pool at the end of the test. Use ',
334 'PlatformTest instead.'
335 ),
336 True,
337 ),
Ewann2ecc8d72022-07-18 07:41:23338 BanRule(
339 ' systemImageNamed:',
340 (
341 '+[UIImage systemImageNamed:] should not be used to create symbols.',
342 'Instead use a wrapper defined in:',
343 'ios/chrome/browser/ui/icons/chrome_symbol.h'
344 ),
345 True,
Ewann450a2ef2022-07-19 14:38:23346 excluded_paths=(
347 'ios/chrome/browser/ui/icons/chrome_symbol.mm',
348 ),
Ewann2ecc8d72022-07-18 07:41:23349 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54350)
351
Daniel Cheng917ce542022-03-15 20:46:57352_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15353 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05354 r'/\bEXPECT_OCMOCK_VERIFY\b',
355 (
356 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
357 'it is meant for GTests. Use [mock verify] instead.'
358 ),
359 True,
360 ),
361)
362
Daniel Cheng917ce542022-03-15 20:46:57363_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15364 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04365 r'/\busing namespace ',
366 (
367 'Using directives ("using namespace x") are banned by the Google Style',
368 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
369 'Explicitly qualify symbols or use using declarations ("using x::foo").',
370 ),
371 True,
372 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
373 ),
Antonio Gomes07300d02019-03-13 20:59:57374 # Make sure that gtest's FRIEND_TEST() macro is not used; the
375 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
376 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15377 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20378 'FRIEND_TEST(',
379 (
[email protected]e3c945502012-06-26 20:01:49380 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20381 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
382 ),
383 False,
[email protected]7345da02012-11-27 14:31:49384 (),
[email protected]23e6cbc2012-06-16 18:51:20385 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15386 BanRule(
tomhudsone2c14d552016-05-26 17:07:46387 'setMatrixClip',
388 (
389 'Overriding setMatrixClip() is prohibited; ',
390 'the base function is deprecated. ',
391 ),
392 True,
393 (),
394 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15395 BanRule(
[email protected]52657f62013-05-20 05:30:31396 'SkRefPtr',
397 (
398 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22399 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31400 ),
401 True,
402 (),
403 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15404 BanRule(
[email protected]52657f62013-05-20 05:30:31405 'SkAutoRef',
406 (
407 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22408 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31409 ),
410 True,
411 (),
412 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15413 BanRule(
[email protected]52657f62013-05-20 05:30:31414 'SkAutoTUnref',
415 (
416 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22417 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31418 ),
419 True,
420 (),
421 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15422 BanRule(
[email protected]52657f62013-05-20 05:30:31423 'SkAutoUnref',
424 (
425 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
426 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22427 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31428 ),
429 True,
430 (),
431 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15432 BanRule(
[email protected]d89eec82013-12-03 14:10:59433 r'/HANDLE_EINTR\(.*close',
434 (
435 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
436 'descriptor will be closed, and it is incorrect to retry the close.',
437 'Either call close directly and ignore its return value, or wrap close',
438 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
439 ),
440 True,
441 (),
442 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15443 BanRule(
[email protected]d89eec82013-12-03 14:10:59444 r'/IGNORE_EINTR\((?!.*close)',
445 (
446 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
447 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
448 ),
449 True,
450 (
451 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04452 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
453 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59454 ),
455 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15456 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43457 r'/v8::Extension\(',
458 (
459 'Do not introduce new v8::Extensions into the code base, use',
460 'gin::Wrappable instead. See http://crbug.com/334679',
461 ),
462 True,
[email protected]f55c90ee62014-04-12 00:50:03463 (
Egor Paskoce145c42018-09-28 19:31:04464 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03465 ),
[email protected]ec5b3f02014-04-04 18:43:43466 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15467 BanRule(
jame2d1a952016-04-02 00:27:10468 '#pragma comment(lib,',
469 (
470 'Specify libraries to link with in build files and not in the source.',
471 ),
472 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41473 (
tzik3f295992018-12-04 20:32:23474 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04475 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41476 ),
jame2d1a952016-04-02 00:27:10477 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15478 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02479 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59480 (
481 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
482 ),
483 False,
484 (),
485 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15486 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02487 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59488 (
489 'Consider using THREAD_CHECKER macros instead of the class directly.',
490 ),
491 False,
492 (),
493 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15494 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06495 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
496 (
497 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
498 'deprecated (http://crbug.com/634507). Please avoid converting away',
499 'from the Time types in Chromium code, especially if any math is',
500 'being done on time values. For interfacing with platform/library',
501 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
502 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48503 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06504 'other use cases, please contact base/time/OWNERS.',
505 ),
506 False,
507 (),
508 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15509 BanRule(
dbeamb6f4fde2017-06-15 04:03:06510 'CallJavascriptFunctionUnsafe',
511 (
512 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
513 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
514 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
515 ),
516 False,
517 (
Egor Paskoce145c42018-09-28 19:31:04518 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
519 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
520 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06521 ),
522 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15523 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24524 'leveldb::DB::Open',
525 (
526 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
527 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
528 "Chrome's tracing, making their memory usage visible.",
529 ),
530 True,
531 (
532 r'^third_party/leveldatabase/.*\.(cc|h)$',
533 ),
Gabriel Charette0592c3a2017-07-26 12:02:04534 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15535 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08536 'leveldb::NewMemEnv',
537 (
538 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58539 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
540 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08541 ),
542 True,
543 (
544 r'^third_party/leveldatabase/.*\.(cc|h)$',
545 ),
546 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15547 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47548 'RunLoop::QuitCurrent',
549 (
Robert Liao64b7ab22017-08-04 23:03:43550 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
551 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47552 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41553 False,
Gabriel Charetted9839bc2017-07-29 14:17:47554 (),
Gabriel Charettea44975052017-08-21 23:14:04555 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15556 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04557 'base::ScopedMockTimeMessageLoopTaskRunner',
558 (
Gabriel Charette87cc1af2018-04-25 20:52:51559 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11560 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51561 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
562 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
563 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04564 ),
Gabriel Charette87cc1af2018-04-25 20:52:51565 False,
Gabriel Charettea44975052017-08-21 23:14:04566 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57567 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15568 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44569 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57570 (
571 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02572 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57573 ),
574 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16575 # Abseil's benchmarks never linked into chrome.
576 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38577 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15578 BanRule(
Peter Kasting991618a62019-06-17 22:00:09579 r'/\bstd::stoi\b',
580 (
581 'std::stoi uses exceptions to communicate results. ',
582 'Use base::StringToInt() instead.',
583 ),
584 True,
585 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
586 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15587 BanRule(
Peter Kasting991618a62019-06-17 22:00:09588 r'/\bstd::stol\b',
589 (
590 'std::stol uses exceptions to communicate results. ',
591 'Use base::StringToInt() instead.',
592 ),
593 True,
594 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
595 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15596 BanRule(
Peter Kasting991618a62019-06-17 22:00:09597 r'/\bstd::stoul\b',
598 (
599 'std::stoul uses exceptions to communicate results. ',
600 'Use base::StringToUint() instead.',
601 ),
602 True,
603 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
604 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15605 BanRule(
Peter Kasting991618a62019-06-17 22:00:09606 r'/\bstd::stoll\b',
607 (
608 'std::stoll uses exceptions to communicate results. ',
609 'Use base::StringToInt64() instead.',
610 ),
611 True,
612 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
613 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15614 BanRule(
Peter Kasting991618a62019-06-17 22:00:09615 r'/\bstd::stoull\b',
616 (
617 'std::stoull uses exceptions to communicate results. ',
618 'Use base::StringToUint64() instead.',
619 ),
620 True,
621 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
622 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15623 BanRule(
Peter Kasting991618a62019-06-17 22:00:09624 r'/\bstd::stof\b',
625 (
626 'std::stof uses exceptions to communicate results. ',
627 'For locale-independent values, e.g. reading numbers from disk',
628 'profiles, use base::StringToDouble().',
629 'For user-visible values, parse using ICU.',
630 ),
631 True,
632 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
633 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15634 BanRule(
Peter Kasting991618a62019-06-17 22:00:09635 r'/\bstd::stod\b',
636 (
637 'std::stod uses exceptions to communicate results. ',
638 'For locale-independent values, e.g. reading numbers from disk',
639 'profiles, use base::StringToDouble().',
640 'For user-visible values, parse using ICU.',
641 ),
642 True,
643 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
644 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15645 BanRule(
Peter Kasting991618a62019-06-17 22:00:09646 r'/\bstd::stold\b',
647 (
648 'std::stold uses exceptions to communicate results. ',
649 'For locale-independent values, e.g. reading numbers from disk',
650 'profiles, use base::StringToDouble().',
651 'For user-visible values, parse using ICU.',
652 ),
653 True,
654 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
655 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15656 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45657 r'/\bstd::to_string\b',
658 (
659 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09660 'For locale-independent strings, e.g. writing numbers to disk',
661 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45662 'For user-visible strings, use base::FormatNumber() and',
663 'the related functions in base/i18n/number_formatting.h.',
664 ),
Peter Kasting991618a62019-06-17 22:00:09665 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21666 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45667 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15668 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45669 r'/\bstd::shared_ptr\b',
670 (
671 'std::shared_ptr should not be used. Use scoped_refptr instead.',
672 ),
673 True,
Ulan Degenbaev947043882021-02-10 14:02:31674 [
675 # Needed for interop with third-party library.
676 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57677 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58678 '^third_party/blink/renderer/bindings/core/v8/' +
679 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58680 '^gin/array_buffer\.(cc|h)',
681 '^chrome/services/sharing/nearby/',
Meilin Wang00efc7cb2021-05-13 01:12:42682 # gRPC provides some C++ libraries that use std::shared_ptr<>.
683 '^chromeos/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59684 '^chromecast/cast_core/grpc',
685 '^chromecast/cast_core/runtime/browser',
Wez5f56be52021-05-04 09:30:58686 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Fabrice de Gans3b87542c2022-04-19 19:40:26687 '^base/fuchsia/filtered_service_directory\.(cc|h)',
688 '^base/fuchsia/service_directory_test_base\.h',
Wez5f56be52021-05-04 09:30:58689 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57690 # Needed for clang plugin tests
691 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57692 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21693 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15694 BanRule(
Peter Kasting991618a62019-06-17 22:00:09695 r'/\bstd::weak_ptr\b',
696 (
697 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
698 ),
699 True,
700 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
701 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15702 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21703 r'/\blong long\b',
704 (
705 'long long is banned. Use stdint.h if you need a 64 bit number.',
706 ),
707 False, # Only a warning since it is already used.
708 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
709 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15710 BanRule(
Daniel Chengc05fcc62022-01-12 16:54:29711 r'\b(absl|std)::any\b',
712 (
Daniel Chenga44a1bcd2022-03-15 20:00:15713 'absl::any / std::any are not safe to use in a component build.',
Daniel Chengc05fcc62022-01-12 16:54:29714 ),
715 True,
716 # Not an error in third party folders, though it probably should be :)
717 [_THIRD_PARTY_EXCEPT_BLINK],
718 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15719 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21720 r'/\bstd::bind\b',
721 (
722 'std::bind is banned because of lifetime risks.',
723 'Use base::BindOnce or base::BindRepeating instead.',
724 ),
725 True,
726 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
727 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15728 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:03729 r'/\bstd::optional\b',
730 (
731 'std::optional is banned. Use absl::optional instead.',
732 ),
733 True,
734 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
735 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15736 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21737 r'/\b#include <chrono>\b',
738 (
739 '<chrono> overlaps with Time APIs in base. Keep using',
740 'base classes.',
741 ),
742 True,
743 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
744 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15745 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21746 r'/\b#include <exception>\b',
747 (
748 'Exceptions are banned and disabled in Chromium.',
749 ),
750 True,
751 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
752 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15753 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21754 r'/\bstd::function\b',
755 (
Colin Blundellea615d422021-05-12 09:35:41756 'std::function is banned. Instead use base::OnceCallback or ',
757 'base::RepeatingCallback, which directly support Chromium\'s weak ',
758 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21759 ),
Peter Kasting991618a62019-06-17 22:00:09760 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21761 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
762 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15763 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21764 r'/\b#include <random>\b',
765 (
766 'Do not use any random number engines from <random>. Instead',
767 'use base::RandomBitGenerator.',
768 ),
769 True,
770 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
771 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15772 BanRule(
Tom Andersona95e12042020-09-09 23:08:00773 r'/\b#include <X11/',
774 (
775 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
776 ),
777 True,
778 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
779 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15780 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21781 r'/\bstd::ratio\b',
782 (
783 'std::ratio is banned by the Google Style Guide.',
784 ),
785 True,
786 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45787 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15788 BanRule(
Gabriel Charetted90bcc92021-09-21 00:23:10789 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:38790 (
Gabriel Charetted90bcc92021-09-21 00:23:10791 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:38792 ),
Gabriel Charette04b138f2018-08-06 00:03:22793 False,
Francois Doray43670e32017-09-27 12:40:38794 (),
795 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15796 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:58797 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19798 (
799 'RunMessageLoop is deprecated, use RunLoop instead.',
800 ),
801 False,
802 (),
803 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15804 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44805 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19806 (
807 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
808 ),
809 False,
810 (),
811 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15812 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44813 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19814 (
815 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
816 "if you're convinced you need this.",
817 ),
818 False,
819 (),
820 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15821 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44822 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19823 (
824 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04825 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19826 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
827 'async events instead of flushing threads.',
828 ),
829 False,
830 (),
831 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15832 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:19833 r'MessageLoopRunner',
834 (
835 'MessageLoopRunner is deprecated, use RunLoop instead.',
836 ),
837 False,
838 (),
839 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15840 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44841 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19842 (
843 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
844 "gab@ if you found a use case where this is the only solution.",
845 ),
846 False,
847 (),
848 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15849 BanRule(
Victor Costane48a2e82019-03-15 22:02:34850 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16851 (
Victor Costane48a2e82019-03-15 22:02:34852 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16853 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
854 ),
855 True,
856 (
857 r'^sql/initialization\.(cc|h)$',
858 r'^third_party/sqlite/.*\.(c|cc|h)$',
859 ),
860 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15861 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44862 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47863 (
864 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
865 'base::RandomShuffle instead.'
866 ),
867 True,
868 (),
869 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15870 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24871 'ios/web/public/test/http_server',
872 (
873 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
874 ),
875 False,
876 (),
877 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15878 BanRule(
Robert Liao764c9492019-01-24 18:46:28879 'GetAddressOf',
880 (
881 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53882 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11883 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53884 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28885 ),
886 True,
887 (),
888 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15889 BanRule(
Ben Lewisa9514602019-04-29 17:53:05890 'SHFileOperation',
891 (
892 'SHFileOperation was deprecated in Windows Vista, and there are less ',
893 'complex functions to achieve the same goals. Use IFileOperation for ',
894 'any esoteric actions instead.'
895 ),
896 True,
897 (),
898 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15899 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:51900 'StringFromGUID2',
901 (
902 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24903 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51904 ),
905 True,
906 (
Daniel Chenga44a1bcd2022-03-15 20:00:15907 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:51908 ),
909 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15910 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:51911 'StringFromCLSID',
912 (
913 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24914 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51915 ),
916 True,
917 (
Daniel Chenga44a1bcd2022-03-15 20:00:15918 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:51919 ),
920 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15921 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13922 'kCFAllocatorNull',
923 (
924 'The use of kCFAllocatorNull with the NoCopy creation of ',
925 'CoreFoundation types is prohibited.',
926 ),
927 True,
928 (),
929 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15930 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:29931 'mojo::ConvertTo',
932 (
933 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
934 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
935 'StringTraits if you would like to convert between custom types and',
936 'the wire format of mojom types.'
937 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22938 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29939 (
David Dorwin13dc48b2022-06-03 21:18:42940 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
941 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29942 r'^third_party/blink/.*\.(cc|h)$',
943 r'^content/renderer/.*\.(cc|h)$',
944 ),
945 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15946 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:16947 'GetInterfaceProvider',
948 (
949 'InterfaceProvider is deprecated.',
950 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
951 'or Platform::GetBrowserInterfaceBroker.'
952 ),
953 False,
954 (),
955 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15956 BanRule(
Robert Liao1d78df52019-11-11 20:02:01957 'CComPtr',
958 (
959 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
960 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
961 'details.'
962 ),
963 False,
964 (),
965 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15966 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:20967 r'/\b(IFACE|STD)METHOD_?\(',
968 (
969 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
970 'Instead, always use IFACEMETHODIMP in the declaration.'
971 ),
972 False,
973 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
974 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15975 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:47976 'set_owned_by_client',
977 (
978 'set_owned_by_client is deprecated.',
979 'views::View already owns the child views by default. This introduces ',
980 'a competing ownership model which makes the code difficult to reason ',
981 'about. See http://crbug.com/1044687 for more details.'
982 ),
983 False,
984 (),
985 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15986 BanRule(
Peter Boström7ff41522021-07-29 03:43:27987 'RemoveAllChildViewsWithoutDeleting',
988 (
989 'RemoveAllChildViewsWithoutDeleting is deprecated.',
990 'This method is deemed dangerous as, unless raw pointers are re-added,',
991 'calls to this method introduce memory leaks.'
992 ),
993 False,
994 (),
995 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15996 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:12997 r'/\bTRACE_EVENT_ASYNC_',
998 (
999 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1000 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1001 ),
1002 False,
1003 (
1004 r'^base/trace_event/.*',
1005 r'^base/tracing/.*',
1006 ),
1007 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151008 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431009 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1010 (
1011 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1012 'dumps and may spam crash reports. Consider if the throttled',
1013 'variants suffice instead.',
1014 ),
1015 False,
1016 (),
1017 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151018 BanRule(
Robert Liao22f66a52021-04-10 00:57:521019 'RoInitialize',
1020 (
Robert Liao48018922021-04-16 23:03:021021 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521022 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1023 'instead. See http://crbug.com/1197722 for more information.'
1024 ),
1025 True,
Robert Liao48018922021-04-16 23:03:021026 (
Daniel Chenga44a1bcd2022-03-15 20:00:151027 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021028 ),
Robert Liao22f66a52021-04-10 00:57:521029 ),
Patrick Monettec343bb982022-06-01 17:18:451030 BanRule(
1031 r'base::Watchdog',
1032 (
1033 'base::Watchdog is deprecated because it creates its own thread.',
1034 'Instead, manually start a timer on a SequencedTaskRunner.',
1035 ),
1036 False,
1037 (),
1038 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091039 BanRule(
1040 'base::Passed',
1041 (
1042 'Do not use base::Passed. It is a legacy helper for capturing ',
1043 'move-only types with base::BindRepeating, but invoking the ',
1044 'resulting RepeatingCallback moves the captured value out of ',
1045 'the callback storage, and subsequent invocations may pass the ',
1046 'value in a valid but undefined state. Prefer base::BindOnce().',
1047 'See http://crbug.com/1326449 for context.'
1048 ),
1049 False,
1050 (),
1051 ),
[email protected]127f18ec2012-06-16 05:05:591052)
1053
Daniel Cheng92c15e32022-03-16 17:48:221054_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1055 BanRule(
1056 'handle<shared_buffer>',
1057 (
1058 'Please use one of the more specific shared memory types instead:',
1059 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1060 ' mojo_base.mojom.WritableSharedMemoryRegion',
1061 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1062 ),
1063 True,
1064 ),
1065)
1066
mlamouria82272622014-09-16 18:45:041067_IPC_ENUM_TRAITS_DEPRECATED = (
1068 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501069 'See http://www.chromium.org/Home/chromium-security/education/'
1070 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041071
Stephen Martinis97a394142018-06-07 23:06:051072_LONG_PATH_ERROR = (
1073 'Some files included in this CL have file names that are too long (> 200'
1074 ' characters). If committed, these files will cause issues on Windows. See'
1075 ' https://crbug.com/612667 for more details.'
1076)
1077
Shenghua Zhangbfaa38b82017-11-16 21:58:021078_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041079 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041080 r".*[\\/]BuildHooksAndroidImpl\.java",
1081 r".*[\\/]LicenseContentProvider\.java",
1082 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281083 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021084]
[email protected]127f18ec2012-06-16 05:05:591085
Mohamed Heikald048240a2019-11-12 16:57:371086# List of image extensions that are used as resources in chromium.
1087_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1088
Sean Kau46e29bc2017-08-28 16:31:161089# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401090_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041091 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401092 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041093 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1094 r'^third_party[\\/]protobuf[\\/]',
Bruce Dawson49a3db522022-05-05 23:54:331095 r'^third_party[\\/]blink[\\/]perf_tests[\\/]speedometer[\\/]resources[\\/]todomvc[\\/]learn.json',
Egor Paskoce145c42018-09-28 19:31:041096 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431097 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
John Chen288dee02022-04-28 17:37:061098 r'^tools[\\/]perf[\\/]',
Bruce Dawson49a3db522022-05-05 23:54:331099 r'^tools[\\/]traceline[\\/]svgui[\\/]startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311100 # vscode configuration files allow comments
1101 r'^tools[\\/]vscode[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161102]
1103
Andrew Grieveb773bad2020-06-05 18:00:381104# These are not checked on the public chromium-presubmit trybot.
1105# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041106# checkouts.
agrievef32bcc72016-04-04 14:57:401107_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381108 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381109]
1110
1111
1112_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101113 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041114 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361115 'base/android/jni_generator/jni_generator.pydeps',
1116 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361117 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041118 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361119 'build/android/gyp/aar.pydeps',
1120 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271121 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361122 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381123 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361124 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021125 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221126 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111127 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361128 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361129 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361130 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111131 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041132 'build/android/gyp/create_app_bundle_apks.pydeps',
1133 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361134 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121135 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091136 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221137 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001138 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361139 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421140 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041141 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361142 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361143 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211144 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361145 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361146 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361147 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581148 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361149 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141150 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261151 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471152 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041153 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361154 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361155 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101156 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361157 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221158 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361159 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221160 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101161 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461162 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301163 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241164 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361165 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461166 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561167 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361168 'build/android/incremental_install/generate_android_manifest.pydeps',
1169 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321170 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041171 'build/android/resource_sizes.pydeps',
1172 'build/android/test_runner.pydeps',
1173 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361174 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361175 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321176 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271177 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1178 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041179 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001180 'components/cronet/tools/generate_javadoc.pydeps',
1181 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381182 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001183 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381184 'net/tools/testserver/testserver.pydeps',
Jonathan Lee10c06dea2022-05-02 23:13:321185 'testing/scripts/run_wpt_tests.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181186 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411187 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1188 'testing/merge_scripts/standard_gtest_merge.pydeps',
1189 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1190 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041191 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421192 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1193 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131194 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501195 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411196 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1197 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061198 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221199 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401200]
1201
wnwenbdc444e2016-05-25 13:44:151202
agrievef32bcc72016-04-04 14:57:401203_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1204
1205
Eric Boren6fd2b932018-01-25 15:05:081206# Bypass the AUTHORS check for these accounts.
1207_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591208 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451209 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591210 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521211 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231212 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471213 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461214 'infra-try-recipes-tester', 'lacros-tracking-roller',
1215 'lacros-sdk-version-roller')
Eric Boren835d71f2018-09-07 21:09:041216 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271217 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041218 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161219 for s in ('chromium-internal-autoroll',)
1220 ) | set('%[email protected]' % s
1221 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081222
Matt Stark6ef08872021-07-29 01:21:461223_INVALID_GRD_FILE_LINE = [
1224 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1225]
Eric Boren6fd2b932018-01-25 15:05:081226
Daniel Bratell65b033262019-04-23 08:17:061227def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501228 """Returns True if this file contains C++-like code (and not Python,
1229 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061230
Sam Maiera6e76d72022-02-11 21:43:501231 ext = input_api.os_path.splitext(file_path)[1]
1232 # This list is compatible with CppChecker.IsCppFile but we should
1233 # consider adding ".c" to it. If we do that we can use this function
1234 # at more places in the code.
1235 return ext in (
1236 '.h',
1237 '.cc',
1238 '.cpp',
1239 '.m',
1240 '.mm',
1241 )
1242
Daniel Bratell65b033262019-04-23 08:17:061243
1244def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501245 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061246
1247
1248def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501249 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061250
1251
1252def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501253 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061254
Mohamed Heikal5e5b7922020-10-29 18:57:591255
Erik Staabc734cd7a2021-11-23 03:11:521256def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501257 ext = input_api.os_path.splitext(file_path)[1]
1258 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521259
1260
Mohamed Heikal5e5b7922020-10-29 18:57:591261def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501262 """Prevent additions of dependencies from the upstream repo on //clank."""
1263 # clank can depend on clank
1264 if input_api.change.RepositoryRoot().endswith('clank'):
1265 return []
1266 build_file_patterns = [
1267 r'(.+/)?BUILD\.gn',
1268 r'.+\.gni',
1269 ]
1270 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1271 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591272
Sam Maiera6e76d72022-02-11 21:43:501273 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591274
Sam Maiera6e76d72022-02-11 21:43:501275 def FilterFile(affected_file):
1276 return input_api.FilterSourceFile(affected_file,
1277 files_to_check=build_file_patterns,
1278 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591279
Sam Maiera6e76d72022-02-11 21:43:501280 problems = []
1281 for f in input_api.AffectedSourceFiles(FilterFile):
1282 local_path = f.LocalPath()
1283 for line_number, line in f.ChangedContents():
1284 if (bad_pattern.search(line)):
1285 problems.append('%s:%d\n %s' %
1286 (local_path, line_number, line.strip()))
1287 if problems:
1288 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1289 else:
1290 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591291
1292
Saagar Sanghavifceeaae2020-08-12 16:40:361293def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501294 """Attempts to prevent use of functions intended only for testing in
1295 non-testing code. For now this is just a best-effort implementation
1296 that ignores header files and may have some false positives. A
1297 better implementation would probably need a proper C++ parser.
1298 """
1299 # We only scan .cc files and the like, as the declaration of
1300 # for-testing functions in header files are hard to distinguish from
1301 # calls to such functions without a proper C++ parser.
1302 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191303
Sam Maiera6e76d72022-02-11 21:43:501304 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1305 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1306 base_function_pattern)
1307 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1308 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1309 exclusion_pattern = input_api.re.compile(
1310 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1311 (base_function_pattern, base_function_pattern))
1312 # Avoid a false positive in this case, where the method name, the ::, and
1313 # the closing { are all on different lines due to line wrapping.
1314 # HelperClassForTesting::
1315 # HelperClassForTesting(
1316 # args)
1317 # : member(0) {}
1318 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191319
Sam Maiera6e76d72022-02-11 21:43:501320 def FilterFile(affected_file):
1321 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1322 input_api.DEFAULT_FILES_TO_SKIP)
1323 return input_api.FilterSourceFile(
1324 affected_file,
1325 files_to_check=file_inclusion_pattern,
1326 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191327
Sam Maiera6e76d72022-02-11 21:43:501328 problems = []
1329 for f in input_api.AffectedSourceFiles(FilterFile):
1330 local_path = f.LocalPath()
1331 in_method_defn = False
1332 for line_number, line in f.ChangedContents():
1333 if (inclusion_pattern.search(line)
1334 and not comment_pattern.search(line)
1335 and not exclusion_pattern.search(line)
1336 and not allowlist_pattern.search(line)
1337 and not in_method_defn):
1338 problems.append('%s:%d\n %s' %
1339 (local_path, line_number, line.strip()))
1340 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191341
Sam Maiera6e76d72022-02-11 21:43:501342 if problems:
1343 return [
1344 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1345 ]
1346 else:
1347 return []
[email protected]55459852011-08-10 15:17:191348
1349
Saagar Sanghavifceeaae2020-08-12 16:40:361350def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501351 """This is a simplified version of
1352 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1353 """
1354 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1355 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1356 name_pattern = r'ForTest(s|ing)?'
1357 # Describes an occurrence of "ForTest*" inside a // comment.
1358 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1359 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1360 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1361 # Catch calls.
1362 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1363 # Ignore definitions. (Comments are ignored separately.)
1364 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231365
Sam Maiera6e76d72022-02-11 21:43:501366 problems = []
1367 sources = lambda x: input_api.FilterSourceFile(
1368 x,
1369 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1370 DEFAULT_FILES_TO_SKIP),
1371 files_to_check=[r'.*\.java$'])
1372 for f in input_api.AffectedFiles(include_deletes=False,
1373 file_filter=sources):
1374 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231375 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501376 for line_number, line in f.ChangedContents():
1377 if is_inside_javadoc and javadoc_end_re.search(line):
1378 is_inside_javadoc = False
1379 if not is_inside_javadoc and javadoc_start_re.search(line):
1380 is_inside_javadoc = True
1381 if is_inside_javadoc:
1382 continue
1383 if (inclusion_re.search(line) and not comment_re.search(line)
1384 and not annotation_re.search(line)
1385 and not exclusion_re.search(line)):
1386 problems.append('%s:%d\n %s' %
1387 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231388
Sam Maiera6e76d72022-02-11 21:43:501389 if problems:
1390 return [
1391 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1392 ]
1393 else:
1394 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231395
1396
Saagar Sanghavifceeaae2020-08-12 16:40:361397def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501398 """Checks to make sure no .h files include <iostream>."""
1399 files = []
1400 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1401 input_api.re.MULTILINE)
1402 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1403 if not f.LocalPath().endswith('.h'):
1404 continue
1405 contents = input_api.ReadFile(f)
1406 if pattern.search(contents):
1407 files.append(f)
[email protected]10689ca2011-09-02 02:31:541408
Sam Maiera6e76d72022-02-11 21:43:501409 if len(files):
1410 return [
1411 output_api.PresubmitError(
1412 'Do not #include <iostream> in header files, since it inserts static '
1413 'initialization into every file including the header. Instead, '
1414 '#include <ostream>. See http://crbug.com/94794', files)
1415 ]
1416 return []
1417
[email protected]10689ca2011-09-02 02:31:541418
Aleksey Khoroshilov9b28c032022-06-03 16:35:321419def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501420 """Checks no windows headers with StrCat redefined are included directly."""
1421 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:321422 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
1423 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
1424 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
1425 _NON_BASE_DEPENDENT_PATHS)
1426 sources_filter = lambda f: input_api.FilterSourceFile(
1427 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
1428
Sam Maiera6e76d72022-02-11 21:43:501429 pattern_deny = input_api.re.compile(
1430 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1431 input_api.re.MULTILINE)
1432 pattern_allow = input_api.re.compile(
1433 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:321434 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:501435 contents = input_api.ReadFile(f)
1436 if pattern_deny.search(
1437 contents) and not pattern_allow.search(contents):
1438 files.append(f.LocalPath())
Danil Chapovalov3518f36e2018-08-11 16:13:431439
Sam Maiera6e76d72022-02-11 21:43:501440 if len(files):
1441 return [
1442 output_api.PresubmitError(
1443 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1444 'directly since they pollute code with StrCat macro. Instead, '
1445 'include matching header from base/win. See http://crbug.com/856536',
1446 files)
1447 ]
1448 return []
Danil Chapovalov3518f36e2018-08-11 16:13:431449
[email protected]10689ca2011-09-02 02:31:541450
Saagar Sanghavifceeaae2020-08-12 16:40:361451def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501452 """Checks to make sure no source files use UNIT_TEST."""
1453 problems = []
1454 for f in input_api.AffectedFiles():
1455 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1456 continue
[email protected]72df4e782012-06-21 16:28:181457
Sam Maiera6e76d72022-02-11 21:43:501458 for line_num, line in f.ChangedContents():
1459 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1460 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181461
Sam Maiera6e76d72022-02-11 21:43:501462 if not problems:
1463 return []
1464 return [
1465 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1466 '\n'.join(problems))
1467 ]
1468
[email protected]72df4e782012-06-21 16:28:181469
Saagar Sanghavifceeaae2020-08-12 16:40:361470def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501471 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341472
Sam Maiera6e76d72022-02-11 21:43:501473 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1474 instead of DISABLED_. To filter false positives, reports are only generated
1475 if a corresponding MAYBE_ line exists.
1476 """
1477 problems = []
Dominic Battre033531052018-09-24 15:45:341478
Sam Maiera6e76d72022-02-11 21:43:501479 # The following two patterns are looked for in tandem - is a test labeled
1480 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1481 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1482 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341483
Sam Maiera6e76d72022-02-11 21:43:501484 # This is for the case that a test is disabled on all platforms.
1485 full_disable_pattern = input_api.re.compile(
1486 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1487 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341488
Sam Maiera6e76d72022-02-11 21:43:501489 for f in input_api.AffectedFiles(False):
1490 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1491 continue
Dominic Battre033531052018-09-24 15:45:341492
Sam Maiera6e76d72022-02-11 21:43:501493 # Search for MABYE_, DISABLE_ pairs.
1494 disable_lines = {} # Maps of test name to line number.
1495 maybe_lines = {}
1496 for line_num, line in f.ChangedContents():
1497 disable_match = disable_pattern.search(line)
1498 if disable_match:
1499 disable_lines[disable_match.group(1)] = line_num
1500 maybe_match = maybe_pattern.search(line)
1501 if maybe_match:
1502 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341503
Sam Maiera6e76d72022-02-11 21:43:501504 # Search for DISABLE_ occurrences within a TEST() macro.
1505 disable_tests = set(disable_lines.keys())
1506 maybe_tests = set(maybe_lines.keys())
1507 for test in disable_tests.intersection(maybe_tests):
1508 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341509
Sam Maiera6e76d72022-02-11 21:43:501510 contents = input_api.ReadFile(f)
1511 full_disable_match = full_disable_pattern.search(contents)
1512 if full_disable_match:
1513 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341514
Sam Maiera6e76d72022-02-11 21:43:501515 if not problems:
1516 return []
1517 return [
1518 output_api.PresubmitPromptWarning(
1519 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1520 '\n'.join(problems))
1521 ]
1522
Dominic Battre033531052018-09-24 15:45:341523
Nina Satragnof7660532021-09-20 18:03:351524def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501525 """Checks to make sure tests disabled conditionally are not missing a
1526 corresponding MAYBE_ prefix.
1527 """
1528 # Expect at least a lowercase character in the test name. This helps rule out
1529 # false positives with macros wrapping the actual tests name.
1530 define_maybe_pattern = input_api.re.compile(
1531 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191532 # The test_maybe_pattern needs to handle all of these forms. The standard:
1533 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1534 # With a wrapper macro around the test name:
1535 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1536 # And the odd-ball NACL_BROWSER_TEST_f format:
1537 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1538 # The optional E2E_ENABLED-style is handled with (\w*\()?
1539 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1540 # trailing ')'.
1541 test_maybe_pattern = (
1542 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501543 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1544 warnings = []
Nina Satragnof7660532021-09-20 18:03:351545
Sam Maiera6e76d72022-02-11 21:43:501546 # Read the entire files. We can't just read the affected lines, forgetting to
1547 # add MAYBE_ on a change would not show up otherwise.
1548 for f in input_api.AffectedFiles(False):
1549 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1550 continue
1551 contents = input_api.ReadFile(f)
1552 lines = contents.splitlines(True)
1553 current_position = 0
1554 warning_test_names = set()
1555 for line_num, line in enumerate(lines, start=1):
1556 current_position += len(line)
1557 maybe_match = define_maybe_pattern.search(line)
1558 if maybe_match:
1559 test_name = maybe_match.group('test_name')
1560 # Do not warn twice for the same test.
1561 if (test_name in warning_test_names):
1562 continue
1563 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351564
Sam Maiera6e76d72022-02-11 21:43:501565 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1566 # the current position.
1567 test_match = input_api.re.compile(
1568 test_maybe_pattern.format(test_name=test_name),
1569 input_api.re.MULTILINE).search(contents, current_position)
1570 suite_match = input_api.re.compile(
1571 suite_maybe_pattern.format(test_name=test_name),
1572 input_api.re.MULTILINE).search(contents, current_position)
1573 if not test_match and not suite_match:
1574 warnings.append(
1575 output_api.PresubmitPromptWarning(
1576 '%s:%d found MAYBE_ defined without corresponding test %s'
1577 % (f.LocalPath(), line_num, test_name)))
1578 return warnings
1579
[email protected]72df4e782012-06-21 16:28:181580
Saagar Sanghavifceeaae2020-08-12 16:40:361581def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501582 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1583 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:161584 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:501585 input_api.re.MULTILINE)
1586 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1587 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1588 continue
1589 for lnum, line in f.ChangedContents():
1590 if input_api.re.search(pattern, line):
1591 errors.append(
1592 output_api.PresubmitError((
1593 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1594 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1595 (f.LocalPath(), lnum)))
1596 return errors
danakj61c1aa22015-10-26 19:55:521597
1598
Weilun Shia487fad2020-10-28 00:10:341599# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1600# more reliable way. See
1601# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191602
wnwenbdc444e2016-05-25 13:44:151603
Saagar Sanghavifceeaae2020-08-12 16:40:361604def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501605 """Check that FlakyTest annotation is our own instead of the android one"""
1606 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1607 files = []
1608 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1609 if f.LocalPath().endswith('Test.java'):
1610 if pattern.search(input_api.ReadFile(f)):
1611 files.append(f)
1612 if len(files):
1613 return [
1614 output_api.PresubmitError(
1615 'Use org.chromium.base.test.util.FlakyTest instead of '
1616 'android.test.FlakyTest', files)
1617 ]
1618 return []
mcasasb7440c282015-02-04 14:52:191619
wnwenbdc444e2016-05-25 13:44:151620
Saagar Sanghavifceeaae2020-08-12 16:40:361621def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501622 """Make sure .DEPS.git is never modified manually."""
1623 if any(f.LocalPath().endswith('.DEPS.git')
1624 for f in input_api.AffectedFiles()):
1625 return [
1626 output_api.PresubmitError(
1627 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1628 'automated system based on what\'s in DEPS and your changes will be\n'
1629 'overwritten.\n'
1630 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1631 'get-the-code#Rolling_DEPS\n'
1632 'for more information')
1633 ]
1634 return []
[email protected]2a8ac9c2011-10-19 17:20:441635
1636
Saagar Sanghavifceeaae2020-08-12 16:40:361637def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501638 """Checks that DEPS file deps are from allowed_hosts."""
1639 # Run only if DEPS file has been modified to annoy fewer bystanders.
1640 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1641 return []
1642 # Outsource work to gclient verify
1643 try:
1644 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
1645 'third_party', 'depot_tools',
1646 'gclient.py')
1647 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:321648 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:501649 stderr=input_api.subprocess.STDOUT)
1650 return []
1651 except input_api.subprocess.CalledProcessError as error:
1652 return [
1653 output_api.PresubmitError(
1654 'DEPS file must have only git dependencies.',
1655 long_text=error.output)
1656 ]
tandriief664692014-09-23 14:51:471657
1658
Mario Sanchez Prada2472cab2019-09-18 10:58:311659def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151660 ban_rule):
Sam Maiera6e76d72022-02-11 21:43:501661 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311662
Sam Maiera6e76d72022-02-11 21:43:501663 Returns an string composed of the name of the file, the line number where the
1664 match has been found and the additional text passed as |message| in case the
1665 target type name matches the text inside the line passed as parameter.
1666 """
1667 result = []
Peng Huang9c5949a02020-06-11 19:20:541668
Daniel Chenga44a1bcd2022-03-15 20:00:151669 # Ignore comments about banned types.
1670 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:501671 return result
Daniel Chenga44a1bcd2022-03-15 20:00:151672 # A // nocheck comment will bypass this error.
1673 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:501674 return result
1675
1676 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:151677 if ban_rule.pattern[0:1] == '/':
1678 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:501679 if input_api.re.search(regex, line):
1680 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:151681 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:501682 matched = True
1683
1684 if matched:
1685 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:151686 for line in ban_rule.explanation:
1687 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:501688
danakjd18e8892020-12-17 17:42:011689 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:311690
1691
Saagar Sanghavifceeaae2020-08-12 16:40:361692def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501693 """Make sure that banned functions are not used."""
1694 warnings = []
1695 errors = []
[email protected]127f18ec2012-06-16 05:05:591696
Sam Maiera6e76d72022-02-11 21:43:501697 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:151698 if not excluded_paths:
1699 return False
1700
Sam Maiera6e76d72022-02-11 21:43:501701 local_path = affected_file.LocalPath()
1702 for item in excluded_paths:
1703 if input_api.re.match(item, local_path):
1704 return True
1705 return False
wnwenbdc444e2016-05-25 13:44:151706
Sam Maiera6e76d72022-02-11 21:43:501707 def IsIosObjcFile(affected_file):
1708 local_path = affected_file.LocalPath()
1709 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
1710 '.h'):
1711 return False
1712 basename = input_api.os_path.basename(local_path)
1713 if 'ios' in basename.split('_'):
1714 return True
1715 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1716 if sep and 'ios' in local_path.split(sep):
1717 return True
1718 return False
Sylvain Defresnea8b73d252018-02-28 15:45:541719
Daniel Chenga44a1bcd2022-03-15 20:00:151720 def CheckForMatch(affected_file, line_num: int, line: str,
1721 ban_rule: BanRule):
1722 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
1723 return
1724
Sam Maiera6e76d72022-02-11 21:43:501725 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151726 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501727 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:151728 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:501729 errors.extend(problems)
1730 else:
1731 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151732
Sam Maiera6e76d72022-02-11 21:43:501733 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1734 for f in input_api.AffectedFiles(file_filter=file_filter):
1735 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151736 for ban_rule in _BANNED_JAVA_FUNCTIONS:
1737 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:411738
Sam Maiera6e76d72022-02-11 21:43:501739 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1740 for f in input_api.AffectedFiles(file_filter=file_filter):
1741 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151742 for ban_rule in _BANNED_OBJC_FUNCTIONS:
1743 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591744
Sam Maiera6e76d72022-02-11 21:43:501745 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
1746 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151747 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
1748 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:541749
Sam Maiera6e76d72022-02-11 21:43:501750 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1751 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1752 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151753 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
1754 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:051755
Sam Maiera6e76d72022-02-11 21:43:501756 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1757 for f in input_api.AffectedFiles(file_filter=file_filter):
1758 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151759 for ban_rule in _BANNED_CPP_FUNCTIONS:
1760 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591761
Daniel Cheng92c15e32022-03-16 17:48:221762 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
1763 for f in input_api.AffectedFiles(file_filter=file_filter):
1764 for line_num, line in f.ChangedContents():
1765 for ban_rule in _BANNED_MOJOM_PATTERNS:
1766 CheckForMatch(f, line_num, line, ban_rule)
1767
1768
Sam Maiera6e76d72022-02-11 21:43:501769 result = []
1770 if (warnings):
1771 result.append(
1772 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
1773 '\n'.join(warnings)))
1774 if (errors):
1775 result.append(
1776 output_api.PresubmitError('Banned functions were used.\n' +
1777 '\n'.join(errors)))
1778 return result
[email protected]127f18ec2012-06-16 05:05:591779
1780
Michael Thiessen44457642020-02-06 00:24:151781def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501782 """Make sure that banned java imports are not used."""
1783 errors = []
Michael Thiessen44457642020-02-06 00:24:151784
Sam Maiera6e76d72022-02-11 21:43:501785 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1786 for f in input_api.AffectedFiles(file_filter=file_filter):
1787 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151788 for ban_rule in _BANNED_JAVA_IMPORTS:
1789 # Consider merging this into the above function. There is no
1790 # real difference anymore other than helping with a little
1791 # bit of boilerplate text. Doing so means things like
1792 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:501793 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:151794 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501795 if problems:
1796 errors.extend(problems)
1797 result = []
1798 if (errors):
1799 result.append(
1800 output_api.PresubmitError('Banned imports were used.\n' +
1801 '\n'.join(errors)))
1802 return result
Michael Thiessen44457642020-02-06 00:24:151803
1804
Saagar Sanghavifceeaae2020-08-12 16:40:361805def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501806 """Make sure that banned functions are not used."""
1807 files = []
1808 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
1809 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1810 if not f.LocalPath().endswith('.h'):
1811 continue
Bruce Dawson4c4c2922022-05-02 18:07:331812 if f.LocalPath().endswith('com_imported_mstscax.h'):
1813 continue
Sam Maiera6e76d72022-02-11 21:43:501814 contents = input_api.ReadFile(f)
1815 if pattern.search(contents):
1816 files.append(f)
[email protected]6c063c62012-07-11 19:11:061817
Sam Maiera6e76d72022-02-11 21:43:501818 if files:
1819 return [
1820 output_api.PresubmitError(
1821 'Do not use #pragma once in header files.\n'
1822 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1823 files)
1824 ]
1825 return []
[email protected]6c063c62012-07-11 19:11:061826
[email protected]127f18ec2012-06-16 05:05:591827
Saagar Sanghavifceeaae2020-08-12 16:40:361828def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501829 """Checks to make sure we don't introduce use of foo ? true : false."""
1830 problems = []
1831 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1832 for f in input_api.AffectedFiles():
1833 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1834 continue
[email protected]e7479052012-09-19 00:26:121835
Sam Maiera6e76d72022-02-11 21:43:501836 for line_num, line in f.ChangedContents():
1837 if pattern.match(line):
1838 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:121839
Sam Maiera6e76d72022-02-11 21:43:501840 if not problems:
1841 return []
1842 return [
1843 output_api.PresubmitPromptWarning(
1844 'Please consider avoiding the "? true : false" pattern if possible.\n'
1845 + '\n'.join(problems))
1846 ]
[email protected]e7479052012-09-19 00:26:121847
1848
Saagar Sanghavifceeaae2020-08-12 16:40:361849def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501850 """Runs checkdeps on #include and import statements added in this
1851 change. Breaking - rules is an error, breaking ! rules is a
1852 warning.
1853 """
1854 # Return early if no relevant file types were modified.
1855 for f in input_api.AffectedFiles():
1856 path = f.LocalPath()
1857 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
1858 or _IsJavaFile(input_api, path)):
1859 break
[email protected]55f9f382012-07-31 11:02:181860 else:
Sam Maiera6e76d72022-02-11 21:43:501861 return []
rhalavati08acd232017-04-03 07:23:281862
Sam Maiera6e76d72022-02-11 21:43:501863 import sys
1864 # We need to wait until we have an input_api object and use this
1865 # roundabout construct to import checkdeps because this file is
1866 # eval-ed and thus doesn't have __file__.
1867 original_sys_path = sys.path
1868 try:
1869 sys.path = sys.path + [
1870 input_api.os_path.join(input_api.PresubmitLocalPath(),
1871 'buildtools', 'checkdeps')
1872 ]
1873 import checkdeps
1874 from rules import Rule
1875 finally:
1876 # Restore sys.path to what it was before.
1877 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:181878
Sam Maiera6e76d72022-02-11 21:43:501879 added_includes = []
1880 added_imports = []
1881 added_java_imports = []
1882 for f in input_api.AffectedFiles():
1883 if _IsCPlusPlusFile(input_api, f.LocalPath()):
1884 changed_lines = [line for _, line in f.ChangedContents()]
1885 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
1886 elif _IsProtoFile(input_api, f.LocalPath()):
1887 changed_lines = [line for _, line in f.ChangedContents()]
1888 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
1889 elif _IsJavaFile(input_api, f.LocalPath()):
1890 changed_lines = [line for _, line in f.ChangedContents()]
1891 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241892
Sam Maiera6e76d72022-02-11 21:43:501893 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
1894
1895 error_descriptions = []
1896 warning_descriptions = []
1897 error_subjects = set()
1898 warning_subjects = set()
1899
1900 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1901 added_includes):
1902 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1903 description_with_path = '%s\n %s' % (path, rule_description)
1904 if rule_type == Rule.DISALLOW:
1905 error_descriptions.append(description_with_path)
1906 error_subjects.add("#includes")
1907 else:
1908 warning_descriptions.append(description_with_path)
1909 warning_subjects.add("#includes")
1910
1911 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1912 added_imports):
1913 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1914 description_with_path = '%s\n %s' % (path, rule_description)
1915 if rule_type == Rule.DISALLOW:
1916 error_descriptions.append(description_with_path)
1917 error_subjects.add("imports")
1918 else:
1919 warning_descriptions.append(description_with_path)
1920 warning_subjects.add("imports")
1921
1922 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
1923 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
1924 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1925 description_with_path = '%s\n %s' % (path, rule_description)
1926 if rule_type == Rule.DISALLOW:
1927 error_descriptions.append(description_with_path)
1928 error_subjects.add("imports")
1929 else:
1930 warning_descriptions.append(description_with_path)
1931 warning_subjects.add("imports")
1932
1933 results = []
1934 if error_descriptions:
1935 results.append(
1936 output_api.PresubmitError(
1937 'You added one or more %s that violate checkdeps rules.' %
1938 " and ".join(error_subjects), error_descriptions))
1939 if warning_descriptions:
1940 results.append(
1941 output_api.PresubmitPromptOrNotify(
1942 'You added one or more %s of files that are temporarily\n'
1943 'allowed but being removed. Can you avoid introducing the\n'
1944 '%s? See relevant DEPS file(s) for details and contacts.' %
1945 (" and ".join(warning_subjects), "/".join(warning_subjects)),
1946 warning_descriptions))
1947 return results
[email protected]55f9f382012-07-31 11:02:181948
1949
Saagar Sanghavifceeaae2020-08-12 16:40:361950def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501951 """Check that all files have their permissions properly set."""
1952 if input_api.platform == 'win32':
1953 return []
1954 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
1955 'tools', 'checkperms',
1956 'checkperms.py')
1957 args = [
Bruce Dawson8a43cf72022-05-13 17:10:321958 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:501959 input_api.change.RepositoryRoot()
1960 ]
1961 with input_api.CreateTemporaryFile() as file_list:
1962 for f in input_api.AffectedFiles():
1963 # checkperms.py file/directory arguments must be relative to the
1964 # repository.
1965 file_list.write((f.LocalPath() + '\n').encode('utf8'))
1966 file_list.close()
1967 args += ['--file-list', file_list.name]
1968 try:
1969 input_api.subprocess.check_output(args)
1970 return []
1971 except input_api.subprocess.CalledProcessError as error:
1972 return [
1973 output_api.PresubmitError('checkperms.py failed:',
1974 long_text=error.output.decode(
1975 'utf-8', 'ignore'))
1976 ]
[email protected]fbcafe5a2012-08-08 15:31:221977
1978
Saagar Sanghavifceeaae2020-08-12 16:40:361979def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501980 """Makes sure we don't include ui/aura/window_property.h
1981 in header files.
1982 """
1983 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1984 errors = []
1985 for f in input_api.AffectedFiles():
1986 if not f.LocalPath().endswith('.h'):
1987 continue
1988 for line_num, line in f.ChangedContents():
1989 if pattern.match(line):
1990 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:491991
Sam Maiera6e76d72022-02-11 21:43:501992 results = []
1993 if errors:
1994 results.append(
1995 output_api.PresubmitError(
1996 'Header files should not include ui/aura/window_property.h',
1997 errors))
1998 return results
[email protected]c8278b32012-10-30 20:35:491999
2000
Omer Katzcc77ea92021-04-26 10:23:282001def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502002 """Makes sure we don't include any headers from
2003 third_party/blink/renderer/platform/heap/impl or
2004 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2005 third_party/blink/renderer/platform/heap
2006 """
2007 impl_pattern = input_api.re.compile(
2008 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2009 v8_wrapper_pattern = input_api.re.compile(
2010 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2011 )
2012 file_filter = lambda f: not input_api.re.match(
2013 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
2014 f.LocalPath())
2015 errors = []
Omer Katzcc77ea92021-04-26 10:23:282016
Sam Maiera6e76d72022-02-11 21:43:502017 for f in input_api.AffectedFiles(file_filter=file_filter):
2018 for line_num, line in f.ChangedContents():
2019 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2020 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282021
Sam Maiera6e76d72022-02-11 21:43:502022 results = []
2023 if errors:
2024 results.append(
2025 output_api.PresubmitError(
2026 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2027 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2028 'relevant counterparts from third_party/blink/renderer/platform/heap',
2029 errors))
2030 return results
Omer Katzcc77ea92021-04-26 10:23:282031
2032
[email protected]70ca77752012-11-20 03:45:032033def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502034 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2035 errors = []
2036 for line_num, line in f.ChangedContents():
2037 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2038 # First-level headers in markdown look a lot like version control
2039 # conflict markers. http://daringfireball.net/projects/markdown/basics
2040 continue
2041 if pattern.match(line):
2042 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2043 return errors
[email protected]70ca77752012-11-20 03:45:032044
2045
Saagar Sanghavifceeaae2020-08-12 16:40:362046def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502047 """Usually this is not intentional and will cause a compile failure."""
2048 errors = []
2049 for f in input_api.AffectedFiles():
2050 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032051
Sam Maiera6e76d72022-02-11 21:43:502052 results = []
2053 if errors:
2054 results.append(
2055 output_api.PresubmitError(
2056 'Version control conflict markers found, please resolve.',
2057 errors))
2058 return results
[email protected]70ca77752012-11-20 03:45:032059
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202060
Saagar Sanghavifceeaae2020-08-12 16:40:362061def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502062 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2063 errors = []
2064 for f in input_api.AffectedFiles():
2065 for line_num, line in f.ChangedContents():
2066 if pattern.search(line):
2067 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162068
Sam Maiera6e76d72022-02-11 21:43:502069 results = []
2070 if errors:
2071 results.append(
2072 output_api.PresubmitPromptWarning(
2073 'Found Google support URL addressed by answer number. Please replace '
2074 'with a p= identifier instead. See crbug.com/679462\n',
2075 errors))
2076 return results
estadee17314a02017-01-12 16:22:162077
[email protected]70ca77752012-11-20 03:45:032078
Saagar Sanghavifceeaae2020-08-12 16:40:362079def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502080 def FilterFile(affected_file):
2081 """Filter function for use with input_api.AffectedSourceFiles,
2082 below. This filters out everything except non-test files from
2083 top-level directories that generally speaking should not hard-code
2084 service URLs (e.g. src/android_webview/, src/content/ and others).
2085 """
2086 return input_api.FilterSourceFile(
2087 affected_file,
2088 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2089 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2090 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442091
Sam Maiera6e76d72022-02-11 21:43:502092 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2093 '\.(com|net)[^"]*"')
2094 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2095 pattern = input_api.re.compile(base_pattern)
2096 problems = [] # items are (filename, line_number, line)
2097 for f in input_api.AffectedSourceFiles(FilterFile):
2098 for line_num, line in f.ChangedContents():
2099 if not comment_pattern.search(line) and pattern.search(line):
2100 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442101
Sam Maiera6e76d72022-02-11 21:43:502102 if problems:
2103 return [
2104 output_api.PresubmitPromptOrNotify(
2105 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2106 'Are you sure this is correct?', [
2107 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2108 for problem in problems
2109 ])
2110 ]
2111 else:
2112 return []
[email protected]06e6d0ff2012-12-11 01:36:442113
2114
Saagar Sanghavifceeaae2020-08-12 16:40:362115def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502116 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292117
Sam Maiera6e76d72022-02-11 21:43:502118 def FileFilter(affected_file):
2119 """Includes directories known to be Chrome OS only."""
2120 return input_api.FilterSourceFile(
2121 affected_file,
2122 files_to_check=(
2123 '^ash/',
2124 '^chromeos/', # Top-level src/chromeos.
2125 '.*/chromeos/', # Any path component.
2126 '^components/arc',
2127 '^components/exo'),
2128 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292129
Sam Maiera6e76d72022-02-11 21:43:502130 prefs = []
2131 priority_prefs = []
2132 for f in input_api.AffectedFiles(file_filter=FileFilter):
2133 for line_num, line in f.ChangedContents():
2134 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2135 line):
2136 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2137 prefs.append(' %s' % line)
2138 if input_api.re.search(
2139 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2140 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2141 priority_prefs.append(' %s' % line)
2142
2143 results = []
2144 if (prefs):
2145 results.append(
2146 output_api.PresubmitPromptWarning(
2147 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2148 'by browser sync settings. If these prefs should be controlled by OS '
2149 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2150 '\n'.join(prefs)))
2151 if (priority_prefs):
2152 results.append(
2153 output_api.PresubmitPromptWarning(
2154 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2155 'controlled by browser sync settings. If these prefs should be '
2156 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2157 'instead.\n' + '\n'.join(prefs)))
2158 return results
James Cook6b6597c2019-11-06 22:05:292159
2160
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492161# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362162def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502163 """Makes sure there are no abbreviations in the name of PNG files.
2164 The native_client_sdk directory is excluded because it has auto-generated PNG
2165 files for documentation.
2166 """
2167 errors = []
2168 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Bruce Dawson3db456212022-05-02 05:34:182169 files_to_skip = [r'^native_client_sdk[\\/]',
2170 r'^services[\\/]test[\\/]',
2171 r'^third_party[\\/]blink[\\/]web_tests[\\/]',
2172 ]
Sam Maiera6e76d72022-02-11 21:43:502173 file_filter = lambda f: input_api.FilterSourceFile(
2174 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2175 for f in input_api.AffectedFiles(include_deletes=False,
2176 file_filter=file_filter):
2177 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272178
Sam Maiera6e76d72022-02-11 21:43:502179 results = []
2180 if errors:
2181 results.append(
2182 output_api.PresubmitError(
2183 'The name of PNG files should not have abbreviations. \n'
2184 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2185 'Contact [email protected] if you have questions.', errors))
2186 return results
[email protected]d2530012013-01-25 16:39:272187
2188
Daniel Cheng4dcdb6b2017-04-13 08:30:172189def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502190 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172191
Sam Maiera6e76d72022-02-11 21:43:502192 Args:
2193 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2194 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172195 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502196 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172197 if rule.startswith('+') or rule.startswith('!')
2198 ])
Sam Maiera6e76d72022-02-11 21:43:502199 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2200 add_rules.update([
2201 rule[1:] for rule in rules
2202 if rule.startswith('+') or rule.startswith('!')
2203 ])
2204 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172205
2206
2207def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502208 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172209
Sam Maiera6e76d72022-02-11 21:43:502210 # Stubs for handling special syntax in the root DEPS file.
2211 class _VarImpl:
2212 def __init__(self, local_scope):
2213 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172214
Sam Maiera6e76d72022-02-11 21:43:502215 def Lookup(self, var_name):
2216 """Implements the Var syntax."""
2217 try:
2218 return self._local_scope['vars'][var_name]
2219 except KeyError:
2220 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172221
Sam Maiera6e76d72022-02-11 21:43:502222 local_scope = {}
2223 global_scope = {
2224 'Var': _VarImpl(local_scope).Lookup,
2225 'Str': str,
2226 }
Dirk Pranke1b9e06382021-05-14 01:16:222227
Sam Maiera6e76d72022-02-11 21:43:502228 exec(contents, global_scope, local_scope)
2229 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172230
2231
2232def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502233 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2234 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412235
Sam Maiera6e76d72022-02-11 21:43:502236 For a directory (rather than a specific filename) we fake a path to
2237 a specific filename by adding /DEPS. This is chosen as a file that
2238 will seldom or never be subject to per-file include_rules.
2239 """
2240 # We ignore deps entries on auto-generated directories.
2241 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082242
Sam Maiera6e76d72022-02-11 21:43:502243 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2244 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172245
Sam Maiera6e76d72022-02-11 21:43:502246 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172247
Sam Maiera6e76d72022-02-11 21:43:502248 results = set()
2249 for added_dep in added_deps:
2250 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2251 continue
2252 # Assume that a rule that ends in .h is a rule for a specific file.
2253 if added_dep.endswith('.h'):
2254 results.add(added_dep)
2255 else:
2256 results.add(os_path.join(added_dep, 'DEPS'))
2257 return results
[email protected]f32e2d1e2013-07-26 21:39:082258
2259
Saagar Sanghavifceeaae2020-08-12 16:40:362260def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502261 """When a dependency prefixed with + is added to a DEPS file, we
2262 want to make sure that the change is reviewed by an OWNER of the
2263 target file or directory, to avoid layering violations from being
2264 introduced. This check verifies that this happens.
2265 """
2266 # We rely on Gerrit's code-owners to check approvals.
2267 # input_api.gerrit is always set for Chromium, but other projects
2268 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102269 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502270 return []
2271 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2272 input_api.change.issue)):
2273 # Skip OWNERS check when Owners-Override label is approved. This is intended
2274 # for global owners, trusted bots, and on-call sheriffs. Review is still
2275 # required for these changes.
2276 return []
Edward Lesmes6fba51082021-01-20 04:20:232277
Sam Maiera6e76d72022-02-11 21:43:502278 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242279
Sam Maiera6e76d72022-02-11 21:43:502280 file_filter = lambda f: not input_api.re.match(
2281 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
2282 for f in input_api.AffectedFiles(include_deletes=False,
2283 file_filter=file_filter):
2284 filename = input_api.os_path.basename(f.LocalPath())
2285 if filename == 'DEPS':
2286 virtual_depended_on_files.update(
2287 _CalculateAddedDeps(input_api.os_path,
2288 '\n'.join(f.OldContents()),
2289 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552290
Sam Maiera6e76d72022-02-11 21:43:502291 if not virtual_depended_on_files:
2292 return []
[email protected]e871964c2013-05-13 14:14:552293
Sam Maiera6e76d72022-02-11 21:43:502294 if input_api.is_committing:
2295 if input_api.tbr:
2296 return [
2297 output_api.PresubmitNotifyResult(
2298 '--tbr was specified, skipping OWNERS check for DEPS additions'
2299 )
2300 ]
Daniel Cheng3008dc12022-05-13 04:02:112301 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2302 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502303 if input_api.dry_run:
2304 return [
2305 output_api.PresubmitNotifyResult(
2306 'This is a dry run, skipping OWNERS check for DEPS additions'
2307 )
2308 ]
2309 if not input_api.change.issue:
2310 return [
2311 output_api.PresubmitError(
2312 "DEPS approval by OWNERS check failed: this change has "
2313 "no change number, so we can't check it for approvals.")
2314 ]
2315 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412316 else:
Sam Maiera6e76d72022-02-11 21:43:502317 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552318
Sam Maiera6e76d72022-02-11 21:43:502319 owner_email, reviewers = (
2320 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2321 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552322
Sam Maiera6e76d72022-02-11 21:43:502323 owner_email = owner_email or input_api.change.author_email
2324
2325 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2326 virtual_depended_on_files, reviewers.union([owner_email]), [])
2327 missing_files = [
2328 f for f in virtual_depended_on_files
2329 if approval_status[f] != input_api.owners_client.APPROVED
2330 ]
2331
2332 # We strip the /DEPS part that was added by
2333 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2334 # directory.
2335 def StripDeps(path):
2336 start_deps = path.rfind('/DEPS')
2337 if start_deps != -1:
2338 return path[:start_deps]
2339 else:
2340 return path
2341
2342 unapproved_dependencies = [
2343 "'+%s'," % StripDeps(path) for path in missing_files
2344 ]
2345
2346 if unapproved_dependencies:
2347 output_list = [
2348 output(
2349 'You need LGTM from owners of depends-on paths in DEPS that were '
2350 'modified in this CL:\n %s' %
2351 '\n '.join(sorted(unapproved_dependencies)))
2352 ]
2353 suggested_owners = input_api.owners_client.SuggestOwners(
2354 missing_files, exclude=[owner_email])
2355 output_list.append(
2356 output('Suggested missing target path OWNERS:\n %s' %
2357 '\n '.join(suggested_owners or [])))
2358 return output_list
2359
2360 return []
[email protected]e871964c2013-05-13 14:14:552361
2362
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492363# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362364def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502365 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2366 files_to_skip = (
2367 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2368 input_api.DEFAULT_FILES_TO_SKIP + (
2369 r"^base[\\/]logging\.h$",
2370 r"^base[\\/]logging\.cc$",
2371 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2372 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2373 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2374 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2375 r"startup_browser_creator\.cc$",
2376 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2377 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2378 r"diagnostics_writer\.cc$",
2379 r"^chrome[\\/]chrome_cleaner[\\/].*",
2380 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2381 r"dll_hash_main\.cc$",
2382 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2383 r"^chromecast[\\/]",
Sam Maiera6e76d72022-02-11 21:43:502384 r"^components[\\/]browser_watcher[\\/]"
Joseph Wang668ab202022-07-26 16:24:492385 r"dump_stability_report_main_win\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502386 r"^components[\\/]media_control[\\/]renderer[\\/]"
2387 r"media_playback_options\.cc$",
2388 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2389 r"overlay_strategy_underlay_cast\.cc$",
2390 r"^components[\\/]zucchini[\\/].*",
2391 # TODO(peter): Remove exception. https://crbug.com/534537
2392 r"^content[\\/]browser[\\/]notifications[\\/]"
2393 r"notification_event_dispatcher_impl\.cc$",
2394 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2395 r"gl_helper_benchmark\.cc$",
2396 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2397 r"^courgette[\\/]courgette_tool\.cc$",
2398 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Joseph Wang668ab202022-07-26 16:24:492399 r"^fuchsia_web[\\/]common[\\/]init_logging\.cc$",
2400 r"^fuchsia_web[\\/]runners[\\/]common[\\/]web_component\.cc$",
2401 r"^fuchsia_web[\\/]shell[\\/].*_shell\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502402 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2403 r"^ipc[\\/]ipc_logging\.cc$",
2404 r"^native_client_sdk[\\/]",
2405 r"^remoting[\\/]base[\\/]logging\.h$",
2406 r"^remoting[\\/]host[\\/].*",
2407 r"^sandbox[\\/]linux[\\/].*",
2408 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Joseph Wang668ab202022-07-26 16:24:492409 r"dump_file_system\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502410 r"^tools[\\/]",
Joseph Wang668ab202022-07-26 16:24:492411 r"^ui[\\/]base[\\/]resource[\\/]data_pack\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502412 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2413 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2414 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2415 r"xwmstartupcheck\.cc$"))
2416 source_file_filter = lambda x: input_api.FilterSourceFile(
2417 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402418
Sam Maiera6e76d72022-02-11 21:43:502419 log_info = set([])
2420 printf = set([])
[email protected]85218562013-11-22 07:41:402421
Sam Maiera6e76d72022-02-11 21:43:502422 for f in input_api.AffectedSourceFiles(source_file_filter):
2423 for _, line in f.ChangedContents():
2424 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2425 log_info.add(f.LocalPath())
2426 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2427 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372428
Sam Maiera6e76d72022-02-11 21:43:502429 if input_api.re.search(r"\bprintf\(", line):
2430 printf.add(f.LocalPath())
2431 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2432 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402433
Sam Maiera6e76d72022-02-11 21:43:502434 if log_info:
2435 return [
2436 output_api.PresubmitError(
2437 'These files spam the console log with LOG(INFO):',
2438 items=log_info)
2439 ]
2440 if printf:
2441 return [
2442 output_api.PresubmitError(
2443 'These files spam the console log with printf/fprintf:',
2444 items=printf)
2445 ]
2446 return []
[email protected]85218562013-11-22 07:41:402447
2448
Saagar Sanghavifceeaae2020-08-12 16:40:362449def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502450 """These types are all expected to hold locks while in scope and
2451 so should never be anonymous (which causes them to be immediately
2452 destroyed)."""
2453 they_who_must_be_named = [
2454 'base::AutoLock',
2455 'base::AutoReset',
2456 'base::AutoUnlock',
2457 'SkAutoAlphaRestore',
2458 'SkAutoBitmapShaderInstall',
2459 'SkAutoBlitterChoose',
2460 'SkAutoBounderCommit',
2461 'SkAutoCallProc',
2462 'SkAutoCanvasRestore',
2463 'SkAutoCommentBlock',
2464 'SkAutoDescriptor',
2465 'SkAutoDisableDirectionCheck',
2466 'SkAutoDisableOvalCheck',
2467 'SkAutoFree',
2468 'SkAutoGlyphCache',
2469 'SkAutoHDC',
2470 'SkAutoLockColors',
2471 'SkAutoLockPixels',
2472 'SkAutoMalloc',
2473 'SkAutoMaskFreeImage',
2474 'SkAutoMutexAcquire',
2475 'SkAutoPathBoundsUpdate',
2476 'SkAutoPDFRelease',
2477 'SkAutoRasterClipValidate',
2478 'SkAutoRef',
2479 'SkAutoTime',
2480 'SkAutoTrace',
2481 'SkAutoUnref',
2482 ]
2483 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2484 # bad: base::AutoLock(lock.get());
2485 # not bad: base::AutoLock lock(lock.get());
2486 bad_pattern = input_api.re.compile(anonymous)
2487 # good: new base::AutoLock(lock.get())
2488 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2489 errors = []
[email protected]49aa76a2013-12-04 06:59:162490
Sam Maiera6e76d72022-02-11 21:43:502491 for f in input_api.AffectedFiles():
2492 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2493 continue
2494 for linenum, line in f.ChangedContents():
2495 if bad_pattern.search(line) and not good_pattern.search(line):
2496 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162497
Sam Maiera6e76d72022-02-11 21:43:502498 if errors:
2499 return [
2500 output_api.PresubmitError(
2501 'These lines create anonymous variables that need to be named:',
2502 items=errors)
2503 ]
2504 return []
[email protected]49aa76a2013-12-04 06:59:162505
2506
Saagar Sanghavifceeaae2020-08-12 16:40:362507def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502508 # Returns whether |template_str| is of the form <T, U...> for some types T
2509 # and U. Assumes that |template_str| is already in the form <...>.
2510 def HasMoreThanOneArg(template_str):
2511 # Level of <...> nesting.
2512 nesting = 0
2513 for c in template_str:
2514 if c == '<':
2515 nesting += 1
2516 elif c == '>':
2517 nesting -= 1
2518 elif c == ',' and nesting == 1:
2519 return True
2520 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532521
Sam Maiera6e76d72022-02-11 21:43:502522 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2523 sources = lambda affected_file: input_api.FilterSourceFile(
2524 affected_file,
2525 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2526 DEFAULT_FILES_TO_SKIP),
2527 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552528
Sam Maiera6e76d72022-02-11 21:43:502529 # Pattern to capture a single "<...>" block of template arguments. It can
2530 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2531 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2532 # latter would likely require counting that < and > match, which is not
2533 # expressible in regular languages. Should the need arise, one can introduce
2534 # limited counting (matching up to a total number of nesting depth), which
2535 # should cover all practical cases for already a low nesting limit.
2536 template_arg_pattern = (
2537 r'<[^>]*' # Opening block of <.
2538 r'>([^<]*>)?') # Closing block of >.
2539 # Prefix expressing that whatever follows is not already inside a <...>
2540 # block.
2541 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2542 null_construct_pattern = input_api.re.compile(
2543 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2544 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552545
Sam Maiera6e76d72022-02-11 21:43:502546 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2547 template_arg_no_array_pattern = (
2548 r'<[^>]*[^]]' # Opening block of <.
2549 r'>([^(<]*[^]]>)?') # Closing block of >.
2550 # Prefix saying that what follows is the start of an expression.
2551 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2552 # Suffix saying that what follows are call parentheses with a non-empty list
2553 # of arguments.
2554 nonempty_arg_list_pattern = r'\(([^)]|$)'
2555 # Put the template argument into a capture group for deeper examination later.
2556 return_construct_pattern = input_api.re.compile(
2557 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2558 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552559
Sam Maiera6e76d72022-02-11 21:43:502560 problems_constructor = []
2561 problems_nullptr = []
2562 for f in input_api.AffectedSourceFiles(sources):
2563 for line_number, line in f.ChangedContents():
2564 # Disallow:
2565 # return std::unique_ptr<T>(foo);
2566 # bar = std::unique_ptr<T>(foo);
2567 # But allow:
2568 # return std::unique_ptr<T[]>(foo);
2569 # bar = std::unique_ptr<T[]>(foo);
2570 # And also allow cases when the second template argument is present. Those
2571 # cases cannot be handled by std::make_unique:
2572 # return std::unique_ptr<T, U>(foo);
2573 # bar = std::unique_ptr<T, U>(foo);
2574 local_path = f.LocalPath()
2575 return_construct_result = return_construct_pattern.search(line)
2576 if return_construct_result and not HasMoreThanOneArg(
2577 return_construct_result.group('template_arg')):
2578 problems_constructor.append(
2579 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2580 # Disallow:
2581 # std::unique_ptr<T>()
2582 if null_construct_pattern.search(line):
2583 problems_nullptr.append(
2584 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052585
Sam Maiera6e76d72022-02-11 21:43:502586 errors = []
2587 if problems_nullptr:
2588 errors.append(
2589 output_api.PresubmitPromptWarning(
2590 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2591 problems_nullptr))
2592 if problems_constructor:
2593 errors.append(
2594 output_api.PresubmitError(
2595 'The following files use explicit std::unique_ptr constructor. '
2596 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2597 'std::make_unique is not an option.', problems_constructor))
2598 return errors
Peter Kasting4844e46e2018-02-23 07:27:102599
2600
Saagar Sanghavifceeaae2020-08-12 16:40:362601def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502602 """Checks if any new user action has been added."""
2603 if any('actions.xml' == input_api.os_path.basename(f)
2604 for f in input_api.LocalPaths()):
2605 # If actions.xml is already included in the changelist, the PRESUBMIT
2606 # for actions.xml will do a more complete presubmit check.
2607 return []
2608
2609 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2610 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2611 input_api.DEFAULT_FILES_TO_SKIP)
2612 file_filter = lambda f: input_api.FilterSourceFile(
2613 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2614
2615 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2616 current_actions = None
2617 for f in input_api.AffectedFiles(file_filter=file_filter):
2618 for line_num, line in f.ChangedContents():
2619 match = input_api.re.search(action_re, line)
2620 if match:
2621 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2622 # loaded only once.
2623 if not current_actions:
2624 with open(
2625 'tools/metrics/actions/actions.xml') as actions_f:
2626 current_actions = actions_f.read()
2627 # Search for the matched user action name in |current_actions|.
2628 for action_name in match.groups():
2629 action = 'name="{0}"'.format(action_name)
2630 if action not in current_actions:
2631 return [
2632 output_api.PresubmitPromptWarning(
2633 'File %s line %d: %s is missing in '
2634 'tools/metrics/actions/actions.xml. Please run '
2635 'tools/metrics/actions/extract_actions.py to update.'
2636 % (f.LocalPath(), line_num, action_name))
2637 ]
[email protected]999261d2014-03-03 20:08:082638 return []
2639
[email protected]999261d2014-03-03 20:08:082640
Daniel Cheng13ca61a882017-08-25 15:11:252641def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502642 import sys
2643 sys.path = sys.path + [
2644 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2645 'json_comment_eater')
2646 ]
2647 import json_comment_eater
2648 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252649
2650
[email protected]99171a92014-06-03 08:44:472651def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172652 try:
Sam Maiera6e76d72022-02-11 21:43:502653 contents = input_api.ReadFile(filename)
2654 if eat_comments:
2655 json_comment_eater = _ImportJSONCommentEater(input_api)
2656 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172657
Sam Maiera6e76d72022-02-11 21:43:502658 input_api.json.loads(contents)
2659 except ValueError as e:
2660 return e
Andrew Grieve4deedb12022-02-03 21:34:502661 return None
2662
2663
Sam Maiera6e76d72022-02-11 21:43:502664def _GetIDLParseError(input_api, filename):
2665 try:
2666 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:282667 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:342668 if not char.isascii():
2669 return (
2670 'Non-ascii character "%s" (ord %d) found at offset %d.' %
2671 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:502672 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2673 'tools', 'json_schema_compiler',
2674 'idl_schema.py')
2675 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282676 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502677 stdin=input_api.subprocess.PIPE,
2678 stdout=input_api.subprocess.PIPE,
2679 stderr=input_api.subprocess.PIPE,
2680 universal_newlines=True)
2681 (_, error) = process.communicate(input=contents)
2682 return error or None
2683 except ValueError as e:
2684 return e
agrievef32bcc72016-04-04 14:57:402685
agrievef32bcc72016-04-04 14:57:402686
Sam Maiera6e76d72022-02-11 21:43:502687def CheckParseErrors(input_api, output_api):
2688 """Check that IDL and JSON files do not contain syntax errors."""
2689 actions = {
2690 '.idl': _GetIDLParseError,
2691 '.json': _GetJSONParseError,
2692 }
2693 # Most JSON files are preprocessed and support comments, but these do not.
2694 json_no_comments_patterns = [
2695 r'^testing[\\/]',
2696 ]
2697 # Only run IDL checker on files in these directories.
2698 idl_included_patterns = [
2699 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2700 r'^extensions[\\/]common[\\/]api[\\/]',
2701 ]
agrievef32bcc72016-04-04 14:57:402702
Sam Maiera6e76d72022-02-11 21:43:502703 def get_action(affected_file):
2704 filename = affected_file.LocalPath()
2705 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:402706
Sam Maiera6e76d72022-02-11 21:43:502707 def FilterFile(affected_file):
2708 action = get_action(affected_file)
2709 if not action:
2710 return False
2711 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:402712
Sam Maiera6e76d72022-02-11 21:43:502713 if _MatchesFile(input_api,
2714 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
2715 return False
2716
2717 if (action == _GetIDLParseError
2718 and not _MatchesFile(input_api, idl_included_patterns, path)):
2719 return False
2720 return True
2721
2722 results = []
2723 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
2724 include_deletes=False):
2725 action = get_action(affected_file)
2726 kwargs = {}
2727 if (action == _GetJSONParseError
2728 and _MatchesFile(input_api, json_no_comments_patterns,
2729 affected_file.LocalPath())):
2730 kwargs['eat_comments'] = False
2731 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
2732 **kwargs)
2733 if parse_error:
2734 results.append(
2735 output_api.PresubmitError(
2736 '%s could not be parsed: %s' %
2737 (affected_file.LocalPath(), parse_error)))
2738 return results
2739
2740
2741def CheckJavaStyle(input_api, output_api):
2742 """Runs checkstyle on changed java files and returns errors if any exist."""
2743
2744 # Return early if no java files were modified.
2745 if not any(
2746 _IsJavaFile(input_api, f.LocalPath())
2747 for f in input_api.AffectedFiles()):
2748 return []
2749
2750 import sys
2751 original_sys_path = sys.path
2752 try:
2753 sys.path = sys.path + [
2754 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2755 'android', 'checkstyle')
2756 ]
2757 import checkstyle
2758 finally:
2759 # Restore sys.path to what it was before.
2760 sys.path = original_sys_path
2761
2762 return checkstyle.RunCheckstyle(
2763 input_api,
2764 output_api,
2765 'tools/android/checkstyle/chromium-style-5.0.xml',
2766 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
2767
2768
2769def CheckPythonDevilInit(input_api, output_api):
2770 """Checks to make sure devil is initialized correctly in python scripts."""
2771 script_common_initialize_pattern = input_api.re.compile(
2772 r'script_common\.InitializeEnvironment\(')
2773 devil_env_config_initialize = input_api.re.compile(
2774 r'devil_env\.config\.Initialize\(')
2775
2776 errors = []
2777
2778 sources = lambda affected_file: input_api.FilterSourceFile(
2779 affected_file,
2780 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
2781 r'^build[\\/]android[\\/]devil_chromium\.py',
2782 r'^third_party[\\/].*',
2783 )),
2784 files_to_check=[r'.*\.py$'])
2785
2786 for f in input_api.AffectedSourceFiles(sources):
2787 for line_num, line in f.ChangedContents():
2788 if (script_common_initialize_pattern.search(line)
2789 or devil_env_config_initialize.search(line)):
2790 errors.append("%s:%d" % (f.LocalPath(), line_num))
2791
2792 results = []
2793
2794 if errors:
2795 results.append(
2796 output_api.PresubmitError(
2797 'Devil initialization should always be done using '
2798 'devil_chromium.Initialize() in the chromium project, to use better '
2799 'defaults for dependencies (ex. up-to-date version of adb).',
2800 errors))
2801
2802 return results
2803
2804
2805def _MatchesFile(input_api, patterns, path):
2806 for pattern in patterns:
2807 if input_api.re.search(pattern, path):
2808 return True
2809 return False
2810
2811
Daniel Chenga37c03db2022-05-12 17:20:342812def _ChangeHasSecurityReviewer(input_api, owners_file):
2813 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:502814
Daniel Chenga37c03db2022-05-12 17:20:342815 Args:
2816 input_api: The presubmit input API.
2817 owners_file: OWNERS file with required reviewers. Typically, this is
2818 something like ipc/SECURITY_OWNERS.
2819
2820 Note: if the presubmit is running for commit rather than for upload, this
2821 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:502822 """
Daniel Chengd88244472022-05-16 09:08:472823 # Owners-Override should bypass all additional OWNERS enforcement checks.
2824 # A CR+1 vote will still be required to land this change.
2825 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2826 input_api.change.issue)):
2827 return True
2828
Daniel Chenga37c03db2022-05-12 17:20:342829 owner_email, reviewers = (
2830 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:112831 input_api,
2832 None,
2833 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:502834
Daniel Chenga37c03db2022-05-12 17:20:342835 security_owners = input_api.owners_client.ListOwners(owners_file)
2836 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:502837
Daniel Chenga37c03db2022-05-12 17:20:342838
2839@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:252840class _SecurityProblemWithItems:
2841 problem: str
2842 items: Sequence[str]
2843
2844
2845@dataclass
Daniel Chenga37c03db2022-05-12 17:20:342846class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:252847 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:342848 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:252849 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:342850
2851
2852def _FindMissingSecurityOwners(input_api,
2853 output_api,
2854 file_patterns: Sequence[str],
2855 excluded_patterns: Sequence[str],
2856 required_owners_file: str,
2857 custom_rule_function: Optional[Callable] = None
2858 ) -> _MissingSecurityOwnersResult:
2859 """Find OWNERS files missing per-file rules for security-sensitive files.
2860
2861 Args:
2862 input_api: the PRESUBMIT input API object.
2863 output_api: the PRESUBMIT output API object.
2864 file_patterns: basename patterns that require a corresponding per-file
2865 security restriction.
2866 excluded_patterns: path patterns that should be exempted from
2867 requiring a security restriction.
2868 required_owners_file: path to the required OWNERS file, e.g.
2869 ipc/SECURITY_OWNERS
2870 cc_alias: If not None, email that will be CCed automatically if the
2871 change contains security-sensitive files, as determined by
2872 `file_patterns` and `excluded_patterns`.
2873 custom_rule_function: If not None, will be called with `input_api` and
2874 the current file under consideration. Returning True will add an
2875 exact match per-file rule check for the current file.
2876 """
2877
2878 # `to_check` is a mapping of an OWNERS file path to Patterns.
2879 #
2880 # Patterns is a dictionary mapping glob patterns (suitable for use in
2881 # per-file rules) to a PatternEntry.
2882 #
Sam Maiera6e76d72022-02-11 21:43:502883 # PatternEntry is a dictionary with two keys:
2884 # - 'files': the files that are matched by this pattern
2885 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:342886 #
Sam Maiera6e76d72022-02-11 21:43:502887 # For example, if we expect OWNERS file to contain rules for *.mojom and
2888 # *_struct_traits*.*, Patterns might look like this:
2889 # {
2890 # '*.mojom': {
2891 # 'files': ...,
2892 # 'rules': [
2893 # 'per-file *.mojom=set noparent',
2894 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2895 # ],
2896 # },
2897 # '*_struct_traits*.*': {
2898 # 'files': ...,
2899 # 'rules': [
2900 # 'per-file *_struct_traits*.*=set noparent',
2901 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2902 # ],
2903 # },
2904 # }
2905 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:342906 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:502907
Daniel Chenga37c03db2022-05-12 17:20:342908 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:502909 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:472910 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:502911 if owners_file not in to_check:
2912 to_check[owners_file] = {}
2913 if pattern not in to_check[owners_file]:
2914 to_check[owners_file][pattern] = {
2915 'files': [],
2916 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:342917 f'per-file {pattern}=set noparent',
2918 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:502919 ]
2920 }
Daniel Chenged57a162022-05-25 02:56:342921 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:342922 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:502923
Daniel Chenga37c03db2022-05-12 17:20:342924 # Only enforce security OWNERS rules for a directory if that directory has a
2925 # file that matches `file_patterns`. For example, if a directory only
2926 # contains *.mojom files and no *_messages*.h files, the check should only
2927 # ensure that rules for *.mojom files are present.
2928 for file in input_api.AffectedFiles(include_deletes=False):
2929 file_basename = input_api.os_path.basename(file.LocalPath())
2930 if custom_rule_function is not None and custom_rule_function(
2931 input_api, file):
2932 AddPatternToCheck(file, file_basename)
2933 continue
Sam Maiera6e76d72022-02-11 21:43:502934
Daniel Chenga37c03db2022-05-12 17:20:342935 if any(
2936 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
2937 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:502938 continue
2939
2940 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:342941 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
2942 # file's basename.
2943 if input_api.fnmatch.fnmatch(file_basename, pattern):
2944 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:502945 break
2946
Daniel Chenga37c03db2022-05-12 17:20:342947 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:252948
2949 # Check if any newly added lines in OWNERS files intersect with required
2950 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
2951 # This is a hack, but is needed because the OWNERS check (by design) ignores
2952 # new OWNERS entries; otherwise, a non-owner could add someone as a new
2953 # OWNER and have that newly-added OWNER self-approve their own addition.
2954 newly_covered_files = []
2955 for file in input_api.AffectedFiles(include_deletes=False):
2956 if not file.LocalPath() in to_check:
2957 continue
2958 for _, line in file.ChangedContents():
2959 for _, entry in to_check[file.LocalPath()].items():
2960 if line in entry['rules']:
2961 newly_covered_files.extend(entry['files'])
2962
2963 missing_reviewer_problems = None
2964 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:342965 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:252966 missing_reviewer_problems = _SecurityProblemWithItems(
2967 f'Review from an owner in {required_owners_file} is required for '
2968 'the following newly-added files:',
2969 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:502970
2971 # Go through the OWNERS files to check, filtering out rules that are already
2972 # present in that OWNERS file.
2973 for owners_file, patterns in to_check.items():
2974 try:
Daniel Cheng171dad8d2022-05-21 00:40:252975 lines = set(
2976 input_api.ReadFile(
2977 input_api.os_path.join(input_api.change.RepositoryRoot(),
2978 owners_file)).splitlines())
2979 for entry in patterns.values():
2980 entry['rules'] = [
2981 rule for rule in entry['rules'] if rule not in lines
2982 ]
Sam Maiera6e76d72022-02-11 21:43:502983 except IOError:
2984 # No OWNERS file, so all the rules are definitely missing.
2985 continue
2986
2987 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:252988 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:342989
Sam Maiera6e76d72022-02-11 21:43:502990 for owners_file, patterns in to_check.items():
2991 missing_lines = []
2992 files = []
2993 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:342994 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:502995 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:502996 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:252997 joined_missing_lines = '\n'.join(line for line in missing_lines)
2998 owners_file_problems.append(
2999 _SecurityProblemWithItems(
3000 'Found missing OWNERS lines for security-sensitive files. '
3001 f'Please add the following lines to {owners_file}:\n'
3002 f'{joined_missing_lines}\n\nTo ensure security review for:',
3003 files))
Daniel Chenga37c03db2022-05-12 17:20:343004
Daniel Cheng171dad8d2022-05-21 00:40:253005 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343006 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253007 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343008
3009
3010def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3011 # Whether or not a file affects IPC is (mostly) determined by a simple list
3012 # of filename patterns.
3013 file_patterns = [
3014 # Legacy IPC:
3015 '*_messages.cc',
3016 '*_messages*.h',
3017 '*_param_traits*.*',
3018 # Mojo IPC:
3019 '*.mojom',
3020 '*_mojom_traits*.*',
3021 '*_type_converter*.*',
3022 # Android native IPC:
3023 '*.aidl',
3024 ]
3025
Daniel Chenga37c03db2022-05-12 17:20:343026 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463027 # These third_party directories do not contain IPCs, but contain files
3028 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343029 'third_party/crashpad/*',
3030 'third_party/blink/renderer/platform/bindings/*',
3031 'third_party/protobuf/benchmarks/python/*',
3032 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473033 # Enum-only mojoms used for web metrics, so no security review needed.
3034 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343035 # These files are just used to communicate between class loaders running
3036 # in the same process.
3037 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3038 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3039 ]
3040
3041 def IsMojoServiceManifestFile(input_api, file):
3042 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3043 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3044 if not manifest_pattern.search(file.LocalPath()):
3045 return False
3046
3047 if test_manifest_pattern.search(file.LocalPath()):
3048 return False
3049
3050 # All actual service manifest files should contain at least one
3051 # qualified reference to service_manager::Manifest.
3052 return any('service_manager::Manifest' in line
3053 for line in file.NewContents())
3054
3055 return _FindMissingSecurityOwners(
3056 input_api,
3057 output_api,
3058 file_patterns,
3059 excluded_patterns,
3060 'ipc/SECURITY_OWNERS',
3061 custom_rule_function=IsMojoServiceManifestFile)
3062
3063
3064def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3065 file_patterns = [
3066 # Component specifications.
3067 '*.cml', # Component Framework v2.
3068 '*.cmx', # Component Framework v1.
3069
3070 # Fuchsia IDL protocol specifications.
3071 '*.fidl',
3072 ]
3073
3074 # Don't check for owners files for changes in these directories.
3075 excluded_patterns = [
3076 'third_party/crashpad/*',
3077 ]
3078
3079 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3080 excluded_patterns,
3081 'build/fuchsia/SECURITY_OWNERS')
3082
3083
3084def CheckSecurityOwners(input_api, output_api):
3085 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3086 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3087 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3088 input_api, output_api)
3089
3090 if ipc_results.has_security_sensitive_files:
3091 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503092
3093 results = []
Daniel Chenga37c03db2022-05-12 17:20:343094
Daniel Cheng171dad8d2022-05-21 00:40:253095 missing_reviewer_problems = []
3096 if ipc_results.missing_reviewer_problem:
3097 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3098 if fuchsia_results.missing_reviewer_problem:
3099 missing_reviewer_problems.append(
3100 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343101
Daniel Cheng171dad8d2022-05-21 00:40:253102 # Missing reviewers are an error unless there's no issue number
3103 # associated with this branch; in that case, the presubmit is being run
3104 # with --all or --files.
3105 #
3106 # Note that upload should never be an error; otherwise, it would be
3107 # impossible to upload changes at all.
3108 if input_api.is_committing and input_api.change.issue:
3109 make_presubmit_message = output_api.PresubmitError
3110 else:
3111 make_presubmit_message = output_api.PresubmitNotifyResult
3112 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503113 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253114 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343115
Daniel Cheng171dad8d2022-05-21 00:40:253116 owners_file_problems = []
3117 owners_file_problems.extend(ipc_results.owners_file_problems)
3118 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343119
Daniel Cheng171dad8d2022-05-21 00:40:253120 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113121 # Missing per-file rules are always an error. While swarming and caching
3122 # means that uploading a patchset with updated OWNERS files and sending
3123 # it to the CQ again should not have a large incremental cost, it is
3124 # still frustrating to discover the error only after the change has
3125 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343126 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253127 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503128
3129 return results
3130
3131
3132def _GetFilesUsingSecurityCriticalFunctions(input_api):
3133 """Checks affected files for changes to security-critical calls. This
3134 function checks the full change diff, to catch both additions/changes
3135 and removals.
3136
3137 Returns a dict keyed by file name, and the value is a set of detected
3138 functions.
3139 """
3140 # Map of function pretty name (displayed in an error) to the pattern to
3141 # match it with.
3142 _PATTERNS_TO_CHECK = {
3143 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3144 }
3145 _PATTERNS_TO_CHECK = {
3146 k: input_api.re.compile(v)
3147 for k, v in _PATTERNS_TO_CHECK.items()
3148 }
3149
Sam Maiera6e76d72022-02-11 21:43:503150 # We don't want to trigger on strings within this file.
3151 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343152 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503153
3154 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3155 files_to_functions = {}
3156 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3157 diff = f.GenerateScmDiff()
3158 for line in diff.split('\n'):
3159 # Not using just RightHandSideLines() because removing a
3160 # call to a security-critical function can be just as important
3161 # as adding or changing the arguments.
3162 if line.startswith('-') or (line.startswith('+')
3163 and not line.startswith('++')):
3164 for name, pattern in _PATTERNS_TO_CHECK.items():
3165 if pattern.search(line):
3166 path = f.LocalPath()
3167 if not path in files_to_functions:
3168 files_to_functions[path] = set()
3169 files_to_functions[path].add(name)
3170 return files_to_functions
3171
3172
3173def CheckSecurityChanges(input_api, output_api):
3174 """Checks that changes involving security-critical functions are reviewed
3175 by the security team.
3176 """
3177 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3178 if not len(files_to_functions):
3179 return []
3180
Sam Maiera6e76d72022-02-11 21:43:503181 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343182 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503183 return []
3184
Daniel Chenga37c03db2022-05-12 17:20:343185 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503186 'that need to be reviewed by {}.\n'.format(owners_file)
3187 for path, names in files_to_functions.items():
3188 msg += ' {}\n'.format(path)
3189 for name in names:
3190 msg += ' {}\n'.format(name)
3191 msg += '\n'
3192
3193 if input_api.is_committing:
3194 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033195 else:
Sam Maiera6e76d72022-02-11 21:43:503196 output = output_api.PresubmitNotifyResult
3197 return [output(msg)]
3198
3199
3200def CheckSetNoParent(input_api, output_api):
3201 """Checks that set noparent is only used together with an OWNERS file in
3202 //build/OWNERS.setnoparent (see also
3203 //docs/code_reviews.md#owners-files-details)
3204 """
3205 # Return early if no OWNERS files were modified.
3206 if not any(f.LocalPath().endswith('OWNERS')
3207 for f in input_api.AffectedFiles(include_deletes=False)):
3208 return []
3209
3210 errors = []
3211
3212 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3213 allowed_owners_files = set()
3214 with open(allowed_owners_files_file, 'r') as f:
3215 for line in f:
3216 line = line.strip()
3217 if not line or line.startswith('#'):
3218 continue
3219 allowed_owners_files.add(line)
3220
3221 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3222
3223 for f in input_api.AffectedFiles(include_deletes=False):
3224 if not f.LocalPath().endswith('OWNERS'):
3225 continue
3226
3227 found_owners_files = set()
3228 found_set_noparent_lines = dict()
3229
3230 # Parse the OWNERS file.
3231 for lineno, line in enumerate(f.NewContents(), 1):
3232 line = line.strip()
3233 if line.startswith('set noparent'):
3234 found_set_noparent_lines[''] = lineno
3235 if line.startswith('file://'):
3236 if line in allowed_owners_files:
3237 found_owners_files.add('')
3238 if line.startswith('per-file'):
3239 match = per_file_pattern.match(line)
3240 if match:
3241 glob = match.group(1).strip()
3242 directive = match.group(2).strip()
3243 if directive == 'set noparent':
3244 found_set_noparent_lines[glob] = lineno
3245 if directive.startswith('file://'):
3246 if directive in allowed_owners_files:
3247 found_owners_files.add(glob)
3248
3249 # Check that every set noparent line has a corresponding file:// line
3250 # listed in build/OWNERS.setnoparent. An exception is made for top level
3251 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493252 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3253 if (linux_path.count('/') != 1
3254 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503255 for set_noparent_line in found_set_noparent_lines:
3256 if set_noparent_line in found_owners_files:
3257 continue
3258 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493259 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503260 found_set_noparent_lines[set_noparent_line]))
3261
3262 results = []
3263 if errors:
3264 if input_api.is_committing:
3265 output = output_api.PresubmitError
3266 else:
3267 output = output_api.PresubmitPromptWarning
3268 results.append(
3269 output(
3270 'Found the following "set noparent" restrictions in OWNERS files that '
3271 'do not include owners from build/OWNERS.setnoparent:',
3272 long_text='\n\n'.join(errors)))
3273 return results
3274
3275
3276def CheckUselessForwardDeclarations(input_api, output_api):
3277 """Checks that added or removed lines in non third party affected
3278 header files do not lead to new useless class or struct forward
3279 declaration.
3280 """
3281 results = []
3282 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3283 input_api.re.MULTILINE)
3284 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3285 input_api.re.MULTILINE)
3286 for f in input_api.AffectedFiles(include_deletes=False):
3287 if (f.LocalPath().startswith('third_party')
3288 and not f.LocalPath().startswith('third_party/blink')
3289 and not f.LocalPath().startswith('third_party\\blink')):
3290 continue
3291
3292 if not f.LocalPath().endswith('.h'):
3293 continue
3294
3295 contents = input_api.ReadFile(f)
3296 fwd_decls = input_api.re.findall(class_pattern, contents)
3297 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3298
3299 useless_fwd_decls = []
3300 for decl in fwd_decls:
3301 count = sum(1 for _ in input_api.re.finditer(
3302 r'\b%s\b' % input_api.re.escape(decl), contents))
3303 if count == 1:
3304 useless_fwd_decls.append(decl)
3305
3306 if not useless_fwd_decls:
3307 continue
3308
3309 for line in f.GenerateScmDiff().splitlines():
3310 if (line.startswith('-') and not line.startswith('--')
3311 or line.startswith('+') and not line.startswith('++')):
3312 for decl in useless_fwd_decls:
3313 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3314 results.append(
3315 output_api.PresubmitPromptWarning(
3316 '%s: %s forward declaration is no longer needed'
3317 % (f.LocalPath(), decl)))
3318 useless_fwd_decls.remove(decl)
3319
3320 return results
3321
3322
3323def _CheckAndroidDebuggableBuild(input_api, output_api):
3324 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3325 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3326 this is a debuggable build of Android.
3327 """
3328 build_type_check_pattern = input_api.re.compile(
3329 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3330
3331 errors = []
3332
3333 sources = lambda affected_file: input_api.FilterSourceFile(
3334 affected_file,
3335 files_to_skip=(
3336 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3337 DEFAULT_FILES_TO_SKIP + (
3338 r"^android_webview[\\/]support_library[\\/]"
3339 "boundary_interfaces[\\/]",
3340 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3341 r'^third_party[\\/].*',
3342 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3343 r"webview[\\/]chromium[\\/]License.*",
3344 )),
3345 files_to_check=[r'.*\.java$'])
3346
3347 for f in input_api.AffectedSourceFiles(sources):
3348 for line_num, line in f.ChangedContents():
3349 if build_type_check_pattern.search(line):
3350 errors.append("%s:%d" % (f.LocalPath(), line_num))
3351
3352 results = []
3353
3354 if errors:
3355 results.append(
3356 output_api.PresubmitPromptWarning(
3357 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3358 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3359
3360 return results
3361
3362# TODO: add unit tests
3363def _CheckAndroidToastUsage(input_api, output_api):
3364 """Checks that code uses org.chromium.ui.widget.Toast instead of
3365 android.widget.Toast (Chromium Toast doesn't force hardware
3366 acceleration on low-end devices, saving memory).
3367 """
3368 toast_import_pattern = input_api.re.compile(
3369 r'^import android\.widget\.Toast;$')
3370
3371 errors = []
3372
3373 sources = lambda affected_file: input_api.FilterSourceFile(
3374 affected_file,
3375 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3376 DEFAULT_FILES_TO_SKIP + (r'^chromecast[\\/].*',
3377 r'^remoting[\\/].*')),
3378 files_to_check=[r'.*\.java$'])
3379
3380 for f in input_api.AffectedSourceFiles(sources):
3381 for line_num, line in f.ChangedContents():
3382 if toast_import_pattern.search(line):
3383 errors.append("%s:%d" % (f.LocalPath(), line_num))
3384
3385 results = []
3386
3387 if errors:
3388 results.append(
3389 output_api.PresubmitError(
3390 'android.widget.Toast usage is detected. Android toasts use hardware'
3391 ' acceleration, and can be\ncostly on low-end devices. Please use'
3392 ' org.chromium.ui.widget.Toast instead.\n'
3393 'Contact [email protected] if you have any questions.',
3394 errors))
3395
3396 return results
3397
3398
3399def _CheckAndroidCrLogUsage(input_api, output_api):
3400 """Checks that new logs using org.chromium.base.Log:
3401 - Are using 'TAG' as variable name for the tags (warn)
3402 - Are using a tag that is shorter than 20 characters (error)
3403 """
3404
3405 # Do not check format of logs in the given files
3406 cr_log_check_excluded_paths = [
3407 # //chrome/android/webapk cannot depend on //base
3408 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3409 # WebView license viewer code cannot depend on //base; used in stub APK.
3410 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3411 r"webview[\\/]chromium[\\/]License.*",
3412 # The customtabs_benchmark is a small app that does not depend on Chromium
3413 # java pieces.
3414 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3415 ]
3416
3417 cr_log_import_pattern = input_api.re.compile(
3418 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3419 class_in_base_pattern = input_api.re.compile(
3420 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3421 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3422 input_api.re.MULTILINE)
3423 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3424 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3425 log_decl_pattern = input_api.re.compile(
3426 r'static final String TAG = "(?P<name>(.*))"')
3427 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3428
3429 REF_MSG = ('See docs/android_logging.md for more info.')
3430 sources = lambda x: input_api.FilterSourceFile(
3431 x,
3432 files_to_check=[r'.*\.java$'],
3433 files_to_skip=cr_log_check_excluded_paths)
3434
3435 tag_decl_errors = []
3436 tag_length_errors = []
3437 tag_errors = []
3438 tag_with_dot_errors = []
3439 util_log_errors = []
3440
3441 for f in input_api.AffectedSourceFiles(sources):
3442 file_content = input_api.ReadFile(f)
3443 has_modified_logs = False
3444 # Per line checks
3445 if (cr_log_import_pattern.search(file_content)
3446 or (class_in_base_pattern.search(file_content)
3447 and not has_some_log_import_pattern.search(file_content))):
3448 # Checks to run for files using cr log
3449 for line_num, line in f.ChangedContents():
3450 if rough_log_decl_pattern.search(line):
3451 has_modified_logs = True
3452
3453 # Check if the new line is doing some logging
3454 match = log_call_pattern.search(line)
3455 if match:
3456 has_modified_logs = True
3457
3458 # Make sure it uses "TAG"
3459 if not match.group('tag') == 'TAG':
3460 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3461 else:
3462 # Report non cr Log function calls in changed lines
3463 for line_num, line in f.ChangedContents():
3464 if log_call_pattern.search(line):
3465 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3466
3467 # Per file checks
3468 if has_modified_logs:
3469 # Make sure the tag is using the "cr" prefix and is not too long
3470 match = log_decl_pattern.search(file_content)
3471 tag_name = match.group('name') if match else None
3472 if not tag_name:
3473 tag_decl_errors.append(f.LocalPath())
3474 elif len(tag_name) > 20:
3475 tag_length_errors.append(f.LocalPath())
3476 elif '.' in tag_name:
3477 tag_with_dot_errors.append(f.LocalPath())
3478
3479 results = []
3480 if tag_decl_errors:
3481 results.append(
3482 output_api.PresubmitPromptWarning(
3483 'Please define your tags using the suggested format: .\n'
3484 '"private static final String TAG = "<package tag>".\n'
3485 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3486 tag_decl_errors))
3487
3488 if tag_length_errors:
3489 results.append(
3490 output_api.PresubmitError(
3491 'The tag length is restricted by the system to be at most '
3492 '20 characters.\n' + REF_MSG, tag_length_errors))
3493
3494 if tag_errors:
3495 results.append(
3496 output_api.PresubmitPromptWarning(
3497 'Please use a variable named "TAG" for your log tags.\n' +
3498 REF_MSG, tag_errors))
3499
3500 if util_log_errors:
3501 results.append(
3502 output_api.PresubmitPromptWarning(
3503 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3504 util_log_errors))
3505
3506 if tag_with_dot_errors:
3507 results.append(
3508 output_api.PresubmitPromptWarning(
3509 'Dot in log tags cause them to be elided in crash reports.\n' +
3510 REF_MSG, tag_with_dot_errors))
3511
3512 return results
3513
3514
3515def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3516 """Checks that junit.framework.* is no longer used."""
3517 deprecated_junit_framework_pattern = input_api.re.compile(
3518 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3519 sources = lambda x: input_api.FilterSourceFile(
3520 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3521 errors = []
3522 for f in input_api.AffectedFiles(file_filter=sources):
3523 for line_num, line in f.ChangedContents():
3524 if deprecated_junit_framework_pattern.search(line):
3525 errors.append("%s:%d" % (f.LocalPath(), line_num))
3526
3527 results = []
3528 if errors:
3529 results.append(
3530 output_api.PresubmitError(
3531 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3532 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3533 ' if you have any question.', errors))
3534 return results
3535
3536
3537def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3538 """Checks that if new Java test classes have inheritance.
3539 Either the new test class is JUnit3 test or it is a JUnit4 test class
3540 with a base class, either case is undesirable.
3541 """
3542 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3543
3544 sources = lambda x: input_api.FilterSourceFile(
3545 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3546 errors = []
3547 for f in input_api.AffectedFiles(file_filter=sources):
3548 if not f.OldContents():
3549 class_declaration_start_flag = False
3550 for line_num, line in f.ChangedContents():
3551 if class_declaration_pattern.search(line):
3552 class_declaration_start_flag = True
3553 if class_declaration_start_flag and ' extends ' in line:
3554 errors.append('%s:%d' % (f.LocalPath(), line_num))
3555 if '{' in line:
3556 class_declaration_start_flag = False
3557
3558 results = []
3559 if errors:
3560 results.append(
3561 output_api.PresubmitPromptWarning(
3562 'The newly created files include Test classes that inherits from base'
3563 ' class. Please do not use inheritance in JUnit4 tests or add new'
3564 ' JUnit3 tests. Contact [email protected] if you have any'
3565 ' questions.', errors))
3566 return results
3567
3568
3569def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3570 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3571 deprecated_annotation_import_pattern = input_api.re.compile(
3572 r'^import android\.test\.suitebuilder\.annotation\..*;',
3573 input_api.re.MULTILINE)
3574 sources = lambda x: input_api.FilterSourceFile(
3575 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3576 errors = []
3577 for f in input_api.AffectedFiles(file_filter=sources):
3578 for line_num, line in f.ChangedContents():
3579 if deprecated_annotation_import_pattern.search(line):
3580 errors.append("%s:%d" % (f.LocalPath(), line_num))
3581
3582 results = []
3583 if errors:
3584 results.append(
3585 output_api.PresubmitError(
3586 'Annotations in android.test.suitebuilder.annotation have been'
3587 ' deprecated since API level 24. Please use android.support.test.filters'
3588 ' from //third_party/android_support_test_runner:runner_java instead.'
3589 ' Contact [email protected] if you have any questions.',
3590 errors))
3591 return results
3592
3593
3594def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3595 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:513596 file_filter = lambda f: (f.LocalPath().endswith(
3597 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
3598 LocalPath() or '/res/drawable-ldrtl/'.replace(
3599 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:503600 errors = []
3601 for f in input_api.AffectedFiles(include_deletes=False,
3602 file_filter=file_filter):
3603 errors.append(' %s' % f.LocalPath())
3604
3605 results = []
3606 if errors:
3607 results.append(
3608 output_api.PresubmitError(
3609 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3610 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3611 '/res/drawable-ldrtl/.\n'
3612 'Contact [email protected] if you have questions.', errors))
3613 return results
3614
3615
3616def _CheckAndroidWebkitImports(input_api, output_api):
3617 """Checks that code uses org.chromium.base.Callback instead of
3618 android.webview.ValueCallback except in the WebView glue layer
3619 and WebLayer.
3620 """
3621 valuecallback_import_pattern = input_api.re.compile(
3622 r'^import android\.webkit\.ValueCallback;$')
3623
3624 errors = []
3625
3626 sources = lambda affected_file: input_api.FilterSourceFile(
3627 affected_file,
3628 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3629 DEFAULT_FILES_TO_SKIP + (
3630 r'^android_webview[\\/]glue[\\/].*',
3631 r'^weblayer[\\/].*',
3632 )),
3633 files_to_check=[r'.*\.java$'])
3634
3635 for f in input_api.AffectedSourceFiles(sources):
3636 for line_num, line in f.ChangedContents():
3637 if valuecallback_import_pattern.search(line):
3638 errors.append("%s:%d" % (f.LocalPath(), line_num))
3639
3640 results = []
3641
3642 if errors:
3643 results.append(
3644 output_api.PresubmitError(
3645 'android.webkit.ValueCallback usage is detected outside of the glue'
3646 ' layer. To stay compatible with the support library, android.webkit.*'
3647 ' classes should only be used inside the glue layer and'
3648 ' org.chromium.base.Callback should be used instead.', errors))
3649
3650 return results
3651
3652
3653def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3654 """Checks Android XML styles """
3655
3656 # Return early if no relevant files were modified.
3657 if not any(
3658 _IsXmlOrGrdFile(input_api, f.LocalPath())
3659 for f in input_api.AffectedFiles(include_deletes=False)):
3660 return []
3661
3662 import sys
3663 original_sys_path = sys.path
3664 try:
3665 sys.path = sys.path + [
3666 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3667 'android', 'checkxmlstyle')
3668 ]
3669 import checkxmlstyle
3670 finally:
3671 # Restore sys.path to what it was before.
3672 sys.path = original_sys_path
3673
3674 if is_check_on_upload:
3675 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3676 else:
3677 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3678
3679
3680def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3681 """Checks Android Infobar Deprecation """
3682
3683 import sys
3684 original_sys_path = sys.path
3685 try:
3686 sys.path = sys.path + [
3687 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3688 'android', 'infobar_deprecation')
3689 ]
3690 import infobar_deprecation
3691 finally:
3692 # Restore sys.path to what it was before.
3693 sys.path = original_sys_path
3694
3695 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3696
3697
3698class _PydepsCheckerResult:
3699 def __init__(self, cmd, pydeps_path, process, old_contents):
3700 self._cmd = cmd
3701 self._pydeps_path = pydeps_path
3702 self._process = process
3703 self._old_contents = old_contents
3704
3705 def GetError(self):
3706 """Returns an error message, or None."""
3707 import difflib
3708 if self._process.wait() != 0:
3709 # STDERR should already be printed.
3710 return 'Command failed: ' + self._cmd
3711 new_contents = self._process.stdout.read().splitlines()[2:]
3712 if self._old_contents != new_contents:
3713 diff = '\n'.join(
3714 difflib.context_diff(self._old_contents, new_contents))
3715 return ('File is stale: {}\n'
3716 'Diff (apply to fix):\n'
3717 '{}\n'
3718 'To regenerate, run:\n\n'
3719 ' {}').format(self._pydeps_path, diff, self._cmd)
3720 return None
3721
3722
3723class PydepsChecker:
3724 def __init__(self, input_api, pydeps_files):
3725 self._file_cache = {}
3726 self._input_api = input_api
3727 self._pydeps_files = pydeps_files
3728
3729 def _LoadFile(self, path):
3730 """Returns the list of paths within a .pydeps file relative to //."""
3731 if path not in self._file_cache:
3732 with open(path, encoding='utf-8') as f:
3733 self._file_cache[path] = f.read()
3734 return self._file_cache[path]
3735
3736 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3737 """Returns an interable of paths within the .pydep, relativized to //."""
3738 pydeps_data = self._LoadFile(pydeps_path)
3739 uses_gn_paths = '--gn-paths' in pydeps_data
3740 entries = (l for l in pydeps_data.splitlines()
3741 if not l.startswith('#'))
3742 if uses_gn_paths:
3743 # Paths look like: //foo/bar/baz
3744 return (e[2:] for e in entries)
3745 else:
3746 # Paths look like: path/relative/to/file.pydeps
3747 os_path = self._input_api.os_path
3748 pydeps_dir = os_path.dirname(pydeps_path)
3749 return (os_path.normpath(os_path.join(pydeps_dir, e))
3750 for e in entries)
3751
3752 def _CreateFilesToPydepsMap(self):
3753 """Returns a map of local_path -> list_of_pydeps."""
3754 ret = {}
3755 for pydep_local_path in self._pydeps_files:
3756 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3757 ret.setdefault(path, []).append(pydep_local_path)
3758 return ret
3759
3760 def ComputeAffectedPydeps(self):
3761 """Returns an iterable of .pydeps files that might need regenerating."""
3762 affected_pydeps = set()
3763 file_to_pydeps_map = None
3764 for f in self._input_api.AffectedFiles(include_deletes=True):
3765 local_path = f.LocalPath()
3766 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3767 # subrepositories. We can't figure out which files change, so re-check
3768 # all files.
3769 # Changes to print_python_deps.py affect all .pydeps.
3770 if local_path in ('DEPS', 'PRESUBMIT.py'
3771 ) or local_path.endswith('print_python_deps.py'):
3772 return self._pydeps_files
3773 elif local_path.endswith('.pydeps'):
3774 if local_path in self._pydeps_files:
3775 affected_pydeps.add(local_path)
3776 elif local_path.endswith('.py'):
3777 if file_to_pydeps_map is None:
3778 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3779 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3780 return affected_pydeps
3781
3782 def DetermineIfStaleAsync(self, pydeps_path):
3783 """Runs print_python_deps.py to see if the files is stale."""
3784 import os
3785
3786 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3787 if old_pydeps_data:
3788 cmd = old_pydeps_data[1][1:].strip()
3789 if '--output' not in cmd:
3790 cmd += ' --output ' + pydeps_path
3791 old_contents = old_pydeps_data[2:]
3792 else:
3793 # A default cmd that should work in most cases (as long as pydeps filename
3794 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3795 # file is empty/new.
3796 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3797 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3798 old_contents = []
3799 env = dict(os.environ)
3800 env['PYTHONDONTWRITEBYTECODE'] = '1'
3801 process = self._input_api.subprocess.Popen(
3802 cmd + ' --output ""',
3803 shell=True,
3804 env=env,
3805 stdout=self._input_api.subprocess.PIPE,
3806 encoding='utf-8')
3807 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:403808
3809
Tibor Goldschwendt360793f72019-06-25 18:23:493810def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:503811 args = {}
3812 with open('build/config/gclient_args.gni', 'r') as f:
3813 for line in f:
3814 line = line.strip()
3815 if not line or line.startswith('#'):
3816 continue
3817 attribute, value = line.split('=')
3818 args[attribute.strip()] = value.strip()
3819 return args
Tibor Goldschwendt360793f72019-06-25 18:23:493820
3821
Saagar Sanghavifceeaae2020-08-12 16:40:363822def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:503823 """Checks if a .pydeps file needs to be regenerated."""
3824 # This check is for Python dependency lists (.pydeps files), and involves
3825 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3826 # doesn't work on Windows and Mac, so skip it on other platforms.
3827 if not input_api.platform.startswith('linux'):
3828 return []
Erik Staabc734cd7a2021-11-23 03:11:523829
Sam Maiera6e76d72022-02-11 21:43:503830 results = []
3831 # First, check for new / deleted .pydeps.
3832 for f in input_api.AffectedFiles(include_deletes=True):
3833 # Check whether we are running the presubmit check for a file in src.
3834 # f.LocalPath is relative to repo (src, or internal repo).
3835 # os_path.exists is relative to src repo.
3836 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3837 # to src and we can conclude that the pydeps is in src.
3838 if f.LocalPath().endswith('.pydeps'):
3839 if input_api.os_path.exists(f.LocalPath()):
3840 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3841 results.append(
3842 output_api.PresubmitError(
3843 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3844 'remove %s' % f.LocalPath()))
3845 elif f.Action() != 'D' and f.LocalPath(
3846 ) not in _ALL_PYDEPS_FILES:
3847 results.append(
3848 output_api.PresubmitError(
3849 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3850 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403851
Sam Maiera6e76d72022-02-11 21:43:503852 if results:
3853 return results
3854
3855 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
3856 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3857 affected_pydeps = set(checker.ComputeAffectedPydeps())
3858 affected_android_pydeps = affected_pydeps.intersection(
3859 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3860 if affected_android_pydeps and not is_android:
3861 results.append(
3862 output_api.PresubmitPromptOrNotify(
3863 'You have changed python files that may affect pydeps for android\n'
3864 'specific scripts. However, the relevant presumbit check cannot be\n'
3865 'run because you are not using an Android checkout. To validate that\n'
3866 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3867 'use the android-internal-presubmit optional trybot.\n'
3868 'Possibly stale pydeps files:\n{}'.format(
3869 '\n'.join(affected_android_pydeps))))
3870
3871 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3872 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
3873 # Process these concurrently, as each one takes 1-2 seconds.
3874 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
3875 for result in pydep_results:
3876 error_msg = result.GetError()
3877 if error_msg:
3878 results.append(output_api.PresubmitError(error_msg))
3879
agrievef32bcc72016-04-04 14:57:403880 return results
3881
agrievef32bcc72016-04-04 14:57:403882
Saagar Sanghavifceeaae2020-08-12 16:40:363883def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503884 """Checks to make sure no header files have |Singleton<|."""
3885
3886 def FileFilter(affected_file):
3887 # It's ok for base/memory/singleton.h to have |Singleton<|.
3888 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
3889 (r"^base[\\/]memory[\\/]singleton\.h$",
3890 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
James Cook24a504192020-07-23 00:08:443891 r"quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:503892 return input_api.FilterSourceFile(affected_file,
3893 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433894
Sam Maiera6e76d72022-02-11 21:43:503895 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
3896 files = []
3897 for f in input_api.AffectedSourceFiles(FileFilter):
3898 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
3899 or f.LocalPath().endswith('.hpp')
3900 or f.LocalPath().endswith('.inl')):
3901 contents = input_api.ReadFile(f)
3902 for line in contents.splitlines(False):
3903 if (not line.lstrip().startswith('//')
3904 and # Strip C++ comment.
3905 pattern.search(line)):
3906 files.append(f)
3907 break
glidere61efad2015-02-18 17:39:433908
Sam Maiera6e76d72022-02-11 21:43:503909 if files:
3910 return [
3911 output_api.PresubmitError(
3912 'Found base::Singleton<T> in the following header files.\n' +
3913 'Please move them to an appropriate source file so that the ' +
3914 'template gets instantiated in a single compilation unit.',
3915 files)
3916 ]
3917 return []
glidere61efad2015-02-18 17:39:433918
3919
[email protected]fd20b902014-05-09 02:14:533920_DEPRECATED_CSS = [
3921 # Values
3922 ( "-webkit-box", "flex" ),
3923 ( "-webkit-inline-box", "inline-flex" ),
3924 ( "-webkit-flex", "flex" ),
3925 ( "-webkit-inline-flex", "inline-flex" ),
3926 ( "-webkit-min-content", "min-content" ),
3927 ( "-webkit-max-content", "max-content" ),
3928
3929 # Properties
3930 ( "-webkit-background-clip", "background-clip" ),
3931 ( "-webkit-background-origin", "background-origin" ),
3932 ( "-webkit-background-size", "background-size" ),
3933 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443934 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533935
3936 # Functions
3937 ( "-webkit-gradient", "gradient" ),
3938 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3939 ( "-webkit-linear-gradient", "linear-gradient" ),
3940 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3941 ( "-webkit-radial-gradient", "radial-gradient" ),
3942 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3943]
3944
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203945
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493946# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363947def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503948 """ Make sure that we don't use deprecated CSS
3949 properties, functions or values. Our external
3950 documentation and iOS CSS for dom distiller
3951 (reader mode) are ignored by the hooks as it
3952 needs to be consumed by WebKit. """
3953 results = []
3954 file_inclusion_pattern = [r".+\.css$"]
3955 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3956 input_api.DEFAULT_FILES_TO_SKIP +
3957 (r"^chrome/common/extensions/docs", r"^chrome/docs",
3958 r"^native_client_sdk"))
3959 file_filter = lambda f: input_api.FilterSourceFile(
3960 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3961 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3962 for line_num, line in fpath.ChangedContents():
3963 for (deprecated_value, value) in _DEPRECATED_CSS:
3964 if deprecated_value in line:
3965 results.append(
3966 output_api.PresubmitError(
3967 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3968 (fpath.LocalPath(), line_num, deprecated_value,
3969 value)))
3970 return results
[email protected]fd20b902014-05-09 02:14:533971
mohan.reddyf21db962014-10-16 12:26:473972
Saagar Sanghavifceeaae2020-08-12 16:40:363973def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503974 bad_files = {}
3975 for f in input_api.AffectedFiles(include_deletes=False):
3976 if (f.LocalPath().startswith('third_party')
3977 and not f.LocalPath().startswith('third_party/blink')
3978 and not f.LocalPath().startswith('third_party\\blink')):
3979 continue
rlanday6802cf632017-05-30 17:48:363980
Sam Maiera6e76d72022-02-11 21:43:503981 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3982 continue
rlanday6802cf632017-05-30 17:48:363983
Sam Maiera6e76d72022-02-11 21:43:503984 relative_includes = [
3985 line for _, line in f.ChangedContents()
3986 if "#include" in line and "../" in line
3987 ]
3988 if not relative_includes:
3989 continue
3990 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:363991
Sam Maiera6e76d72022-02-11 21:43:503992 if not bad_files:
3993 return []
rlanday6802cf632017-05-30 17:48:363994
Sam Maiera6e76d72022-02-11 21:43:503995 error_descriptions = []
3996 for file_path, bad_lines in bad_files.items():
3997 error_description = file_path
3998 for line in bad_lines:
3999 error_description += '\n ' + line
4000 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364001
Sam Maiera6e76d72022-02-11 21:43:504002 results = []
4003 results.append(
4004 output_api.PresubmitError(
4005 'You added one or more relative #include paths (including "../").\n'
4006 'These shouldn\'t be used because they can be used to include headers\n'
4007 'from code that\'s not correctly specified as a dependency in the\n'
4008 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364009
Sam Maiera6e76d72022-02-11 21:43:504010 return results
rlanday6802cf632017-05-30 17:48:364011
Takeshi Yoshinoe387aa32017-08-02 13:16:134012
Saagar Sanghavifceeaae2020-08-12 16:40:364013def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504014 """Check that nobody tries to include a cc file. It's a relatively
4015 common error which results in duplicate symbols in object
4016 files. This may not always break the build until someone later gets
4017 very confusing linking errors."""
4018 results = []
4019 for f in input_api.AffectedFiles(include_deletes=False):
4020 # We let third_party code do whatever it wants
4021 if (f.LocalPath().startswith('third_party')
4022 and not f.LocalPath().startswith('third_party/blink')
4023 and not f.LocalPath().startswith('third_party\\blink')):
4024 continue
Daniel Bratell65b033262019-04-23 08:17:064025
Sam Maiera6e76d72022-02-11 21:43:504026 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4027 continue
Daniel Bratell65b033262019-04-23 08:17:064028
Sam Maiera6e76d72022-02-11 21:43:504029 for _, line in f.ChangedContents():
4030 if line.startswith('#include "'):
4031 included_file = line.split('"')[1]
4032 if _IsCPlusPlusFile(input_api, included_file):
4033 # The most common naming for external files with C++ code,
4034 # apart from standard headers, is to call them foo.inc, but
4035 # Chromium sometimes uses foo-inc.cc so allow that as well.
4036 if not included_file.endswith(('.h', '-inc.cc')):
4037 results.append(
4038 output_api.PresubmitError(
4039 'Only header files or .inc files should be included in other\n'
4040 'C++ files. Compiling the contents of a cc file more than once\n'
4041 'will cause duplicate information in the build which may later\n'
4042 'result in strange link_errors.\n' +
4043 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064044
Sam Maiera6e76d72022-02-11 21:43:504045 return results
Daniel Bratell65b033262019-04-23 08:17:064046
4047
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204048def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504049 if not isinstance(key, ast.Str):
4050 return 'Key at line %d must be a string literal' % key.lineno
4051 if not isinstance(value, ast.Dict):
4052 return 'Value at line %d must be a dict' % value.lineno
4053 if len(value.keys) != 1:
4054 return 'Dict at line %d must have single entry' % value.lineno
4055 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4056 return (
4057 'Entry at line %d must have a string literal \'filepath\' as key' %
4058 value.lineno)
4059 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134060
Takeshi Yoshinoe387aa32017-08-02 13:16:134061
Sergey Ulanov4af16052018-11-08 02:41:464062def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504063 if not isinstance(key, ast.Str):
4064 return 'Key at line %d must be a string literal' % key.lineno
4065 if not isinstance(value, ast.List):
4066 return 'Value at line %d must be a list' % value.lineno
4067 for element in value.elts:
4068 if not isinstance(element, ast.Str):
4069 return 'Watchlist elements on line %d is not a string' % key.lineno
4070 if not email_regex.match(element.s):
4071 return ('Watchlist element on line %d doesn\'t look like a valid '
4072 + 'email: %s') % (key.lineno, element.s)
4073 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134074
Takeshi Yoshinoe387aa32017-08-02 13:16:134075
Sergey Ulanov4af16052018-11-08 02:41:464076def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504077 mismatch_template = (
4078 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4079 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134080
Sam Maiera6e76d72022-02-11 21:43:504081 email_regex = input_api.re.compile(
4082 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464083
Sam Maiera6e76d72022-02-11 21:43:504084 ast = input_api.ast
4085 i = 0
4086 last_key = ''
4087 while True:
4088 if i >= len(wd_dict.keys):
4089 if i >= len(w_dict.keys):
4090 return None
4091 return mismatch_template % ('missing',
4092 'line %d' % w_dict.keys[i].lineno)
4093 elif i >= len(w_dict.keys):
4094 return (mismatch_template %
4095 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134096
Sam Maiera6e76d72022-02-11 21:43:504097 wd_key = wd_dict.keys[i]
4098 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134099
Sam Maiera6e76d72022-02-11 21:43:504100 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4101 wd_dict.values[i], ast)
4102 if result is not None:
4103 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134104
Sam Maiera6e76d72022-02-11 21:43:504105 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4106 email_regex)
4107 if result is not None:
4108 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204109
Sam Maiera6e76d72022-02-11 21:43:504110 if wd_key.s != w_key.s:
4111 return mismatch_template % ('%s at line %d' %
4112 (wd_key.s, wd_key.lineno),
4113 '%s at line %d' %
4114 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204115
Sam Maiera6e76d72022-02-11 21:43:504116 if wd_key.s < last_key:
4117 return (
4118 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4119 % (wd_key.lineno, w_key.lineno))
4120 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204121
Sam Maiera6e76d72022-02-11 21:43:504122 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204123
4124
Sergey Ulanov4af16052018-11-08 02:41:464125def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504126 ast = input_api.ast
4127 if not isinstance(expression, ast.Expression):
4128 return 'WATCHLISTS file must contain a valid expression'
4129 dictionary = expression.body
4130 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4131 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204132
Sam Maiera6e76d72022-02-11 21:43:504133 first_key = dictionary.keys[0]
4134 first_value = dictionary.values[0]
4135 second_key = dictionary.keys[1]
4136 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204137
Sam Maiera6e76d72022-02-11 21:43:504138 if (not isinstance(first_key, ast.Str)
4139 or first_key.s != 'WATCHLIST_DEFINITIONS'
4140 or not isinstance(first_value, ast.Dict)):
4141 return ('The first entry of the dict in WATCHLISTS file must be '
4142 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204143
Sam Maiera6e76d72022-02-11 21:43:504144 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4145 or not isinstance(second_value, ast.Dict)):
4146 return ('The second entry of the dict in WATCHLISTS file must be '
4147 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204148
Sam Maiera6e76d72022-02-11 21:43:504149 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134150
4151
Saagar Sanghavifceeaae2020-08-12 16:40:364152def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504153 for f in input_api.AffectedFiles(include_deletes=False):
4154 if f.LocalPath() == 'WATCHLISTS':
4155 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134156
Sam Maiera6e76d72022-02-11 21:43:504157 try:
4158 # First, make sure that it can be evaluated.
4159 input_api.ast.literal_eval(contents)
4160 # Get an AST tree for it and scan the tree for detailed style checking.
4161 expression = input_api.ast.parse(contents,
4162 filename='WATCHLISTS',
4163 mode='eval')
4164 except ValueError as e:
4165 return [
4166 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4167 long_text=repr(e))
4168 ]
4169 except SyntaxError as e:
4170 return [
4171 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4172 long_text=repr(e))
4173 ]
4174 except TypeError as e:
4175 return [
4176 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4177 long_text=repr(e))
4178 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134179
Sam Maiera6e76d72022-02-11 21:43:504180 result = _CheckWATCHLISTSSyntax(expression, input_api)
4181 if result is not None:
4182 return [output_api.PresubmitError(result)]
4183 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134184
Sam Maiera6e76d72022-02-11 21:43:504185 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134186
4187
Andrew Grieve1b290e4a22020-11-24 20:07:014188def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504189 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014190
Sam Maiera6e76d72022-02-11 21:43:504191 As documented at //build/docs/writing_gn_templates.md
4192 """
Andrew Grieve1b290e4a22020-11-24 20:07:014193
Sam Maiera6e76d72022-02-11 21:43:504194 def gn_files(f):
4195 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014196
Sam Maiera6e76d72022-02-11 21:43:504197 problems = []
4198 for f in input_api.AffectedSourceFiles(gn_files):
4199 for line_num, line in f.ChangedContents():
4200 if 'forward_variables_from(invoker, "*")' in line:
4201 problems.append(
4202 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4203 (f.LocalPath(), line_num))
4204
4205 if problems:
4206 return [
4207 output_api.PresubmitPromptWarning(
4208 'forward_variables_from("*") without exclusions',
4209 items=sorted(problems),
4210 long_text=(
4211 'The variables "visibilty" and "test_only" should be '
4212 'explicitly listed in forward_variables_from(). For more '
4213 'details, see:\n'
4214 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4215 'build/docs/writing_gn_templates.md'
4216 '#Using-forward_variables_from'))
4217 ]
4218 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014219
4220
Saagar Sanghavifceeaae2020-08-12 16:40:364221def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504222 """Checks that newly added header files have corresponding GN changes.
4223 Note that this is only a heuristic. To be precise, run script:
4224 build/check_gn_headers.py.
4225 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194226
Sam Maiera6e76d72022-02-11 21:43:504227 def headers(f):
4228 return input_api.FilterSourceFile(
4229 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194230
Sam Maiera6e76d72022-02-11 21:43:504231 new_headers = []
4232 for f in input_api.AffectedSourceFiles(headers):
4233 if f.Action() != 'A':
4234 continue
4235 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194236
Sam Maiera6e76d72022-02-11 21:43:504237 def gn_files(f):
4238 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194239
Sam Maiera6e76d72022-02-11 21:43:504240 all_gn_changed_contents = ''
4241 for f in input_api.AffectedSourceFiles(gn_files):
4242 for _, line in f.ChangedContents():
4243 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194244
Sam Maiera6e76d72022-02-11 21:43:504245 problems = []
4246 for header in new_headers:
4247 basename = input_api.os_path.basename(header)
4248 if basename not in all_gn_changed_contents:
4249 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194250
Sam Maiera6e76d72022-02-11 21:43:504251 if problems:
4252 return [
4253 output_api.PresubmitPromptWarning(
4254 'Missing GN changes for new header files',
4255 items=sorted(problems),
4256 long_text=
4257 'Please double check whether newly added header files need '
4258 'corresponding changes in gn or gni files.\nThis checking is only a '
4259 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4260 'Read https://crbug.com/661774 for more info.')
4261 ]
4262 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194263
4264
Saagar Sanghavifceeaae2020-08-12 16:40:364265def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504266 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024267
Sam Maiera6e76d72022-02-11 21:43:504268 This assumes we won't intentionally reference one product from the other
4269 product.
4270 """
4271 all_problems = []
4272 test_cases = [{
4273 "filename_postfix": "google_chrome_strings.grd",
4274 "correct_name": "Chrome",
4275 "incorrect_name": "Chromium",
4276 }, {
4277 "filename_postfix": "chromium_strings.grd",
4278 "correct_name": "Chromium",
4279 "incorrect_name": "Chrome",
4280 }]
Michael Giuffridad3bc8672018-10-25 22:48:024281
Sam Maiera6e76d72022-02-11 21:43:504282 for test_case in test_cases:
4283 problems = []
4284 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4285 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024286
Sam Maiera6e76d72022-02-11 21:43:504287 # Check each new line. Can yield false positives in multiline comments, but
4288 # easier than trying to parse the XML because messages can have nested
4289 # children, and associating message elements with affected lines is hard.
4290 for f in input_api.AffectedSourceFiles(filename_filter):
4291 for line_num, line in f.ChangedContents():
4292 if "<message" in line or "<!--" in line or "-->" in line:
4293 continue
4294 if test_case["incorrect_name"] in line:
4295 problems.append("Incorrect product name in %s:%d" %
4296 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024297
Sam Maiera6e76d72022-02-11 21:43:504298 if problems:
4299 message = (
4300 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4301 % (test_case["correct_name"], test_case["correct_name"],
4302 test_case["incorrect_name"]))
4303 all_problems.append(
4304 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024305
Sam Maiera6e76d72022-02-11 21:43:504306 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024307
4308
Saagar Sanghavifceeaae2020-08-12 16:40:364309def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504310 """Avoid large files, especially binary files, in the repository since
4311 git doesn't scale well for those. They will be in everyone's repo
4312 clones forever, forever making Chromium slower to clone and work
4313 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364314
Sam Maiera6e76d72022-02-11 21:43:504315 # Uploading files to cloud storage is not trivial so we don't want
4316 # to set the limit too low, but the upper limit for "normal" large
4317 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4318 # anything over 20 MB is exceptional.
4319 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364320
Sam Maiera6e76d72022-02-11 21:43:504321 too_large_files = []
4322 for f in input_api.AffectedFiles():
4323 # Check both added and modified files (but not deleted files).
4324 if f.Action() in ('A', 'M'):
4325 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4326 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4327 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364328
Sam Maiera6e76d72022-02-11 21:43:504329 if too_large_files:
4330 message = (
4331 'Do not commit large files to git since git scales badly for those.\n'
4332 +
4333 'Instead put the large files in cloud storage and use DEPS to\n' +
4334 'fetch them.\n' + '\n'.join(too_large_files))
4335 return [
4336 output_api.PresubmitError('Too large files found in commit',
4337 long_text=message + '\n')
4338 ]
4339 else:
4340 return []
Daniel Bratell93eb6c62019-04-29 20:13:364341
Max Morozb47503b2019-08-08 21:03:274342
Saagar Sanghavifceeaae2020-08-12 16:40:364343def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504344 """Checks specific for fuzz target sources."""
4345 EXPORTED_SYMBOLS = [
4346 'LLVMFuzzerInitialize',
4347 'LLVMFuzzerCustomMutator',
4348 'LLVMFuzzerCustomCrossOver',
4349 'LLVMFuzzerMutate',
4350 ]
Max Morozb47503b2019-08-08 21:03:274351
Sam Maiera6e76d72022-02-11 21:43:504352 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274353
Sam Maiera6e76d72022-02-11 21:43:504354 def FilterFile(affected_file):
4355 """Ignore libFuzzer source code."""
4356 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4357 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274358
Sam Maiera6e76d72022-02-11 21:43:504359 return input_api.FilterSourceFile(affected_file,
4360 files_to_check=[files_to_check],
4361 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274362
Sam Maiera6e76d72022-02-11 21:43:504363 files_with_missing_header = []
4364 for f in input_api.AffectedSourceFiles(FilterFile):
4365 contents = input_api.ReadFile(f, 'r')
4366 if REQUIRED_HEADER in contents:
4367 continue
Max Morozb47503b2019-08-08 21:03:274368
Sam Maiera6e76d72022-02-11 21:43:504369 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4370 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274371
Sam Maiera6e76d72022-02-11 21:43:504372 if not files_with_missing_header:
4373 return []
Max Morozb47503b2019-08-08 21:03:274374
Sam Maiera6e76d72022-02-11 21:43:504375 long_text = (
4376 'If you define any of the libFuzzer optional functions (%s), it is '
4377 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4378 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4379 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4380 'to access command line arguments passed to the fuzzer. Instead, prefer '
4381 'static initialization and shared resources as documented in '
4382 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4383 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4384 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274385
Sam Maiera6e76d72022-02-11 21:43:504386 return [
4387 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4388 REQUIRED_HEADER,
4389 items=files_with_missing_header,
4390 long_text=long_text)
4391 ]
Max Morozb47503b2019-08-08 21:03:274392
4393
Mohamed Heikald048240a2019-11-12 16:57:374394def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504395 """
4396 Warns authors who add images into the repo to make sure their images are
4397 optimized before committing.
4398 """
4399 images_added = False
4400 image_paths = []
4401 errors = []
4402 filter_lambda = lambda x: input_api.FilterSourceFile(
4403 x,
4404 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4405 DEFAULT_FILES_TO_SKIP),
4406 files_to_check=[r'.*\/(drawable|mipmap)'])
4407 for f in input_api.AffectedFiles(include_deletes=False,
4408 file_filter=filter_lambda):
4409 local_path = f.LocalPath().lower()
4410 if any(
4411 local_path.endswith(extension)
4412 for extension in _IMAGE_EXTENSIONS):
4413 images_added = True
4414 image_paths.append(f)
4415 if images_added:
4416 errors.append(
4417 output_api.PresubmitPromptWarning(
4418 'It looks like you are trying to commit some images. If these are '
4419 'non-test-only images, please make sure to read and apply the tips in '
4420 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4421 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4422 'FYI only and will not block your CL on the CQ.', image_paths))
4423 return errors
Mohamed Heikald048240a2019-11-12 16:57:374424
4425
Saagar Sanghavifceeaae2020-08-12 16:40:364426def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504427 """Groups upload checks that target android code."""
4428 results = []
4429 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4430 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4431 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4432 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4433 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4434 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4435 input_api, output_api))
4436 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4437 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4438 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4439 results.extend(_CheckNewImagesWarning(input_api, output_api))
4440 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4441 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4442 return results
4443
Becky Zhou7c69b50992018-12-10 19:37:574444
Saagar Sanghavifceeaae2020-08-12 16:40:364445def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504446 """Groups commit checks that target android code."""
4447 results = []
4448 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4449 return results
dgnaa68d5e2015-06-10 10:08:224450
Chris Hall59f8d0c72020-05-01 07:31:194451# TODO(chrishall): could we additionally match on any path owned by
4452# ui/accessibility/OWNERS ?
4453_ACCESSIBILITY_PATHS = (
4454 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4455 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4456 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4457 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4458 r"^content[\\/]browser[\\/]accessibility[\\/]",
4459 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4460 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4461 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4462 r"^ui[\\/]accessibility[\\/]",
4463 r"^ui[\\/]views[\\/]accessibility[\\/]",
4464)
4465
Saagar Sanghavifceeaae2020-08-12 16:40:364466def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504467 """Checks that commits to accessibility code contain an AX-Relnotes field in
4468 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194469
Sam Maiera6e76d72022-02-11 21:43:504470 def FileFilter(affected_file):
4471 paths = _ACCESSIBILITY_PATHS
4472 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194473
Sam Maiera6e76d72022-02-11 21:43:504474 # Only consider changes affecting accessibility paths.
4475 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4476 return []
Akihiro Ota08108e542020-05-20 15:30:534477
Sam Maiera6e76d72022-02-11 21:43:504478 # AX-Relnotes can appear in either the description or the footer.
4479 # When searching the description, require 'AX-Relnotes:' to appear at the
4480 # beginning of a line.
4481 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4482 description_has_relnotes = any(
4483 ax_regex.match(line)
4484 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194485
Sam Maiera6e76d72022-02-11 21:43:504486 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4487 'AX-Relnotes', [])
4488 if description_has_relnotes or footer_relnotes:
4489 return []
Chris Hall59f8d0c72020-05-01 07:31:194490
Sam Maiera6e76d72022-02-11 21:43:504491 # TODO(chrishall): link to Relnotes documentation in message.
4492 message = (
4493 "Missing 'AX-Relnotes:' field required for accessibility changes"
4494 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4495 "user-facing changes"
4496 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4497 "user-facing effects"
4498 "\n if this is confusing or annoying then please contact members "
4499 "of ui/accessibility/OWNERS.")
4500
4501 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224502
Mark Schillacie5a0be22022-01-19 00:38:394503
4504_ACCESSIBILITY_EVENTS_TEST_PATH = (
4505 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]event[\\/].*\.html",
4506)
4507
4508_ACCESSIBILITY_TREE_TEST_PATH = (
4509 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]accname[\\/].*\.html",
4510 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]aria[\\/].*\.html",
4511 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]css[\\/].*\.html",
4512 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]html[\\/].*\.html",
4513)
4514
4515_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
4516 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4517)
4518
4519_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Mark Schillaci6f568a52022-02-17 18:41:444520 r"^.*[\\/]WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394521)
4522
4523def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504524 """Checks that commits that include a newly added, renamed/moved, or deleted
4525 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4526 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394527
Sam Maiera6e76d72022-02-11 21:43:504528 def FilePathFilter(affected_file):
4529 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4530 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394531
Sam Maiera6e76d72022-02-11 21:43:504532 def AndroidFilePathFilter(affected_file):
4533 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4534 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394535
Sam Maiera6e76d72022-02-11 21:43:504536 # Only consider changes in the events test data path with html type.
4537 if not any(
4538 input_api.AffectedFiles(include_deletes=True,
4539 file_filter=FilePathFilter)):
4540 return []
Mark Schillacie5a0be22022-01-19 00:38:394541
Sam Maiera6e76d72022-02-11 21:43:504542 # If the commit contains any change to the Android test file, ignore.
4543 if any(
4544 input_api.AffectedFiles(include_deletes=True,
4545 file_filter=AndroidFilePathFilter)):
4546 return []
Mark Schillacie5a0be22022-01-19 00:38:394547
Sam Maiera6e76d72022-02-11 21:43:504548 # Only consider changes that are adding/renaming or deleting a file
4549 message = []
4550 for f in input_api.AffectedFiles(include_deletes=True,
4551 file_filter=FilePathFilter):
4552 if f.Action() == 'A' or f.Action() == 'D':
4553 message = (
4554 "It appears that you are adding, renaming or deleting"
4555 "\na dump_accessibility_events* test, but have not included"
4556 "\na corresponding change for Android."
4557 "\nPlease include (or remove) the test from:"
4558 "\n content/public/android/javatests/src/org/chromium/"
4559 "content/browser/accessibility/"
4560 "WebContentsAccessibilityEventsTest.java"
4561 "\nIf this message is confusing or annoying, please contact"
4562 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394563
Sam Maiera6e76d72022-02-11 21:43:504564 # If no message was set, return empty.
4565 if not len(message):
4566 return []
4567
4568 return [output_api.PresubmitPromptWarning(message)]
4569
Mark Schillacie5a0be22022-01-19 00:38:394570
4571def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504572 """Checks that commits that include a newly added, renamed/moved, or deleted
4573 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4574 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394575
Sam Maiera6e76d72022-02-11 21:43:504576 def FilePathFilter(affected_file):
4577 paths = _ACCESSIBILITY_TREE_TEST_PATH
4578 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394579
Sam Maiera6e76d72022-02-11 21:43:504580 def AndroidFilePathFilter(affected_file):
4581 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4582 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394583
Sam Maiera6e76d72022-02-11 21:43:504584 # Only consider changes in the various tree test data paths with html type.
4585 if not any(
4586 input_api.AffectedFiles(include_deletes=True,
4587 file_filter=FilePathFilter)):
4588 return []
Mark Schillacie5a0be22022-01-19 00:38:394589
Sam Maiera6e76d72022-02-11 21:43:504590 # If the commit contains any change to the Android test file, ignore.
4591 if any(
4592 input_api.AffectedFiles(include_deletes=True,
4593 file_filter=AndroidFilePathFilter)):
4594 return []
Mark Schillacie5a0be22022-01-19 00:38:394595
Sam Maiera6e76d72022-02-11 21:43:504596 # Only consider changes that are adding/renaming or deleting a file
4597 message = []
4598 for f in input_api.AffectedFiles(include_deletes=True,
4599 file_filter=FilePathFilter):
4600 if f.Action() == 'A' or f.Action() == 'D':
4601 message = (
4602 "It appears that you are adding, renaming or deleting"
4603 "\na dump_accessibility_tree* test, but have not included"
4604 "\na corresponding change for Android."
4605 "\nPlease include (or remove) the test from:"
4606 "\n content/public/android/javatests/src/org/chromium/"
4607 "content/browser/accessibility/"
4608 "WebContentsAccessibilityTreeTest.java"
4609 "\nIf this message is confusing or annoying, please contact"
4610 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394611
Sam Maiera6e76d72022-02-11 21:43:504612 # If no message was set, return empty.
4613 if not len(message):
4614 return []
4615
4616 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394617
4618
seanmccullough4a9356252021-04-08 19:54:094619# string pattern, sequence of strings to show when pattern matches,
4620# error flag. True if match is a presubmit error, otherwise it's a warning.
4621_NON_INCLUSIVE_TERMS = (
4622 (
4623 # Note that \b pattern in python re is pretty particular. In this
4624 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4625 # ...' will not. This may require some tweaking to catch these cases
4626 # without triggering a lot of false positives. Leaving it naive and
4627 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324628 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094629 (
4630 'Please don\'t use blacklist, whitelist, ' # nocheck
4631 'or slave in your', # nocheck
4632 'code and make every effort to use other terms. Using "// nocheck"',
4633 '"# nocheck" or "<!-- nocheck -->"',
4634 'at the end of the offending line will bypass this PRESUBMIT error',
4635 'but avoid using this whenever possible. Reach out to',
4636 '[email protected] if you have questions'),
4637 True),)
4638
Saagar Sanghavifceeaae2020-08-12 16:40:364639def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504640 """Checks common to both upload and commit."""
4641 results = []
Eric Boren6fd2b932018-01-25 15:05:084642 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504643 input_api.canned_checks.PanProjectChecks(
4644 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084645
Sam Maiera6e76d72022-02-11 21:43:504646 author = input_api.change.author_email
4647 if author and author not in _KNOWN_ROBOTS:
4648 results.extend(
4649 input_api.canned_checks.CheckAuthorizedAuthor(
4650 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244651
Sam Maiera6e76d72022-02-11 21:43:504652 results.extend(
4653 input_api.canned_checks.CheckChangeHasNoTabs(
4654 input_api,
4655 output_api,
4656 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
4657 results.extend(
4658 input_api.RunTests(
4659 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:174660
Bruce Dawsonc8054482022-03-28 15:33:374661 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:504662 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:374663 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:504664 results.extend(
4665 input_api.RunTests(
4666 input_api.canned_checks.CheckDirMetadataFormat(
4667 input_api, output_api, dirmd_bin)))
4668 results.extend(
4669 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4670 input_api, output_api))
4671 results.extend(
4672 input_api.canned_checks.CheckNoNewMetadataInOwners(
4673 input_api, output_api))
4674 results.extend(
4675 input_api.canned_checks.CheckInclusiveLanguage(
4676 input_api,
4677 output_api,
4678 excluded_directories_relative_path=[
4679 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
4680 ],
4681 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:594682
Aleksey Khoroshilov2978c942022-06-13 16:14:124683 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
4684 f, files_to_check=[r'PRESUBMIT\.py$'])
4685 for f in input_api.AffectedFiles(include_deletes=False,
4686 file_filter=presubmit_py_filter):
4687 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
4688 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
4689 # The PRESUBMIT.py file (and the directory containing it) might have
4690 # been affected by being moved or removed, so only try to run the tests
4691 # if they still exist.
4692 if not input_api.os_path.exists(test_file):
4693 continue
Sam Maiera6e76d72022-02-11 21:43:504694
Aleksey Khoroshilov2978c942022-06-13 16:14:124695 use_python3 = False
4696 with open(f.LocalPath()) as fp:
4697 use_python3 = any(
4698 line.startswith('USE_PYTHON3 = True')
4699 for line in fp.readlines())
4700
4701 results.extend(
4702 input_api.canned_checks.RunUnitTestsInDirectory(
4703 input_api,
4704 output_api,
4705 full_path,
4706 files_to_check=[r'^PRESUBMIT_test\.py$'],
4707 run_on_python2=not use_python3,
4708 run_on_python3=use_python3,
4709 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:504710 return results
[email protected]1f7b4172010-01-28 01:17:344711
[email protected]b337cb5b2011-01-23 21:24:054712
Saagar Sanghavifceeaae2020-08-12 16:40:364713def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504714 problems = [
4715 f.LocalPath() for f in input_api.AffectedFiles()
4716 if f.LocalPath().endswith(('.orig', '.rej'))
4717 ]
4718 # Cargo.toml.orig files are part of third-party crates downloaded from
4719 # crates.io and should be included.
4720 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
4721 if problems:
4722 return [
4723 output_api.PresubmitError("Don't commit .rej and .orig files.",
4724 problems)
4725 ]
4726 else:
4727 return []
[email protected]b8079ae4a2012-12-05 19:56:494728
4729
Saagar Sanghavifceeaae2020-08-12 16:40:364730def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504731 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4732 macro_re = input_api.re.compile(
4733 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
4734 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
4735 input_api.re.MULTILINE)
4736 extension_re = input_api.re.compile(r'\.[a-z]+$')
4737 errors = []
4738 for f in input_api.AffectedFiles(include_deletes=False):
4739 if not f.LocalPath().endswith(
4740 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4741 continue
4742 found_line_number = None
4743 found_macro = None
4744 all_lines = input_api.ReadFile(f, 'r').splitlines()
4745 for line_num, line in enumerate(all_lines):
4746 match = macro_re.search(line)
4747 if match:
4748 found_line_number = line_num
4749 found_macro = match.group(2)
4750 break
4751 if not found_line_number:
4752 continue
Kent Tamura5a8755d2017-06-29 23:37:074753
Sam Maiera6e76d72022-02-11 21:43:504754 found_include_line = -1
4755 for line_num, line in enumerate(all_lines):
4756 if include_re.search(line):
4757 found_include_line = line_num
4758 break
4759 if found_include_line >= 0 and found_include_line < found_line_number:
4760 continue
Kent Tamura5a8755d2017-06-29 23:37:074761
Sam Maiera6e76d72022-02-11 21:43:504762 if not f.LocalPath().endswith('.h'):
4763 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4764 try:
4765 content = input_api.ReadFile(primary_header_path, 'r')
4766 if include_re.search(content):
4767 continue
4768 except IOError:
4769 pass
4770 errors.append('%s:%d %s macro is used without first including build/'
4771 'build_config.h.' %
4772 (f.LocalPath(), found_line_number, found_macro))
4773 if errors:
4774 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4775 return []
Kent Tamura5a8755d2017-06-29 23:37:074776
4777
Lei Zhang1c12a22f2021-05-12 11:28:454778def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504779 stl_include_re = input_api.re.compile(r'^#include\s+<('
4780 r'algorithm|'
4781 r'array|'
4782 r'limits|'
4783 r'list|'
4784 r'map|'
4785 r'memory|'
4786 r'queue|'
4787 r'set|'
4788 r'string|'
4789 r'unordered_map|'
4790 r'unordered_set|'
4791 r'utility|'
4792 r'vector)>')
4793 std_namespace_re = input_api.re.compile(r'std::')
4794 errors = []
4795 for f in input_api.AffectedFiles():
4796 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4797 continue
Lei Zhang1c12a22f2021-05-12 11:28:454798
Sam Maiera6e76d72022-02-11 21:43:504799 uses_std_namespace = False
4800 has_stl_include = False
4801 for line in f.NewContents():
4802 if has_stl_include and uses_std_namespace:
4803 break
Lei Zhang1c12a22f2021-05-12 11:28:454804
Sam Maiera6e76d72022-02-11 21:43:504805 if not has_stl_include and stl_include_re.search(line):
4806 has_stl_include = True
4807 continue
Lei Zhang1c12a22f2021-05-12 11:28:454808
Bruce Dawson4a5579a2022-04-08 17:11:364809 if not uses_std_namespace and (std_namespace_re.search(line)
4810 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504811 uses_std_namespace = True
4812 continue
Lei Zhang1c12a22f2021-05-12 11:28:454813
Sam Maiera6e76d72022-02-11 21:43:504814 if has_stl_include and not uses_std_namespace:
4815 errors.append(
4816 '%s: Includes STL header(s) but does not reference std::' %
4817 f.LocalPath())
4818 if errors:
4819 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4820 return []
Lei Zhang1c12a22f2021-05-12 11:28:454821
4822
Xiaohan Wang42d96c22022-01-20 17:23:114823def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504824 """Check for sensible looking, totally invalid OS macros."""
4825 preprocessor_statement = input_api.re.compile(r'^\s*#')
4826 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
4827 results = []
4828 for lnum, line in f.ChangedContents():
4829 if preprocessor_statement.search(line):
4830 for match in os_macro.finditer(line):
4831 results.append(
4832 ' %s:%d: %s' %
4833 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
4834 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
4835 return results
[email protected]b00342e7f2013-03-26 16:21:544836
4837
Xiaohan Wang42d96c22022-01-20 17:23:114838def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504839 """Check all affected files for invalid OS macros."""
4840 bad_macros = []
4841 for f in input_api.AffectedSourceFiles(None):
4842 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
4843 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:544844
Sam Maiera6e76d72022-02-11 21:43:504845 if not bad_macros:
4846 return []
[email protected]b00342e7f2013-03-26 16:21:544847
Sam Maiera6e76d72022-02-11 21:43:504848 return [
4849 output_api.PresubmitError(
4850 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
4851 'defined in build_config.h):', bad_macros)
4852 ]
[email protected]b00342e7f2013-03-26 16:21:544853
lliabraa35bab3932014-10-01 12:16:444854
4855def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504856 """Check all affected files for invalid "if defined" macros."""
4857 ALWAYS_DEFINED_MACROS = (
4858 "TARGET_CPU_PPC",
4859 "TARGET_CPU_PPC64",
4860 "TARGET_CPU_68K",
4861 "TARGET_CPU_X86",
4862 "TARGET_CPU_ARM",
4863 "TARGET_CPU_MIPS",
4864 "TARGET_CPU_SPARC",
4865 "TARGET_CPU_ALPHA",
4866 "TARGET_IPHONE_SIMULATOR",
4867 "TARGET_OS_EMBEDDED",
4868 "TARGET_OS_IPHONE",
4869 "TARGET_OS_MAC",
4870 "TARGET_OS_UNIX",
4871 "TARGET_OS_WIN32",
4872 )
4873 ifdef_macro = input_api.re.compile(
4874 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4875 results = []
4876 for lnum, line in f.ChangedContents():
4877 for match in ifdef_macro.finditer(line):
4878 if match.group(1) in ALWAYS_DEFINED_MACROS:
4879 always_defined = ' %s is always defined. ' % match.group(1)
4880 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4881 results.append(
4882 ' %s:%d %s\n\t%s' %
4883 (f.LocalPath(), lnum, always_defined, did_you_mean))
4884 return results
lliabraa35bab3932014-10-01 12:16:444885
4886
Saagar Sanghavifceeaae2020-08-12 16:40:364887def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504888 """Check all affected files for invalid "if defined" macros."""
4889 bad_macros = []
4890 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
4891 for f in input_api.AffectedFiles():
4892 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
4893 continue
4894 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4895 bad_macros.extend(
4896 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:444897
Sam Maiera6e76d72022-02-11 21:43:504898 if not bad_macros:
4899 return []
lliabraa35bab3932014-10-01 12:16:444900
Sam Maiera6e76d72022-02-11 21:43:504901 return [
4902 output_api.PresubmitError(
4903 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4904 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4905 bad_macros)
4906 ]
lliabraa35bab3932014-10-01 12:16:444907
4908
Saagar Sanghavifceeaae2020-08-12 16:40:364909def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504910 """Check for same IPC rules described in
4911 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4912 """
4913 base_pattern = r'IPC_ENUM_TRAITS\('
4914 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4915 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:044916
Sam Maiera6e76d72022-02-11 21:43:504917 problems = []
4918 for f in input_api.AffectedSourceFiles(None):
4919 local_path = f.LocalPath()
4920 if not local_path.endswith('.h'):
4921 continue
4922 for line_number, line in f.ChangedContents():
4923 if inclusion_pattern.search(
4924 line) and not comment_pattern.search(line):
4925 problems.append('%s:%d\n %s' %
4926 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:044927
Sam Maiera6e76d72022-02-11 21:43:504928 if problems:
4929 return [
4930 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
4931 problems)
4932 ]
4933 else:
4934 return []
mlamouria82272622014-09-16 18:45:044935
[email protected]b00342e7f2013-03-26 16:21:544936
Saagar Sanghavifceeaae2020-08-12 16:40:364937def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504938 """Check to make sure no files being submitted have long paths.
4939 This causes issues on Windows.
4940 """
4941 problems = []
4942 for f in input_api.AffectedTestableFiles():
4943 local_path = f.LocalPath()
4944 # Windows has a path limit of 260 characters. Limit path length to 200 so
4945 # that we have some extra for the prefix on dev machines and the bots.
4946 if len(local_path) > 200:
4947 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:054948
Sam Maiera6e76d72022-02-11 21:43:504949 if problems:
4950 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4951 else:
4952 return []
Stephen Martinis97a394142018-06-07 23:06:054953
4954
Saagar Sanghavifceeaae2020-08-12 16:40:364955def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504956 """Check that header files have proper guards against multiple inclusion.
4957 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:364958 should include the string "no-include-guard-because-multiply-included" or
4959 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:504960 """
Daniel Bratell8ba52722018-03-02 16:06:144961
Sam Maiera6e76d72022-02-11 21:43:504962 def is_chromium_header_file(f):
4963 # We only check header files under the control of the Chromium
4964 # project. That is, those outside third_party apart from
4965 # third_party/blink.
4966 # We also exclude *_message_generator.h headers as they use
4967 # include guards in a special, non-typical way.
4968 file_with_path = input_api.os_path.normpath(f.LocalPath())
4969 return (file_with_path.endswith('.h')
4970 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:334971 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:504972 and (not file_with_path.startswith('third_party')
4973 or file_with_path.startswith(
4974 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144975
Sam Maiera6e76d72022-02-11 21:43:504976 def replace_special_with_underscore(string):
4977 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144978
Sam Maiera6e76d72022-02-11 21:43:504979 errors = []
Daniel Bratell8ba52722018-03-02 16:06:144980
Sam Maiera6e76d72022-02-11 21:43:504981 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
4982 guard_name = None
4983 guard_line_number = None
4984 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:144985
Sam Maiera6e76d72022-02-11 21:43:504986 file_with_path = input_api.os_path.normpath(f.LocalPath())
4987 base_file_name = input_api.os_path.splitext(
4988 input_api.os_path.basename(file_with_path))[0]
4989 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:144990
Sam Maiera6e76d72022-02-11 21:43:504991 expected_guard = replace_special_with_underscore(
4992 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144993
Sam Maiera6e76d72022-02-11 21:43:504994 # For "path/elem/file_name.h" we should really only accept
4995 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4996 # are too many (1000+) files with slight deviations from the
4997 # coding style. The most important part is that the include guard
4998 # is there, and that it's unique, not the name so this check is
4999 # forgiving for existing files.
5000 #
5001 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145002
Sam Maiera6e76d72022-02-11 21:43:505003 guard_name_pattern_list = [
5004 # Anything with the right suffix (maybe with an extra _).
5005 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145006
Sam Maiera6e76d72022-02-11 21:43:505007 # To cover include guards with old Blink style.
5008 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145009
Sam Maiera6e76d72022-02-11 21:43:505010 # Anything including the uppercase name of the file.
5011 r'\w*' + input_api.re.escape(
5012 replace_special_with_underscore(upper_base_file_name)) +
5013 r'\w*',
5014 ]
5015 guard_name_pattern = '|'.join(guard_name_pattern_list)
5016 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5017 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145018
Sam Maiera6e76d72022-02-11 21:43:505019 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365020 if ('no-include-guard-because-multiply-included' in line
5021 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505022 guard_name = 'DUMMY' # To not trigger check outside the loop.
5023 break
Daniel Bratell8ba52722018-03-02 16:06:145024
Sam Maiera6e76d72022-02-11 21:43:505025 if guard_name is None:
5026 match = guard_pattern.match(line)
5027 if match:
5028 guard_name = match.group(1)
5029 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145030
Sam Maiera6e76d72022-02-11 21:43:505031 # We allow existing files to use include guards whose names
5032 # don't match the chromium style guide, but new files should
5033 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495034 if guard_name != expected_guard:
5035 if not f.OldContents():
Sam Maiera6e76d72022-02-11 21:43:505036 errors.append(
5037 output_api.PresubmitPromptWarning(
5038 'Header using the wrong include guard name %s'
5039 % guard_name, [
5040 '%s:%d' %
5041 (f.LocalPath(), line_number + 1)
5042 ], 'Expected: %r\nFound: %r' %
5043 (expected_guard, guard_name)))
5044 else:
5045 # The line after #ifndef should have a #define of the same name.
5046 if line_number == guard_line_number + 1:
5047 expected_line = '#define %s' % guard_name
5048 if line != expected_line:
5049 errors.append(
5050 output_api.PresubmitPromptWarning(
5051 'Missing "%s" for include guard' %
5052 expected_line,
5053 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5054 'Expected: %r\nGot: %r' %
5055 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145056
Sam Maiera6e76d72022-02-11 21:43:505057 if not seen_guard_end and line == '#endif // %s' % guard_name:
5058 seen_guard_end = True
5059 elif seen_guard_end:
5060 if line.strip() != '':
5061 errors.append(
5062 output_api.PresubmitPromptWarning(
5063 'Include guard %s not covering the whole file'
5064 % (guard_name), [f.LocalPath()]))
5065 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145066
Sam Maiera6e76d72022-02-11 21:43:505067 if guard_name is None:
5068 errors.append(
5069 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495070 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505071 'Recommended name: %s\n'
5072 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365073 '"no-include-guard-because-multiply-included" or\n'
5074 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505075 % (f.LocalPath(), expected_guard)))
5076
5077 return errors
Daniel Bratell8ba52722018-03-02 16:06:145078
5079
Saagar Sanghavifceeaae2020-08-12 16:40:365080def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505081 """Check source code and known ascii text files for Windows style line
5082 endings.
5083 """
Bruce Dawson5efbdc652022-04-11 19:29:515084 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235085
Sam Maiera6e76d72022-02-11 21:43:505086 file_inclusion_pattern = (known_text_files,
5087 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5088 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235089
Sam Maiera6e76d72022-02-11 21:43:505090 problems = []
5091 source_file_filter = lambda f: input_api.FilterSourceFile(
5092 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5093 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515094 # Ignore test files that contain crlf intentionally.
5095 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345096 continue
Sam Maiera6e76d72022-02-11 21:43:505097 include_file = False
5098 for line in input_api.ReadFile(f, 'r').splitlines(True):
5099 if line.endswith('\r\n'):
5100 include_file = True
5101 if include_file:
5102 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235103
Sam Maiera6e76d72022-02-11 21:43:505104 if problems:
5105 return [
5106 output_api.PresubmitPromptWarning(
5107 'Are you sure that you want '
5108 'these files to contain Windows style line endings?\n' +
5109 '\n'.join(problems))
5110 ]
mostynbb639aca52015-01-07 20:31:235111
Sam Maiera6e76d72022-02-11 21:43:505112 return []
5113
mostynbb639aca52015-01-07 20:31:235114
Evan Stade6cfc964c12021-05-18 20:21:165115def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505116 """Check that .icon files (which are fragments of C++) have license headers.
5117 """
Evan Stade6cfc964c12021-05-18 20:21:165118
Sam Maiera6e76d72022-02-11 21:43:505119 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165120
Sam Maiera6e76d72022-02-11 21:43:505121 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5122 return input_api.canned_checks.CheckLicense(input_api,
5123 output_api,
5124 source_file_filter=icons)
5125
Evan Stade6cfc964c12021-05-18 20:21:165126
Jose Magana2b456f22021-03-09 23:26:405127def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505128 """Check source code for use of Chrome App technologies being
5129 deprecated.
5130 """
Jose Magana2b456f22021-03-09 23:26:405131
Sam Maiera6e76d72022-02-11 21:43:505132 def _CheckForDeprecatedTech(input_api,
5133 output_api,
5134 detection_list,
5135 files_to_check=None,
5136 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405137
Sam Maiera6e76d72022-02-11 21:43:505138 if (files_to_check or files_to_skip):
5139 source_file_filter = lambda f: input_api.FilterSourceFile(
5140 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5141 else:
5142 source_file_filter = None
5143
5144 problems = []
5145
5146 for f in input_api.AffectedSourceFiles(source_file_filter):
5147 if f.Action() == 'D':
5148 continue
5149 for _, line in f.ChangedContents():
5150 if any(detect in line for detect in detection_list):
5151 problems.append(f.LocalPath())
5152
5153 return problems
5154
5155 # to avoid this presubmit script triggering warnings
5156 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405157
5158 problems = []
5159
Sam Maiera6e76d72022-02-11 21:43:505160 # NMF: any files with extensions .nmf or NMF
5161 _NMF_FILES = r'\.(nmf|NMF)$'
5162 problems += _CheckForDeprecatedTech(
5163 input_api,
5164 output_api,
5165 detection_list=[''], # any change to the file will trigger warning
5166 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405167
Sam Maiera6e76d72022-02-11 21:43:505168 # MANIFEST: any manifest.json that in its diff includes "app":
5169 _MANIFEST_FILES = r'(manifest\.json)$'
5170 problems += _CheckForDeprecatedTech(
5171 input_api,
5172 output_api,
5173 detection_list=['"app":'],
5174 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405175
Sam Maiera6e76d72022-02-11 21:43:505176 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5177 problems += _CheckForDeprecatedTech(
5178 input_api,
5179 output_api,
5180 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
5181 files_to_skip=files_to_skip + [r"^native_client_sdk[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405182
Sam Maiera6e76d72022-02-11 21:43:505183 # PPAPI: any C/C++ file that in its diff includes a ppappi library
5184 problems += _CheckForDeprecatedTech(
5185 input_api,
5186 output_api,
5187 detection_list=['#include "ppapi', '#include <ppapi'],
5188 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5189 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
5190 files_to_skip=[r"^ppapi[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405191
Sam Maiera6e76d72022-02-11 21:43:505192 if problems:
5193 return [
5194 output_api.PresubmitPromptWarning(
5195 'You are adding/modifying code'
5196 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5197 ' PNaCl, PPAPI). See this blog post for more details:\n'
5198 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5199 'and this documentation for options to replace these technologies:\n'
5200 'https://developer.chrome.com/docs/apps/migration/\n' +
5201 '\n'.join(problems))
5202 ]
Jose Magana2b456f22021-03-09 23:26:405203
Sam Maiera6e76d72022-02-11 21:43:505204 return []
Jose Magana2b456f22021-03-09 23:26:405205
mostynbb639aca52015-01-07 20:31:235206
Saagar Sanghavifceeaae2020-08-12 16:40:365207def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505208 """Checks that all source files use SYSLOG properly."""
5209 syslog_files = []
5210 for f in input_api.AffectedSourceFiles(src_file_filter):
5211 for line_number, line in f.ChangedContents():
5212 if 'SYSLOG' in line:
5213 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565214
Sam Maiera6e76d72022-02-11 21:43:505215 if syslog_files:
5216 return [
5217 output_api.PresubmitPromptWarning(
5218 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5219 ' calls.\nFiles to check:\n',
5220 items=syslog_files)
5221 ]
5222 return []
pastarmovj89f7ee12016-09-20 14:58:135223
5224
[email protected]1f7b4172010-01-28 01:17:345225def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505226 if input_api.version < [2, 0, 0]:
5227 return [
5228 output_api.PresubmitError(
5229 "Your depot_tools is out of date. "
5230 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5231 "but your version is %d.%d.%d" % tuple(input_api.version))
5232 ]
5233 results = []
5234 results.extend(
5235 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5236 return results
[email protected]ca8d19842009-02-19 16:33:125237
5238
[email protected]ca8d19842009-02-19 16:33:125239def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505240 if input_api.version < [2, 0, 0]:
5241 return [
5242 output_api.PresubmitError(
5243 "Your depot_tools is out of date. "
5244 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5245 "but your version is %d.%d.%d" % tuple(input_api.version))
5246 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365247
Sam Maiera6e76d72022-02-11 21:43:505248 results = []
5249 # Make sure the tree is 'open'.
5250 results.extend(
5251 input_api.canned_checks.CheckTreeIsOpen(
5252 input_api,
5253 output_api,
5254 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275255
Sam Maiera6e76d72022-02-11 21:43:505256 results.extend(
5257 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5258 results.extend(
5259 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5260 results.extend(
5261 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5262 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505263 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145264
5265
Saagar Sanghavifceeaae2020-08-12 16:40:365266def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505267 """Check string ICU syntax validity and if translation screenshots exist."""
5268 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5269 # footer is set to true.
5270 git_footers = input_api.change.GitFootersFromDescription()
5271 skip_screenshot_check_footer = [
5272 footer.lower() for footer in git_footers.get(
5273 u'Skip-Translation-Screenshots-Check', [])
5274 ]
5275 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025276
Sam Maiera6e76d72022-02-11 21:43:505277 import os
5278 import re
5279 import sys
5280 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145281
Sam Maiera6e76d72022-02-11 21:43:505282 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5283 if (f.Action() == 'A' or f.Action() == 'M'))
5284 removed_paths = set(f.LocalPath()
5285 for f in input_api.AffectedFiles(include_deletes=True)
5286 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145287
Sam Maiera6e76d72022-02-11 21:43:505288 affected_grds = [
5289 f for f in input_api.AffectedFiles()
5290 if f.LocalPath().endswith(('.grd', '.grdp'))
5291 ]
5292 affected_grds = [
5293 f for f in affected_grds if not 'testdata' in f.LocalPath()
5294 ]
5295 if not affected_grds:
5296 return []
meacer8c0d3832019-12-26 21:46:165297
Sam Maiera6e76d72022-02-11 21:43:505298 affected_png_paths = [
5299 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5300 if (f.LocalPath().endswith('.png'))
5301 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145302
Sam Maiera6e76d72022-02-11 21:43:505303 # Check for screenshots. Developers can upload screenshots using
5304 # tools/translation/upload_screenshots.py which finds and uploads
5305 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5306 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5307 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5308 #
5309 # The logic here is as follows:
5310 #
5311 # - If the CL has a .png file under the screenshots directory for a grd
5312 # file, warn the developer. Actual images should never be checked into the
5313 # Chrome repo.
5314 #
5315 # - If the CL contains modified or new messages in grd files and doesn't
5316 # contain the corresponding .sha1 files, warn the developer to add images
5317 # and upload them via tools/translation/upload_screenshots.py.
5318 #
5319 # - If the CL contains modified or new messages in grd files and the
5320 # corresponding .sha1 files, everything looks good.
5321 #
5322 # - If the CL contains removed messages in grd files but the corresponding
5323 # .sha1 files aren't removed, warn the developer to remove them.
5324 unnecessary_screenshots = []
5325 missing_sha1 = []
5326 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145327
Sam Maiera6e76d72022-02-11 21:43:505328 # This checks verifies that the ICU syntax of messages this CL touched is
5329 # valid, and reports any found syntax errors.
5330 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5331 # without developers being aware of them. Later on, such ICU syntax errors
5332 # break message extraction for translation, hence would block Chromium
5333 # translations until they are fixed.
5334 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145335
Sam Maiera6e76d72022-02-11 21:43:505336 def _CheckScreenshotAdded(screenshots_dir, message_id):
5337 sha1_path = input_api.os_path.join(screenshots_dir,
5338 message_id + '.png.sha1')
5339 if sha1_path not in new_or_added_paths:
5340 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145341
Sam Maiera6e76d72022-02-11 21:43:505342 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5343 sha1_path = input_api.os_path.join(screenshots_dir,
5344 message_id + '.png.sha1')
5345 if input_api.os_path.exists(
5346 sha1_path) and sha1_path not in removed_paths:
5347 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145348
Sam Maiera6e76d72022-02-11 21:43:505349 def _ValidateIcuSyntax(text, level, signatures):
5350 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145351
Sam Maiera6e76d72022-02-11 21:43:505352 Check if text looks similar to ICU and checks for ICU syntax correctness
5353 in this case. Reports various issues with ICU syntax and values of
5354 variants. Supports checking of nested messages. Accumulate information of
5355 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265356
Sam Maiera6e76d72022-02-11 21:43:505357 Args:
5358 text: a string to check.
5359 level: a number of current nesting level.
5360 signatures: an accumulator, a list of tuple of (level, variable,
5361 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265362
Sam Maiera6e76d72022-02-11 21:43:505363 Returns:
5364 None if a string is not ICU or no issue detected.
5365 A tuple of (message, start index, end index) if an issue detected.
5366 """
5367 valid_types = {
5368 'plural': (frozenset(
5369 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5370 'other']), frozenset(['=1', 'other'])),
5371 'selectordinal': (frozenset(
5372 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5373 'other']), frozenset(['one', 'other'])),
5374 'select': (frozenset(), frozenset(['other'])),
5375 }
Rainhard Findlingfc31844c52020-05-15 09:58:265376
Sam Maiera6e76d72022-02-11 21:43:505377 # Check if the message looks like an attempt to use ICU
5378 # plural. If yes - check if its syntax strictly matches ICU format.
5379 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5380 text)
5381 if not like:
5382 signatures.append((level, None, None, None))
5383 return
Rainhard Findlingfc31844c52020-05-15 09:58:265384
Sam Maiera6e76d72022-02-11 21:43:505385 # Check for valid prefix and suffix
5386 m = re.match(
5387 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5388 r'(plural|selectordinal|select),\s*'
5389 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5390 if not m:
5391 return (('This message looks like an ICU plural, '
5392 'but does not follow ICU syntax.'), like.start(),
5393 like.end())
5394 starting, variable, kind, variant_pairs = m.groups()
5395 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5396 m.start(4))
5397 if depth:
5398 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5399 len(text))
5400 first = text[0]
5401 ending = text[last_pos:]
5402 if not starting:
5403 return ('Invalid ICU format. No initial opening bracket',
5404 last_pos - 1, last_pos)
5405 if not ending or '}' not in ending:
5406 return ('Invalid ICU format. No final closing bracket',
5407 last_pos - 1, last_pos)
5408 elif first != '{':
5409 return ((
5410 'Invalid ICU format. Extra characters at the start of a complex '
5411 'message (go/icu-message-migration): "%s"') % starting, 0,
5412 len(starting))
5413 elif ending != '}':
5414 return ((
5415 'Invalid ICU format. Extra characters at the end of a complex '
5416 'message (go/icu-message-migration): "%s"') % ending,
5417 last_pos - 1, len(text) - 1)
5418 if kind not in valid_types:
5419 return (('Unknown ICU message type %s. '
5420 'Valid types are: plural, select, selectordinal') % kind,
5421 0, 0)
5422 known, required = valid_types[kind]
5423 defined_variants = set()
5424 for variant, variant_range, value, value_range in variants:
5425 start, end = variant_range
5426 if variant in defined_variants:
5427 return ('Variant "%s" is defined more than once' % variant,
5428 start, end)
5429 elif known and variant not in known:
5430 return ('Variant "%s" is not valid for %s message' %
5431 (variant, kind), start, end)
5432 defined_variants.add(variant)
5433 # Check for nested structure
5434 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5435 if res:
5436 return (res[0], res[1] + value_range[0] + 1,
5437 res[2] + value_range[0] + 1)
5438 missing = required - defined_variants
5439 if missing:
5440 return ('Required variants missing: %s' % ', '.join(missing), 0,
5441 len(text))
5442 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265443
Sam Maiera6e76d72022-02-11 21:43:505444 def _ParseIcuVariants(text, offset=0):
5445 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265446
Sam Maiera6e76d72022-02-11 21:43:505447 Builds a tuple of variant names and values, as well as
5448 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265449
Sam Maiera6e76d72022-02-11 21:43:505450 Args:
5451 text: a string to parse
5452 offset: additional offset to add to positions in the text to get correct
5453 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265454
Sam Maiera6e76d72022-02-11 21:43:505455 Returns:
5456 List of tuples, each tuple consist of four fields: variant name,
5457 variant name span (tuple of two integers), variant value, value
5458 span (tuple of two integers).
5459 """
5460 depth, start, end = 0, -1, -1
5461 variants = []
5462 key = None
5463 for idx, char in enumerate(text):
5464 if char == '{':
5465 if not depth:
5466 start = idx
5467 chunk = text[end + 1:start]
5468 key = chunk.strip()
5469 pos = offset + end + 1 + chunk.find(key)
5470 span = (pos, pos + len(key))
5471 depth += 1
5472 elif char == '}':
5473 if not depth:
5474 return variants, depth, offset + idx
5475 depth -= 1
5476 if not depth:
5477 end = idx
5478 variants.append((key, span, text[start:end + 1],
5479 (offset + start, offset + end + 1)))
5480 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265481
Sam Maiera6e76d72022-02-11 21:43:505482 try:
5483 old_sys_path = sys.path
5484 sys.path = sys.path + [
5485 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5486 'translation')
5487 ]
5488 from helper import grd_helper
5489 finally:
5490 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265491
Sam Maiera6e76d72022-02-11 21:43:505492 for f in affected_grds:
5493 file_path = f.LocalPath()
5494 old_id_to_msg_map = {}
5495 new_id_to_msg_map = {}
5496 # Note that this code doesn't check if the file has been deleted. This is
5497 # OK because it only uses the old and new file contents and doesn't load
5498 # the file via its path.
5499 # It's also possible that a file's content refers to a renamed or deleted
5500 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5501 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5502 # .grdp files.
5503 if file_path.endswith('.grdp'):
5504 if f.OldContents():
5505 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5506 '\n'.join(f.OldContents()))
5507 if f.NewContents():
5508 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5509 '\n'.join(f.NewContents()))
5510 else:
5511 file_dir = input_api.os_path.dirname(file_path) or '.'
5512 if f.OldContents():
5513 old_id_to_msg_map = grd_helper.GetGrdMessages(
5514 StringIO('\n'.join(f.OldContents())), file_dir)
5515 if f.NewContents():
5516 new_id_to_msg_map = grd_helper.GetGrdMessages(
5517 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265518
Sam Maiera6e76d72022-02-11 21:43:505519 grd_name, ext = input_api.os_path.splitext(
5520 input_api.os_path.basename(file_path))
5521 screenshots_dir = input_api.os_path.join(
5522 input_api.os_path.dirname(file_path),
5523 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265524
Sam Maiera6e76d72022-02-11 21:43:505525 # Compute added, removed and modified message IDs.
5526 old_ids = set(old_id_to_msg_map)
5527 new_ids = set(new_id_to_msg_map)
5528 added_ids = new_ids - old_ids
5529 removed_ids = old_ids - new_ids
5530 modified_ids = set([])
5531 for key in old_ids.intersection(new_ids):
5532 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5533 new_id_to_msg_map[key].ContentsAsXml('', True)):
5534 # The message content itself changed. Require an updated screenshot.
5535 modified_ids.add(key)
5536 elif old_id_to_msg_map[key].attrs['meaning'] != \
5537 new_id_to_msg_map[key].attrs['meaning']:
5538 # The message meaning changed. Ensure there is a screenshot for it.
5539 sha1_path = input_api.os_path.join(screenshots_dir,
5540 key + '.png.sha1')
5541 if sha1_path not in new_or_added_paths and not \
5542 input_api.os_path.exists(sha1_path):
5543 # There is neither a previous screenshot nor is a new one added now.
5544 # Require a screenshot.
5545 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145546
Sam Maiera6e76d72022-02-11 21:43:505547 if run_screenshot_check:
5548 # Check the screenshot directory for .png files. Warn if there is any.
5549 for png_path in affected_png_paths:
5550 if png_path.startswith(screenshots_dir):
5551 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145552
Sam Maiera6e76d72022-02-11 21:43:505553 for added_id in added_ids:
5554 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095555
Sam Maiera6e76d72022-02-11 21:43:505556 for modified_id in modified_ids:
5557 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145558
Sam Maiera6e76d72022-02-11 21:43:505559 for removed_id in removed_ids:
5560 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5561
5562 # Check new and changed strings for ICU syntax errors.
5563 for key in added_ids.union(modified_ids):
5564 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5565 err = _ValidateIcuSyntax(msg, 0, [])
5566 if err is not None:
5567 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5568
5569 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265570 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505571 if unnecessary_screenshots:
5572 results.append(
5573 output_api.PresubmitError(
5574 'Do not include actual screenshots in the changelist. Run '
5575 'tools/translate/upload_screenshots.py to upload them instead:',
5576 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145577
Sam Maiera6e76d72022-02-11 21:43:505578 if missing_sha1:
5579 results.append(
5580 output_api.PresubmitError(
5581 'You are adding or modifying UI strings.\n'
5582 'To ensure the best translations, take screenshots of the relevant UI '
5583 '(https://g.co/chrome/translation) and add these files to your '
5584 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145585
Sam Maiera6e76d72022-02-11 21:43:505586 if unnecessary_sha1_files:
5587 results.append(
5588 output_api.PresubmitError(
5589 'You removed strings associated with these files. Remove:',
5590 sorted(unnecessary_sha1_files)))
5591 else:
5592 results.append(
5593 output_api.PresubmitPromptOrNotify('Skipping translation '
5594 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145595
Sam Maiera6e76d72022-02-11 21:43:505596 if icu_syntax_errors:
5597 results.append(
5598 output_api.PresubmitPromptWarning(
5599 'ICU syntax errors were found in the following strings (problems or '
5600 'feedback? Contact [email protected]):',
5601 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265602
Sam Maiera6e76d72022-02-11 21:43:505603 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125604
5605
Saagar Sanghavifceeaae2020-08-12 16:40:365606def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125607 repo_root=None,
5608 translation_expectations_path=None,
5609 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505610 import sys
5611 affected_grds = [
5612 f for f in input_api.AffectedFiles()
5613 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5614 ]
5615 if not affected_grds:
5616 return []
5617
5618 try:
5619 old_sys_path = sys.path
5620 sys.path = sys.path + [
5621 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5622 'translation')
5623 ]
5624 from helper import git_helper
5625 from helper import translation_helper
5626 finally:
5627 sys.path = old_sys_path
5628
5629 # Check that translation expectations can be parsed and we can get a list of
5630 # translatable grd files. |repo_root| and |translation_expectations_path| are
5631 # only passed by tests.
5632 if not repo_root:
5633 repo_root = input_api.PresubmitLocalPath()
5634 if not translation_expectations_path:
5635 translation_expectations_path = input_api.os_path.join(
5636 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5637 if not grd_files:
5638 grd_files = git_helper.list_grds_in_repository(repo_root)
5639
5640 # Ignore bogus grd files used only for testing
5641 # ui/webui/resoucres/tools/generate_grd.py.
5642 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
5643 'tests')
5644 grd_files = [p for p in grd_files if ignore_path not in p]
5645
5646 try:
5647 translation_helper.get_translatable_grds(
5648 repo_root, grd_files, translation_expectations_path)
5649 except Exception as e:
5650 return [
5651 output_api.PresubmitNotifyResult(
5652 'Failed to get a list of translatable grd files. This happens when:\n'
5653 ' - One of the modified grd or grdp files cannot be parsed or\n'
5654 ' - %s is not updated.\n'
5655 'Stack:\n%s' % (translation_expectations_path, str(e)))
5656 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:125657 return []
5658
Ken Rockotc31f4832020-05-29 18:58:515659
Saagar Sanghavifceeaae2020-08-12 16:40:365660def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505661 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5662 changed_mojoms = input_api.AffectedFiles(
5663 include_deletes=True,
5664 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525665
Bruce Dawson344ab262022-06-04 11:35:105666 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:505667 return []
5668
5669 delta = []
5670 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:505671 delta.append({
5672 'filename': mojom.LocalPath(),
5673 'old': '\n'.join(mojom.OldContents()) or None,
5674 'new': '\n'.join(mojom.NewContents()) or None,
5675 })
5676
5677 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:215678 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:505679 input_api.os_path.join(
5680 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
5681 'check_stable_mojom_compatibility.py'), '--src-root',
5682 input_api.PresubmitLocalPath()
5683 ],
5684 stdin=input_api.subprocess.PIPE,
5685 stdout=input_api.subprocess.PIPE,
5686 stderr=input_api.subprocess.PIPE,
5687 universal_newlines=True)
5688 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5689 if process.returncode:
5690 return [
5691 output_api.PresubmitError(
5692 'One or more [Stable] mojom definitions appears to have been changed '
5693 'in a way that is not backward-compatible.',
5694 long_text=error)
5695 ]
Erik Staabc734cd7a2021-11-23 03:11:525696 return []
5697
Dominic Battre645d42342020-12-04 16:14:105698def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505699 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:105700
Sam Maiera6e76d72022-02-11 21:43:505701 def FilterFile(affected_file):
5702 """Accept only .cc files and the like."""
5703 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5704 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5705 input_api.DEFAULT_FILES_TO_SKIP)
5706 return input_api.FilterSourceFile(
5707 affected_file,
5708 files_to_check=file_inclusion_pattern,
5709 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:105710
Sam Maiera6e76d72022-02-11 21:43:505711 def ModifiedLines(affected_file):
5712 """Returns a list of tuples (line number, line text) of added and removed
5713 lines.
Dominic Battre645d42342020-12-04 16:14:105714
Sam Maiera6e76d72022-02-11 21:43:505715 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:105716
Sam Maiera6e76d72022-02-11 21:43:505717 This relies on the scm diff output describing each changed code section
5718 with a line of the form
Dominic Battre645d42342020-12-04 16:14:105719
Sam Maiera6e76d72022-02-11 21:43:505720 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5721 """
5722 line_num = 0
5723 modified_lines = []
5724 for line in affected_file.GenerateScmDiff().splitlines():
5725 # Extract <new line num> of the patch fragment (see format above).
5726 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
5727 line)
5728 if m:
5729 line_num = int(m.groups(1)[0])
5730 continue
5731 if ((line.startswith('+') and not line.startswith('++'))
5732 or (line.startswith('-') and not line.startswith('--'))):
5733 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:105734
Sam Maiera6e76d72022-02-11 21:43:505735 if not line.startswith('-'):
5736 line_num += 1
5737 return modified_lines
Dominic Battre645d42342020-12-04 16:14:105738
Sam Maiera6e76d72022-02-11 21:43:505739 def FindLineWith(lines, needle):
5740 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:105741
Sam Maiera6e76d72022-02-11 21:43:505742 If 0 or >1 lines contain `needle`, -1 is returned.
5743 """
5744 matching_line_numbers = [
5745 # + 1 for 1-based counting of line numbers.
5746 i + 1 for i, line in enumerate(lines) if needle in line
5747 ]
5748 return matching_line_numbers[0] if len(
5749 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:105750
Sam Maiera6e76d72022-02-11 21:43:505751 def ModifiedPrefMigration(affected_file):
5752 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5753 # Determine first and last lines of MigrateObsolete.*Pref functions.
5754 new_contents = affected_file.NewContents()
5755 range_1 = (FindLineWith(new_contents,
5756 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5757 FindLineWith(new_contents,
5758 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5759 range_2 = (FindLineWith(new_contents,
5760 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5761 FindLineWith(new_contents,
5762 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5763 if (-1 in range_1 + range_2):
5764 raise Exception(
5765 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
5766 )
Dominic Battre645d42342020-12-04 16:14:105767
Sam Maiera6e76d72022-02-11 21:43:505768 # Check whether any of the modified lines are part of the
5769 # MigrateObsolete.*Pref functions.
5770 for line_nr, line in ModifiedLines(affected_file):
5771 if (range_1[0] <= line_nr <= range_1[1]
5772 or range_2[0] <= line_nr <= range_2[1]):
5773 return True
5774 return False
Dominic Battre645d42342020-12-04 16:14:105775
Sam Maiera6e76d72022-02-11 21:43:505776 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5777 browser_prefs_file_pattern = input_api.re.compile(
5778 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:105779
Sam Maiera6e76d72022-02-11 21:43:505780 changes = input_api.AffectedFiles(include_deletes=True,
5781 file_filter=FilterFile)
5782 potential_problems = []
5783 for f in changes:
5784 for line in f.GenerateScmDiff().splitlines():
5785 # Check deleted lines for pref registrations.
5786 if (line.startswith('-') and not line.startswith('--')
5787 and register_pref_pattern.search(line)):
5788 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:105789
Sam Maiera6e76d72022-02-11 21:43:505790 if browser_prefs_file_pattern.search(f.LocalPath()):
5791 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5792 # assume that they knew that they have to deprecate preferences and don't
5793 # warn.
5794 try:
5795 if ModifiedPrefMigration(f):
5796 return []
5797 except Exception as e:
5798 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:105799
Sam Maiera6e76d72022-02-11 21:43:505800 if potential_problems:
5801 return [
5802 output_api.PresubmitPromptWarning(
5803 'Discovered possible removal of preference registrations.\n\n'
5804 'Please make sure to properly deprecate preferences by clearing their\n'
5805 'value for a couple of milestones before finally removing the code.\n'
5806 'Otherwise data may stay in the preferences files forever. See\n'
5807 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5808 'chrome/browser/prefs/README.md for examples.\n'
5809 'This may be a false positive warning (e.g. if you move preference\n'
5810 'registrations to a different place).\n', potential_problems)
5811 ]
5812 return []
5813
Matt Stark6ef08872021-07-29 01:21:465814
5815def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505816 """Changes to GRD files must be consistent for tools to read them."""
5817 changed_grds = input_api.AffectedFiles(
5818 include_deletes=False,
5819 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5820 errors = []
5821 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5822 for matcher, msg in _INVALID_GRD_FILE_LINE]
5823 for grd in changed_grds:
5824 for i, line in enumerate(grd.NewContents()):
5825 for matcher, msg in invalid_file_regexes:
5826 if matcher.search(line):
5827 errors.append(
5828 output_api.PresubmitError(
5829 'Problem on {grd}:{i} - {msg}'.format(
5830 grd=grd.LocalPath(), i=i + 1, msg=msg)))
5831 return errors
5832
Kevin McNee967dd2d22021-11-15 16:09:295833
5834def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505835 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5836 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5837 """
Kevin McNee967dd2d22021-11-15 16:09:295838
Ian Vollickdba956c2022-04-20 23:53:455839 # Only consider top-level directories that (1) can use content APIs or
5840 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
5841 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:505842 files_to_check = (
Ian Vollickdba956c2022-04-20 23:53:455843 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Kevin McNee967dd2d22021-11-15 16:09:295844 _IMPLEMENTATION_EXTENSIONS,
Ian Vollickdba956c2022-04-20 23:53:455845 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Sam Maiera6e76d72022-02-11 21:43:505846 _HEADER_EXTENSIONS,
5847 )
5848 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5849 input_api.DEFAULT_FILES_TO_SKIP)
5850 source_file_filter = lambda f: input_api.FilterSourceFile(
5851 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:295852
Sam Maiera6e76d72022-02-11 21:43:505853 # Note that since these are are just regular expressions and we don't have
5854 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5855 # could have a method named IsInMainFrame).
5856 concerning_class_pattern = input_api.re.compile(
5857 r'WebContentsObserver|WebContentsUserData')
5858 # A subset of WebContentsObserver overrides where there's particular risk for
5859 # confusing tab and page level operations and data (e.g. incorrectly
5860 # resetting page state in DidFinishNavigation).
5861 concerning_wco_methods = [
5862 'DidStartNavigation',
5863 'ReadyToCommitNavigation',
5864 'DidFinishNavigation',
5865 'RenderViewReady',
5866 'RenderViewDeleted',
5867 'RenderViewHostChanged',
5868 'PrimaryMainDocumentElementAvailable',
5869 'DocumentOnLoadCompletedInPrimaryMainFrame',
5870 'DOMContentLoaded',
5871 'DidFinishLoad',
5872 ]
5873 concerning_nav_handle_methods = [
5874 'IsInMainFrame',
5875 ]
5876 concerning_web_contents_methods = [
5877 'ForEachFrame',
5878 'GetAllFrames',
5879 'FromRenderFrameHost',
5880 'FromRenderViewHost',
5881 'GetMainFrame',
5882 'GetRenderViewHost',
5883 ]
5884 concerning_rfh_methods = [
5885 'GetParent',
5886 'GetMainFrame',
5887 'GetFrameTreeNodeId',
5888 ]
Ian Vollickc825b1f2022-04-19 14:30:155889 concerning_rfhi_methods = [
5890 'is_main_frame',
5891 ]
Ian Vollicka77a73ea2022-04-06 18:08:015892 concerning_ftn_methods = [
5893 'IsMainFrame',
5894 ]
Ian Vollickdba956c2022-04-20 23:53:455895 concerning_blink_frame_methods = [
Ian Vollick4d785d22022-06-18 00:10:025896 'IsCrossOriginToNearestMainFrame',
Ian Vollickdba956c2022-04-20 23:53:455897 ]
Sam Maiera6e76d72022-02-11 21:43:505898 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5899 item for sublist in [
5900 concerning_wco_methods, concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:015901 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:155902 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:455903 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:505904 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:295905
Kevin McNee4eeec792022-02-14 20:02:045906 used_apis = set()
Sam Maiera6e76d72022-02-11 21:43:505907 for f in input_api.AffectedFiles(include_deletes=False,
5908 file_filter=source_file_filter):
5909 for line_num, line in f.ChangedContents():
Kevin McNee4eeec792022-02-14 20:02:045910 class_match = concerning_class_pattern.search(line)
5911 if class_match:
5912 used_apis.add(class_match[0])
5913 method_match = concerning_method_pattern.search(line)
5914 if method_match:
5915 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:505916
Kevin McNee4eeec792022-02-14 20:02:045917 if not used_apis:
5918 return []
Kevin McNee967dd2d22021-11-15 16:09:295919
Kevin McNee4eeec792022-02-14 20:02:045920 output_api.AppendCC('[email protected]')
5921 message = ('This change uses API(s) that are ambiguous in the presence of '
5922 'MPArch features such as bfcache, prerendering, and fenced '
5923 'frames.')
5924 explaination = (
5925 'Please double check whether new code assumes that a WebContents only '
5926 'contains a single page at a time. For example, it is discouraged to '
5927 'reset per-document state in response to the observation of a '
5928 'navigation. See this doc [1] and the comments on the individual APIs '
5929 'for guidance and this doc [2] for context. The MPArch review '
5930 'watchlist has been CC\'d on this change to help identify any issues.\n'
5931 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
5932 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
5933 )
5934 return [
5935 output_api.PresubmitNotifyResult(message,
5936 items=list(used_apis),
5937 long_text=explaination)
5938 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:365939
5940
5941def CheckAssertAshOnlyCode(input_api, output_api):
5942 """Errors if a BUILD.gn file in an ash/ directory doesn't include
5943 assert(is_chromeos_ash).
5944 """
5945
5946 def FileFilter(affected_file):
5947 """Includes directories known to be Ash only."""
5948 return input_api.FilterSourceFile(
5949 affected_file,
5950 files_to_check=(
5951 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
5952 r'.*/ash/.*BUILD\.gn'), # Any path component.
5953 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
5954
5955 errors = []
5956 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:565957 for f in input_api.AffectedFiles(include_deletes=False,
5958 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:365959 if (not pattern.search(input_api.ReadFile(f))):
5960 errors.append(
5961 output_api.PresubmitError(
5962 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
5963 'possible, please create and issue and add a comment such '
5964 'as:\n # TODO(https://crbug.com/XXX): add '
5965 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
5966 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:275967
5968
5969def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:505970 path = affected_file.LocalPath()
5971 if not _IsCPlusPlusFile(input_api, path):
5972 return False
5973
5974 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
5975 if "/renderer/" in path:
5976 return True
5977
5978 # Blink's public/web API is only used/included by Renderer-only code. Note
5979 # that public/platform API may be used in non-Renderer processes (e.g. there
5980 # are some includes in code used by Utility, PDF, or Plugin processes).
5981 if "/blink/public/web/" in path:
5982 return True
5983
5984 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:275985 return False
5986
Lukasz Anforowicz7016d05e2021-11-30 03:56:275987# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
5988# by the Chromium Clang Plugin (which will be preferable because it will
5989# 1) report errors earlier - at compile-time and 2) cover more rules).
5990def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505991 """Rough checks that raw_ptr<T> usage guidelines are followed."""
5992 errors = []
5993 # The regex below matches "raw_ptr<" following a word boundary, but not in a
5994 # C++ comment.
5995 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
5996 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
5997 for f, line_num, line in input_api.RightHandSideLines(file_filter):
5998 if raw_ptr_matcher.search(line):
5999 errors.append(
6000 output_api.PresubmitError(
6001 'Problem on {path}:{line} - '\
6002 'raw_ptr<T> should not be used in Renderer-only code '\
6003 '(as documented in the "Pointers to unprotected memory" '\
6004 'section in //base/memory/raw_ptr.md)'.format(
6005 path=f.LocalPath(), line=line_num)))
6006 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566007
6008
6009def CheckPythonShebang(input_api, output_api):
6010 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6011 system-wide python.
6012 """
6013 errors = []
6014 sources = lambda affected_file: input_api.FilterSourceFile(
6015 affected_file,
6016 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6017 r'third_party/blink/web_tests/external/') + input_api.
6018 DEFAULT_FILES_TO_SKIP),
6019 files_to_check=[r'.*\.py$'])
6020 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276021 for line_num, line in f.ChangedContents():
6022 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6023 errors.append(f.LocalPath())
6024 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566025
6026 result = []
6027 for file in errors:
6028 result.append(
6029 output_api.PresubmitError(
6030 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6031 file))
6032 return result
James Shen81cc0e22022-06-15 21:10:456033
6034
6035def CheckBatchAnnotation(input_api, output_api):
6036 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6037 is not an instrumentation test, disregard."""
6038
6039 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6040 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6041 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6042 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6043 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6044
ckitagawae8fd23b2022-06-17 15:29:386045 missing_annotation_errors = []
6046 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456047
6048 def _FilterFile(affected_file):
6049 return input_api.FilterSourceFile(
6050 affected_file,
6051 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6052 files_to_check=[r'.*Test\.java$'])
6053
6054 for f in input_api.AffectedSourceFiles(_FilterFile):
6055 batch_matched = None
6056 do_not_batch_matched = None
6057 is_instrumentation_test = True
6058 for line in f.NewContents():
6059 if robolectric_test.search(line) or uiautomator_test.search(line):
6060 # Skip Robolectric and UiAutomator tests.
6061 is_instrumentation_test = False
6062 break
6063 if not batch_matched:
6064 batch_matched = batch_annotation.search(line)
6065 if not do_not_batch_matched:
6066 do_not_batch_matched = do_not_batch_annotation.search(line)
6067 test_class_declaration_matched = test_class_declaration.search(
6068 line)
6069 if test_class_declaration_matched:
6070 break
6071 if (is_instrumentation_test and
6072 not batch_matched and
6073 not do_not_batch_matched):
ckitagawae8fd23b2022-06-17 15:29:386074 missing_annotation_errors.append(str(f.LocalPath()))
6075 if (not is_instrumentation_test and
6076 (batch_matched or
6077 do_not_batch_matched)):
6078 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456079
6080 results = []
6081
ckitagawae8fd23b2022-06-17 15:29:386082 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456083 results.append(
6084 output_api.PresubmitPromptWarning(
6085 """
6086Instrumentation tests should use either @Batch or @DoNotBatch. If tests are not
6087safe to run in batch, please use @DoNotBatch with reasons.
ckitagawae8fd23b2022-06-17 15:29:386088""", missing_annotation_errors))
6089 if extra_annotation_errors:
6090 results.append(
6091 output_api.PresubmitPromptWarning(
6092 """
6093Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6094""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456095
6096 return results