blob: 6c4cbfaf122c541bea2103f66d4a2892e7a84e32 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
14from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1217
Dirk Prankee3c9c62d2021-05-18 18:35:5918# This line is 'magic' in that git-cl looks for it to decide whether to
19# use Python3 instead of Python2 when running the code in this file.
20USE_PYTHON3 = True
21
[email protected]379e7dd2010-01-28 17:39:2122_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1823 # Generated file
Bruce 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]ca8d1982009-02-19 16:33:1254
John Abd-El-Malek759fea62021-03-13 03:41:1455_EXCLUDED_SET_NO_PARENT_PATHS = (
56 # It's for historical reasons that blink isn't a top level directory, where
57 # it would be allowed to have "set noparent" to avoid top level owners
58 # accidentally +1ing changes.
59 'third_party/blink/OWNERS',
60)
61
wnwenbdc444e2016-05-25 13:44:1562
[email protected]06e6d0ff2012-12-11 01:36:4463# Fragment of a regular expression that matches C++ and Objective-C++
64# implementation files.
65_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
66
wnwenbdc444e2016-05-25 13:44:1567
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1968# Fragment of a regular expression that matches C++ and Objective-C++
69# header files.
70_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
71
72
Aleksey Khoroshilov9b28c032022-06-03 16:35:3273# Paths with sources that don't use //base.
74_NON_BASE_DEPENDENT_PATHS = (
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]ca8d1982009-02-19 16:33:12109
Daniel Bratell609102be2019-03-27 20:53:21110_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15111
[email protected]eea609a2011-11-18 13:10:12112_TEST_ONLY_WARNING = (
113 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55114 'production code. If you are doing this from inside another method\n'
115 'named as *ForTesting(), then consider exposing things to have tests\n'
116 'make that same call directly.\n'
117 'If that is not possible, you may put a comment on the same line with\n'
118 ' // IN-TEST \n'
119 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
120 'method and can be ignored. Do not do this inside production code.\n'
121 'The android-binary-size trybot will block if the method exists in the\n'
122 'release apk.')
[email protected]eea609a2011-11-18 13:10:12123
124
Daniel Chenga44a1bcd2022-03-15 20:00:15125@dataclass
126class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34127 # String pattern. If the pattern begins with a slash, the pattern will be
128 # treated as a regular expression instead.
129 pattern: str
130 # Explanation as a sequence of strings. Each string in the sequence will be
131 # printed on its own line.
132 explanation: Sequence[str]
133 # Whether or not to treat this ban as a fatal error. If unspecified,
134 # defaults to true.
135 treat_as_error: Optional[bool] = None
136 # Paths that should be excluded from the ban check. Each string is a regular
137 # expression that will be matched against the path of the file being checked
138 # relative to the root of the source tree.
139 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28140
Daniel Chenga44a1bcd2022-03-15 20:00:15141
Daniel Cheng917ce542022-03-15 20:46:57142_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15143 BanRule(
144 'import java.net.URI;',
145 (
146 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
147 ),
148 excluded_paths=(
149 (r'net/android/javatests/src/org/chromium/net/'
150 'AndroidProxySelectorTest\.java'),
151 r'components/cronet/',
152 r'third_party/robolectric/local/',
153 ),
Michael Thiessen44457642020-02-06 00:24:15154 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15155 BanRule(
156 'import android.annotation.TargetApi;',
157 (
158 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
159 'RequiresApi ensures that any calls are guarded by the appropriate '
160 'SDK_INT check. See https://crbug.com/1116486.',
161 ),
162 ),
163 BanRule(
164 'import android.support.test.rule.UiThreadTestRule;',
165 (
166 'Do not use UiThreadTestRule, just use '
167 '@org.chromium.base.test.UiThreadTest on test methods that should run '
168 'on the UI thread. See https://crbug.com/1111893.',
169 ),
170 ),
171 BanRule(
172 'import android.support.test.annotation.UiThreadTest;',
173 ('Do not use android.support.test.annotation.UiThreadTest, use '
174 'org.chromium.base.test.UiThreadTest instead. See '
175 'https://crbug.com/1111893.',
176 ),
177 ),
178 BanRule(
179 'import android.support.test.rule.ActivityTestRule;',
180 (
181 'Do not use ActivityTestRule, use '
182 'org.chromium.base.test.BaseActivityTestRule instead.',
183 ),
184 excluded_paths=(
185 'components/cronet/',
186 ),
187 ),
188)
wnwenbdc444e2016-05-25 13:44:15189
Daniel Cheng917ce542022-03-15 20:46:57190_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15191 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41192 'StrictMode.allowThreadDiskReads()',
193 (
194 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
195 'directly.',
196 ),
197 False,
198 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15199 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41200 'StrictMode.allowThreadDiskWrites()',
201 (
202 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
203 'directly.',
204 ),
205 False,
206 ),
Daniel Cheng917ce542022-03-15 20:46:57207 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36208 '.waitForIdleSync()',
209 (
210 'Do not use waitForIdleSync as it masks underlying issues. There is '
211 'almost always something else you should wait on instead.',
212 ),
213 False,
214 ),
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 Wang00efc7c2021-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 Gans3b875422022-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 ),
Daniel Cheng2248b332022-07-27 06:16:591052 BanRule(
1053 r'/\babsl::FunctionRef\b',
1054 (
1055 'absl::FunctionRef is banned. Use base::FunctionRef instead.',
1056 ),
Daniel Cheng4dd164d2022-07-27 17:39:001057 True,
Daniel Cheng2248b332022-07-27 06:16:591058 [
1059 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
1060 # interoperability.
1061 r'^base[\\/]bind_internal\.h',
1062 # base::FunctionRef is implemented on top of absl::FunctionRef.
1063 r'^base[\\/]functional[\\/]function_ref.*\..+',
1064 # Not an error in third_party folders.
1065 _THIRD_PARTY_EXCEPT_BLINK,
1066 ],
1067 ),
[email protected]127f18ec2012-06-16 05:05:591068)
1069
Daniel Cheng92c15e32022-03-16 17:48:221070_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1071 BanRule(
1072 'handle<shared_buffer>',
1073 (
1074 'Please use one of the more specific shared memory types instead:',
1075 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1076 ' mojo_base.mojom.WritableSharedMemoryRegion',
1077 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1078 ),
1079 True,
1080 ),
1081)
1082
mlamouria82272622014-09-16 18:45:041083_IPC_ENUM_TRAITS_DEPRECATED = (
1084 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501085 'See http://www.chromium.org/Home/chromium-security/education/'
1086 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041087
Stephen Martinis97a394142018-06-07 23:06:051088_LONG_PATH_ERROR = (
1089 'Some files included in this CL have file names that are too long (> 200'
1090 ' characters). If committed, these files will cause issues on Windows. See'
1091 ' https://crbug.com/612667 for more details.'
1092)
1093
Shenghua Zhangbfaa38b82017-11-16 21:58:021094_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041095 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041096 r".*[\\/]BuildHooksAndroidImpl\.java",
1097 r".*[\\/]LicenseContentProvider\.java",
1098 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281099 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021100]
[email protected]127f18ec2012-06-16 05:05:591101
Mohamed Heikald048240a2019-11-12 16:57:371102# List of image extensions that are used as resources in chromium.
1103_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1104
Sean Kau46e29bc2017-08-28 16:31:161105# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401106_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041107 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401108 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041109 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1110 r'^third_party[\\/]protobuf[\\/]',
Bruce Dawson49a3db522022-05-05 23:54:331111 r'^third_party[\\/]blink[\\/]perf_tests[\\/]speedometer[\\/]resources[\\/]todomvc[\\/]learn.json',
Egor Paskoce145c42018-09-28 19:31:041112 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431113 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
John Chen288dee02022-04-28 17:37:061114 r'^tools[\\/]perf[\\/]',
Bruce Dawson49a3db522022-05-05 23:54:331115 r'^tools[\\/]traceline[\\/]svgui[\\/]startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311116 # vscode configuration files allow comments
1117 r'^tools[\\/]vscode[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161118]
1119
Andrew Grieveb773bad2020-06-05 18:00:381120# These are not checked on the public chromium-presubmit trybot.
1121# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041122# checkouts.
agrievef32bcc72016-04-04 14:57:401123_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381124 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381125]
1126
1127
1128_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101129 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041130 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361131 'base/android/jni_generator/jni_generator.pydeps',
1132 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361133 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041134 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361135 'build/android/gyp/aar.pydeps',
1136 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271137 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361138 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381139 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361140 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021141 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221142 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111143 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361144 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361145 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361146 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111147 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041148 'build/android/gyp/create_app_bundle_apks.pydeps',
1149 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361150 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121151 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091152 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221153 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401154 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001155 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361156 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421157 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041158 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361159 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361160 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211161 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361162 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361163 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361164 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581165 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361166 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141167 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261168 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471169 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041170 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361171 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361172 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101173 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361174 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221175 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361176 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221177 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101178 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461179 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301180 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241181 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361182 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461183 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561184 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361185 'build/android/incremental_install/generate_android_manifest.pydeps',
1186 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321187 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041188 'build/android/resource_sizes.pydeps',
1189 'build/android/test_runner.pydeps',
1190 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361191 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361192 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321193 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271194 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1195 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041196 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001197 'components/cronet/tools/generate_javadoc.pydeps',
1198 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381199 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001200 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381201 'net/tools/testserver/testserver.pydeps',
Jonathan Lee10c06dea2022-05-02 23:13:321202 'testing/scripts/run_wpt_tests.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181203 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411204 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1205 'testing/merge_scripts/standard_gtest_merge.pydeps',
1206 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1207 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041208 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421209 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1210 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131211 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501212 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411213 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1214 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061215 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221216 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451217 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401218]
1219
wnwenbdc444e2016-05-25 13:44:151220
agrievef32bcc72016-04-04 14:57:401221_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1222
1223
Eric Boren6fd2b932018-01-25 15:05:081224# Bypass the AUTHORS check for these accounts.
1225_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591226 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451227 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591228 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521229 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231230 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471231 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461232 'infra-try-recipes-tester', 'lacros-tracking-roller',
1233 'lacros-sdk-version-roller')
Eric Boren835d71f2018-09-07 21:09:041234 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271235 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041236 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161237 for s in ('chromium-internal-autoroll',)
1238 ) | set('%[email protected]' % s
1239 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081240
Matt Stark6ef08872021-07-29 01:21:461241_INVALID_GRD_FILE_LINE = [
1242 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1243]
Eric Boren6fd2b932018-01-25 15:05:081244
Daniel Bratell65b033262019-04-23 08:17:061245def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501246 """Returns True if this file contains C++-like code (and not Python,
1247 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061248
Sam Maiera6e76d72022-02-11 21:43:501249 ext = input_api.os_path.splitext(file_path)[1]
1250 # This list is compatible with CppChecker.IsCppFile but we should
1251 # consider adding ".c" to it. If we do that we can use this function
1252 # at more places in the code.
1253 return ext in (
1254 '.h',
1255 '.cc',
1256 '.cpp',
1257 '.m',
1258 '.mm',
1259 )
1260
Daniel Bratell65b033262019-04-23 08:17:061261
1262def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501263 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061264
1265
1266def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501267 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061268
1269
1270def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501271 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061272
Mohamed Heikal5e5b7922020-10-29 18:57:591273
Erik Staabc734cd7a2021-11-23 03:11:521274def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501275 ext = input_api.os_path.splitext(file_path)[1]
1276 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521277
1278
Mohamed Heikal5e5b7922020-10-29 18:57:591279def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501280 """Prevent additions of dependencies from the upstream repo on //clank."""
1281 # clank can depend on clank
1282 if input_api.change.RepositoryRoot().endswith('clank'):
1283 return []
1284 build_file_patterns = [
1285 r'(.+/)?BUILD\.gn',
1286 r'.+\.gni',
1287 ]
1288 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1289 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591290
Sam Maiera6e76d72022-02-11 21:43:501291 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591292
Sam Maiera6e76d72022-02-11 21:43:501293 def FilterFile(affected_file):
1294 return input_api.FilterSourceFile(affected_file,
1295 files_to_check=build_file_patterns,
1296 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591297
Sam Maiera6e76d72022-02-11 21:43:501298 problems = []
1299 for f in input_api.AffectedSourceFiles(FilterFile):
1300 local_path = f.LocalPath()
1301 for line_number, line in f.ChangedContents():
1302 if (bad_pattern.search(line)):
1303 problems.append('%s:%d\n %s' %
1304 (local_path, line_number, line.strip()))
1305 if problems:
1306 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1307 else:
1308 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591309
1310
Saagar Sanghavifceeaae2020-08-12 16:40:361311def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501312 """Attempts to prevent use of functions intended only for testing in
1313 non-testing code. For now this is just a best-effort implementation
1314 that ignores header files and may have some false positives. A
1315 better implementation would probably need a proper C++ parser.
1316 """
1317 # We only scan .cc files and the like, as the declaration of
1318 # for-testing functions in header files are hard to distinguish from
1319 # calls to such functions without a proper C++ parser.
1320 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191321
Sam Maiera6e76d72022-02-11 21:43:501322 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1323 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1324 base_function_pattern)
1325 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1326 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1327 exclusion_pattern = input_api.re.compile(
1328 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1329 (base_function_pattern, base_function_pattern))
1330 # Avoid a false positive in this case, where the method name, the ::, and
1331 # the closing { are all on different lines due to line wrapping.
1332 # HelperClassForTesting::
1333 # HelperClassForTesting(
1334 # args)
1335 # : member(0) {}
1336 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191337
Sam Maiera6e76d72022-02-11 21:43:501338 def FilterFile(affected_file):
1339 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1340 input_api.DEFAULT_FILES_TO_SKIP)
1341 return input_api.FilterSourceFile(
1342 affected_file,
1343 files_to_check=file_inclusion_pattern,
1344 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191345
Sam Maiera6e76d72022-02-11 21:43:501346 problems = []
1347 for f in input_api.AffectedSourceFiles(FilterFile):
1348 local_path = f.LocalPath()
1349 in_method_defn = False
1350 for line_number, line in f.ChangedContents():
1351 if (inclusion_pattern.search(line)
1352 and not comment_pattern.search(line)
1353 and not exclusion_pattern.search(line)
1354 and not allowlist_pattern.search(line)
1355 and not in_method_defn):
1356 problems.append('%s:%d\n %s' %
1357 (local_path, line_number, line.strip()))
1358 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191359
Sam Maiera6e76d72022-02-11 21:43:501360 if problems:
1361 return [
1362 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1363 ]
1364 else:
1365 return []
[email protected]55459852011-08-10 15:17:191366
1367
Saagar Sanghavifceeaae2020-08-12 16:40:361368def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501369 """This is a simplified version of
1370 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1371 """
1372 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1373 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1374 name_pattern = r'ForTest(s|ing)?'
1375 # Describes an occurrence of "ForTest*" inside a // comment.
1376 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1377 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1378 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1379 # Catch calls.
1380 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1381 # Ignore definitions. (Comments are ignored separately.)
1382 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231383
Sam Maiera6e76d72022-02-11 21:43:501384 problems = []
1385 sources = lambda x: input_api.FilterSourceFile(
1386 x,
1387 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1388 DEFAULT_FILES_TO_SKIP),
1389 files_to_check=[r'.*\.java$'])
1390 for f in input_api.AffectedFiles(include_deletes=False,
1391 file_filter=sources):
1392 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231393 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501394 for line_number, line in f.ChangedContents():
1395 if is_inside_javadoc and javadoc_end_re.search(line):
1396 is_inside_javadoc = False
1397 if not is_inside_javadoc and javadoc_start_re.search(line):
1398 is_inside_javadoc = True
1399 if is_inside_javadoc:
1400 continue
1401 if (inclusion_re.search(line) and not comment_re.search(line)
1402 and not annotation_re.search(line)
1403 and not exclusion_re.search(line)):
1404 problems.append('%s:%d\n %s' %
1405 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231406
Sam Maiera6e76d72022-02-11 21:43:501407 if problems:
1408 return [
1409 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1410 ]
1411 else:
1412 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231413
1414
Saagar Sanghavifceeaae2020-08-12 16:40:361415def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501416 """Checks to make sure no .h files include <iostream>."""
1417 files = []
1418 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1419 input_api.re.MULTILINE)
1420 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1421 if not f.LocalPath().endswith('.h'):
1422 continue
1423 contents = input_api.ReadFile(f)
1424 if pattern.search(contents):
1425 files.append(f)
[email protected]10689ca2011-09-02 02:31:541426
Sam Maiera6e76d72022-02-11 21:43:501427 if len(files):
1428 return [
1429 output_api.PresubmitError(
1430 'Do not #include <iostream> in header files, since it inserts static '
1431 'initialization into every file including the header. Instead, '
1432 '#include <ostream>. See http://crbug.com/94794', files)
1433 ]
1434 return []
1435
[email protected]10689ca2011-09-02 02:31:541436
Aleksey Khoroshilov9b28c032022-06-03 16:35:321437def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501438 """Checks no windows headers with StrCat redefined are included directly."""
1439 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:321440 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
1441 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
1442 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
1443 _NON_BASE_DEPENDENT_PATHS)
1444 sources_filter = lambda f: input_api.FilterSourceFile(
1445 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
1446
Sam Maiera6e76d72022-02-11 21:43:501447 pattern_deny = input_api.re.compile(
1448 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1449 input_api.re.MULTILINE)
1450 pattern_allow = input_api.re.compile(
1451 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:321452 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:501453 contents = input_api.ReadFile(f)
1454 if pattern_deny.search(
1455 contents) and not pattern_allow.search(contents):
1456 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431457
Sam Maiera6e76d72022-02-11 21:43:501458 if len(files):
1459 return [
1460 output_api.PresubmitError(
1461 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1462 'directly since they pollute code with StrCat macro. Instead, '
1463 'include matching header from base/win. See http://crbug.com/856536',
1464 files)
1465 ]
1466 return []
Danil Chapovalov3518f362018-08-11 16:13:431467
[email protected]10689ca2011-09-02 02:31:541468
Saagar Sanghavifceeaae2020-08-12 16:40:361469def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501470 """Checks to make sure no source files use UNIT_TEST."""
1471 problems = []
1472 for f in input_api.AffectedFiles():
1473 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1474 continue
[email protected]72df4e782012-06-21 16:28:181475
Sam Maiera6e76d72022-02-11 21:43:501476 for line_num, line in f.ChangedContents():
1477 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1478 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181479
Sam Maiera6e76d72022-02-11 21:43:501480 if not problems:
1481 return []
1482 return [
1483 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1484 '\n'.join(problems))
1485 ]
1486
[email protected]72df4e782012-06-21 16:28:181487
Saagar Sanghavifceeaae2020-08-12 16:40:361488def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501489 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341490
Sam Maiera6e76d72022-02-11 21:43:501491 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1492 instead of DISABLED_. To filter false positives, reports are only generated
1493 if a corresponding MAYBE_ line exists.
1494 """
1495 problems = []
Dominic Battre033531052018-09-24 15:45:341496
Sam Maiera6e76d72022-02-11 21:43:501497 # The following two patterns are looked for in tandem - is a test labeled
1498 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1499 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1500 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341501
Sam Maiera6e76d72022-02-11 21:43:501502 # This is for the case that a test is disabled on all platforms.
1503 full_disable_pattern = input_api.re.compile(
1504 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1505 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341506
Sam Maiera6e76d72022-02-11 21:43:501507 for f in input_api.AffectedFiles(False):
1508 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1509 continue
Dominic Battre033531052018-09-24 15:45:341510
Sam Maiera6e76d72022-02-11 21:43:501511 # Search for MABYE_, DISABLE_ pairs.
1512 disable_lines = {} # Maps of test name to line number.
1513 maybe_lines = {}
1514 for line_num, line in f.ChangedContents():
1515 disable_match = disable_pattern.search(line)
1516 if disable_match:
1517 disable_lines[disable_match.group(1)] = line_num
1518 maybe_match = maybe_pattern.search(line)
1519 if maybe_match:
1520 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341521
Sam Maiera6e76d72022-02-11 21:43:501522 # Search for DISABLE_ occurrences within a TEST() macro.
1523 disable_tests = set(disable_lines.keys())
1524 maybe_tests = set(maybe_lines.keys())
1525 for test in disable_tests.intersection(maybe_tests):
1526 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341527
Sam Maiera6e76d72022-02-11 21:43:501528 contents = input_api.ReadFile(f)
1529 full_disable_match = full_disable_pattern.search(contents)
1530 if full_disable_match:
1531 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341532
Sam Maiera6e76d72022-02-11 21:43:501533 if not problems:
1534 return []
1535 return [
1536 output_api.PresubmitPromptWarning(
1537 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1538 '\n'.join(problems))
1539 ]
1540
Dominic Battre033531052018-09-24 15:45:341541
Nina Satragnof7660532021-09-20 18:03:351542def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501543 """Checks to make sure tests disabled conditionally are not missing a
1544 corresponding MAYBE_ prefix.
1545 """
1546 # Expect at least a lowercase character in the test name. This helps rule out
1547 # false positives with macros wrapping the actual tests name.
1548 define_maybe_pattern = input_api.re.compile(
1549 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191550 # The test_maybe_pattern needs to handle all of these forms. The standard:
1551 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1552 # With a wrapper macro around the test name:
1553 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1554 # And the odd-ball NACL_BROWSER_TEST_f format:
1555 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1556 # The optional E2E_ENABLED-style is handled with (\w*\()?
1557 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1558 # trailing ')'.
1559 test_maybe_pattern = (
1560 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501561 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1562 warnings = []
Nina Satragnof7660532021-09-20 18:03:351563
Sam Maiera6e76d72022-02-11 21:43:501564 # Read the entire files. We can't just read the affected lines, forgetting to
1565 # add MAYBE_ on a change would not show up otherwise.
1566 for f in input_api.AffectedFiles(False):
1567 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1568 continue
1569 contents = input_api.ReadFile(f)
1570 lines = contents.splitlines(True)
1571 current_position = 0
1572 warning_test_names = set()
1573 for line_num, line in enumerate(lines, start=1):
1574 current_position += len(line)
1575 maybe_match = define_maybe_pattern.search(line)
1576 if maybe_match:
1577 test_name = maybe_match.group('test_name')
1578 # Do not warn twice for the same test.
1579 if (test_name in warning_test_names):
1580 continue
1581 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351582
Sam Maiera6e76d72022-02-11 21:43:501583 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1584 # the current position.
1585 test_match = input_api.re.compile(
1586 test_maybe_pattern.format(test_name=test_name),
1587 input_api.re.MULTILINE).search(contents, current_position)
1588 suite_match = input_api.re.compile(
1589 suite_maybe_pattern.format(test_name=test_name),
1590 input_api.re.MULTILINE).search(contents, current_position)
1591 if not test_match and not suite_match:
1592 warnings.append(
1593 output_api.PresubmitPromptWarning(
1594 '%s:%d found MAYBE_ defined without corresponding test %s'
1595 % (f.LocalPath(), line_num, test_name)))
1596 return warnings
1597
[email protected]72df4e782012-06-21 16:28:181598
Saagar Sanghavifceeaae2020-08-12 16:40:361599def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501600 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1601 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:161602 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:501603 input_api.re.MULTILINE)
1604 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1605 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1606 continue
1607 for lnum, line in f.ChangedContents():
1608 if input_api.re.search(pattern, line):
1609 errors.append(
1610 output_api.PresubmitError((
1611 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1612 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1613 (f.LocalPath(), lnum)))
1614 return errors
danakj61c1aa22015-10-26 19:55:521615
1616
Weilun Shia487fad2020-10-28 00:10:341617# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1618# more reliable way. See
1619# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191620
wnwenbdc444e2016-05-25 13:44:151621
Saagar Sanghavifceeaae2020-08-12 16:40:361622def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501623 """Check that FlakyTest annotation is our own instead of the android one"""
1624 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1625 files = []
1626 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1627 if f.LocalPath().endswith('Test.java'):
1628 if pattern.search(input_api.ReadFile(f)):
1629 files.append(f)
1630 if len(files):
1631 return [
1632 output_api.PresubmitError(
1633 'Use org.chromium.base.test.util.FlakyTest instead of '
1634 'android.test.FlakyTest', files)
1635 ]
1636 return []
mcasasb7440c282015-02-04 14:52:191637
wnwenbdc444e2016-05-25 13:44:151638
Saagar Sanghavifceeaae2020-08-12 16:40:361639def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501640 """Make sure .DEPS.git is never modified manually."""
1641 if any(f.LocalPath().endswith('.DEPS.git')
1642 for f in input_api.AffectedFiles()):
1643 return [
1644 output_api.PresubmitError(
1645 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1646 'automated system based on what\'s in DEPS and your changes will be\n'
1647 'overwritten.\n'
1648 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1649 'get-the-code#Rolling_DEPS\n'
1650 'for more information')
1651 ]
1652 return []
[email protected]2a8ac9c2011-10-19 17:20:441653
1654
Saagar Sanghavifceeaae2020-08-12 16:40:361655def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501656 """Checks that DEPS file deps are from allowed_hosts."""
1657 # Run only if DEPS file has been modified to annoy fewer bystanders.
1658 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1659 return []
1660 # Outsource work to gclient verify
1661 try:
1662 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
1663 'third_party', 'depot_tools',
1664 'gclient.py')
1665 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:321666 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:501667 stderr=input_api.subprocess.STDOUT)
1668 return []
1669 except input_api.subprocess.CalledProcessError as error:
1670 return [
1671 output_api.PresubmitError(
1672 'DEPS file must have only git dependencies.',
1673 long_text=error.output)
1674 ]
tandriief664692014-09-23 14:51:471675
1676
Mario Sanchez Prada2472cab2019-09-18 10:58:311677def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151678 ban_rule):
Sam Maiera6e76d72022-02-11 21:43:501679 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311680
Sam Maiera6e76d72022-02-11 21:43:501681 Returns an string composed of the name of the file, the line number where the
1682 match has been found and the additional text passed as |message| in case the
1683 target type name matches the text inside the line passed as parameter.
1684 """
1685 result = []
Peng Huang9c5949a02020-06-11 19:20:541686
Daniel Chenga44a1bcd2022-03-15 20:00:151687 # Ignore comments about banned types.
1688 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:501689 return result
Daniel Chenga44a1bcd2022-03-15 20:00:151690 # A // nocheck comment will bypass this error.
1691 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:501692 return result
1693
1694 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:151695 if ban_rule.pattern[0:1] == '/':
1696 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:501697 if input_api.re.search(regex, line):
1698 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:151699 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:501700 matched = True
1701
1702 if matched:
1703 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:151704 for line in ban_rule.explanation:
1705 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:501706
danakjd18e8892020-12-17 17:42:011707 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:311708
1709
Saagar Sanghavifceeaae2020-08-12 16:40:361710def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501711 """Make sure that banned functions are not used."""
1712 warnings = []
1713 errors = []
[email protected]127f18ec2012-06-16 05:05:591714
Sam Maiera6e76d72022-02-11 21:43:501715 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:151716 if not excluded_paths:
1717 return False
1718
Sam Maiera6e76d72022-02-11 21:43:501719 local_path = affected_file.LocalPath()
1720 for item in excluded_paths:
1721 if input_api.re.match(item, local_path):
1722 return True
1723 return False
wnwenbdc444e2016-05-25 13:44:151724
Sam Maiera6e76d72022-02-11 21:43:501725 def IsIosObjcFile(affected_file):
1726 local_path = affected_file.LocalPath()
1727 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
1728 '.h'):
1729 return False
1730 basename = input_api.os_path.basename(local_path)
1731 if 'ios' in basename.split('_'):
1732 return True
1733 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1734 if sep and 'ios' in local_path.split(sep):
1735 return True
1736 return False
Sylvain Defresnea8b73d252018-02-28 15:45:541737
Daniel Chenga44a1bcd2022-03-15 20:00:151738 def CheckForMatch(affected_file, line_num: int, line: str,
1739 ban_rule: BanRule):
1740 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
1741 return
1742
Sam Maiera6e76d72022-02-11 21:43:501743 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151744 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501745 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:151746 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:501747 errors.extend(problems)
1748 else:
1749 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151750
Sam Maiera6e76d72022-02-11 21:43:501751 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1752 for f in input_api.AffectedFiles(file_filter=file_filter):
1753 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151754 for ban_rule in _BANNED_JAVA_FUNCTIONS:
1755 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:411756
Sam Maiera6e76d72022-02-11 21:43:501757 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1758 for f in input_api.AffectedFiles(file_filter=file_filter):
1759 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151760 for ban_rule in _BANNED_OBJC_FUNCTIONS:
1761 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591762
Sam Maiera6e76d72022-02-11 21:43:501763 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
1764 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151765 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
1766 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:541767
Sam Maiera6e76d72022-02-11 21:43:501768 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1769 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1770 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151771 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
1772 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:051773
Sam Maiera6e76d72022-02-11 21:43:501774 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1775 for f in input_api.AffectedFiles(file_filter=file_filter):
1776 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151777 for ban_rule in _BANNED_CPP_FUNCTIONS:
1778 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591779
Daniel Cheng92c15e32022-03-16 17:48:221780 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
1781 for f in input_api.AffectedFiles(file_filter=file_filter):
1782 for line_num, line in f.ChangedContents():
1783 for ban_rule in _BANNED_MOJOM_PATTERNS:
1784 CheckForMatch(f, line_num, line, ban_rule)
1785
1786
Sam Maiera6e76d72022-02-11 21:43:501787 result = []
1788 if (warnings):
1789 result.append(
1790 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
1791 '\n'.join(warnings)))
1792 if (errors):
1793 result.append(
1794 output_api.PresubmitError('Banned functions were used.\n' +
1795 '\n'.join(errors)))
1796 return result
[email protected]127f18ec2012-06-16 05:05:591797
1798
Michael Thiessen44457642020-02-06 00:24:151799def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501800 """Make sure that banned java imports are not used."""
1801 errors = []
Michael Thiessen44457642020-02-06 00:24:151802
Sam Maiera6e76d72022-02-11 21:43:501803 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1804 for f in input_api.AffectedFiles(file_filter=file_filter):
1805 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151806 for ban_rule in _BANNED_JAVA_IMPORTS:
1807 # Consider merging this into the above function. There is no
1808 # real difference anymore other than helping with a little
1809 # bit of boilerplate text. Doing so means things like
1810 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:501811 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:151812 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501813 if problems:
1814 errors.extend(problems)
1815 result = []
1816 if (errors):
1817 result.append(
1818 output_api.PresubmitError('Banned imports were used.\n' +
1819 '\n'.join(errors)))
1820 return result
Michael Thiessen44457642020-02-06 00:24:151821
1822
Saagar Sanghavifceeaae2020-08-12 16:40:361823def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501824 """Make sure that banned functions are not used."""
1825 files = []
1826 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
1827 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1828 if not f.LocalPath().endswith('.h'):
1829 continue
Bruce Dawson4c4c2922022-05-02 18:07:331830 if f.LocalPath().endswith('com_imported_mstscax.h'):
1831 continue
Sam Maiera6e76d72022-02-11 21:43:501832 contents = input_api.ReadFile(f)
1833 if pattern.search(contents):
1834 files.append(f)
[email protected]6c063c62012-07-11 19:11:061835
Sam Maiera6e76d72022-02-11 21:43:501836 if files:
1837 return [
1838 output_api.PresubmitError(
1839 'Do not use #pragma once in header files.\n'
1840 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1841 files)
1842 ]
1843 return []
[email protected]6c063c62012-07-11 19:11:061844
[email protected]127f18ec2012-06-16 05:05:591845
Saagar Sanghavifceeaae2020-08-12 16:40:361846def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501847 """Checks to make sure we don't introduce use of foo ? true : false."""
1848 problems = []
1849 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1850 for f in input_api.AffectedFiles():
1851 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1852 continue
[email protected]e7479052012-09-19 00:26:121853
Sam Maiera6e76d72022-02-11 21:43:501854 for line_num, line in f.ChangedContents():
1855 if pattern.match(line):
1856 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:121857
Sam Maiera6e76d72022-02-11 21:43:501858 if not problems:
1859 return []
1860 return [
1861 output_api.PresubmitPromptWarning(
1862 'Please consider avoiding the "? true : false" pattern if possible.\n'
1863 + '\n'.join(problems))
1864 ]
[email protected]e7479052012-09-19 00:26:121865
1866
Saagar Sanghavifceeaae2020-08-12 16:40:361867def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501868 """Runs checkdeps on #include and import statements added in this
1869 change. Breaking - rules is an error, breaking ! rules is a
1870 warning.
1871 """
1872 # Return early if no relevant file types were modified.
1873 for f in input_api.AffectedFiles():
1874 path = f.LocalPath()
1875 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
1876 or _IsJavaFile(input_api, path)):
1877 break
[email protected]55f9f382012-07-31 11:02:181878 else:
Sam Maiera6e76d72022-02-11 21:43:501879 return []
rhalavati08acd232017-04-03 07:23:281880
Sam Maiera6e76d72022-02-11 21:43:501881 import sys
1882 # We need to wait until we have an input_api object and use this
1883 # roundabout construct to import checkdeps because this file is
1884 # eval-ed and thus doesn't have __file__.
1885 original_sys_path = sys.path
1886 try:
1887 sys.path = sys.path + [
1888 input_api.os_path.join(input_api.PresubmitLocalPath(),
1889 'buildtools', 'checkdeps')
1890 ]
1891 import checkdeps
1892 from rules import Rule
1893 finally:
1894 # Restore sys.path to what it was before.
1895 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:181896
Sam Maiera6e76d72022-02-11 21:43:501897 added_includes = []
1898 added_imports = []
1899 added_java_imports = []
1900 for f in input_api.AffectedFiles():
1901 if _IsCPlusPlusFile(input_api, f.LocalPath()):
1902 changed_lines = [line for _, line in f.ChangedContents()]
1903 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
1904 elif _IsProtoFile(input_api, f.LocalPath()):
1905 changed_lines = [line for _, line in f.ChangedContents()]
1906 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
1907 elif _IsJavaFile(input_api, f.LocalPath()):
1908 changed_lines = [line for _, line in f.ChangedContents()]
1909 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241910
Sam Maiera6e76d72022-02-11 21:43:501911 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
1912
1913 error_descriptions = []
1914 warning_descriptions = []
1915 error_subjects = set()
1916 warning_subjects = set()
1917
1918 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1919 added_includes):
1920 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1921 description_with_path = '%s\n %s' % (path, rule_description)
1922 if rule_type == Rule.DISALLOW:
1923 error_descriptions.append(description_with_path)
1924 error_subjects.add("#includes")
1925 else:
1926 warning_descriptions.append(description_with_path)
1927 warning_subjects.add("#includes")
1928
1929 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1930 added_imports):
1931 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1932 description_with_path = '%s\n %s' % (path, rule_description)
1933 if rule_type == Rule.DISALLOW:
1934 error_descriptions.append(description_with_path)
1935 error_subjects.add("imports")
1936 else:
1937 warning_descriptions.append(description_with_path)
1938 warning_subjects.add("imports")
1939
1940 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
1941 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
1942 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1943 description_with_path = '%s\n %s' % (path, rule_description)
1944 if rule_type == Rule.DISALLOW:
1945 error_descriptions.append(description_with_path)
1946 error_subjects.add("imports")
1947 else:
1948 warning_descriptions.append(description_with_path)
1949 warning_subjects.add("imports")
1950
1951 results = []
1952 if error_descriptions:
1953 results.append(
1954 output_api.PresubmitError(
1955 'You added one or more %s that violate checkdeps rules.' %
1956 " and ".join(error_subjects), error_descriptions))
1957 if warning_descriptions:
1958 results.append(
1959 output_api.PresubmitPromptOrNotify(
1960 'You added one or more %s of files that are temporarily\n'
1961 'allowed but being removed. Can you avoid introducing the\n'
1962 '%s? See relevant DEPS file(s) for details and contacts.' %
1963 (" and ".join(warning_subjects), "/".join(warning_subjects)),
1964 warning_descriptions))
1965 return results
[email protected]55f9f382012-07-31 11:02:181966
1967
Saagar Sanghavifceeaae2020-08-12 16:40:361968def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501969 """Check that all files have their permissions properly set."""
1970 if input_api.platform == 'win32':
1971 return []
1972 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
1973 'tools', 'checkperms',
1974 'checkperms.py')
1975 args = [
Bruce Dawson8a43cf72022-05-13 17:10:321976 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:501977 input_api.change.RepositoryRoot()
1978 ]
1979 with input_api.CreateTemporaryFile() as file_list:
1980 for f in input_api.AffectedFiles():
1981 # checkperms.py file/directory arguments must be relative to the
1982 # repository.
1983 file_list.write((f.LocalPath() + '\n').encode('utf8'))
1984 file_list.close()
1985 args += ['--file-list', file_list.name]
1986 try:
1987 input_api.subprocess.check_output(args)
1988 return []
1989 except input_api.subprocess.CalledProcessError as error:
1990 return [
1991 output_api.PresubmitError('checkperms.py failed:',
1992 long_text=error.output.decode(
1993 'utf-8', 'ignore'))
1994 ]
[email protected]fbcafe5a2012-08-08 15:31:221995
1996
Saagar Sanghavifceeaae2020-08-12 16:40:361997def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501998 """Makes sure we don't include ui/aura/window_property.h
1999 in header files.
2000 """
2001 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2002 errors = []
2003 for f in input_api.AffectedFiles():
2004 if not f.LocalPath().endswith('.h'):
2005 continue
2006 for line_num, line in f.ChangedContents():
2007 if pattern.match(line):
2008 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:492009
Sam Maiera6e76d72022-02-11 21:43:502010 results = []
2011 if errors:
2012 results.append(
2013 output_api.PresubmitError(
2014 'Header files should not include ui/aura/window_property.h',
2015 errors))
2016 return results
[email protected]c8278b32012-10-30 20:35:492017
2018
Omer Katzcc77ea92021-04-26 10:23:282019def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502020 """Makes sure we don't include any headers from
2021 third_party/blink/renderer/platform/heap/impl or
2022 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2023 third_party/blink/renderer/platform/heap
2024 """
2025 impl_pattern = input_api.re.compile(
2026 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2027 v8_wrapper_pattern = input_api.re.compile(
2028 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2029 )
2030 file_filter = lambda f: not input_api.re.match(
2031 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
2032 f.LocalPath())
2033 errors = []
Omer Katzcc77ea92021-04-26 10:23:282034
Sam Maiera6e76d72022-02-11 21:43:502035 for f in input_api.AffectedFiles(file_filter=file_filter):
2036 for line_num, line in f.ChangedContents():
2037 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2038 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282039
Sam Maiera6e76d72022-02-11 21:43:502040 results = []
2041 if errors:
2042 results.append(
2043 output_api.PresubmitError(
2044 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2045 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2046 'relevant counterparts from third_party/blink/renderer/platform/heap',
2047 errors))
2048 return results
Omer Katzcc77ea92021-04-26 10:23:282049
2050
[email protected]70ca77752012-11-20 03:45:032051def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502052 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2053 errors = []
2054 for line_num, line in f.ChangedContents():
2055 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2056 # First-level headers in markdown look a lot like version control
2057 # conflict markers. http://daringfireball.net/projects/markdown/basics
2058 continue
2059 if pattern.match(line):
2060 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2061 return errors
[email protected]70ca77752012-11-20 03:45:032062
2063
Saagar Sanghavifceeaae2020-08-12 16:40:362064def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502065 """Usually this is not intentional and will cause a compile failure."""
2066 errors = []
2067 for f in input_api.AffectedFiles():
2068 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032069
Sam Maiera6e76d72022-02-11 21:43:502070 results = []
2071 if errors:
2072 results.append(
2073 output_api.PresubmitError(
2074 'Version control conflict markers found, please resolve.',
2075 errors))
2076 return results
[email protected]70ca77752012-11-20 03:45:032077
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202078
Saagar Sanghavifceeaae2020-08-12 16:40:362079def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502080 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2081 errors = []
2082 for f in input_api.AffectedFiles():
2083 for line_num, line in f.ChangedContents():
2084 if pattern.search(line):
2085 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162086
Sam Maiera6e76d72022-02-11 21:43:502087 results = []
2088 if errors:
2089 results.append(
2090 output_api.PresubmitPromptWarning(
2091 'Found Google support URL addressed by answer number. Please replace '
2092 'with a p= identifier instead. See crbug.com/679462\n',
2093 errors))
2094 return results
estadee17314a02017-01-12 16:22:162095
[email protected]70ca77752012-11-20 03:45:032096
Saagar Sanghavifceeaae2020-08-12 16:40:362097def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502098 def FilterFile(affected_file):
2099 """Filter function for use with input_api.AffectedSourceFiles,
2100 below. This filters out everything except non-test files from
2101 top-level directories that generally speaking should not hard-code
2102 service URLs (e.g. src/android_webview/, src/content/ and others).
2103 """
2104 return input_api.FilterSourceFile(
2105 affected_file,
2106 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2107 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2108 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442109
Sam Maiera6e76d72022-02-11 21:43:502110 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2111 '\.(com|net)[^"]*"')
2112 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2113 pattern = input_api.re.compile(base_pattern)
2114 problems = [] # items are (filename, line_number, line)
2115 for f in input_api.AffectedSourceFiles(FilterFile):
2116 for line_num, line in f.ChangedContents():
2117 if not comment_pattern.search(line) and pattern.search(line):
2118 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442119
Sam Maiera6e76d72022-02-11 21:43:502120 if problems:
2121 return [
2122 output_api.PresubmitPromptOrNotify(
2123 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2124 'Are you sure this is correct?', [
2125 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2126 for problem in problems
2127 ])
2128 ]
2129 else:
2130 return []
[email protected]06e6d0ff2012-12-11 01:36:442131
2132
Saagar Sanghavifceeaae2020-08-12 16:40:362133def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502134 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292135
Sam Maiera6e76d72022-02-11 21:43:502136 def FileFilter(affected_file):
2137 """Includes directories known to be Chrome OS only."""
2138 return input_api.FilterSourceFile(
2139 affected_file,
2140 files_to_check=(
2141 '^ash/',
2142 '^chromeos/', # Top-level src/chromeos.
2143 '.*/chromeos/', # Any path component.
2144 '^components/arc',
2145 '^components/exo'),
2146 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292147
Sam Maiera6e76d72022-02-11 21:43:502148 prefs = []
2149 priority_prefs = []
2150 for f in input_api.AffectedFiles(file_filter=FileFilter):
2151 for line_num, line in f.ChangedContents():
2152 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2153 line):
2154 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2155 prefs.append(' %s' % line)
2156 if input_api.re.search(
2157 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2158 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2159 priority_prefs.append(' %s' % line)
2160
2161 results = []
2162 if (prefs):
2163 results.append(
2164 output_api.PresubmitPromptWarning(
2165 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2166 'by browser sync settings. If these prefs should be controlled by OS '
2167 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2168 '\n'.join(prefs)))
2169 if (priority_prefs):
2170 results.append(
2171 output_api.PresubmitPromptWarning(
2172 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2173 'controlled by browser sync settings. If these prefs should be '
2174 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2175 'instead.\n' + '\n'.join(prefs)))
2176 return results
James Cook6b6597c2019-11-06 22:05:292177
2178
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492179# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362180def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502181 """Makes sure there are no abbreviations in the name of PNG files.
2182 The native_client_sdk directory is excluded because it has auto-generated PNG
2183 files for documentation.
2184 """
2185 errors = []
2186 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Bruce Dawson3db456212022-05-02 05:34:182187 files_to_skip = [r'^native_client_sdk[\\/]',
2188 r'^services[\\/]test[\\/]',
2189 r'^third_party[\\/]blink[\\/]web_tests[\\/]',
2190 ]
Sam Maiera6e76d72022-02-11 21:43:502191 file_filter = lambda f: input_api.FilterSourceFile(
2192 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2193 for f in input_api.AffectedFiles(include_deletes=False,
2194 file_filter=file_filter):
2195 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272196
Sam Maiera6e76d72022-02-11 21:43:502197 results = []
2198 if errors:
2199 results.append(
2200 output_api.PresubmitError(
2201 'The name of PNG files should not have abbreviations. \n'
2202 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2203 'Contact [email protected] if you have questions.', errors))
2204 return results
[email protected]d2530012013-01-25 16:39:272205
Evan Stade7cd4a2c2022-08-04 23:37:252206def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2207 """Heuristically identifies product icons based on their file name and reminds
2208 contributors not to add them to the Chromium repository.
2209 """
2210 errors = []
2211 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2212 file_filter = lambda f: input_api.FilterSourceFile(
2213 f, files_to_check=files_to_check)
2214 for f in input_api.AffectedFiles(include_deletes=False,
2215 file_filter=file_filter):
2216 errors.append(' %s' % f.LocalPath())
2217
2218 results = []
2219 if errors:
2220 results.append(
2221 output_api.PresubmitError(
2222 'Trademarked images should not be added to the public repo. '
2223 'See crbug.com/944754', errors))
2224 return results
2225
[email protected]d2530012013-01-25 16:39:272226
Daniel Cheng4dcdb6b2017-04-13 08:30:172227def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502228 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172229
Sam Maiera6e76d72022-02-11 21:43:502230 Args:
2231 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2232 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172233 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502234 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172235 if rule.startswith('+') or rule.startswith('!')
2236 ])
Sam Maiera6e76d72022-02-11 21:43:502237 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2238 add_rules.update([
2239 rule[1:] for rule in rules
2240 if rule.startswith('+') or rule.startswith('!')
2241 ])
2242 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172243
2244
2245def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502246 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172247
Sam Maiera6e76d72022-02-11 21:43:502248 # Stubs for handling special syntax in the root DEPS file.
2249 class _VarImpl:
2250 def __init__(self, local_scope):
2251 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172252
Sam Maiera6e76d72022-02-11 21:43:502253 def Lookup(self, var_name):
2254 """Implements the Var syntax."""
2255 try:
2256 return self._local_scope['vars'][var_name]
2257 except KeyError:
2258 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172259
Sam Maiera6e76d72022-02-11 21:43:502260 local_scope = {}
2261 global_scope = {
2262 'Var': _VarImpl(local_scope).Lookup,
2263 'Str': str,
2264 }
Dirk Pranke1b9e06382021-05-14 01:16:222265
Sam Maiera6e76d72022-02-11 21:43:502266 exec(contents, global_scope, local_scope)
2267 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172268
2269
2270def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502271 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2272 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412273
Sam Maiera6e76d72022-02-11 21:43:502274 For a directory (rather than a specific filename) we fake a path to
2275 a specific filename by adding /DEPS. This is chosen as a file that
2276 will seldom or never be subject to per-file include_rules.
2277 """
2278 # We ignore deps entries on auto-generated directories.
2279 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082280
Sam Maiera6e76d72022-02-11 21:43:502281 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2282 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172283
Sam Maiera6e76d72022-02-11 21:43:502284 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172285
Sam Maiera6e76d72022-02-11 21:43:502286 results = set()
2287 for added_dep in added_deps:
2288 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2289 continue
2290 # Assume that a rule that ends in .h is a rule for a specific file.
2291 if added_dep.endswith('.h'):
2292 results.add(added_dep)
2293 else:
2294 results.add(os_path.join(added_dep, 'DEPS'))
2295 return results
[email protected]f32e2d1e2013-07-26 21:39:082296
2297
Saagar Sanghavifceeaae2020-08-12 16:40:362298def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502299 """When a dependency prefixed with + is added to a DEPS file, we
2300 want to make sure that the change is reviewed by an OWNER of the
2301 target file or directory, to avoid layering violations from being
2302 introduced. This check verifies that this happens.
2303 """
2304 # We rely on Gerrit's code-owners to check approvals.
2305 # input_api.gerrit is always set for Chromium, but other projects
2306 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102307 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502308 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302309 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502310 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302311 try:
2312 if (input_api.change.issue and
2313 input_api.gerrit.IsOwnersOverrideApproved(
2314 input_api.change.issue)):
2315 # Skip OWNERS check when Owners-Override label is approved. This is
2316 # intended for global owners, trusted bots, and on-call sheriffs.
2317 # Review is still required for these changes.
2318 return []
2319 except Exception as e:
2320 return [output_api.PresubmitPromptWarning(
2321 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232322
Sam Maiera6e76d72022-02-11 21:43:502323 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242324
Sam Maiera6e76d72022-02-11 21:43:502325 file_filter = lambda f: not input_api.re.match(
2326 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
2327 for f in input_api.AffectedFiles(include_deletes=False,
2328 file_filter=file_filter):
2329 filename = input_api.os_path.basename(f.LocalPath())
2330 if filename == 'DEPS':
2331 virtual_depended_on_files.update(
2332 _CalculateAddedDeps(input_api.os_path,
2333 '\n'.join(f.OldContents()),
2334 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552335
Sam Maiera6e76d72022-02-11 21:43:502336 if not virtual_depended_on_files:
2337 return []
[email protected]e871964c2013-05-13 14:14:552338
Sam Maiera6e76d72022-02-11 21:43:502339 if input_api.is_committing:
2340 if input_api.tbr:
2341 return [
2342 output_api.PresubmitNotifyResult(
2343 '--tbr was specified, skipping OWNERS check for DEPS additions'
2344 )
2345 ]
Daniel Cheng3008dc12022-05-13 04:02:112346 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2347 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502348 if input_api.dry_run:
2349 return [
2350 output_api.PresubmitNotifyResult(
2351 'This is a dry run, skipping OWNERS check for DEPS additions'
2352 )
2353 ]
2354 if not input_api.change.issue:
2355 return [
2356 output_api.PresubmitError(
2357 "DEPS approval by OWNERS check failed: this change has "
2358 "no change number, so we can't check it for approvals.")
2359 ]
2360 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412361 else:
Sam Maiera6e76d72022-02-11 21:43:502362 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552363
Sam Maiera6e76d72022-02-11 21:43:502364 owner_email, reviewers = (
2365 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2366 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552367
Sam Maiera6e76d72022-02-11 21:43:502368 owner_email = owner_email or input_api.change.author_email
2369
2370 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2371 virtual_depended_on_files, reviewers.union([owner_email]), [])
2372 missing_files = [
2373 f for f in virtual_depended_on_files
2374 if approval_status[f] != input_api.owners_client.APPROVED
2375 ]
2376
2377 # We strip the /DEPS part that was added by
2378 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2379 # directory.
2380 def StripDeps(path):
2381 start_deps = path.rfind('/DEPS')
2382 if start_deps != -1:
2383 return path[:start_deps]
2384 else:
2385 return path
2386
2387 unapproved_dependencies = [
2388 "'+%s'," % StripDeps(path) for path in missing_files
2389 ]
2390
2391 if unapproved_dependencies:
2392 output_list = [
2393 output(
2394 'You need LGTM from owners of depends-on paths in DEPS that were '
2395 'modified in this CL:\n %s' %
2396 '\n '.join(sorted(unapproved_dependencies)))
2397 ]
2398 suggested_owners = input_api.owners_client.SuggestOwners(
2399 missing_files, exclude=[owner_email])
2400 output_list.append(
2401 output('Suggested missing target path OWNERS:\n %s' %
2402 '\n '.join(suggested_owners or [])))
2403 return output_list
2404
2405 return []
[email protected]e871964c2013-05-13 14:14:552406
2407
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492408# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362409def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502410 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2411 files_to_skip = (
2412 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2413 input_api.DEFAULT_FILES_TO_SKIP + (
2414 r"^base[\\/]logging\.h$",
2415 r"^base[\\/]logging\.cc$",
2416 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2417 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2418 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2419 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2420 r"startup_browser_creator\.cc$",
2421 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2422 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2423 r"diagnostics_writer\.cc$",
2424 r"^chrome[\\/]chrome_cleaner[\\/].*",
2425 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2426 r"dll_hash_main\.cc$",
2427 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2428 r"^chromecast[\\/]",
Sam Maiera6e76d72022-02-11 21:43:502429 r"^components[\\/]browser_watcher[\\/]"
Joseph Wang668ab202022-07-26 16:24:492430 r"dump_stability_report_main_win\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502431 r"^components[\\/]media_control[\\/]renderer[\\/]"
2432 r"media_playback_options\.cc$",
2433 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2434 r"overlay_strategy_underlay_cast\.cc$",
2435 r"^components[\\/]zucchini[\\/].*",
2436 # TODO(peter): Remove exception. https://crbug.com/534537
2437 r"^content[\\/]browser[\\/]notifications[\\/]"
2438 r"notification_event_dispatcher_impl\.cc$",
2439 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2440 r"gl_helper_benchmark\.cc$",
2441 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2442 r"^courgette[\\/]courgette_tool\.cc$",
2443 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Joseph Wang668ab202022-07-26 16:24:492444 r"^fuchsia_web[\\/]common[\\/]init_logging\.cc$",
2445 r"^fuchsia_web[\\/]runners[\\/]common[\\/]web_component\.cc$",
2446 r"^fuchsia_web[\\/]shell[\\/].*_shell\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502447 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2448 r"^ipc[\\/]ipc_logging\.cc$",
2449 r"^native_client_sdk[\\/]",
2450 r"^remoting[\\/]base[\\/]logging\.h$",
2451 r"^remoting[\\/]host[\\/].*",
2452 r"^sandbox[\\/]linux[\\/].*",
2453 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Joseph Wang668ab202022-07-26 16:24:492454 r"dump_file_system\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502455 r"^tools[\\/]",
Joseph Wang668ab202022-07-26 16:24:492456 r"^ui[\\/]base[\\/]resource[\\/]data_pack\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502457 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2458 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2459 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2460 r"xwmstartupcheck\.cc$"))
2461 source_file_filter = lambda x: input_api.FilterSourceFile(
2462 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402463
Sam Maiera6e76d72022-02-11 21:43:502464 log_info = set([])
2465 printf = set([])
[email protected]85218562013-11-22 07:41:402466
Sam Maiera6e76d72022-02-11 21:43:502467 for f in input_api.AffectedSourceFiles(source_file_filter):
2468 for _, line in f.ChangedContents():
2469 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2470 log_info.add(f.LocalPath())
2471 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2472 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372473
Sam Maiera6e76d72022-02-11 21:43:502474 if input_api.re.search(r"\bprintf\(", line):
2475 printf.add(f.LocalPath())
2476 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2477 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402478
Sam Maiera6e76d72022-02-11 21:43:502479 if log_info:
2480 return [
2481 output_api.PresubmitError(
2482 'These files spam the console log with LOG(INFO):',
2483 items=log_info)
2484 ]
2485 if printf:
2486 return [
2487 output_api.PresubmitError(
2488 'These files spam the console log with printf/fprintf:',
2489 items=printf)
2490 ]
2491 return []
[email protected]85218562013-11-22 07:41:402492
2493
Saagar Sanghavifceeaae2020-08-12 16:40:362494def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502495 """These types are all expected to hold locks while in scope and
2496 so should never be anonymous (which causes them to be immediately
2497 destroyed)."""
2498 they_who_must_be_named = [
2499 'base::AutoLock',
2500 'base::AutoReset',
2501 'base::AutoUnlock',
2502 'SkAutoAlphaRestore',
2503 'SkAutoBitmapShaderInstall',
2504 'SkAutoBlitterChoose',
2505 'SkAutoBounderCommit',
2506 'SkAutoCallProc',
2507 'SkAutoCanvasRestore',
2508 'SkAutoCommentBlock',
2509 'SkAutoDescriptor',
2510 'SkAutoDisableDirectionCheck',
2511 'SkAutoDisableOvalCheck',
2512 'SkAutoFree',
2513 'SkAutoGlyphCache',
2514 'SkAutoHDC',
2515 'SkAutoLockColors',
2516 'SkAutoLockPixels',
2517 'SkAutoMalloc',
2518 'SkAutoMaskFreeImage',
2519 'SkAutoMutexAcquire',
2520 'SkAutoPathBoundsUpdate',
2521 'SkAutoPDFRelease',
2522 'SkAutoRasterClipValidate',
2523 'SkAutoRef',
2524 'SkAutoTime',
2525 'SkAutoTrace',
2526 'SkAutoUnref',
2527 ]
2528 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2529 # bad: base::AutoLock(lock.get());
2530 # not bad: base::AutoLock lock(lock.get());
2531 bad_pattern = input_api.re.compile(anonymous)
2532 # good: new base::AutoLock(lock.get())
2533 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2534 errors = []
[email protected]49aa76a2013-12-04 06:59:162535
Sam Maiera6e76d72022-02-11 21:43:502536 for f in input_api.AffectedFiles():
2537 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2538 continue
2539 for linenum, line in f.ChangedContents():
2540 if bad_pattern.search(line) and not good_pattern.search(line):
2541 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162542
Sam Maiera6e76d72022-02-11 21:43:502543 if errors:
2544 return [
2545 output_api.PresubmitError(
2546 'These lines create anonymous variables that need to be named:',
2547 items=errors)
2548 ]
2549 return []
[email protected]49aa76a2013-12-04 06:59:162550
2551
Saagar Sanghavifceeaae2020-08-12 16:40:362552def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502553 # Returns whether |template_str| is of the form <T, U...> for some types T
2554 # and U. Assumes that |template_str| is already in the form <...>.
2555 def HasMoreThanOneArg(template_str):
2556 # Level of <...> nesting.
2557 nesting = 0
2558 for c in template_str:
2559 if c == '<':
2560 nesting += 1
2561 elif c == '>':
2562 nesting -= 1
2563 elif c == ',' and nesting == 1:
2564 return True
2565 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532566
Sam Maiera6e76d72022-02-11 21:43:502567 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2568 sources = lambda affected_file: input_api.FilterSourceFile(
2569 affected_file,
2570 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2571 DEFAULT_FILES_TO_SKIP),
2572 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552573
Sam Maiera6e76d72022-02-11 21:43:502574 # Pattern to capture a single "<...>" block of template arguments. It can
2575 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2576 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2577 # latter would likely require counting that < and > match, which is not
2578 # expressible in regular languages. Should the need arise, one can introduce
2579 # limited counting (matching up to a total number of nesting depth), which
2580 # should cover all practical cases for already a low nesting limit.
2581 template_arg_pattern = (
2582 r'<[^>]*' # Opening block of <.
2583 r'>([^<]*>)?') # Closing block of >.
2584 # Prefix expressing that whatever follows is not already inside a <...>
2585 # block.
2586 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2587 null_construct_pattern = input_api.re.compile(
2588 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2589 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552590
Sam Maiera6e76d72022-02-11 21:43:502591 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2592 template_arg_no_array_pattern = (
2593 r'<[^>]*[^]]' # Opening block of <.
2594 r'>([^(<]*[^]]>)?') # Closing block of >.
2595 # Prefix saying that what follows is the start of an expression.
2596 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2597 # Suffix saying that what follows are call parentheses with a non-empty list
2598 # of arguments.
2599 nonempty_arg_list_pattern = r'\(([^)]|$)'
2600 # Put the template argument into a capture group for deeper examination later.
2601 return_construct_pattern = input_api.re.compile(
2602 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2603 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552604
Sam Maiera6e76d72022-02-11 21:43:502605 problems_constructor = []
2606 problems_nullptr = []
2607 for f in input_api.AffectedSourceFiles(sources):
2608 for line_number, line in f.ChangedContents():
2609 # Disallow:
2610 # return std::unique_ptr<T>(foo);
2611 # bar = std::unique_ptr<T>(foo);
2612 # But allow:
2613 # return std::unique_ptr<T[]>(foo);
2614 # bar = std::unique_ptr<T[]>(foo);
2615 # And also allow cases when the second template argument is present. Those
2616 # cases cannot be handled by std::make_unique:
2617 # return std::unique_ptr<T, U>(foo);
2618 # bar = std::unique_ptr<T, U>(foo);
2619 local_path = f.LocalPath()
2620 return_construct_result = return_construct_pattern.search(line)
2621 if return_construct_result and not HasMoreThanOneArg(
2622 return_construct_result.group('template_arg')):
2623 problems_constructor.append(
2624 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2625 # Disallow:
2626 # std::unique_ptr<T>()
2627 if null_construct_pattern.search(line):
2628 problems_nullptr.append(
2629 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052630
Sam Maiera6e76d72022-02-11 21:43:502631 errors = []
2632 if problems_nullptr:
2633 errors.append(
2634 output_api.PresubmitPromptWarning(
2635 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2636 problems_nullptr))
2637 if problems_constructor:
2638 errors.append(
2639 output_api.PresubmitError(
2640 'The following files use explicit std::unique_ptr constructor. '
2641 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2642 'std::make_unique is not an option.', problems_constructor))
2643 return errors
Peter Kasting4844e46e2018-02-23 07:27:102644
2645
Saagar Sanghavifceeaae2020-08-12 16:40:362646def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502647 """Checks if any new user action has been added."""
2648 if any('actions.xml' == input_api.os_path.basename(f)
2649 for f in input_api.LocalPaths()):
2650 # If actions.xml is already included in the changelist, the PRESUBMIT
2651 # for actions.xml will do a more complete presubmit check.
2652 return []
2653
2654 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2655 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2656 input_api.DEFAULT_FILES_TO_SKIP)
2657 file_filter = lambda f: input_api.FilterSourceFile(
2658 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2659
2660 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2661 current_actions = None
2662 for f in input_api.AffectedFiles(file_filter=file_filter):
2663 for line_num, line in f.ChangedContents():
2664 match = input_api.re.search(action_re, line)
2665 if match:
2666 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2667 # loaded only once.
2668 if not current_actions:
2669 with open(
2670 'tools/metrics/actions/actions.xml') as actions_f:
2671 current_actions = actions_f.read()
2672 # Search for the matched user action name in |current_actions|.
2673 for action_name in match.groups():
2674 action = 'name="{0}"'.format(action_name)
2675 if action not in current_actions:
2676 return [
2677 output_api.PresubmitPromptWarning(
2678 'File %s line %d: %s is missing in '
2679 'tools/metrics/actions/actions.xml. Please run '
2680 'tools/metrics/actions/extract_actions.py to update.'
2681 % (f.LocalPath(), line_num, action_name))
2682 ]
[email protected]999261d2014-03-03 20:08:082683 return []
2684
[email protected]999261d2014-03-03 20:08:082685
Daniel Cheng13ca61a882017-08-25 15:11:252686def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502687 import sys
2688 sys.path = sys.path + [
2689 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2690 'json_comment_eater')
2691 ]
2692 import json_comment_eater
2693 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252694
2695
[email protected]99171a92014-06-03 08:44:472696def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172697 try:
Sam Maiera6e76d72022-02-11 21:43:502698 contents = input_api.ReadFile(filename)
2699 if eat_comments:
2700 json_comment_eater = _ImportJSONCommentEater(input_api)
2701 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172702
Sam Maiera6e76d72022-02-11 21:43:502703 input_api.json.loads(contents)
2704 except ValueError as e:
2705 return e
Andrew Grieve4deedb12022-02-03 21:34:502706 return None
2707
2708
Sam Maiera6e76d72022-02-11 21:43:502709def _GetIDLParseError(input_api, filename):
2710 try:
2711 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:282712 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:342713 if not char.isascii():
2714 return (
2715 'Non-ascii character "%s" (ord %d) found at offset %d.' %
2716 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:502717 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2718 'tools', 'json_schema_compiler',
2719 'idl_schema.py')
2720 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282721 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502722 stdin=input_api.subprocess.PIPE,
2723 stdout=input_api.subprocess.PIPE,
2724 stderr=input_api.subprocess.PIPE,
2725 universal_newlines=True)
2726 (_, error) = process.communicate(input=contents)
2727 return error or None
2728 except ValueError as e:
2729 return e
agrievef32bcc72016-04-04 14:57:402730
agrievef32bcc72016-04-04 14:57:402731
Sam Maiera6e76d72022-02-11 21:43:502732def CheckParseErrors(input_api, output_api):
2733 """Check that IDL and JSON files do not contain syntax errors."""
2734 actions = {
2735 '.idl': _GetIDLParseError,
2736 '.json': _GetJSONParseError,
2737 }
2738 # Most JSON files are preprocessed and support comments, but these do not.
2739 json_no_comments_patterns = [
2740 r'^testing[\\/]',
2741 ]
2742 # Only run IDL checker on files in these directories.
2743 idl_included_patterns = [
2744 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2745 r'^extensions[\\/]common[\\/]api[\\/]',
2746 ]
agrievef32bcc72016-04-04 14:57:402747
Sam Maiera6e76d72022-02-11 21:43:502748 def get_action(affected_file):
2749 filename = affected_file.LocalPath()
2750 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:402751
Sam Maiera6e76d72022-02-11 21:43:502752 def FilterFile(affected_file):
2753 action = get_action(affected_file)
2754 if not action:
2755 return False
2756 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:402757
Sam Maiera6e76d72022-02-11 21:43:502758 if _MatchesFile(input_api,
2759 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
2760 return False
2761
2762 if (action == _GetIDLParseError
2763 and not _MatchesFile(input_api, idl_included_patterns, path)):
2764 return False
2765 return True
2766
2767 results = []
2768 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
2769 include_deletes=False):
2770 action = get_action(affected_file)
2771 kwargs = {}
2772 if (action == _GetJSONParseError
2773 and _MatchesFile(input_api, json_no_comments_patterns,
2774 affected_file.LocalPath())):
2775 kwargs['eat_comments'] = False
2776 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
2777 **kwargs)
2778 if parse_error:
2779 results.append(
2780 output_api.PresubmitError(
2781 '%s could not be parsed: %s' %
2782 (affected_file.LocalPath(), parse_error)))
2783 return results
2784
2785
2786def CheckJavaStyle(input_api, output_api):
2787 """Runs checkstyle on changed java files and returns errors if any exist."""
2788
2789 # Return early if no java files were modified.
2790 if not any(
2791 _IsJavaFile(input_api, f.LocalPath())
2792 for f in input_api.AffectedFiles()):
2793 return []
2794
2795 import sys
2796 original_sys_path = sys.path
2797 try:
2798 sys.path = sys.path + [
2799 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2800 'android', 'checkstyle')
2801 ]
2802 import checkstyle
2803 finally:
2804 # Restore sys.path to what it was before.
2805 sys.path = original_sys_path
2806
2807 return checkstyle.RunCheckstyle(
2808 input_api,
2809 output_api,
2810 'tools/android/checkstyle/chromium-style-5.0.xml',
2811 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
2812
2813
2814def CheckPythonDevilInit(input_api, output_api):
2815 """Checks to make sure devil is initialized correctly in python scripts."""
2816 script_common_initialize_pattern = input_api.re.compile(
2817 r'script_common\.InitializeEnvironment\(')
2818 devil_env_config_initialize = input_api.re.compile(
2819 r'devil_env\.config\.Initialize\(')
2820
2821 errors = []
2822
2823 sources = lambda affected_file: input_api.FilterSourceFile(
2824 affected_file,
2825 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
2826 r'^build[\\/]android[\\/]devil_chromium\.py',
2827 r'^third_party[\\/].*',
2828 )),
2829 files_to_check=[r'.*\.py$'])
2830
2831 for f in input_api.AffectedSourceFiles(sources):
2832 for line_num, line in f.ChangedContents():
2833 if (script_common_initialize_pattern.search(line)
2834 or devil_env_config_initialize.search(line)):
2835 errors.append("%s:%d" % (f.LocalPath(), line_num))
2836
2837 results = []
2838
2839 if errors:
2840 results.append(
2841 output_api.PresubmitError(
2842 'Devil initialization should always be done using '
2843 'devil_chromium.Initialize() in the chromium project, to use better '
2844 'defaults for dependencies (ex. up-to-date version of adb).',
2845 errors))
2846
2847 return results
2848
2849
2850def _MatchesFile(input_api, patterns, path):
2851 for pattern in patterns:
2852 if input_api.re.search(pattern, path):
2853 return True
2854 return False
2855
2856
Daniel Chenga37c03db2022-05-12 17:20:342857def _ChangeHasSecurityReviewer(input_api, owners_file):
2858 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:502859
Daniel Chenga37c03db2022-05-12 17:20:342860 Args:
2861 input_api: The presubmit input API.
2862 owners_file: OWNERS file with required reviewers. Typically, this is
2863 something like ipc/SECURITY_OWNERS.
2864
2865 Note: if the presubmit is running for commit rather than for upload, this
2866 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:502867 """
Daniel Chengd88244472022-05-16 09:08:472868 # Owners-Override should bypass all additional OWNERS enforcement checks.
2869 # A CR+1 vote will still be required to land this change.
2870 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2871 input_api.change.issue)):
2872 return True
2873
Daniel Chenga37c03db2022-05-12 17:20:342874 owner_email, reviewers = (
2875 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:112876 input_api,
2877 None,
2878 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:502879
Daniel Chenga37c03db2022-05-12 17:20:342880 security_owners = input_api.owners_client.ListOwners(owners_file)
2881 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:502882
Daniel Chenga37c03db2022-05-12 17:20:342883
2884@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:252885class _SecurityProblemWithItems:
2886 problem: str
2887 items: Sequence[str]
2888
2889
2890@dataclass
Daniel Chenga37c03db2022-05-12 17:20:342891class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:252892 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:342893 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:252894 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:342895
2896
2897def _FindMissingSecurityOwners(input_api,
2898 output_api,
2899 file_patterns: Sequence[str],
2900 excluded_patterns: Sequence[str],
2901 required_owners_file: str,
2902 custom_rule_function: Optional[Callable] = None
2903 ) -> _MissingSecurityOwnersResult:
2904 """Find OWNERS files missing per-file rules for security-sensitive files.
2905
2906 Args:
2907 input_api: the PRESUBMIT input API object.
2908 output_api: the PRESUBMIT output API object.
2909 file_patterns: basename patterns that require a corresponding per-file
2910 security restriction.
2911 excluded_patterns: path patterns that should be exempted from
2912 requiring a security restriction.
2913 required_owners_file: path to the required OWNERS file, e.g.
2914 ipc/SECURITY_OWNERS
2915 cc_alias: If not None, email that will be CCed automatically if the
2916 change contains security-sensitive files, as determined by
2917 `file_patterns` and `excluded_patterns`.
2918 custom_rule_function: If not None, will be called with `input_api` and
2919 the current file under consideration. Returning True will add an
2920 exact match per-file rule check for the current file.
2921 """
2922
2923 # `to_check` is a mapping of an OWNERS file path to Patterns.
2924 #
2925 # Patterns is a dictionary mapping glob patterns (suitable for use in
2926 # per-file rules) to a PatternEntry.
2927 #
Sam Maiera6e76d72022-02-11 21:43:502928 # PatternEntry is a dictionary with two keys:
2929 # - 'files': the files that are matched by this pattern
2930 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:342931 #
Sam Maiera6e76d72022-02-11 21:43:502932 # For example, if we expect OWNERS file to contain rules for *.mojom and
2933 # *_struct_traits*.*, Patterns might look like this:
2934 # {
2935 # '*.mojom': {
2936 # 'files': ...,
2937 # 'rules': [
2938 # 'per-file *.mojom=set noparent',
2939 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2940 # ],
2941 # },
2942 # '*_struct_traits*.*': {
2943 # 'files': ...,
2944 # 'rules': [
2945 # 'per-file *_struct_traits*.*=set noparent',
2946 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2947 # ],
2948 # },
2949 # }
2950 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:342951 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:502952
Daniel Chenga37c03db2022-05-12 17:20:342953 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:502954 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:472955 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:502956 if owners_file not in to_check:
2957 to_check[owners_file] = {}
2958 if pattern not in to_check[owners_file]:
2959 to_check[owners_file][pattern] = {
2960 'files': [],
2961 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:342962 f'per-file {pattern}=set noparent',
2963 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:502964 ]
2965 }
Daniel Chenged57a162022-05-25 02:56:342966 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:342967 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:502968
Daniel Chenga37c03db2022-05-12 17:20:342969 # Only enforce security OWNERS rules for a directory if that directory has a
2970 # file that matches `file_patterns`. For example, if a directory only
2971 # contains *.mojom files and no *_messages*.h files, the check should only
2972 # ensure that rules for *.mojom files are present.
2973 for file in input_api.AffectedFiles(include_deletes=False):
2974 file_basename = input_api.os_path.basename(file.LocalPath())
2975 if custom_rule_function is not None and custom_rule_function(
2976 input_api, file):
2977 AddPatternToCheck(file, file_basename)
2978 continue
Sam Maiera6e76d72022-02-11 21:43:502979
Daniel Chenga37c03db2022-05-12 17:20:342980 if any(
2981 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
2982 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:502983 continue
2984
2985 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:342986 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
2987 # file's basename.
2988 if input_api.fnmatch.fnmatch(file_basename, pattern):
2989 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:502990 break
2991
Daniel Chenga37c03db2022-05-12 17:20:342992 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:252993
2994 # Check if any newly added lines in OWNERS files intersect with required
2995 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
2996 # This is a hack, but is needed because the OWNERS check (by design) ignores
2997 # new OWNERS entries; otherwise, a non-owner could add someone as a new
2998 # OWNER and have that newly-added OWNER self-approve their own addition.
2999 newly_covered_files = []
3000 for file in input_api.AffectedFiles(include_deletes=False):
3001 if not file.LocalPath() in to_check:
3002 continue
3003 for _, line in file.ChangedContents():
3004 for _, entry in to_check[file.LocalPath()].items():
3005 if line in entry['rules']:
3006 newly_covered_files.extend(entry['files'])
3007
3008 missing_reviewer_problems = None
3009 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343010 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253011 missing_reviewer_problems = _SecurityProblemWithItems(
3012 f'Review from an owner in {required_owners_file} is required for '
3013 'the following newly-added files:',
3014 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503015
3016 # Go through the OWNERS files to check, filtering out rules that are already
3017 # present in that OWNERS file.
3018 for owners_file, patterns in to_check.items():
3019 try:
Daniel Cheng171dad8d2022-05-21 00:40:253020 lines = set(
3021 input_api.ReadFile(
3022 input_api.os_path.join(input_api.change.RepositoryRoot(),
3023 owners_file)).splitlines())
3024 for entry in patterns.values():
3025 entry['rules'] = [
3026 rule for rule in entry['rules'] if rule not in lines
3027 ]
Sam Maiera6e76d72022-02-11 21:43:503028 except IOError:
3029 # No OWNERS file, so all the rules are definitely missing.
3030 continue
3031
3032 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253033 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343034
Sam Maiera6e76d72022-02-11 21:43:503035 for owners_file, patterns in to_check.items():
3036 missing_lines = []
3037 files = []
3038 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343039 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503040 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503041 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253042 joined_missing_lines = '\n'.join(line for line in missing_lines)
3043 owners_file_problems.append(
3044 _SecurityProblemWithItems(
3045 'Found missing OWNERS lines for security-sensitive files. '
3046 f'Please add the following lines to {owners_file}:\n'
3047 f'{joined_missing_lines}\n\nTo ensure security review for:',
3048 files))
Daniel Chenga37c03db2022-05-12 17:20:343049
Daniel Cheng171dad8d2022-05-21 00:40:253050 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343051 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253052 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343053
3054
3055def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3056 # Whether or not a file affects IPC is (mostly) determined by a simple list
3057 # of filename patterns.
3058 file_patterns = [
3059 # Legacy IPC:
3060 '*_messages.cc',
3061 '*_messages*.h',
3062 '*_param_traits*.*',
3063 # Mojo IPC:
3064 '*.mojom',
3065 '*_mojom_traits*.*',
3066 '*_type_converter*.*',
3067 # Android native IPC:
3068 '*.aidl',
3069 ]
3070
Daniel Chenga37c03db2022-05-12 17:20:343071 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463072 # These third_party directories do not contain IPCs, but contain files
3073 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343074 'third_party/crashpad/*',
3075 'third_party/blink/renderer/platform/bindings/*',
3076 'third_party/protobuf/benchmarks/python/*',
3077 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473078 # Enum-only mojoms used for web metrics, so no security review needed.
3079 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343080 # These files are just used to communicate between class loaders running
3081 # in the same process.
3082 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3083 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3084 ]
3085
3086 def IsMojoServiceManifestFile(input_api, file):
3087 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3088 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3089 if not manifest_pattern.search(file.LocalPath()):
3090 return False
3091
3092 if test_manifest_pattern.search(file.LocalPath()):
3093 return False
3094
3095 # All actual service manifest files should contain at least one
3096 # qualified reference to service_manager::Manifest.
3097 return any('service_manager::Manifest' in line
3098 for line in file.NewContents())
3099
3100 return _FindMissingSecurityOwners(
3101 input_api,
3102 output_api,
3103 file_patterns,
3104 excluded_patterns,
3105 'ipc/SECURITY_OWNERS',
3106 custom_rule_function=IsMojoServiceManifestFile)
3107
3108
3109def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3110 file_patterns = [
3111 # Component specifications.
3112 '*.cml', # Component Framework v2.
3113 '*.cmx', # Component Framework v1.
3114
3115 # Fuchsia IDL protocol specifications.
3116 '*.fidl',
3117 ]
3118
3119 # Don't check for owners files for changes in these directories.
3120 excluded_patterns = [
3121 'third_party/crashpad/*',
3122 ]
3123
3124 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3125 excluded_patterns,
3126 'build/fuchsia/SECURITY_OWNERS')
3127
3128
3129def CheckSecurityOwners(input_api, output_api):
3130 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3131 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3132 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3133 input_api, output_api)
3134
3135 if ipc_results.has_security_sensitive_files:
3136 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503137
3138 results = []
Daniel Chenga37c03db2022-05-12 17:20:343139
Daniel Cheng171dad8d2022-05-21 00:40:253140 missing_reviewer_problems = []
3141 if ipc_results.missing_reviewer_problem:
3142 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3143 if fuchsia_results.missing_reviewer_problem:
3144 missing_reviewer_problems.append(
3145 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343146
Daniel Cheng171dad8d2022-05-21 00:40:253147 # Missing reviewers are an error unless there's no issue number
3148 # associated with this branch; in that case, the presubmit is being run
3149 # with --all or --files.
3150 #
3151 # Note that upload should never be an error; otherwise, it would be
3152 # impossible to upload changes at all.
3153 if input_api.is_committing and input_api.change.issue:
3154 make_presubmit_message = output_api.PresubmitError
3155 else:
3156 make_presubmit_message = output_api.PresubmitNotifyResult
3157 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503158 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253159 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343160
Daniel Cheng171dad8d2022-05-21 00:40:253161 owners_file_problems = []
3162 owners_file_problems.extend(ipc_results.owners_file_problems)
3163 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343164
Daniel Cheng171dad8d2022-05-21 00:40:253165 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113166 # Missing per-file rules are always an error. While swarming and caching
3167 # means that uploading a patchset with updated OWNERS files and sending
3168 # it to the CQ again should not have a large incremental cost, it is
3169 # still frustrating to discover the error only after the change has
3170 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343171 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253172 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503173
3174 return results
3175
3176
3177def _GetFilesUsingSecurityCriticalFunctions(input_api):
3178 """Checks affected files for changes to security-critical calls. This
3179 function checks the full change diff, to catch both additions/changes
3180 and removals.
3181
3182 Returns a dict keyed by file name, and the value is a set of detected
3183 functions.
3184 """
3185 # Map of function pretty name (displayed in an error) to the pattern to
3186 # match it with.
3187 _PATTERNS_TO_CHECK = {
3188 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3189 }
3190 _PATTERNS_TO_CHECK = {
3191 k: input_api.re.compile(v)
3192 for k, v in _PATTERNS_TO_CHECK.items()
3193 }
3194
Sam Maiera6e76d72022-02-11 21:43:503195 # We don't want to trigger on strings within this file.
3196 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343197 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503198
3199 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3200 files_to_functions = {}
3201 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3202 diff = f.GenerateScmDiff()
3203 for line in diff.split('\n'):
3204 # Not using just RightHandSideLines() because removing a
3205 # call to a security-critical function can be just as important
3206 # as adding or changing the arguments.
3207 if line.startswith('-') or (line.startswith('+')
3208 and not line.startswith('++')):
3209 for name, pattern in _PATTERNS_TO_CHECK.items():
3210 if pattern.search(line):
3211 path = f.LocalPath()
3212 if not path in files_to_functions:
3213 files_to_functions[path] = set()
3214 files_to_functions[path].add(name)
3215 return files_to_functions
3216
3217
3218def CheckSecurityChanges(input_api, output_api):
3219 """Checks that changes involving security-critical functions are reviewed
3220 by the security team.
3221 """
3222 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3223 if not len(files_to_functions):
3224 return []
3225
Sam Maiera6e76d72022-02-11 21:43:503226 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343227 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503228 return []
3229
Daniel Chenga37c03db2022-05-12 17:20:343230 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503231 'that need to be reviewed by {}.\n'.format(owners_file)
3232 for path, names in files_to_functions.items():
3233 msg += ' {}\n'.format(path)
3234 for name in names:
3235 msg += ' {}\n'.format(name)
3236 msg += '\n'
3237
3238 if input_api.is_committing:
3239 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033240 else:
Sam Maiera6e76d72022-02-11 21:43:503241 output = output_api.PresubmitNotifyResult
3242 return [output(msg)]
3243
3244
3245def CheckSetNoParent(input_api, output_api):
3246 """Checks that set noparent is only used together with an OWNERS file in
3247 //build/OWNERS.setnoparent (see also
3248 //docs/code_reviews.md#owners-files-details)
3249 """
3250 # Return early if no OWNERS files were modified.
3251 if not any(f.LocalPath().endswith('OWNERS')
3252 for f in input_api.AffectedFiles(include_deletes=False)):
3253 return []
3254
3255 errors = []
3256
3257 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3258 allowed_owners_files = set()
3259 with open(allowed_owners_files_file, 'r') as f:
3260 for line in f:
3261 line = line.strip()
3262 if not line or line.startswith('#'):
3263 continue
3264 allowed_owners_files.add(line)
3265
3266 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3267
3268 for f in input_api.AffectedFiles(include_deletes=False):
3269 if not f.LocalPath().endswith('OWNERS'):
3270 continue
3271
3272 found_owners_files = set()
3273 found_set_noparent_lines = dict()
3274
3275 # Parse the OWNERS file.
3276 for lineno, line in enumerate(f.NewContents(), 1):
3277 line = line.strip()
3278 if line.startswith('set noparent'):
3279 found_set_noparent_lines[''] = lineno
3280 if line.startswith('file://'):
3281 if line in allowed_owners_files:
3282 found_owners_files.add('')
3283 if line.startswith('per-file'):
3284 match = per_file_pattern.match(line)
3285 if match:
3286 glob = match.group(1).strip()
3287 directive = match.group(2).strip()
3288 if directive == 'set noparent':
3289 found_set_noparent_lines[glob] = lineno
3290 if directive.startswith('file://'):
3291 if directive in allowed_owners_files:
3292 found_owners_files.add(glob)
3293
3294 # Check that every set noparent line has a corresponding file:// line
3295 # listed in build/OWNERS.setnoparent. An exception is made for top level
3296 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493297 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3298 if (linux_path.count('/') != 1
3299 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503300 for set_noparent_line in found_set_noparent_lines:
3301 if set_noparent_line in found_owners_files:
3302 continue
3303 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493304 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503305 found_set_noparent_lines[set_noparent_line]))
3306
3307 results = []
3308 if errors:
3309 if input_api.is_committing:
3310 output = output_api.PresubmitError
3311 else:
3312 output = output_api.PresubmitPromptWarning
3313 results.append(
3314 output(
3315 'Found the following "set noparent" restrictions in OWNERS files that '
3316 'do not include owners from build/OWNERS.setnoparent:',
3317 long_text='\n\n'.join(errors)))
3318 return results
3319
3320
3321def CheckUselessForwardDeclarations(input_api, output_api):
3322 """Checks that added or removed lines in non third party affected
3323 header files do not lead to new useless class or struct forward
3324 declaration.
3325 """
3326 results = []
3327 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3328 input_api.re.MULTILINE)
3329 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3330 input_api.re.MULTILINE)
3331 for f in input_api.AffectedFiles(include_deletes=False):
3332 if (f.LocalPath().startswith('third_party')
3333 and not f.LocalPath().startswith('third_party/blink')
3334 and not f.LocalPath().startswith('third_party\\blink')):
3335 continue
3336
3337 if not f.LocalPath().endswith('.h'):
3338 continue
3339
3340 contents = input_api.ReadFile(f)
3341 fwd_decls = input_api.re.findall(class_pattern, contents)
3342 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3343
3344 useless_fwd_decls = []
3345 for decl in fwd_decls:
3346 count = sum(1 for _ in input_api.re.finditer(
3347 r'\b%s\b' % input_api.re.escape(decl), contents))
3348 if count == 1:
3349 useless_fwd_decls.append(decl)
3350
3351 if not useless_fwd_decls:
3352 continue
3353
3354 for line in f.GenerateScmDiff().splitlines():
3355 if (line.startswith('-') and not line.startswith('--')
3356 or line.startswith('+') and not line.startswith('++')):
3357 for decl in useless_fwd_decls:
3358 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3359 results.append(
3360 output_api.PresubmitPromptWarning(
3361 '%s: %s forward declaration is no longer needed'
3362 % (f.LocalPath(), decl)))
3363 useless_fwd_decls.remove(decl)
3364
3365 return results
3366
3367
3368def _CheckAndroidDebuggableBuild(input_api, output_api):
3369 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3370 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3371 this is a debuggable build of Android.
3372 """
3373 build_type_check_pattern = input_api.re.compile(
3374 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3375
3376 errors = []
3377
3378 sources = lambda affected_file: input_api.FilterSourceFile(
3379 affected_file,
3380 files_to_skip=(
3381 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3382 DEFAULT_FILES_TO_SKIP + (
3383 r"^android_webview[\\/]support_library[\\/]"
3384 "boundary_interfaces[\\/]",
3385 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3386 r'^third_party[\\/].*',
3387 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3388 r"webview[\\/]chromium[\\/]License.*",
3389 )),
3390 files_to_check=[r'.*\.java$'])
3391
3392 for f in input_api.AffectedSourceFiles(sources):
3393 for line_num, line in f.ChangedContents():
3394 if build_type_check_pattern.search(line):
3395 errors.append("%s:%d" % (f.LocalPath(), line_num))
3396
3397 results = []
3398
3399 if errors:
3400 results.append(
3401 output_api.PresubmitPromptWarning(
3402 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3403 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3404
3405 return results
3406
3407# TODO: add unit tests
3408def _CheckAndroidToastUsage(input_api, output_api):
3409 """Checks that code uses org.chromium.ui.widget.Toast instead of
3410 android.widget.Toast (Chromium Toast doesn't force hardware
3411 acceleration on low-end devices, saving memory).
3412 """
3413 toast_import_pattern = input_api.re.compile(
3414 r'^import android\.widget\.Toast;$')
3415
3416 errors = []
3417
3418 sources = lambda affected_file: input_api.FilterSourceFile(
3419 affected_file,
3420 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3421 DEFAULT_FILES_TO_SKIP + (r'^chromecast[\\/].*',
3422 r'^remoting[\\/].*')),
3423 files_to_check=[r'.*\.java$'])
3424
3425 for f in input_api.AffectedSourceFiles(sources):
3426 for line_num, line in f.ChangedContents():
3427 if toast_import_pattern.search(line):
3428 errors.append("%s:%d" % (f.LocalPath(), line_num))
3429
3430 results = []
3431
3432 if errors:
3433 results.append(
3434 output_api.PresubmitError(
3435 'android.widget.Toast usage is detected. Android toasts use hardware'
3436 ' acceleration, and can be\ncostly on low-end devices. Please use'
3437 ' org.chromium.ui.widget.Toast instead.\n'
3438 'Contact [email protected] if you have any questions.',
3439 errors))
3440
3441 return results
3442
3443
3444def _CheckAndroidCrLogUsage(input_api, output_api):
3445 """Checks that new logs using org.chromium.base.Log:
3446 - Are using 'TAG' as variable name for the tags (warn)
3447 - Are using a tag that is shorter than 20 characters (error)
3448 """
3449
3450 # Do not check format of logs in the given files
3451 cr_log_check_excluded_paths = [
3452 # //chrome/android/webapk cannot depend on //base
3453 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3454 # WebView license viewer code cannot depend on //base; used in stub APK.
3455 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3456 r"webview[\\/]chromium[\\/]License.*",
3457 # The customtabs_benchmark is a small app that does not depend on Chromium
3458 # java pieces.
3459 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3460 ]
3461
3462 cr_log_import_pattern = input_api.re.compile(
3463 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3464 class_in_base_pattern = input_api.re.compile(
3465 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3466 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3467 input_api.re.MULTILINE)
3468 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3469 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3470 log_decl_pattern = input_api.re.compile(
3471 r'static final String TAG = "(?P<name>(.*))"')
3472 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3473
3474 REF_MSG = ('See docs/android_logging.md for more info.')
3475 sources = lambda x: input_api.FilterSourceFile(
3476 x,
3477 files_to_check=[r'.*\.java$'],
3478 files_to_skip=cr_log_check_excluded_paths)
3479
3480 tag_decl_errors = []
3481 tag_length_errors = []
3482 tag_errors = []
3483 tag_with_dot_errors = []
3484 util_log_errors = []
3485
3486 for f in input_api.AffectedSourceFiles(sources):
3487 file_content = input_api.ReadFile(f)
3488 has_modified_logs = False
3489 # Per line checks
3490 if (cr_log_import_pattern.search(file_content)
3491 or (class_in_base_pattern.search(file_content)
3492 and not has_some_log_import_pattern.search(file_content))):
3493 # Checks to run for files using cr log
3494 for line_num, line in f.ChangedContents():
3495 if rough_log_decl_pattern.search(line):
3496 has_modified_logs = True
3497
3498 # Check if the new line is doing some logging
3499 match = log_call_pattern.search(line)
3500 if match:
3501 has_modified_logs = True
3502
3503 # Make sure it uses "TAG"
3504 if not match.group('tag') == 'TAG':
3505 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3506 else:
3507 # Report non cr Log function calls in changed lines
3508 for line_num, line in f.ChangedContents():
3509 if log_call_pattern.search(line):
3510 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3511
3512 # Per file checks
3513 if has_modified_logs:
3514 # Make sure the tag is using the "cr" prefix and is not too long
3515 match = log_decl_pattern.search(file_content)
3516 tag_name = match.group('name') if match else None
3517 if not tag_name:
3518 tag_decl_errors.append(f.LocalPath())
3519 elif len(tag_name) > 20:
3520 tag_length_errors.append(f.LocalPath())
3521 elif '.' in tag_name:
3522 tag_with_dot_errors.append(f.LocalPath())
3523
3524 results = []
3525 if tag_decl_errors:
3526 results.append(
3527 output_api.PresubmitPromptWarning(
3528 'Please define your tags using the suggested format: .\n'
3529 '"private static final String TAG = "<package tag>".\n'
3530 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3531 tag_decl_errors))
3532
3533 if tag_length_errors:
3534 results.append(
3535 output_api.PresubmitError(
3536 'The tag length is restricted by the system to be at most '
3537 '20 characters.\n' + REF_MSG, tag_length_errors))
3538
3539 if tag_errors:
3540 results.append(
3541 output_api.PresubmitPromptWarning(
3542 'Please use a variable named "TAG" for your log tags.\n' +
3543 REF_MSG, tag_errors))
3544
3545 if util_log_errors:
3546 results.append(
3547 output_api.PresubmitPromptWarning(
3548 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3549 util_log_errors))
3550
3551 if tag_with_dot_errors:
3552 results.append(
3553 output_api.PresubmitPromptWarning(
3554 'Dot in log tags cause them to be elided in crash reports.\n' +
3555 REF_MSG, tag_with_dot_errors))
3556
3557 return results
3558
3559
3560def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3561 """Checks that junit.framework.* is no longer used."""
3562 deprecated_junit_framework_pattern = input_api.re.compile(
3563 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3564 sources = lambda x: input_api.FilterSourceFile(
3565 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3566 errors = []
3567 for f in input_api.AffectedFiles(file_filter=sources):
3568 for line_num, line in f.ChangedContents():
3569 if deprecated_junit_framework_pattern.search(line):
3570 errors.append("%s:%d" % (f.LocalPath(), line_num))
3571
3572 results = []
3573 if errors:
3574 results.append(
3575 output_api.PresubmitError(
3576 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3577 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3578 ' if you have any question.', errors))
3579 return results
3580
3581
3582def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3583 """Checks that if new Java test classes have inheritance.
3584 Either the new test class is JUnit3 test or it is a JUnit4 test class
3585 with a base class, either case is undesirable.
3586 """
3587 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3588
3589 sources = lambda x: input_api.FilterSourceFile(
3590 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3591 errors = []
3592 for f in input_api.AffectedFiles(file_filter=sources):
3593 if not f.OldContents():
3594 class_declaration_start_flag = False
3595 for line_num, line in f.ChangedContents():
3596 if class_declaration_pattern.search(line):
3597 class_declaration_start_flag = True
3598 if class_declaration_start_flag and ' extends ' in line:
3599 errors.append('%s:%d' % (f.LocalPath(), line_num))
3600 if '{' in line:
3601 class_declaration_start_flag = False
3602
3603 results = []
3604 if errors:
3605 results.append(
3606 output_api.PresubmitPromptWarning(
3607 'The newly created files include Test classes that inherits from base'
3608 ' class. Please do not use inheritance in JUnit4 tests or add new'
3609 ' JUnit3 tests. Contact [email protected] if you have any'
3610 ' questions.', errors))
3611 return results
3612
3613
3614def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3615 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3616 deprecated_annotation_import_pattern = input_api.re.compile(
3617 r'^import android\.test\.suitebuilder\.annotation\..*;',
3618 input_api.re.MULTILINE)
3619 sources = lambda x: input_api.FilterSourceFile(
3620 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3621 errors = []
3622 for f in input_api.AffectedFiles(file_filter=sources):
3623 for line_num, line in f.ChangedContents():
3624 if deprecated_annotation_import_pattern.search(line):
3625 errors.append("%s:%d" % (f.LocalPath(), line_num))
3626
3627 results = []
3628 if errors:
3629 results.append(
3630 output_api.PresubmitError(
3631 'Annotations in android.test.suitebuilder.annotation have been'
3632 ' deprecated since API level 24. Please use android.support.test.filters'
3633 ' from //third_party/android_support_test_runner:runner_java instead.'
3634 ' Contact [email protected] if you have any questions.',
3635 errors))
3636 return results
3637
3638
3639def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3640 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:513641 file_filter = lambda f: (f.LocalPath().endswith(
3642 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
3643 LocalPath() or '/res/drawable-ldrtl/'.replace(
3644 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:503645 errors = []
3646 for f in input_api.AffectedFiles(include_deletes=False,
3647 file_filter=file_filter):
3648 errors.append(' %s' % f.LocalPath())
3649
3650 results = []
3651 if errors:
3652 results.append(
3653 output_api.PresubmitError(
3654 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3655 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3656 '/res/drawable-ldrtl/.\n'
3657 'Contact [email protected] if you have questions.', errors))
3658 return results
3659
3660
3661def _CheckAndroidWebkitImports(input_api, output_api):
3662 """Checks that code uses org.chromium.base.Callback instead of
3663 android.webview.ValueCallback except in the WebView glue layer
3664 and WebLayer.
3665 """
3666 valuecallback_import_pattern = input_api.re.compile(
3667 r'^import android\.webkit\.ValueCallback;$')
3668
3669 errors = []
3670
3671 sources = lambda affected_file: input_api.FilterSourceFile(
3672 affected_file,
3673 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3674 DEFAULT_FILES_TO_SKIP + (
3675 r'^android_webview[\\/]glue[\\/].*',
3676 r'^weblayer[\\/].*',
3677 )),
3678 files_to_check=[r'.*\.java$'])
3679
3680 for f in input_api.AffectedSourceFiles(sources):
3681 for line_num, line in f.ChangedContents():
3682 if valuecallback_import_pattern.search(line):
3683 errors.append("%s:%d" % (f.LocalPath(), line_num))
3684
3685 results = []
3686
3687 if errors:
3688 results.append(
3689 output_api.PresubmitError(
3690 'android.webkit.ValueCallback usage is detected outside of the glue'
3691 ' layer. To stay compatible with the support library, android.webkit.*'
3692 ' classes should only be used inside the glue layer and'
3693 ' org.chromium.base.Callback should be used instead.', errors))
3694
3695 return results
3696
3697
3698def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3699 """Checks Android XML styles """
3700
3701 # Return early if no relevant files were modified.
3702 if not any(
3703 _IsXmlOrGrdFile(input_api, f.LocalPath())
3704 for f in input_api.AffectedFiles(include_deletes=False)):
3705 return []
3706
3707 import sys
3708 original_sys_path = sys.path
3709 try:
3710 sys.path = sys.path + [
3711 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3712 'android', 'checkxmlstyle')
3713 ]
3714 import checkxmlstyle
3715 finally:
3716 # Restore sys.path to what it was before.
3717 sys.path = original_sys_path
3718
3719 if is_check_on_upload:
3720 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3721 else:
3722 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3723
3724
3725def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3726 """Checks Android Infobar Deprecation """
3727
3728 import sys
3729 original_sys_path = sys.path
3730 try:
3731 sys.path = sys.path + [
3732 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3733 'android', 'infobar_deprecation')
3734 ]
3735 import infobar_deprecation
3736 finally:
3737 # Restore sys.path to what it was before.
3738 sys.path = original_sys_path
3739
3740 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3741
3742
3743class _PydepsCheckerResult:
3744 def __init__(self, cmd, pydeps_path, process, old_contents):
3745 self._cmd = cmd
3746 self._pydeps_path = pydeps_path
3747 self._process = process
3748 self._old_contents = old_contents
3749
3750 def GetError(self):
3751 """Returns an error message, or None."""
3752 import difflib
3753 if self._process.wait() != 0:
3754 # STDERR should already be printed.
3755 return 'Command failed: ' + self._cmd
3756 new_contents = self._process.stdout.read().splitlines()[2:]
3757 if self._old_contents != new_contents:
3758 diff = '\n'.join(
3759 difflib.context_diff(self._old_contents, new_contents))
3760 return ('File is stale: {}\n'
3761 'Diff (apply to fix):\n'
3762 '{}\n'
3763 'To regenerate, run:\n\n'
3764 ' {}').format(self._pydeps_path, diff, self._cmd)
3765 return None
3766
3767
3768class PydepsChecker:
3769 def __init__(self, input_api, pydeps_files):
3770 self._file_cache = {}
3771 self._input_api = input_api
3772 self._pydeps_files = pydeps_files
3773
3774 def _LoadFile(self, path):
3775 """Returns the list of paths within a .pydeps file relative to //."""
3776 if path not in self._file_cache:
3777 with open(path, encoding='utf-8') as f:
3778 self._file_cache[path] = f.read()
3779 return self._file_cache[path]
3780
3781 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:593782 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:503783 pydeps_data = self._LoadFile(pydeps_path)
3784 uses_gn_paths = '--gn-paths' in pydeps_data
3785 entries = (l for l in pydeps_data.splitlines()
3786 if not l.startswith('#'))
3787 if uses_gn_paths:
3788 # Paths look like: //foo/bar/baz
3789 return (e[2:] for e in entries)
3790 else:
3791 # Paths look like: path/relative/to/file.pydeps
3792 os_path = self._input_api.os_path
3793 pydeps_dir = os_path.dirname(pydeps_path)
3794 return (os_path.normpath(os_path.join(pydeps_dir, e))
3795 for e in entries)
3796
3797 def _CreateFilesToPydepsMap(self):
3798 """Returns a map of local_path -> list_of_pydeps."""
3799 ret = {}
3800 for pydep_local_path in self._pydeps_files:
3801 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3802 ret.setdefault(path, []).append(pydep_local_path)
3803 return ret
3804
3805 def ComputeAffectedPydeps(self):
3806 """Returns an iterable of .pydeps files that might need regenerating."""
3807 affected_pydeps = set()
3808 file_to_pydeps_map = None
3809 for f in self._input_api.AffectedFiles(include_deletes=True):
3810 local_path = f.LocalPath()
3811 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3812 # subrepositories. We can't figure out which files change, so re-check
3813 # all files.
3814 # Changes to print_python_deps.py affect all .pydeps.
3815 if local_path in ('DEPS', 'PRESUBMIT.py'
3816 ) or local_path.endswith('print_python_deps.py'):
3817 return self._pydeps_files
3818 elif local_path.endswith('.pydeps'):
3819 if local_path in self._pydeps_files:
3820 affected_pydeps.add(local_path)
3821 elif local_path.endswith('.py'):
3822 if file_to_pydeps_map is None:
3823 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3824 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3825 return affected_pydeps
3826
3827 def DetermineIfStaleAsync(self, pydeps_path):
3828 """Runs print_python_deps.py to see if the files is stale."""
3829 import os
3830
3831 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3832 if old_pydeps_data:
3833 cmd = old_pydeps_data[1][1:].strip()
3834 if '--output' not in cmd:
3835 cmd += ' --output ' + pydeps_path
3836 old_contents = old_pydeps_data[2:]
3837 else:
3838 # A default cmd that should work in most cases (as long as pydeps filename
3839 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3840 # file is empty/new.
3841 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3842 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3843 old_contents = []
3844 env = dict(os.environ)
3845 env['PYTHONDONTWRITEBYTECODE'] = '1'
3846 process = self._input_api.subprocess.Popen(
3847 cmd + ' --output ""',
3848 shell=True,
3849 env=env,
3850 stdout=self._input_api.subprocess.PIPE,
3851 encoding='utf-8')
3852 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:403853
3854
Tibor Goldschwendt360793f72019-06-25 18:23:493855def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:503856 args = {}
3857 with open('build/config/gclient_args.gni', 'r') as f:
3858 for line in f:
3859 line = line.strip()
3860 if not line or line.startswith('#'):
3861 continue
3862 attribute, value = line.split('=')
3863 args[attribute.strip()] = value.strip()
3864 return args
Tibor Goldschwendt360793f72019-06-25 18:23:493865
3866
Saagar Sanghavifceeaae2020-08-12 16:40:363867def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:503868 """Checks if a .pydeps file needs to be regenerated."""
3869 # This check is for Python dependency lists (.pydeps files), and involves
3870 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3871 # doesn't work on Windows and Mac, so skip it on other platforms.
3872 if not input_api.platform.startswith('linux'):
3873 return []
Erik Staabc734cd7a2021-11-23 03:11:523874
Sam Maiera6e76d72022-02-11 21:43:503875 results = []
3876 # First, check for new / deleted .pydeps.
3877 for f in input_api.AffectedFiles(include_deletes=True):
3878 # Check whether we are running the presubmit check for a file in src.
3879 # f.LocalPath is relative to repo (src, or internal repo).
3880 # os_path.exists is relative to src repo.
3881 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3882 # to src and we can conclude that the pydeps is in src.
3883 if f.LocalPath().endswith('.pydeps'):
3884 if input_api.os_path.exists(f.LocalPath()):
3885 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3886 results.append(
3887 output_api.PresubmitError(
3888 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3889 'remove %s' % f.LocalPath()))
3890 elif f.Action() != 'D' and f.LocalPath(
3891 ) not in _ALL_PYDEPS_FILES:
3892 results.append(
3893 output_api.PresubmitError(
3894 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3895 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403896
Sam Maiera6e76d72022-02-11 21:43:503897 if results:
3898 return results
3899
3900 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
3901 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3902 affected_pydeps = set(checker.ComputeAffectedPydeps())
3903 affected_android_pydeps = affected_pydeps.intersection(
3904 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3905 if affected_android_pydeps and not is_android:
3906 results.append(
3907 output_api.PresubmitPromptOrNotify(
3908 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:593909 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:503910 'run because you are not using an Android checkout. To validate that\n'
3911 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3912 'use the android-internal-presubmit optional trybot.\n'
3913 'Possibly stale pydeps files:\n{}'.format(
3914 '\n'.join(affected_android_pydeps))))
3915
3916 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3917 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
3918 # Process these concurrently, as each one takes 1-2 seconds.
3919 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
3920 for result in pydep_results:
3921 error_msg = result.GetError()
3922 if error_msg:
3923 results.append(output_api.PresubmitError(error_msg))
3924
agrievef32bcc72016-04-04 14:57:403925 return results
3926
agrievef32bcc72016-04-04 14:57:403927
Saagar Sanghavifceeaae2020-08-12 16:40:363928def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503929 """Checks to make sure no header files have |Singleton<|."""
3930
3931 def FileFilter(affected_file):
3932 # It's ok for base/memory/singleton.h to have |Singleton<|.
3933 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
3934 (r"^base[\\/]memory[\\/]singleton\.h$",
3935 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
James Cook24a504192020-07-23 00:08:443936 r"quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:503937 return input_api.FilterSourceFile(affected_file,
3938 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433939
Sam Maiera6e76d72022-02-11 21:43:503940 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
3941 files = []
3942 for f in input_api.AffectedSourceFiles(FileFilter):
3943 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
3944 or f.LocalPath().endswith('.hpp')
3945 or f.LocalPath().endswith('.inl')):
3946 contents = input_api.ReadFile(f)
3947 for line in contents.splitlines(False):
3948 if (not line.lstrip().startswith('//')
3949 and # Strip C++ comment.
3950 pattern.search(line)):
3951 files.append(f)
3952 break
glidere61efad2015-02-18 17:39:433953
Sam Maiera6e76d72022-02-11 21:43:503954 if files:
3955 return [
3956 output_api.PresubmitError(
3957 'Found base::Singleton<T> in the following header files.\n' +
3958 'Please move them to an appropriate source file so that the ' +
3959 'template gets instantiated in a single compilation unit.',
3960 files)
3961 ]
3962 return []
glidere61efad2015-02-18 17:39:433963
3964
[email protected]fd20b902014-05-09 02:14:533965_DEPRECATED_CSS = [
3966 # Values
3967 ( "-webkit-box", "flex" ),
3968 ( "-webkit-inline-box", "inline-flex" ),
3969 ( "-webkit-flex", "flex" ),
3970 ( "-webkit-inline-flex", "inline-flex" ),
3971 ( "-webkit-min-content", "min-content" ),
3972 ( "-webkit-max-content", "max-content" ),
3973
3974 # Properties
3975 ( "-webkit-background-clip", "background-clip" ),
3976 ( "-webkit-background-origin", "background-origin" ),
3977 ( "-webkit-background-size", "background-size" ),
3978 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443979 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533980
3981 # Functions
3982 ( "-webkit-gradient", "gradient" ),
3983 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3984 ( "-webkit-linear-gradient", "linear-gradient" ),
3985 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3986 ( "-webkit-radial-gradient", "radial-gradient" ),
3987 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3988]
3989
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203990
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493991# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363992def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503993 """ Make sure that we don't use deprecated CSS
3994 properties, functions or values. Our external
3995 documentation and iOS CSS for dom distiller
3996 (reader mode) are ignored by the hooks as it
3997 needs to be consumed by WebKit. """
3998 results = []
3999 file_inclusion_pattern = [r".+\.css$"]
4000 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4001 input_api.DEFAULT_FILES_TO_SKIP +
4002 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4003 r"^native_client_sdk"))
4004 file_filter = lambda f: input_api.FilterSourceFile(
4005 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4006 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4007 for line_num, line in fpath.ChangedContents():
4008 for (deprecated_value, value) in _DEPRECATED_CSS:
4009 if deprecated_value in line:
4010 results.append(
4011 output_api.PresubmitError(
4012 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4013 (fpath.LocalPath(), line_num, deprecated_value,
4014 value)))
4015 return results
[email protected]fd20b902014-05-09 02:14:534016
mohan.reddyf21db962014-10-16 12:26:474017
Saagar Sanghavifceeaae2020-08-12 16:40:364018def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504019 bad_files = {}
4020 for f in input_api.AffectedFiles(include_deletes=False):
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
rlanday6802cf632017-05-30 17:48:364025
Sam Maiera6e76d72022-02-11 21:43:504026 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4027 continue
rlanday6802cf632017-05-30 17:48:364028
Sam Maiera6e76d72022-02-11 21:43:504029 relative_includes = [
4030 line for _, line in f.ChangedContents()
4031 if "#include" in line and "../" in line
4032 ]
4033 if not relative_includes:
4034 continue
4035 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364036
Sam Maiera6e76d72022-02-11 21:43:504037 if not bad_files:
4038 return []
rlanday6802cf632017-05-30 17:48:364039
Sam Maiera6e76d72022-02-11 21:43:504040 error_descriptions = []
4041 for file_path, bad_lines in bad_files.items():
4042 error_description = file_path
4043 for line in bad_lines:
4044 error_description += '\n ' + line
4045 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364046
Sam Maiera6e76d72022-02-11 21:43:504047 results = []
4048 results.append(
4049 output_api.PresubmitError(
4050 'You added one or more relative #include paths (including "../").\n'
4051 'These shouldn\'t be used because they can be used to include headers\n'
4052 'from code that\'s not correctly specified as a dependency in the\n'
4053 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364054
Sam Maiera6e76d72022-02-11 21:43:504055 return results
rlanday6802cf632017-05-30 17:48:364056
Takeshi Yoshinoe387aa32017-08-02 13:16:134057
Saagar Sanghavifceeaae2020-08-12 16:40:364058def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504059 """Check that nobody tries to include a cc file. It's a relatively
4060 common error which results in duplicate symbols in object
4061 files. This may not always break the build until someone later gets
4062 very confusing linking errors."""
4063 results = []
4064 for f in input_api.AffectedFiles(include_deletes=False):
4065 # We let third_party code do whatever it wants
4066 if (f.LocalPath().startswith('third_party')
4067 and not f.LocalPath().startswith('third_party/blink')
4068 and not f.LocalPath().startswith('third_party\\blink')):
4069 continue
Daniel Bratell65b033262019-04-23 08:17:064070
Sam Maiera6e76d72022-02-11 21:43:504071 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4072 continue
Daniel Bratell65b033262019-04-23 08:17:064073
Sam Maiera6e76d72022-02-11 21:43:504074 for _, line in f.ChangedContents():
4075 if line.startswith('#include "'):
4076 included_file = line.split('"')[1]
4077 if _IsCPlusPlusFile(input_api, included_file):
4078 # The most common naming for external files with C++ code,
4079 # apart from standard headers, is to call them foo.inc, but
4080 # Chromium sometimes uses foo-inc.cc so allow that as well.
4081 if not included_file.endswith(('.h', '-inc.cc')):
4082 results.append(
4083 output_api.PresubmitError(
4084 'Only header files or .inc files should be included in other\n'
4085 'C++ files. Compiling the contents of a cc file more than once\n'
4086 'will cause duplicate information in the build which may later\n'
4087 'result in strange link_errors.\n' +
4088 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064089
Sam Maiera6e76d72022-02-11 21:43:504090 return results
Daniel Bratell65b033262019-04-23 08:17:064091
4092
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204093def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504094 if not isinstance(key, ast.Str):
4095 return 'Key at line %d must be a string literal' % key.lineno
4096 if not isinstance(value, ast.Dict):
4097 return 'Value at line %d must be a dict' % value.lineno
4098 if len(value.keys) != 1:
4099 return 'Dict at line %d must have single entry' % value.lineno
4100 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4101 return (
4102 'Entry at line %d must have a string literal \'filepath\' as key' %
4103 value.lineno)
4104 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134105
Takeshi Yoshinoe387aa32017-08-02 13:16:134106
Sergey Ulanov4af16052018-11-08 02:41:464107def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504108 if not isinstance(key, ast.Str):
4109 return 'Key at line %d must be a string literal' % key.lineno
4110 if not isinstance(value, ast.List):
4111 return 'Value at line %d must be a list' % value.lineno
4112 for element in value.elts:
4113 if not isinstance(element, ast.Str):
4114 return 'Watchlist elements on line %d is not a string' % key.lineno
4115 if not email_regex.match(element.s):
4116 return ('Watchlist element on line %d doesn\'t look like a valid '
4117 + 'email: %s') % (key.lineno, element.s)
4118 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134119
Takeshi Yoshinoe387aa32017-08-02 13:16:134120
Sergey Ulanov4af16052018-11-08 02:41:464121def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504122 mismatch_template = (
4123 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4124 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134125
Sam Maiera6e76d72022-02-11 21:43:504126 email_regex = input_api.re.compile(
4127 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464128
Sam Maiera6e76d72022-02-11 21:43:504129 ast = input_api.ast
4130 i = 0
4131 last_key = ''
4132 while True:
4133 if i >= len(wd_dict.keys):
4134 if i >= len(w_dict.keys):
4135 return None
4136 return mismatch_template % ('missing',
4137 'line %d' % w_dict.keys[i].lineno)
4138 elif i >= len(w_dict.keys):
4139 return (mismatch_template %
4140 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134141
Sam Maiera6e76d72022-02-11 21:43:504142 wd_key = wd_dict.keys[i]
4143 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134144
Sam Maiera6e76d72022-02-11 21:43:504145 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4146 wd_dict.values[i], ast)
4147 if result is not None:
4148 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134149
Sam Maiera6e76d72022-02-11 21:43:504150 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4151 email_regex)
4152 if result is not None:
4153 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204154
Sam Maiera6e76d72022-02-11 21:43:504155 if wd_key.s != w_key.s:
4156 return mismatch_template % ('%s at line %d' %
4157 (wd_key.s, wd_key.lineno),
4158 '%s at line %d' %
4159 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204160
Sam Maiera6e76d72022-02-11 21:43:504161 if wd_key.s < last_key:
4162 return (
4163 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4164 % (wd_key.lineno, w_key.lineno))
4165 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204166
Sam Maiera6e76d72022-02-11 21:43:504167 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204168
4169
Sergey Ulanov4af16052018-11-08 02:41:464170def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504171 ast = input_api.ast
4172 if not isinstance(expression, ast.Expression):
4173 return 'WATCHLISTS file must contain a valid expression'
4174 dictionary = expression.body
4175 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4176 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204177
Sam Maiera6e76d72022-02-11 21:43:504178 first_key = dictionary.keys[0]
4179 first_value = dictionary.values[0]
4180 second_key = dictionary.keys[1]
4181 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204182
Sam Maiera6e76d72022-02-11 21:43:504183 if (not isinstance(first_key, ast.Str)
4184 or first_key.s != 'WATCHLIST_DEFINITIONS'
4185 or not isinstance(first_value, ast.Dict)):
4186 return ('The first entry of the dict in WATCHLISTS file must be '
4187 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204188
Sam Maiera6e76d72022-02-11 21:43:504189 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4190 or not isinstance(second_value, ast.Dict)):
4191 return ('The second entry of the dict in WATCHLISTS file must be '
4192 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204193
Sam Maiera6e76d72022-02-11 21:43:504194 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134195
4196
Saagar Sanghavifceeaae2020-08-12 16:40:364197def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504198 for f in input_api.AffectedFiles(include_deletes=False):
4199 if f.LocalPath() == 'WATCHLISTS':
4200 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134201
Sam Maiera6e76d72022-02-11 21:43:504202 try:
4203 # First, make sure that it can be evaluated.
4204 input_api.ast.literal_eval(contents)
4205 # Get an AST tree for it and scan the tree for detailed style checking.
4206 expression = input_api.ast.parse(contents,
4207 filename='WATCHLISTS',
4208 mode='eval')
4209 except ValueError as e:
4210 return [
4211 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4212 long_text=repr(e))
4213 ]
4214 except SyntaxError as e:
4215 return [
4216 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4217 long_text=repr(e))
4218 ]
4219 except TypeError as e:
4220 return [
4221 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4222 long_text=repr(e))
4223 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134224
Sam Maiera6e76d72022-02-11 21:43:504225 result = _CheckWATCHLISTSSyntax(expression, input_api)
4226 if result is not None:
4227 return [output_api.PresubmitError(result)]
4228 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134229
Sam Maiera6e76d72022-02-11 21:43:504230 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134231
4232
Andrew Grieve1b290e4a22020-11-24 20:07:014233def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504234 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014235
Sam Maiera6e76d72022-02-11 21:43:504236 As documented at //build/docs/writing_gn_templates.md
4237 """
Andrew Grieve1b290e4a22020-11-24 20:07:014238
Sam Maiera6e76d72022-02-11 21:43:504239 def gn_files(f):
4240 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014241
Sam Maiera6e76d72022-02-11 21:43:504242 problems = []
4243 for f in input_api.AffectedSourceFiles(gn_files):
4244 for line_num, line in f.ChangedContents():
4245 if 'forward_variables_from(invoker, "*")' in line:
4246 problems.append(
4247 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4248 (f.LocalPath(), line_num))
4249
4250 if problems:
4251 return [
4252 output_api.PresubmitPromptWarning(
4253 'forward_variables_from("*") without exclusions',
4254 items=sorted(problems),
4255 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594256 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504257 'explicitly listed in forward_variables_from(). For more '
4258 'details, see:\n'
4259 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4260 'build/docs/writing_gn_templates.md'
4261 '#Using-forward_variables_from'))
4262 ]
4263 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014264
4265
Saagar Sanghavifceeaae2020-08-12 16:40:364266def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504267 """Checks that newly added header files have corresponding GN changes.
4268 Note that this is only a heuristic. To be precise, run script:
4269 build/check_gn_headers.py.
4270 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194271
Sam Maiera6e76d72022-02-11 21:43:504272 def headers(f):
4273 return input_api.FilterSourceFile(
4274 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194275
Sam Maiera6e76d72022-02-11 21:43:504276 new_headers = []
4277 for f in input_api.AffectedSourceFiles(headers):
4278 if f.Action() != 'A':
4279 continue
4280 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194281
Sam Maiera6e76d72022-02-11 21:43:504282 def gn_files(f):
4283 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194284
Sam Maiera6e76d72022-02-11 21:43:504285 all_gn_changed_contents = ''
4286 for f in input_api.AffectedSourceFiles(gn_files):
4287 for _, line in f.ChangedContents():
4288 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194289
Sam Maiera6e76d72022-02-11 21:43:504290 problems = []
4291 for header in new_headers:
4292 basename = input_api.os_path.basename(header)
4293 if basename not in all_gn_changed_contents:
4294 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194295
Sam Maiera6e76d72022-02-11 21:43:504296 if problems:
4297 return [
4298 output_api.PresubmitPromptWarning(
4299 'Missing GN changes for new header files',
4300 items=sorted(problems),
4301 long_text=
4302 'Please double check whether newly added header files need '
4303 'corresponding changes in gn or gni files.\nThis checking is only a '
4304 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4305 'Read https://crbug.com/661774 for more info.')
4306 ]
4307 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194308
4309
Saagar Sanghavifceeaae2020-08-12 16:40:364310def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504311 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024312
Sam Maiera6e76d72022-02-11 21:43:504313 This assumes we won't intentionally reference one product from the other
4314 product.
4315 """
4316 all_problems = []
4317 test_cases = [{
4318 "filename_postfix": "google_chrome_strings.grd",
4319 "correct_name": "Chrome",
4320 "incorrect_name": "Chromium",
4321 }, {
4322 "filename_postfix": "chromium_strings.grd",
4323 "correct_name": "Chromium",
4324 "incorrect_name": "Chrome",
4325 }]
Michael Giuffridad3bc8672018-10-25 22:48:024326
Sam Maiera6e76d72022-02-11 21:43:504327 for test_case in test_cases:
4328 problems = []
4329 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4330 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024331
Sam Maiera6e76d72022-02-11 21:43:504332 # Check each new line. Can yield false positives in multiline comments, but
4333 # easier than trying to parse the XML because messages can have nested
4334 # children, and associating message elements with affected lines is hard.
4335 for f in input_api.AffectedSourceFiles(filename_filter):
4336 for line_num, line in f.ChangedContents():
4337 if "<message" in line or "<!--" in line or "-->" in line:
4338 continue
4339 if test_case["incorrect_name"] in line:
4340 problems.append("Incorrect product name in %s:%d" %
4341 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024342
Sam Maiera6e76d72022-02-11 21:43:504343 if problems:
4344 message = (
4345 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4346 % (test_case["correct_name"], test_case["correct_name"],
4347 test_case["incorrect_name"]))
4348 all_problems.append(
4349 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024350
Sam Maiera6e76d72022-02-11 21:43:504351 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024352
4353
Saagar Sanghavifceeaae2020-08-12 16:40:364354def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504355 """Avoid large files, especially binary files, in the repository since
4356 git doesn't scale well for those. They will be in everyone's repo
4357 clones forever, forever making Chromium slower to clone and work
4358 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364359
Sam Maiera6e76d72022-02-11 21:43:504360 # Uploading files to cloud storage is not trivial so we don't want
4361 # to set the limit too low, but the upper limit for "normal" large
4362 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4363 # anything over 20 MB is exceptional.
4364 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364365
Sam Maiera6e76d72022-02-11 21:43:504366 too_large_files = []
4367 for f in input_api.AffectedFiles():
4368 # Check both added and modified files (but not deleted files).
4369 if f.Action() in ('A', 'M'):
4370 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4371 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4372 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364373
Sam Maiera6e76d72022-02-11 21:43:504374 if too_large_files:
4375 message = (
4376 'Do not commit large files to git since git scales badly for those.\n'
4377 +
4378 'Instead put the large files in cloud storage and use DEPS to\n' +
4379 'fetch them.\n' + '\n'.join(too_large_files))
4380 return [
4381 output_api.PresubmitError('Too large files found in commit',
4382 long_text=message + '\n')
4383 ]
4384 else:
4385 return []
Daniel Bratell93eb6c62019-04-29 20:13:364386
Max Morozb47503b2019-08-08 21:03:274387
Saagar Sanghavifceeaae2020-08-12 16:40:364388def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504389 """Checks specific for fuzz target sources."""
4390 EXPORTED_SYMBOLS = [
4391 'LLVMFuzzerInitialize',
4392 'LLVMFuzzerCustomMutator',
4393 'LLVMFuzzerCustomCrossOver',
4394 'LLVMFuzzerMutate',
4395 ]
Max Morozb47503b2019-08-08 21:03:274396
Sam Maiera6e76d72022-02-11 21:43:504397 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274398
Sam Maiera6e76d72022-02-11 21:43:504399 def FilterFile(affected_file):
4400 """Ignore libFuzzer source code."""
4401 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4402 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274403
Sam Maiera6e76d72022-02-11 21:43:504404 return input_api.FilterSourceFile(affected_file,
4405 files_to_check=[files_to_check],
4406 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274407
Sam Maiera6e76d72022-02-11 21:43:504408 files_with_missing_header = []
4409 for f in input_api.AffectedSourceFiles(FilterFile):
4410 contents = input_api.ReadFile(f, 'r')
4411 if REQUIRED_HEADER in contents:
4412 continue
Max Morozb47503b2019-08-08 21:03:274413
Sam Maiera6e76d72022-02-11 21:43:504414 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4415 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274416
Sam Maiera6e76d72022-02-11 21:43:504417 if not files_with_missing_header:
4418 return []
Max Morozb47503b2019-08-08 21:03:274419
Sam Maiera6e76d72022-02-11 21:43:504420 long_text = (
4421 'If you define any of the libFuzzer optional functions (%s), it is '
4422 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4423 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4424 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4425 'to access command line arguments passed to the fuzzer. Instead, prefer '
4426 'static initialization and shared resources as documented in '
4427 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4428 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4429 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274430
Sam Maiera6e76d72022-02-11 21:43:504431 return [
4432 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4433 REQUIRED_HEADER,
4434 items=files_with_missing_header,
4435 long_text=long_text)
4436 ]
Max Morozb47503b2019-08-08 21:03:274437
4438
Mohamed Heikald048240a2019-11-12 16:57:374439def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504440 """
4441 Warns authors who add images into the repo to make sure their images are
4442 optimized before committing.
4443 """
4444 images_added = False
4445 image_paths = []
4446 errors = []
4447 filter_lambda = lambda x: input_api.FilterSourceFile(
4448 x,
4449 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4450 DEFAULT_FILES_TO_SKIP),
4451 files_to_check=[r'.*\/(drawable|mipmap)'])
4452 for f in input_api.AffectedFiles(include_deletes=False,
4453 file_filter=filter_lambda):
4454 local_path = f.LocalPath().lower()
4455 if any(
4456 local_path.endswith(extension)
4457 for extension in _IMAGE_EXTENSIONS):
4458 images_added = True
4459 image_paths.append(f)
4460 if images_added:
4461 errors.append(
4462 output_api.PresubmitPromptWarning(
4463 'It looks like you are trying to commit some images. If these are '
4464 'non-test-only images, please make sure to read and apply the tips in '
4465 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4466 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4467 'FYI only and will not block your CL on the CQ.', image_paths))
4468 return errors
Mohamed Heikald048240a2019-11-12 16:57:374469
4470
Saagar Sanghavifceeaae2020-08-12 16:40:364471def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504472 """Groups upload checks that target android code."""
4473 results = []
4474 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4475 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4476 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4477 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4478 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4479 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4480 input_api, output_api))
4481 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4482 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4483 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4484 results.extend(_CheckNewImagesWarning(input_api, output_api))
4485 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4486 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4487 return results
4488
Becky Zhou7c69b50992018-12-10 19:37:574489
Saagar Sanghavifceeaae2020-08-12 16:40:364490def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504491 """Groups commit checks that target android code."""
4492 results = []
4493 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4494 return results
dgnaa68d5e2015-06-10 10:08:224495
Chris Hall59f8d0c72020-05-01 07:31:194496# TODO(chrishall): could we additionally match on any path owned by
4497# ui/accessibility/OWNERS ?
4498_ACCESSIBILITY_PATHS = (
4499 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4500 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4501 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4502 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4503 r"^content[\\/]browser[\\/]accessibility[\\/]",
4504 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4505 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4506 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4507 r"^ui[\\/]accessibility[\\/]",
4508 r"^ui[\\/]views[\\/]accessibility[\\/]",
4509)
4510
Saagar Sanghavifceeaae2020-08-12 16:40:364511def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504512 """Checks that commits to accessibility code contain an AX-Relnotes field in
4513 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194514
Sam Maiera6e76d72022-02-11 21:43:504515 def FileFilter(affected_file):
4516 paths = _ACCESSIBILITY_PATHS
4517 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194518
Sam Maiera6e76d72022-02-11 21:43:504519 # Only consider changes affecting accessibility paths.
4520 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4521 return []
Akihiro Ota08108e542020-05-20 15:30:534522
Sam Maiera6e76d72022-02-11 21:43:504523 # AX-Relnotes can appear in either the description or the footer.
4524 # When searching the description, require 'AX-Relnotes:' to appear at the
4525 # beginning of a line.
4526 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4527 description_has_relnotes = any(
4528 ax_regex.match(line)
4529 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194530
Sam Maiera6e76d72022-02-11 21:43:504531 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4532 'AX-Relnotes', [])
4533 if description_has_relnotes or footer_relnotes:
4534 return []
Chris Hall59f8d0c72020-05-01 07:31:194535
Sam Maiera6e76d72022-02-11 21:43:504536 # TODO(chrishall): link to Relnotes documentation in message.
4537 message = (
4538 "Missing 'AX-Relnotes:' field required for accessibility changes"
4539 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4540 "user-facing changes"
4541 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4542 "user-facing effects"
4543 "\n if this is confusing or annoying then please contact members "
4544 "of ui/accessibility/OWNERS.")
4545
4546 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224547
Mark Schillacie5a0be22022-01-19 00:38:394548
4549_ACCESSIBILITY_EVENTS_TEST_PATH = (
4550 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]event[\\/].*\.html",
4551)
4552
4553_ACCESSIBILITY_TREE_TEST_PATH = (
4554 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]accname[\\/].*\.html",
4555 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]aria[\\/].*\.html",
4556 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]css[\\/].*\.html",
4557 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]html[\\/].*\.html",
4558)
4559
4560_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
4561 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4562)
4563
4564_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Mark Schillaci6f568a52022-02-17 18:41:444565 r"^.*[\\/]WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394566)
4567
4568def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504569 """Checks that commits that include a newly added, renamed/moved, or deleted
4570 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4571 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394572
Sam Maiera6e76d72022-02-11 21:43:504573 def FilePathFilter(affected_file):
4574 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4575 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394576
Sam Maiera6e76d72022-02-11 21:43:504577 def AndroidFilePathFilter(affected_file):
4578 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4579 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394580
Sam Maiera6e76d72022-02-11 21:43:504581 # Only consider changes in the events test data path with html type.
4582 if not any(
4583 input_api.AffectedFiles(include_deletes=True,
4584 file_filter=FilePathFilter)):
4585 return []
Mark Schillacie5a0be22022-01-19 00:38:394586
Sam Maiera6e76d72022-02-11 21:43:504587 # If the commit contains any change to the Android test file, ignore.
4588 if any(
4589 input_api.AffectedFiles(include_deletes=True,
4590 file_filter=AndroidFilePathFilter)):
4591 return []
Mark Schillacie5a0be22022-01-19 00:38:394592
Sam Maiera6e76d72022-02-11 21:43:504593 # Only consider changes that are adding/renaming or deleting a file
4594 message = []
4595 for f in input_api.AffectedFiles(include_deletes=True,
4596 file_filter=FilePathFilter):
4597 if f.Action() == 'A' or f.Action() == 'D':
4598 message = (
4599 "It appears that you are adding, renaming or deleting"
4600 "\na dump_accessibility_events* test, but have not included"
4601 "\na corresponding change for Android."
4602 "\nPlease include (or remove) the test from:"
4603 "\n content/public/android/javatests/src/org/chromium/"
4604 "content/browser/accessibility/"
4605 "WebContentsAccessibilityEventsTest.java"
4606 "\nIf this message is confusing or annoying, please contact"
4607 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394608
Sam Maiera6e76d72022-02-11 21:43:504609 # If no message was set, return empty.
4610 if not len(message):
4611 return []
4612
4613 return [output_api.PresubmitPromptWarning(message)]
4614
Mark Schillacie5a0be22022-01-19 00:38:394615
4616def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504617 """Checks that commits that include a newly added, renamed/moved, or deleted
4618 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4619 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394620
Sam Maiera6e76d72022-02-11 21:43:504621 def FilePathFilter(affected_file):
4622 paths = _ACCESSIBILITY_TREE_TEST_PATH
4623 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394624
Sam Maiera6e76d72022-02-11 21:43:504625 def AndroidFilePathFilter(affected_file):
4626 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4627 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394628
Sam Maiera6e76d72022-02-11 21:43:504629 # Only consider changes in the various tree test data paths with html type.
4630 if not any(
4631 input_api.AffectedFiles(include_deletes=True,
4632 file_filter=FilePathFilter)):
4633 return []
Mark Schillacie5a0be22022-01-19 00:38:394634
Sam Maiera6e76d72022-02-11 21:43:504635 # If the commit contains any change to the Android test file, ignore.
4636 if any(
4637 input_api.AffectedFiles(include_deletes=True,
4638 file_filter=AndroidFilePathFilter)):
4639 return []
Mark Schillacie5a0be22022-01-19 00:38:394640
Sam Maiera6e76d72022-02-11 21:43:504641 # Only consider changes that are adding/renaming or deleting a file
4642 message = []
4643 for f in input_api.AffectedFiles(include_deletes=True,
4644 file_filter=FilePathFilter):
4645 if f.Action() == 'A' or f.Action() == 'D':
4646 message = (
4647 "It appears that you are adding, renaming or deleting"
4648 "\na dump_accessibility_tree* test, but have not included"
4649 "\na corresponding change for Android."
4650 "\nPlease include (or remove) the test from:"
4651 "\n content/public/android/javatests/src/org/chromium/"
4652 "content/browser/accessibility/"
4653 "WebContentsAccessibilityTreeTest.java"
4654 "\nIf this message is confusing or annoying, please contact"
4655 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394656
Sam Maiera6e76d72022-02-11 21:43:504657 # If no message was set, return empty.
4658 if not len(message):
4659 return []
4660
4661 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394662
4663
seanmccullough4a9356252021-04-08 19:54:094664# string pattern, sequence of strings to show when pattern matches,
4665# error flag. True if match is a presubmit error, otherwise it's a warning.
4666_NON_INCLUSIVE_TERMS = (
4667 (
4668 # Note that \b pattern in python re is pretty particular. In this
4669 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4670 # ...' will not. This may require some tweaking to catch these cases
4671 # without triggering a lot of false positives. Leaving it naive and
4672 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324673 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094674 (
4675 'Please don\'t use blacklist, whitelist, ' # nocheck
4676 'or slave in your', # nocheck
4677 'code and make every effort to use other terms. Using "// nocheck"',
4678 '"# nocheck" or "<!-- nocheck -->"',
4679 'at the end of the offending line will bypass this PRESUBMIT error',
4680 'but avoid using this whenever possible. Reach out to',
4681 '[email protected] if you have questions'),
4682 True),)
4683
Saagar Sanghavifceeaae2020-08-12 16:40:364684def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504685 """Checks common to both upload and commit."""
4686 results = []
Eric Boren6fd2b932018-01-25 15:05:084687 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504688 input_api.canned_checks.PanProjectChecks(
4689 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084690
Sam Maiera6e76d72022-02-11 21:43:504691 author = input_api.change.author_email
4692 if author and author not in _KNOWN_ROBOTS:
4693 results.extend(
4694 input_api.canned_checks.CheckAuthorizedAuthor(
4695 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244696
Sam Maiera6e76d72022-02-11 21:43:504697 results.extend(
4698 input_api.canned_checks.CheckChangeHasNoTabs(
4699 input_api,
4700 output_api,
4701 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
4702 results.extend(
4703 input_api.RunTests(
4704 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:174705
Bruce Dawsonc8054482022-03-28 15:33:374706 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:504707 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:374708 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:504709 results.extend(
4710 input_api.RunTests(
4711 input_api.canned_checks.CheckDirMetadataFormat(
4712 input_api, output_api, dirmd_bin)))
4713 results.extend(
4714 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4715 input_api, output_api))
4716 results.extend(
4717 input_api.canned_checks.CheckNoNewMetadataInOwners(
4718 input_api, output_api))
4719 results.extend(
4720 input_api.canned_checks.CheckInclusiveLanguage(
4721 input_api,
4722 output_api,
4723 excluded_directories_relative_path=[
4724 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
4725 ],
4726 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:594727
Aleksey Khoroshilov2978c942022-06-13 16:14:124728 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
4729 f, files_to_check=[r'PRESUBMIT\.py$'])
4730 for f in input_api.AffectedFiles(include_deletes=False,
4731 file_filter=presubmit_py_filter):
4732 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
4733 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
4734 # The PRESUBMIT.py file (and the directory containing it) might have
4735 # been affected by being moved or removed, so only try to run the tests
4736 # if they still exist.
4737 if not input_api.os_path.exists(test_file):
4738 continue
Sam Maiera6e76d72022-02-11 21:43:504739
Aleksey Khoroshilov2978c942022-06-13 16:14:124740 use_python3 = False
4741 with open(f.LocalPath()) as fp:
4742 use_python3 = any(
4743 line.startswith('USE_PYTHON3 = True')
4744 for line in fp.readlines())
4745
4746 results.extend(
4747 input_api.canned_checks.RunUnitTestsInDirectory(
4748 input_api,
4749 output_api,
4750 full_path,
4751 files_to_check=[r'^PRESUBMIT_test\.py$'],
4752 run_on_python2=not use_python3,
4753 run_on_python3=use_python3,
4754 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:504755 return results
[email protected]1f7b4172010-01-28 01:17:344756
[email protected]b337cb5b2011-01-23 21:24:054757
Saagar Sanghavifceeaae2020-08-12 16:40:364758def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504759 problems = [
4760 f.LocalPath() for f in input_api.AffectedFiles()
4761 if f.LocalPath().endswith(('.orig', '.rej'))
4762 ]
4763 # Cargo.toml.orig files are part of third-party crates downloaded from
4764 # crates.io and should be included.
4765 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
4766 if problems:
4767 return [
4768 output_api.PresubmitError("Don't commit .rej and .orig files.",
4769 problems)
4770 ]
4771 else:
4772 return []
[email protected]b8079ae4a2012-12-05 19:56:494773
4774
Saagar Sanghavifceeaae2020-08-12 16:40:364775def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504776 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4777 macro_re = input_api.re.compile(
4778 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
4779 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
4780 input_api.re.MULTILINE)
4781 extension_re = input_api.re.compile(r'\.[a-z]+$')
4782 errors = []
Bruce Dawsonf7679202022-08-09 20:24:004783 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:504784 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:004785 # The build-config macros are allowed to be used in build_config.h
4786 # without including itself.
4787 if f.LocalPath() == config_h_file:
4788 continue
Sam Maiera6e76d72022-02-11 21:43:504789 if not f.LocalPath().endswith(
4790 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4791 continue
4792 found_line_number = None
4793 found_macro = None
4794 all_lines = input_api.ReadFile(f, 'r').splitlines()
4795 for line_num, line in enumerate(all_lines):
4796 match = macro_re.search(line)
4797 if match:
4798 found_line_number = line_num
4799 found_macro = match.group(2)
4800 break
4801 if not found_line_number:
4802 continue
Kent Tamura5a8755d2017-06-29 23:37:074803
Sam Maiera6e76d72022-02-11 21:43:504804 found_include_line = -1
4805 for line_num, line in enumerate(all_lines):
4806 if include_re.search(line):
4807 found_include_line = line_num
4808 break
4809 if found_include_line >= 0 and found_include_line < found_line_number:
4810 continue
Kent Tamura5a8755d2017-06-29 23:37:074811
Sam Maiera6e76d72022-02-11 21:43:504812 if not f.LocalPath().endswith('.h'):
4813 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4814 try:
4815 content = input_api.ReadFile(primary_header_path, 'r')
4816 if include_re.search(content):
4817 continue
4818 except IOError:
4819 pass
4820 errors.append('%s:%d %s macro is used without first including build/'
4821 'build_config.h.' %
4822 (f.LocalPath(), found_line_number, found_macro))
4823 if errors:
4824 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4825 return []
Kent Tamura5a8755d2017-06-29 23:37:074826
4827
Lei Zhang1c12a22f2021-05-12 11:28:454828def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504829 stl_include_re = input_api.re.compile(r'^#include\s+<('
4830 r'algorithm|'
4831 r'array|'
4832 r'limits|'
4833 r'list|'
4834 r'map|'
4835 r'memory|'
4836 r'queue|'
4837 r'set|'
4838 r'string|'
4839 r'unordered_map|'
4840 r'unordered_set|'
4841 r'utility|'
4842 r'vector)>')
4843 std_namespace_re = input_api.re.compile(r'std::')
4844 errors = []
4845 for f in input_api.AffectedFiles():
4846 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4847 continue
Lei Zhang1c12a22f2021-05-12 11:28:454848
Sam Maiera6e76d72022-02-11 21:43:504849 uses_std_namespace = False
4850 has_stl_include = False
4851 for line in f.NewContents():
4852 if has_stl_include and uses_std_namespace:
4853 break
Lei Zhang1c12a22f2021-05-12 11:28:454854
Sam Maiera6e76d72022-02-11 21:43:504855 if not has_stl_include and stl_include_re.search(line):
4856 has_stl_include = True
4857 continue
Lei Zhang1c12a22f2021-05-12 11:28:454858
Bruce Dawson4a5579a2022-04-08 17:11:364859 if not uses_std_namespace and (std_namespace_re.search(line)
4860 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504861 uses_std_namespace = True
4862 continue
Lei Zhang1c12a22f2021-05-12 11:28:454863
Sam Maiera6e76d72022-02-11 21:43:504864 if has_stl_include and not uses_std_namespace:
4865 errors.append(
4866 '%s: Includes STL header(s) but does not reference std::' %
4867 f.LocalPath())
4868 if errors:
4869 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4870 return []
Lei Zhang1c12a22f2021-05-12 11:28:454871
4872
Xiaohan Wang42d96c22022-01-20 17:23:114873def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504874 """Check for sensible looking, totally invalid OS macros."""
4875 preprocessor_statement = input_api.re.compile(r'^\s*#')
4876 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
4877 results = []
4878 for lnum, line in f.ChangedContents():
4879 if preprocessor_statement.search(line):
4880 for match in os_macro.finditer(line):
4881 results.append(
4882 ' %s:%d: %s' %
4883 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
4884 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
4885 return results
[email protected]b00342e7f2013-03-26 16:21:544886
4887
Xiaohan Wang42d96c22022-01-20 17:23:114888def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504889 """Check all affected files for invalid OS macros."""
4890 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:004891 # The OS_ macros are allowed to be used in build/build_config.h.
4892 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:504893 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:004894 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
4895 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:504896 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:544897
Sam Maiera6e76d72022-02-11 21:43:504898 if not bad_macros:
4899 return []
[email protected]b00342e7f2013-03-26 16:21:544900
Sam Maiera6e76d72022-02-11 21:43:504901 return [
4902 output_api.PresubmitError(
4903 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
4904 'defined in build_config.h):', bad_macros)
4905 ]
[email protected]b00342e7f2013-03-26 16:21:544906
lliabraa35bab3932014-10-01 12:16:444907
4908def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504909 """Check all affected files for invalid "if defined" macros."""
4910 ALWAYS_DEFINED_MACROS = (
4911 "TARGET_CPU_PPC",
4912 "TARGET_CPU_PPC64",
4913 "TARGET_CPU_68K",
4914 "TARGET_CPU_X86",
4915 "TARGET_CPU_ARM",
4916 "TARGET_CPU_MIPS",
4917 "TARGET_CPU_SPARC",
4918 "TARGET_CPU_ALPHA",
4919 "TARGET_IPHONE_SIMULATOR",
4920 "TARGET_OS_EMBEDDED",
4921 "TARGET_OS_IPHONE",
4922 "TARGET_OS_MAC",
4923 "TARGET_OS_UNIX",
4924 "TARGET_OS_WIN32",
4925 )
4926 ifdef_macro = input_api.re.compile(
4927 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4928 results = []
4929 for lnum, line in f.ChangedContents():
4930 for match in ifdef_macro.finditer(line):
4931 if match.group(1) in ALWAYS_DEFINED_MACROS:
4932 always_defined = ' %s is always defined. ' % match.group(1)
4933 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4934 results.append(
4935 ' %s:%d %s\n\t%s' %
4936 (f.LocalPath(), lnum, always_defined, did_you_mean))
4937 return results
lliabraa35bab3932014-10-01 12:16:444938
4939
Saagar Sanghavifceeaae2020-08-12 16:40:364940def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504941 """Check all affected files for invalid "if defined" macros."""
4942 bad_macros = []
4943 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
4944 for f in input_api.AffectedFiles():
4945 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
4946 continue
4947 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4948 bad_macros.extend(
4949 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:444950
Sam Maiera6e76d72022-02-11 21:43:504951 if not bad_macros:
4952 return []
lliabraa35bab3932014-10-01 12:16:444953
Sam Maiera6e76d72022-02-11 21:43:504954 return [
4955 output_api.PresubmitError(
4956 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4957 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4958 bad_macros)
4959 ]
lliabraa35bab3932014-10-01 12:16:444960
4961
Saagar Sanghavifceeaae2020-08-12 16:40:364962def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504963 """Check for same IPC rules described in
4964 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4965 """
4966 base_pattern = r'IPC_ENUM_TRAITS\('
4967 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4968 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:044969
Sam Maiera6e76d72022-02-11 21:43:504970 problems = []
4971 for f in input_api.AffectedSourceFiles(None):
4972 local_path = f.LocalPath()
4973 if not local_path.endswith('.h'):
4974 continue
4975 for line_number, line in f.ChangedContents():
4976 if inclusion_pattern.search(
4977 line) and not comment_pattern.search(line):
4978 problems.append('%s:%d\n %s' %
4979 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:044980
Sam Maiera6e76d72022-02-11 21:43:504981 if problems:
4982 return [
4983 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
4984 problems)
4985 ]
4986 else:
4987 return []
mlamouria82272622014-09-16 18:45:044988
[email protected]b00342e7f2013-03-26 16:21:544989
Saagar Sanghavifceeaae2020-08-12 16:40:364990def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504991 """Check to make sure no files being submitted have long paths.
4992 This causes issues on Windows.
4993 """
4994 problems = []
4995 for f in input_api.AffectedTestableFiles():
4996 local_path = f.LocalPath()
4997 # Windows has a path limit of 260 characters. Limit path length to 200 so
4998 # that we have some extra for the prefix on dev machines and the bots.
4999 if len(local_path) > 200:
5000 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055001
Sam Maiera6e76d72022-02-11 21:43:505002 if problems:
5003 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5004 else:
5005 return []
Stephen Martinis97a394142018-06-07 23:06:055006
5007
Saagar Sanghavifceeaae2020-08-12 16:40:365008def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505009 """Check that header files have proper guards against multiple inclusion.
5010 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365011 should include the string "no-include-guard-because-multiply-included" or
5012 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505013 """
Daniel Bratell8ba52722018-03-02 16:06:145014
Sam Maiera6e76d72022-02-11 21:43:505015 def is_chromium_header_file(f):
5016 # We only check header files under the control of the Chromium
5017 # project. That is, those outside third_party apart from
5018 # third_party/blink.
5019 # We also exclude *_message_generator.h headers as they use
5020 # include guards in a special, non-typical way.
5021 file_with_path = input_api.os_path.normpath(f.LocalPath())
5022 return (file_with_path.endswith('.h')
5023 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335024 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505025 and (not file_with_path.startswith('third_party')
5026 or file_with_path.startswith(
5027 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145028
Sam Maiera6e76d72022-02-11 21:43:505029 def replace_special_with_underscore(string):
5030 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145031
Sam Maiera6e76d72022-02-11 21:43:505032 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145033
Sam Maiera6e76d72022-02-11 21:43:505034 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5035 guard_name = None
5036 guard_line_number = None
5037 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145038
Sam Maiera6e76d72022-02-11 21:43:505039 file_with_path = input_api.os_path.normpath(f.LocalPath())
5040 base_file_name = input_api.os_path.splitext(
5041 input_api.os_path.basename(file_with_path))[0]
5042 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145043
Sam Maiera6e76d72022-02-11 21:43:505044 expected_guard = replace_special_with_underscore(
5045 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145046
Sam Maiera6e76d72022-02-11 21:43:505047 # For "path/elem/file_name.h" we should really only accept
5048 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5049 # are too many (1000+) files with slight deviations from the
5050 # coding style. The most important part is that the include guard
5051 # is there, and that it's unique, not the name so this check is
5052 # forgiving for existing files.
5053 #
5054 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145055
Sam Maiera6e76d72022-02-11 21:43:505056 guard_name_pattern_list = [
5057 # Anything with the right suffix (maybe with an extra _).
5058 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145059
Sam Maiera6e76d72022-02-11 21:43:505060 # To cover include guards with old Blink style.
5061 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145062
Sam Maiera6e76d72022-02-11 21:43:505063 # Anything including the uppercase name of the file.
5064 r'\w*' + input_api.re.escape(
5065 replace_special_with_underscore(upper_base_file_name)) +
5066 r'\w*',
5067 ]
5068 guard_name_pattern = '|'.join(guard_name_pattern_list)
5069 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5070 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145071
Sam Maiera6e76d72022-02-11 21:43:505072 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365073 if ('no-include-guard-because-multiply-included' in line
5074 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505075 guard_name = 'DUMMY' # To not trigger check outside the loop.
5076 break
Daniel Bratell8ba52722018-03-02 16:06:145077
Sam Maiera6e76d72022-02-11 21:43:505078 if guard_name is None:
5079 match = guard_pattern.match(line)
5080 if match:
5081 guard_name = match.group(1)
5082 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145083
Sam Maiera6e76d72022-02-11 21:43:505084 # We allow existing files to use include guards whose names
5085 # don't match the chromium style guide, but new files should
5086 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495087 if guard_name != expected_guard:
5088 if not f.OldContents():
Sam Maiera6e76d72022-02-11 21:43:505089 errors.append(
5090 output_api.PresubmitPromptWarning(
5091 'Header using the wrong include guard name %s'
5092 % guard_name, [
5093 '%s:%d' %
5094 (f.LocalPath(), line_number + 1)
5095 ], 'Expected: %r\nFound: %r' %
5096 (expected_guard, guard_name)))
5097 else:
5098 # The line after #ifndef should have a #define of the same name.
5099 if line_number == guard_line_number + 1:
5100 expected_line = '#define %s' % guard_name
5101 if line != expected_line:
5102 errors.append(
5103 output_api.PresubmitPromptWarning(
5104 'Missing "%s" for include guard' %
5105 expected_line,
5106 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5107 'Expected: %r\nGot: %r' %
5108 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145109
Sam Maiera6e76d72022-02-11 21:43:505110 if not seen_guard_end and line == '#endif // %s' % guard_name:
5111 seen_guard_end = True
5112 elif seen_guard_end:
5113 if line.strip() != '':
5114 errors.append(
5115 output_api.PresubmitPromptWarning(
5116 'Include guard %s not covering the whole file'
5117 % (guard_name), [f.LocalPath()]))
5118 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145119
Sam Maiera6e76d72022-02-11 21:43:505120 if guard_name is None:
5121 errors.append(
5122 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495123 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505124 'Recommended name: %s\n'
5125 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365126 '"no-include-guard-because-multiply-included" or\n'
5127 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505128 % (f.LocalPath(), expected_guard)))
5129
5130 return errors
Daniel Bratell8ba52722018-03-02 16:06:145131
5132
Saagar Sanghavifceeaae2020-08-12 16:40:365133def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505134 """Check source code and known ascii text files for Windows style line
5135 endings.
5136 """
Bruce Dawson5efbdc652022-04-11 19:29:515137 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235138
Sam Maiera6e76d72022-02-11 21:43:505139 file_inclusion_pattern = (known_text_files,
5140 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5141 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235142
Sam Maiera6e76d72022-02-11 21:43:505143 problems = []
5144 source_file_filter = lambda f: input_api.FilterSourceFile(
5145 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5146 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515147 # Ignore test files that contain crlf intentionally.
5148 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345149 continue
Sam Maiera6e76d72022-02-11 21:43:505150 include_file = False
5151 for line in input_api.ReadFile(f, 'r').splitlines(True):
5152 if line.endswith('\r\n'):
5153 include_file = True
5154 if include_file:
5155 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235156
Sam Maiera6e76d72022-02-11 21:43:505157 if problems:
5158 return [
5159 output_api.PresubmitPromptWarning(
5160 'Are you sure that you want '
5161 'these files to contain Windows style line endings?\n' +
5162 '\n'.join(problems))
5163 ]
mostynbb639aca52015-01-07 20:31:235164
Sam Maiera6e76d72022-02-11 21:43:505165 return []
5166
mostynbb639aca52015-01-07 20:31:235167
Evan Stade6cfc964c12021-05-18 20:21:165168def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505169 """Check that .icon files (which are fragments of C++) have license headers.
5170 """
Evan Stade6cfc964c12021-05-18 20:21:165171
Sam Maiera6e76d72022-02-11 21:43:505172 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165173
Sam Maiera6e76d72022-02-11 21:43:505174 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5175 return input_api.canned_checks.CheckLicense(input_api,
5176 output_api,
5177 source_file_filter=icons)
5178
Evan Stade6cfc964c12021-05-18 20:21:165179
Jose Magana2b456f22021-03-09 23:26:405180def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505181 """Check source code for use of Chrome App technologies being
5182 deprecated.
5183 """
Jose Magana2b456f22021-03-09 23:26:405184
Sam Maiera6e76d72022-02-11 21:43:505185 def _CheckForDeprecatedTech(input_api,
5186 output_api,
5187 detection_list,
5188 files_to_check=None,
5189 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405190
Sam Maiera6e76d72022-02-11 21:43:505191 if (files_to_check or files_to_skip):
5192 source_file_filter = lambda f: input_api.FilterSourceFile(
5193 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5194 else:
5195 source_file_filter = None
5196
5197 problems = []
5198
5199 for f in input_api.AffectedSourceFiles(source_file_filter):
5200 if f.Action() == 'D':
5201 continue
5202 for _, line in f.ChangedContents():
5203 if any(detect in line for detect in detection_list):
5204 problems.append(f.LocalPath())
5205
5206 return problems
5207
5208 # to avoid this presubmit script triggering warnings
5209 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405210
5211 problems = []
5212
Sam Maiera6e76d72022-02-11 21:43:505213 # NMF: any files with extensions .nmf or NMF
5214 _NMF_FILES = r'\.(nmf|NMF)$'
5215 problems += _CheckForDeprecatedTech(
5216 input_api,
5217 output_api,
5218 detection_list=[''], # any change to the file will trigger warning
5219 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405220
Sam Maiera6e76d72022-02-11 21:43:505221 # MANIFEST: any manifest.json that in its diff includes "app":
5222 _MANIFEST_FILES = r'(manifest\.json)$'
5223 problems += _CheckForDeprecatedTech(
5224 input_api,
5225 output_api,
5226 detection_list=['"app":'],
5227 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405228
Sam Maiera6e76d72022-02-11 21:43:505229 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5230 problems += _CheckForDeprecatedTech(
5231 input_api,
5232 output_api,
5233 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
5234 files_to_skip=files_to_skip + [r"^native_client_sdk[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405235
Gao Shenga79ebd42022-08-08 17:25:595236 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505237 problems += _CheckForDeprecatedTech(
5238 input_api,
5239 output_api,
5240 detection_list=['#include "ppapi', '#include <ppapi'],
5241 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5242 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
5243 files_to_skip=[r"^ppapi[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405244
Sam Maiera6e76d72022-02-11 21:43:505245 if problems:
5246 return [
5247 output_api.PresubmitPromptWarning(
5248 'You are adding/modifying code'
5249 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5250 ' PNaCl, PPAPI). See this blog post for more details:\n'
5251 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5252 'and this documentation for options to replace these technologies:\n'
5253 'https://developer.chrome.com/docs/apps/migration/\n' +
5254 '\n'.join(problems))
5255 ]
Jose Magana2b456f22021-03-09 23:26:405256
Sam Maiera6e76d72022-02-11 21:43:505257 return []
Jose Magana2b456f22021-03-09 23:26:405258
mostynbb639aca52015-01-07 20:31:235259
Saagar Sanghavifceeaae2020-08-12 16:40:365260def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505261 """Checks that all source files use SYSLOG properly."""
5262 syslog_files = []
5263 for f in input_api.AffectedSourceFiles(src_file_filter):
5264 for line_number, line in f.ChangedContents():
5265 if 'SYSLOG' in line:
5266 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565267
Sam Maiera6e76d72022-02-11 21:43:505268 if syslog_files:
5269 return [
5270 output_api.PresubmitPromptWarning(
5271 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5272 ' calls.\nFiles to check:\n',
5273 items=syslog_files)
5274 ]
5275 return []
pastarmovj89f7ee12016-09-20 14:58:135276
5277
[email protected]1f7b4172010-01-28 01:17:345278def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505279 if input_api.version < [2, 0, 0]:
5280 return [
5281 output_api.PresubmitError(
5282 "Your depot_tools is out of date. "
5283 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5284 "but your version is %d.%d.%d" % tuple(input_api.version))
5285 ]
5286 results = []
5287 results.extend(
5288 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5289 return results
[email protected]ca8d1982009-02-19 16:33:125290
5291
5292def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505293 if input_api.version < [2, 0, 0]:
5294 return [
5295 output_api.PresubmitError(
5296 "Your depot_tools is out of date. "
5297 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5298 "but your version is %d.%d.%d" % tuple(input_api.version))
5299 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365300
Sam Maiera6e76d72022-02-11 21:43:505301 results = []
5302 # Make sure the tree is 'open'.
5303 results.extend(
5304 input_api.canned_checks.CheckTreeIsOpen(
5305 input_api,
5306 output_api,
5307 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275308
Sam Maiera6e76d72022-02-11 21:43:505309 results.extend(
5310 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5311 results.extend(
5312 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5313 results.extend(
5314 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5315 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505316 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145317
5318
Saagar Sanghavifceeaae2020-08-12 16:40:365319def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505320 """Check string ICU syntax validity and if translation screenshots exist."""
5321 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5322 # footer is set to true.
5323 git_footers = input_api.change.GitFootersFromDescription()
5324 skip_screenshot_check_footer = [
5325 footer.lower() for footer in git_footers.get(
5326 u'Skip-Translation-Screenshots-Check', [])
5327 ]
5328 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025329
Sam Maiera6e76d72022-02-11 21:43:505330 import os
5331 import re
5332 import sys
5333 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145334
Sam Maiera6e76d72022-02-11 21:43:505335 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5336 if (f.Action() == 'A' or f.Action() == 'M'))
5337 removed_paths = set(f.LocalPath()
5338 for f in input_api.AffectedFiles(include_deletes=True)
5339 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145340
Sam Maiera6e76d72022-02-11 21:43:505341 affected_grds = [
5342 f for f in input_api.AffectedFiles()
5343 if f.LocalPath().endswith(('.grd', '.grdp'))
5344 ]
5345 affected_grds = [
5346 f for f in affected_grds if not 'testdata' in f.LocalPath()
5347 ]
5348 if not affected_grds:
5349 return []
meacer8c0d3832019-12-26 21:46:165350
Sam Maiera6e76d72022-02-11 21:43:505351 affected_png_paths = [
5352 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5353 if (f.LocalPath().endswith('.png'))
5354 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145355
Sam Maiera6e76d72022-02-11 21:43:505356 # Check for screenshots. Developers can upload screenshots using
5357 # tools/translation/upload_screenshots.py which finds and uploads
5358 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5359 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5360 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5361 #
5362 # The logic here is as follows:
5363 #
5364 # - If the CL has a .png file under the screenshots directory for a grd
5365 # file, warn the developer. Actual images should never be checked into the
5366 # Chrome repo.
5367 #
5368 # - If the CL contains modified or new messages in grd files and doesn't
5369 # contain the corresponding .sha1 files, warn the developer to add images
5370 # and upload them via tools/translation/upload_screenshots.py.
5371 #
5372 # - If the CL contains modified or new messages in grd files and the
5373 # corresponding .sha1 files, everything looks good.
5374 #
5375 # - If the CL contains removed messages in grd files but the corresponding
5376 # .sha1 files aren't removed, warn the developer to remove them.
5377 unnecessary_screenshots = []
5378 missing_sha1 = []
5379 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145380
Sam Maiera6e76d72022-02-11 21:43:505381 # This checks verifies that the ICU syntax of messages this CL touched is
5382 # valid, and reports any found syntax errors.
5383 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5384 # without developers being aware of them. Later on, such ICU syntax errors
5385 # break message extraction for translation, hence would block Chromium
5386 # translations until they are fixed.
5387 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145388
Sam Maiera6e76d72022-02-11 21:43:505389 def _CheckScreenshotAdded(screenshots_dir, message_id):
5390 sha1_path = input_api.os_path.join(screenshots_dir,
5391 message_id + '.png.sha1')
5392 if sha1_path not in new_or_added_paths:
5393 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145394
Sam Maiera6e76d72022-02-11 21:43:505395 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5396 sha1_path = input_api.os_path.join(screenshots_dir,
5397 message_id + '.png.sha1')
5398 if input_api.os_path.exists(
5399 sha1_path) and sha1_path not in removed_paths:
5400 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145401
Sam Maiera6e76d72022-02-11 21:43:505402 def _ValidateIcuSyntax(text, level, signatures):
5403 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145404
Sam Maiera6e76d72022-02-11 21:43:505405 Check if text looks similar to ICU and checks for ICU syntax correctness
5406 in this case. Reports various issues with ICU syntax and values of
5407 variants. Supports checking of nested messages. Accumulate information of
5408 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265409
Sam Maiera6e76d72022-02-11 21:43:505410 Args:
5411 text: a string to check.
5412 level: a number of current nesting level.
5413 signatures: an accumulator, a list of tuple of (level, variable,
5414 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265415
Sam Maiera6e76d72022-02-11 21:43:505416 Returns:
5417 None if a string is not ICU or no issue detected.
5418 A tuple of (message, start index, end index) if an issue detected.
5419 """
5420 valid_types = {
5421 'plural': (frozenset(
5422 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5423 'other']), frozenset(['=1', 'other'])),
5424 'selectordinal': (frozenset(
5425 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5426 'other']), frozenset(['one', 'other'])),
5427 'select': (frozenset(), frozenset(['other'])),
5428 }
Rainhard Findlingfc31844c52020-05-15 09:58:265429
Sam Maiera6e76d72022-02-11 21:43:505430 # Check if the message looks like an attempt to use ICU
5431 # plural. If yes - check if its syntax strictly matches ICU format.
5432 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5433 text)
5434 if not like:
5435 signatures.append((level, None, None, None))
5436 return
Rainhard Findlingfc31844c52020-05-15 09:58:265437
Sam Maiera6e76d72022-02-11 21:43:505438 # Check for valid prefix and suffix
5439 m = re.match(
5440 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5441 r'(plural|selectordinal|select),\s*'
5442 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5443 if not m:
5444 return (('This message looks like an ICU plural, '
5445 'but does not follow ICU syntax.'), like.start(),
5446 like.end())
5447 starting, variable, kind, variant_pairs = m.groups()
5448 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5449 m.start(4))
5450 if depth:
5451 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5452 len(text))
5453 first = text[0]
5454 ending = text[last_pos:]
5455 if not starting:
5456 return ('Invalid ICU format. No initial opening bracket',
5457 last_pos - 1, last_pos)
5458 if not ending or '}' not in ending:
5459 return ('Invalid ICU format. No final closing bracket',
5460 last_pos - 1, last_pos)
5461 elif first != '{':
5462 return ((
5463 'Invalid ICU format. Extra characters at the start of a complex '
5464 'message (go/icu-message-migration): "%s"') % starting, 0,
5465 len(starting))
5466 elif ending != '}':
5467 return ((
5468 'Invalid ICU format. Extra characters at the end of a complex '
5469 'message (go/icu-message-migration): "%s"') % ending,
5470 last_pos - 1, len(text) - 1)
5471 if kind not in valid_types:
5472 return (('Unknown ICU message type %s. '
5473 'Valid types are: plural, select, selectordinal') % kind,
5474 0, 0)
5475 known, required = valid_types[kind]
5476 defined_variants = set()
5477 for variant, variant_range, value, value_range in variants:
5478 start, end = variant_range
5479 if variant in defined_variants:
5480 return ('Variant "%s" is defined more than once' % variant,
5481 start, end)
5482 elif known and variant not in known:
5483 return ('Variant "%s" is not valid for %s message' %
5484 (variant, kind), start, end)
5485 defined_variants.add(variant)
5486 # Check for nested structure
5487 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5488 if res:
5489 return (res[0], res[1] + value_range[0] + 1,
5490 res[2] + value_range[0] + 1)
5491 missing = required - defined_variants
5492 if missing:
5493 return ('Required variants missing: %s' % ', '.join(missing), 0,
5494 len(text))
5495 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265496
Sam Maiera6e76d72022-02-11 21:43:505497 def _ParseIcuVariants(text, offset=0):
5498 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265499
Sam Maiera6e76d72022-02-11 21:43:505500 Builds a tuple of variant names and values, as well as
5501 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265502
Sam Maiera6e76d72022-02-11 21:43:505503 Args:
5504 text: a string to parse
5505 offset: additional offset to add to positions in the text to get correct
5506 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265507
Sam Maiera6e76d72022-02-11 21:43:505508 Returns:
5509 List of tuples, each tuple consist of four fields: variant name,
5510 variant name span (tuple of two integers), variant value, value
5511 span (tuple of two integers).
5512 """
5513 depth, start, end = 0, -1, -1
5514 variants = []
5515 key = None
5516 for idx, char in enumerate(text):
5517 if char == '{':
5518 if not depth:
5519 start = idx
5520 chunk = text[end + 1:start]
5521 key = chunk.strip()
5522 pos = offset + end + 1 + chunk.find(key)
5523 span = (pos, pos + len(key))
5524 depth += 1
5525 elif char == '}':
5526 if not depth:
5527 return variants, depth, offset + idx
5528 depth -= 1
5529 if not depth:
5530 end = idx
5531 variants.append((key, span, text[start:end + 1],
5532 (offset + start, offset + end + 1)))
5533 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265534
Sam Maiera6e76d72022-02-11 21:43:505535 try:
5536 old_sys_path = sys.path
5537 sys.path = sys.path + [
5538 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5539 'translation')
5540 ]
5541 from helper import grd_helper
5542 finally:
5543 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265544
Sam Maiera6e76d72022-02-11 21:43:505545 for f in affected_grds:
5546 file_path = f.LocalPath()
5547 old_id_to_msg_map = {}
5548 new_id_to_msg_map = {}
5549 # Note that this code doesn't check if the file has been deleted. This is
5550 # OK because it only uses the old and new file contents and doesn't load
5551 # the file via its path.
5552 # It's also possible that a file's content refers to a renamed or deleted
5553 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5554 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5555 # .grdp files.
5556 if file_path.endswith('.grdp'):
5557 if f.OldContents():
5558 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5559 '\n'.join(f.OldContents()))
5560 if f.NewContents():
5561 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5562 '\n'.join(f.NewContents()))
5563 else:
5564 file_dir = input_api.os_path.dirname(file_path) or '.'
5565 if f.OldContents():
5566 old_id_to_msg_map = grd_helper.GetGrdMessages(
5567 StringIO('\n'.join(f.OldContents())), file_dir)
5568 if f.NewContents():
5569 new_id_to_msg_map = grd_helper.GetGrdMessages(
5570 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265571
Sam Maiera6e76d72022-02-11 21:43:505572 grd_name, ext = input_api.os_path.splitext(
5573 input_api.os_path.basename(file_path))
5574 screenshots_dir = input_api.os_path.join(
5575 input_api.os_path.dirname(file_path),
5576 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265577
Sam Maiera6e76d72022-02-11 21:43:505578 # Compute added, removed and modified message IDs.
5579 old_ids = set(old_id_to_msg_map)
5580 new_ids = set(new_id_to_msg_map)
5581 added_ids = new_ids - old_ids
5582 removed_ids = old_ids - new_ids
5583 modified_ids = set([])
5584 for key in old_ids.intersection(new_ids):
5585 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5586 new_id_to_msg_map[key].ContentsAsXml('', True)):
5587 # The message content itself changed. Require an updated screenshot.
5588 modified_ids.add(key)
5589 elif old_id_to_msg_map[key].attrs['meaning'] != \
5590 new_id_to_msg_map[key].attrs['meaning']:
5591 # The message meaning changed. Ensure there is a screenshot for it.
5592 sha1_path = input_api.os_path.join(screenshots_dir,
5593 key + '.png.sha1')
5594 if sha1_path not in new_or_added_paths and not \
5595 input_api.os_path.exists(sha1_path):
5596 # There is neither a previous screenshot nor is a new one added now.
5597 # Require a screenshot.
5598 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145599
Sam Maiera6e76d72022-02-11 21:43:505600 if run_screenshot_check:
5601 # Check the screenshot directory for .png files. Warn if there is any.
5602 for png_path in affected_png_paths:
5603 if png_path.startswith(screenshots_dir):
5604 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145605
Sam Maiera6e76d72022-02-11 21:43:505606 for added_id in added_ids:
5607 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095608
Sam Maiera6e76d72022-02-11 21:43:505609 for modified_id in modified_ids:
5610 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145611
Sam Maiera6e76d72022-02-11 21:43:505612 for removed_id in removed_ids:
5613 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5614
5615 # Check new and changed strings for ICU syntax errors.
5616 for key in added_ids.union(modified_ids):
5617 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5618 err = _ValidateIcuSyntax(msg, 0, [])
5619 if err is not None:
5620 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5621
5622 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265623 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505624 if unnecessary_screenshots:
5625 results.append(
5626 output_api.PresubmitError(
5627 'Do not include actual screenshots in the changelist. Run '
5628 'tools/translate/upload_screenshots.py to upload them instead:',
5629 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145630
Sam Maiera6e76d72022-02-11 21:43:505631 if missing_sha1:
5632 results.append(
5633 output_api.PresubmitError(
5634 'You are adding or modifying UI strings.\n'
5635 'To ensure the best translations, take screenshots of the relevant UI '
5636 '(https://g.co/chrome/translation) and add these files to your '
5637 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145638
Sam Maiera6e76d72022-02-11 21:43:505639 if unnecessary_sha1_files:
5640 results.append(
5641 output_api.PresubmitError(
5642 'You removed strings associated with these files. Remove:',
5643 sorted(unnecessary_sha1_files)))
5644 else:
5645 results.append(
5646 output_api.PresubmitPromptOrNotify('Skipping translation '
5647 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145648
Sam Maiera6e76d72022-02-11 21:43:505649 if icu_syntax_errors:
5650 results.append(
5651 output_api.PresubmitPromptWarning(
5652 'ICU syntax errors were found in the following strings (problems or '
5653 'feedback? Contact [email protected]):',
5654 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265655
Sam Maiera6e76d72022-02-11 21:43:505656 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125657
5658
Saagar Sanghavifceeaae2020-08-12 16:40:365659def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125660 repo_root=None,
5661 translation_expectations_path=None,
5662 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505663 import sys
5664 affected_grds = [
5665 f for f in input_api.AffectedFiles()
5666 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5667 ]
5668 if not affected_grds:
5669 return []
5670
5671 try:
5672 old_sys_path = sys.path
5673 sys.path = sys.path + [
5674 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5675 'translation')
5676 ]
5677 from helper import git_helper
5678 from helper import translation_helper
5679 finally:
5680 sys.path = old_sys_path
5681
5682 # Check that translation expectations can be parsed and we can get a list of
5683 # translatable grd files. |repo_root| and |translation_expectations_path| are
5684 # only passed by tests.
5685 if not repo_root:
5686 repo_root = input_api.PresubmitLocalPath()
5687 if not translation_expectations_path:
5688 translation_expectations_path = input_api.os_path.join(
5689 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5690 if not grd_files:
5691 grd_files = git_helper.list_grds_in_repository(repo_root)
5692
5693 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:595694 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:505695 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
5696 'tests')
5697 grd_files = [p for p in grd_files if ignore_path not in p]
5698
5699 try:
5700 translation_helper.get_translatable_grds(
5701 repo_root, grd_files, translation_expectations_path)
5702 except Exception as e:
5703 return [
5704 output_api.PresubmitNotifyResult(
5705 'Failed to get a list of translatable grd files. This happens when:\n'
5706 ' - One of the modified grd or grdp files cannot be parsed or\n'
5707 ' - %s is not updated.\n'
5708 'Stack:\n%s' % (translation_expectations_path, str(e)))
5709 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:125710 return []
5711
Ken Rockotc31f4832020-05-29 18:58:515712
Saagar Sanghavifceeaae2020-08-12 16:40:365713def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505714 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5715 changed_mojoms = input_api.AffectedFiles(
5716 include_deletes=True,
5717 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525718
Bruce Dawson344ab262022-06-04 11:35:105719 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:505720 return []
5721
5722 delta = []
5723 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:505724 delta.append({
5725 'filename': mojom.LocalPath(),
5726 'old': '\n'.join(mojom.OldContents()) or None,
5727 'new': '\n'.join(mojom.NewContents()) or None,
5728 })
5729
5730 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:215731 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:505732 input_api.os_path.join(
5733 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
5734 'check_stable_mojom_compatibility.py'), '--src-root',
5735 input_api.PresubmitLocalPath()
5736 ],
5737 stdin=input_api.subprocess.PIPE,
5738 stdout=input_api.subprocess.PIPE,
5739 stderr=input_api.subprocess.PIPE,
5740 universal_newlines=True)
5741 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5742 if process.returncode:
5743 return [
5744 output_api.PresubmitError(
5745 'One or more [Stable] mojom definitions appears to have been changed '
5746 'in a way that is not backward-compatible.',
5747 long_text=error)
5748 ]
Erik Staabc734cd7a2021-11-23 03:11:525749 return []
5750
Dominic Battre645d42342020-12-04 16:14:105751def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505752 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:105753
Sam Maiera6e76d72022-02-11 21:43:505754 def FilterFile(affected_file):
5755 """Accept only .cc files and the like."""
5756 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5757 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5758 input_api.DEFAULT_FILES_TO_SKIP)
5759 return input_api.FilterSourceFile(
5760 affected_file,
5761 files_to_check=file_inclusion_pattern,
5762 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:105763
Sam Maiera6e76d72022-02-11 21:43:505764 def ModifiedLines(affected_file):
5765 """Returns a list of tuples (line number, line text) of added and removed
5766 lines.
Dominic Battre645d42342020-12-04 16:14:105767
Sam Maiera6e76d72022-02-11 21:43:505768 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:105769
Sam Maiera6e76d72022-02-11 21:43:505770 This relies on the scm diff output describing each changed code section
5771 with a line of the form
Dominic Battre645d42342020-12-04 16:14:105772
Sam Maiera6e76d72022-02-11 21:43:505773 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5774 """
5775 line_num = 0
5776 modified_lines = []
5777 for line in affected_file.GenerateScmDiff().splitlines():
5778 # Extract <new line num> of the patch fragment (see format above).
5779 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
5780 line)
5781 if m:
5782 line_num = int(m.groups(1)[0])
5783 continue
5784 if ((line.startswith('+') and not line.startswith('++'))
5785 or (line.startswith('-') and not line.startswith('--'))):
5786 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:105787
Sam Maiera6e76d72022-02-11 21:43:505788 if not line.startswith('-'):
5789 line_num += 1
5790 return modified_lines
Dominic Battre645d42342020-12-04 16:14:105791
Sam Maiera6e76d72022-02-11 21:43:505792 def FindLineWith(lines, needle):
5793 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:105794
Sam Maiera6e76d72022-02-11 21:43:505795 If 0 or >1 lines contain `needle`, -1 is returned.
5796 """
5797 matching_line_numbers = [
5798 # + 1 for 1-based counting of line numbers.
5799 i + 1 for i, line in enumerate(lines) if needle in line
5800 ]
5801 return matching_line_numbers[0] if len(
5802 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:105803
Sam Maiera6e76d72022-02-11 21:43:505804 def ModifiedPrefMigration(affected_file):
5805 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5806 # Determine first and last lines of MigrateObsolete.*Pref functions.
5807 new_contents = affected_file.NewContents()
5808 range_1 = (FindLineWith(new_contents,
5809 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5810 FindLineWith(new_contents,
5811 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5812 range_2 = (FindLineWith(new_contents,
5813 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5814 FindLineWith(new_contents,
5815 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5816 if (-1 in range_1 + range_2):
5817 raise Exception(
5818 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
5819 )
Dominic Battre645d42342020-12-04 16:14:105820
Sam Maiera6e76d72022-02-11 21:43:505821 # Check whether any of the modified lines are part of the
5822 # MigrateObsolete.*Pref functions.
5823 for line_nr, line in ModifiedLines(affected_file):
5824 if (range_1[0] <= line_nr <= range_1[1]
5825 or range_2[0] <= line_nr <= range_2[1]):
5826 return True
5827 return False
Dominic Battre645d42342020-12-04 16:14:105828
Sam Maiera6e76d72022-02-11 21:43:505829 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5830 browser_prefs_file_pattern = input_api.re.compile(
5831 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:105832
Sam Maiera6e76d72022-02-11 21:43:505833 changes = input_api.AffectedFiles(include_deletes=True,
5834 file_filter=FilterFile)
5835 potential_problems = []
5836 for f in changes:
5837 for line in f.GenerateScmDiff().splitlines():
5838 # Check deleted lines for pref registrations.
5839 if (line.startswith('-') and not line.startswith('--')
5840 and register_pref_pattern.search(line)):
5841 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:105842
Sam Maiera6e76d72022-02-11 21:43:505843 if browser_prefs_file_pattern.search(f.LocalPath()):
5844 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5845 # assume that they knew that they have to deprecate preferences and don't
5846 # warn.
5847 try:
5848 if ModifiedPrefMigration(f):
5849 return []
5850 except Exception as e:
5851 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:105852
Sam Maiera6e76d72022-02-11 21:43:505853 if potential_problems:
5854 return [
5855 output_api.PresubmitPromptWarning(
5856 'Discovered possible removal of preference registrations.\n\n'
5857 'Please make sure to properly deprecate preferences by clearing their\n'
5858 'value for a couple of milestones before finally removing the code.\n'
5859 'Otherwise data may stay in the preferences files forever. See\n'
5860 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5861 'chrome/browser/prefs/README.md for examples.\n'
5862 'This may be a false positive warning (e.g. if you move preference\n'
5863 'registrations to a different place).\n', potential_problems)
5864 ]
5865 return []
5866
Matt Stark6ef08872021-07-29 01:21:465867
5868def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505869 """Changes to GRD files must be consistent for tools to read them."""
5870 changed_grds = input_api.AffectedFiles(
5871 include_deletes=False,
5872 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5873 errors = []
5874 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5875 for matcher, msg in _INVALID_GRD_FILE_LINE]
5876 for grd in changed_grds:
5877 for i, line in enumerate(grd.NewContents()):
5878 for matcher, msg in invalid_file_regexes:
5879 if matcher.search(line):
5880 errors.append(
5881 output_api.PresubmitError(
5882 'Problem on {grd}:{i} - {msg}'.format(
5883 grd=grd.LocalPath(), i=i + 1, msg=msg)))
5884 return errors
5885
Kevin McNee967dd2d22021-11-15 16:09:295886
5887def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505888 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5889 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5890 """
Kevin McNee967dd2d22021-11-15 16:09:295891
Ian Vollickdba956c2022-04-20 23:53:455892 # Only consider top-level directories that (1) can use content APIs or
5893 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
5894 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:505895 files_to_check = (
Ian Vollickdba956c2022-04-20 23:53:455896 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Kevin McNee967dd2d22021-11-15 16:09:295897 _IMPLEMENTATION_EXTENSIONS,
Ian Vollickdba956c2022-04-20 23:53:455898 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Sam Maiera6e76d72022-02-11 21:43:505899 _HEADER_EXTENSIONS,
5900 )
5901 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5902 input_api.DEFAULT_FILES_TO_SKIP)
5903 source_file_filter = lambda f: input_api.FilterSourceFile(
5904 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:295905
Kevin McNee29c0e8232022-08-05 15:36:095906 # Here we list the classes/methods we're monitoring. For the "fyi" cases,
5907 # we add the CL to the watchlist, but we don't omit a warning or have it be
5908 # included in the triage rotation.
Sam Maiera6e76d72022-02-11 21:43:505909 # Note that since these are are just regular expressions and we don't have
5910 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5911 # could have a method named IsInMainFrame).
Kevin McNee29c0e8232022-08-05 15:36:095912 fyi_concerning_class_pattern = input_api.re.compile(
Sam Maiera6e76d72022-02-11 21:43:505913 r'WebContentsObserver|WebContentsUserData')
5914 # A subset of WebContentsObserver overrides where there's particular risk for
5915 # confusing tab and page level operations and data (e.g. incorrectly
5916 # resetting page state in DidFinishNavigation).
Kevin McNee29c0e8232022-08-05 15:36:095917 fyi_concerning_wco_methods = [
Sam Maiera6e76d72022-02-11 21:43:505918 'DidStartNavigation',
5919 'ReadyToCommitNavigation',
5920 'DidFinishNavigation',
5921 'RenderViewReady',
5922 'RenderViewDeleted',
5923 'RenderViewHostChanged',
Sam Maiera6e76d72022-02-11 21:43:505924 'DOMContentLoaded',
5925 'DidFinishLoad',
5926 ]
5927 concerning_nav_handle_methods = [
5928 'IsInMainFrame',
5929 ]
5930 concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:505931 'FromRenderFrameHost',
5932 'FromRenderViewHost',
Kevin McNee29c0e8232022-08-05 15:36:095933 ]
5934 fyi_concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:505935 'GetRenderViewHost',
5936 ]
5937 concerning_rfh_methods = [
5938 'GetParent',
5939 'GetMainFrame',
Kevin McNee29c0e8232022-08-05 15:36:095940 ]
5941 fyi_concerning_rfh_methods = [
Sam Maiera6e76d72022-02-11 21:43:505942 'GetFrameTreeNodeId',
5943 ]
Ian Vollickc825b1f2022-04-19 14:30:155944 concerning_rfhi_methods = [
5945 'is_main_frame',
5946 ]
Ian Vollicka77a73ea2022-04-06 18:08:015947 concerning_ftn_methods = [
5948 'IsMainFrame',
5949 ]
Ian Vollickdba956c2022-04-20 23:53:455950 concerning_blink_frame_methods = [
Ian Vollick4d785d22022-06-18 00:10:025951 'IsCrossOriginToNearestMainFrame',
Ian Vollickdba956c2022-04-20 23:53:455952 ]
Sam Maiera6e76d72022-02-11 21:43:505953 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5954 item for sublist in [
Kevin McNee29c0e8232022-08-05 15:36:095955 concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:015956 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:155957 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:455958 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:505959 ] for item in sublist) + r')\(')
Kevin McNee29c0e8232022-08-05 15:36:095960 fyi_concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5961 item for sublist in [
5962 fyi_concerning_wco_methods, fyi_concerning_web_contents_methods,
5963 fyi_concerning_rfh_methods,
5964 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:295965
Kevin McNee4eeec792022-02-14 20:02:045966 used_apis = set()
Kevin McNee29c0e8232022-08-05 15:36:095967 used_fyi_methods = False
Sam Maiera6e76d72022-02-11 21:43:505968 for f in input_api.AffectedFiles(include_deletes=False,
5969 file_filter=source_file_filter):
5970 for line_num, line in f.ChangedContents():
Kevin McNee29c0e8232022-08-05 15:36:095971 fyi_class_match = fyi_concerning_class_pattern.search(line)
5972 if fyi_class_match:
5973 used_fyi_methods = True
5974 fyi_method_match = fyi_concerning_method_pattern.search(line)
5975 if fyi_method_match:
5976 used_fyi_methods = True
Kevin McNee4eeec792022-02-14 20:02:045977 method_match = concerning_method_pattern.search(line)
5978 if method_match:
5979 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:505980
Kevin McNee4eeec792022-02-14 20:02:045981 if not used_apis:
Kevin McNee29c0e8232022-08-05 15:36:095982 if used_fyi_methods:
5983 output_api.AppendCC('[email protected]')
5984
Kevin McNee4eeec792022-02-14 20:02:045985 return []
Kevin McNee967dd2d22021-11-15 16:09:295986
Kevin McNee4eeec792022-02-14 20:02:045987 output_api.AppendCC('[email protected]')
5988 message = ('This change uses API(s) that are ambiguous in the presence of '
5989 'MPArch features such as bfcache, prerendering, and fenced '
5990 'frames.')
Kevin McNee29c0e8232022-08-05 15:36:095991 explanation = (
Kevin McNee4eeec792022-02-14 20:02:045992 'Please double check whether new code assumes that a WebContents only '
Kevin McNee29c0e8232022-08-05 15:36:095993 'contains a single page at a time. Notably, checking whether a frame '
5994 'is the \"main frame\" is not specific enough to determine whether it '
5995 'corresponds to the document reflected in the omnibox. A WebContents '
5996 'may have additional main frames for prerendered pages, bfcached '
5997 'pages, fenced frames, etc. '
5998 'See this doc [1] and the comments on the individual APIs '
Kevin McNee4eeec792022-02-14 20:02:045999 'for guidance and this doc [2] for context. The MPArch review '
6000 'watchlist has been CC\'d on this change to help identify any issues.\n'
6001 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
6002 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
6003 )
6004 return [
6005 output_api.PresubmitNotifyResult(message,
6006 items=list(used_apis),
Kevin McNee29c0e8232022-08-05 15:36:096007 long_text=explanation)
Kevin McNee4eeec792022-02-14 20:02:046008 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:366009
6010
6011def CheckAssertAshOnlyCode(input_api, output_api):
6012 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6013 assert(is_chromeos_ash).
6014 """
6015
6016 def FileFilter(affected_file):
6017 """Includes directories known to be Ash only."""
6018 return input_api.FilterSourceFile(
6019 affected_file,
6020 files_to_check=(
6021 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6022 r'.*/ash/.*BUILD\.gn'), # Any path component.
6023 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6024
6025 errors = []
6026 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566027 for f in input_api.AffectedFiles(include_deletes=False,
6028 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366029 if (not pattern.search(input_api.ReadFile(f))):
6030 errors.append(
6031 output_api.PresubmitError(
6032 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6033 'possible, please create and issue and add a comment such '
6034 'as:\n # TODO(https://crbug.com/XXX): add '
6035 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6036 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276037
6038
6039def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506040 path = affected_file.LocalPath()
6041 if not _IsCPlusPlusFile(input_api, path):
6042 return False
6043
6044 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6045 if "/renderer/" in path:
6046 return True
6047
6048 # Blink's public/web API is only used/included by Renderer-only code. Note
6049 # that public/platform API may be used in non-Renderer processes (e.g. there
6050 # are some includes in code used by Utility, PDF, or Plugin processes).
6051 if "/blink/public/web/" in path:
6052 return True
6053
6054 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276055 return False
6056
Lukasz Anforowicz7016d05e2021-11-30 03:56:276057# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6058# by the Chromium Clang Plugin (which will be preferable because it will
6059# 1) report errors earlier - at compile-time and 2) cover more rules).
6060def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506061 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6062 errors = []
6063 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6064 # C++ comment.
6065 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6066 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6067 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6068 if raw_ptr_matcher.search(line):
6069 errors.append(
6070 output_api.PresubmitError(
6071 'Problem on {path}:{line} - '\
6072 'raw_ptr<T> should not be used in Renderer-only code '\
6073 '(as documented in the "Pointers to unprotected memory" '\
6074 'section in //base/memory/raw_ptr.md)'.format(
6075 path=f.LocalPath(), line=line_num)))
6076 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566077
6078
6079def CheckPythonShebang(input_api, output_api):
6080 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6081 system-wide python.
6082 """
6083 errors = []
6084 sources = lambda affected_file: input_api.FilterSourceFile(
6085 affected_file,
6086 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6087 r'third_party/blink/web_tests/external/') + input_api.
6088 DEFAULT_FILES_TO_SKIP),
6089 files_to_check=[r'.*\.py$'])
6090 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276091 for line_num, line in f.ChangedContents():
6092 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6093 errors.append(f.LocalPath())
6094 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566095
6096 result = []
6097 for file in errors:
6098 result.append(
6099 output_api.PresubmitError(
6100 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6101 file))
6102 return result
James Shen81cc0e22022-06-15 21:10:456103
6104
6105def CheckBatchAnnotation(input_api, output_api):
6106 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6107 is not an instrumentation test, disregard."""
6108
6109 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6110 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6111 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6112 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6113 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6114
ckitagawae8fd23b2022-06-17 15:29:386115 missing_annotation_errors = []
6116 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456117
6118 def _FilterFile(affected_file):
6119 return input_api.FilterSourceFile(
6120 affected_file,
6121 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6122 files_to_check=[r'.*Test\.java$'])
6123
6124 for f in input_api.AffectedSourceFiles(_FilterFile):
6125 batch_matched = None
6126 do_not_batch_matched = None
6127 is_instrumentation_test = True
6128 for line in f.NewContents():
6129 if robolectric_test.search(line) or uiautomator_test.search(line):
6130 # Skip Robolectric and UiAutomator tests.
6131 is_instrumentation_test = False
6132 break
6133 if not batch_matched:
6134 batch_matched = batch_annotation.search(line)
6135 if not do_not_batch_matched:
6136 do_not_batch_matched = do_not_batch_annotation.search(line)
6137 test_class_declaration_matched = test_class_declaration.search(
6138 line)
6139 if test_class_declaration_matched:
6140 break
6141 if (is_instrumentation_test and
6142 not batch_matched and
6143 not do_not_batch_matched):
ckitagawae8fd23b2022-06-17 15:29:386144 missing_annotation_errors.append(str(f.LocalPath()))
6145 if (not is_instrumentation_test and
6146 (batch_matched or
6147 do_not_batch_matched)):
6148 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456149
6150 results = []
6151
ckitagawae8fd23b2022-06-17 15:29:386152 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456153 results.append(
6154 output_api.PresubmitPromptWarning(
6155 """
6156Instrumentation tests should use either @Batch or @DoNotBatch. If tests are not
6157safe to run in batch, please use @DoNotBatch with reasons.
ckitagawae8fd23b2022-06-17 15:29:386158""", missing_annotation_errors))
6159 if extra_annotation_errors:
6160 results.append(
6161 output_api.PresubmitPromptWarning(
6162 """
6163Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6164""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456165
6166 return results