Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 9465ee1bda8dce382275f9acd709a29ceb088002 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
14from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1217
Dirk Prankee3c9c62d2021-05-18 18:35:5918# This line is 'magic' in that git-cl looks for it to decide whether to
19# use Python3 instead of Python2 when running the code in this file.
20USE_PYTHON3 = True
21
[email protected]379e7dd2010-01-28 17:39:2122_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1823 # Generated file
Bruce Dawson3bd976c2022-05-06 22:47:5224 (r"chrome[\\/]android[\\/]webapk[\\/]shell_apk[\\/]src[\\/]org[\\/]chromium"
25 r"[\\/]webapk[\\/]lib[\\/]runtime_library[\\/]IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0826 # File needs to write to stdout to emulate a tool it's replacing.
Mila Greend3fc6a42021-09-10 17:38:2327 r"chrome[\\/]updater[\\/]mac[\\/]keystone[\\/]ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4728 # Generated file.
29 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2630 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5231 # These are video files, not typescript.
32 r"^media[\\/]test[\\/]data[\\/].*.ts",
Mila Greene3aa7222021-09-07 16:34:0833 r"^native_client_sdksrc[\\/]build_tools[\\/]make_rules.py",
Egor Paskoce145c42018-09-28 19:31:0434 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
35 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
36 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
37 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4938 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0439 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4640 # sqlite is an imported third party dependency.
41 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0442 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5443 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5344 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1245 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0446 r".+[\\/]pnacl_shim\.c$",
47 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0448 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1449 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0450 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5451 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0452 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4053)
[email protected]ca8d19842009-02-19 16:33:1254
John Abd-El-Malek759fea62021-03-13 03:41:1455_EXCLUDED_SET_NO_PARENT_PATHS = (
56 # It's for historical reasons that blink isn't a top level directory, where
57 # it would be allowed to have "set noparent" to avoid top level owners
58 # accidentally +1ing changes.
59 'third_party/blink/OWNERS',
60)
61
wnwenbdc444e2016-05-25 13:44:1562
[email protected]06e6d0ff2012-12-11 01:36:4463# Fragment of a regular expression that matches C++ and Objective-C++
64# implementation files.
65_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
66
wnwenbdc444e2016-05-25 13:44:1567
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1968# Fragment of a regular expression that matches C++ and Objective-C++
69# header files.
70_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
71
72
Aleksey Khoroshilov9b28c032022-06-03 16:35:3273# Paths with sources that don't use //base.
74_NON_BASE_DEPENDENT_PATHS = (
75 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/]",
76 r"^tools[\\/]win[\\/]",
77)
78
79
[email protected]06e6d0ff2012-12-11 01:36:4480# Regular expression that matches code only used for test binaries
81# (best effort).
82_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0483 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4484 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1385 # Test suite files, like:
86 # foo_browsertest.cc
87 # bar_unittest_mac.cc (suffix)
88 # baz_unittests.cc (plural)
89 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1290 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1891 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2192 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0493 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4394 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0495 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4396 # Web test harness.
97 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4798 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0499 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:08100 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:04101 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41102 # EarlGrey app side code for tests.
103 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17104 # Views Examples code
105 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:41106 # Chromium Codelab
107 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:44108)
[email protected]ca8d19842009-02-19 16:33:12109
Daniel Bratell609102be2019-03-27 20:53:21110_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15111
[email protected]eea609a2011-11-18 13:10:12112_TEST_ONLY_WARNING = (
113 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55114 'production code. If you are doing this from inside another method\n'
115 'named as *ForTesting(), then consider exposing things to have tests\n'
116 'make that same call directly.\n'
117 'If that is not possible, you may put a comment on the same line with\n'
118 ' // IN-TEST \n'
119 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
120 'method and can be ignored. Do not do this inside production code.\n'
121 'The android-binary-size trybot will block if the method exists in the\n'
122 'release apk.')
[email protected]eea609a2011-11-18 13:10:12123
124
Daniel Chenga44a1bcd2022-03-15 20:00:15125@dataclass
126class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34127 # String pattern. If the pattern begins with a slash, the pattern will be
128 # treated as a regular expression instead.
129 pattern: str
130 # Explanation as a sequence of strings. Each string in the sequence will be
131 # printed on its own line.
132 explanation: Sequence[str]
133 # Whether or not to treat this ban as a fatal error. If unspecified,
134 # defaults to true.
135 treat_as_error: Optional[bool] = None
136 # Paths that should be excluded from the ban check. Each string is a regular
137 # expression that will be matched against the path of the file being checked
138 # relative to the root of the source tree.
139 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28140
Daniel Chenga44a1bcd2022-03-15 20:00:15141
Daniel Cheng917ce542022-03-15 20:46:57142_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15143 BanRule(
144 'import java.net.URI;',
145 (
146 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
147 ),
148 excluded_paths=(
149 (r'net/android/javatests/src/org/chromium/net/'
150 'AndroidProxySelectorTest\.java'),
151 r'components/cronet/',
152 r'third_party/robolectric/local/',
153 ),
Michael Thiessen44457642020-02-06 00:24:15154 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15155 BanRule(
156 'import android.annotation.TargetApi;',
157 (
158 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
159 'RequiresApi ensures that any calls are guarded by the appropriate '
160 'SDK_INT check. See https://crbug.com/1116486.',
161 ),
162 ),
163 BanRule(
164 'import android.support.test.rule.UiThreadTestRule;',
165 (
166 'Do not use UiThreadTestRule, just use '
167 '@org.chromium.base.test.UiThreadTest on test methods that should run '
168 'on the UI thread. See https://crbug.com/1111893.',
169 ),
170 ),
171 BanRule(
172 'import android.support.test.annotation.UiThreadTest;',
173 ('Do not use android.support.test.annotation.UiThreadTest, use '
174 'org.chromium.base.test.UiThreadTest instead. See '
175 'https://crbug.com/1111893.',
176 ),
177 ),
178 BanRule(
179 'import android.support.test.rule.ActivityTestRule;',
180 (
181 'Do not use ActivityTestRule, use '
182 'org.chromium.base.test.BaseActivityTestRule instead.',
183 ),
184 excluded_paths=(
185 'components/cronet/',
186 ),
187 ),
188)
wnwenbdc444e2016-05-25 13:44:15189
Daniel Cheng917ce542022-03-15 20:46:57190_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15191 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41192 'StrictMode.allowThreadDiskReads()',
193 (
194 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
195 'directly.',
196 ),
197 False,
198 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15199 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41200 'StrictMode.allowThreadDiskWrites()',
201 (
202 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
203 'directly.',
204 ),
205 False,
206 ),
Daniel Cheng917ce542022-03-15 20:46:57207 BanRule(
Michael Thiessen0f2547e32020-07-27 21:55:36208 '.waitForIdleSync()',
209 (
210 'Do not use waitForIdleSync as it masks underlying issues. There is '
211 'almost always something else you should wait on instead.',
212 ),
213 False,
214 ),
Eric Stevensona9a980972017-09-23 00:04:41215)
216
Daniel Cheng917ce542022-03-15 20:46:57217_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15218 BanRule(
[email protected]127f18ec2012-06-16 05:05:59219 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20220 (
221 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59222 'prohibited. Please use CrTrackingArea instead.',
223 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
224 ),
225 False,
226 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15227 BanRule(
[email protected]eaae1972014-04-16 04:17:26228 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20229 (
230 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59231 'instead.',
232 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
233 ),
234 False,
235 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15236 BanRule(
[email protected]127f18ec2012-06-16 05:05:59237 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20238 (
239 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59240 'Please use |convertPoint:(point) fromView:nil| instead.',
241 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
242 ),
243 True,
244 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15245 BanRule(
[email protected]127f18ec2012-06-16 05:05:59246 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20247 (
248 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59249 'Please use |convertPoint:(point) toView:nil| instead.',
250 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
251 ),
252 True,
253 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15254 BanRule(
[email protected]127f18ec2012-06-16 05:05:59255 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20256 (
257 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59258 'Please use |convertRect:(point) fromView:nil| instead.',
259 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
260 ),
261 True,
262 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15263 BanRule(
[email protected]127f18ec2012-06-16 05:05:59264 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20265 (
266 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59267 'Please use |convertRect:(point) toView:nil| instead.',
268 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
269 ),
270 True,
271 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15272 BanRule(
[email protected]127f18ec2012-06-16 05:05:59273 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20274 (
275 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59276 'Please use |convertSize:(point) fromView:nil| instead.',
277 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
278 ),
279 True,
280 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15281 BanRule(
[email protected]127f18ec2012-06-16 05:05:59282 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20283 (
284 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59285 'Please use |convertSize:(point) toView:nil| instead.',
286 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
287 ),
288 True,
289 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15290 BanRule(
jif65398702016-10-27 10:19:48291 r"/\s+UTF8String\s*]",
292 (
293 'The use of -[NSString UTF8String] is dangerous as it can return null',
294 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
295 'Please use |SysNSStringToUTF8| instead.',
296 ),
297 True,
298 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15299 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34300 r'__unsafe_unretained',
301 (
302 'The use of __unsafe_unretained is almost certainly wrong, unless',
303 'when interacting with NSFastEnumeration or NSInvocation.',
304 'Please use __weak in files build with ARC, nothing otherwise.',
305 ),
306 False,
307 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15308 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13309 'freeWhenDone:NO',
310 (
311 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
312 'Foundation types is prohibited.',
313 ),
314 True,
315 ),
[email protected]127f18ec2012-06-16 05:05:59316)
317
Sylvain Defresnea8b73d252018-02-28 15:45:54318_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15319 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54320 r'/\bTEST[(]',
321 (
322 'TEST() macro should not be used in Objective-C++ code as it does not ',
323 'drain the autorelease pool at the end of the test. Use TEST_F() ',
324 'macro instead with a fixture inheriting from PlatformTest (or a ',
325 'typedef).'
326 ),
327 True,
328 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15329 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54330 r'/\btesting::Test\b',
331 (
332 'testing::Test should not be used in Objective-C++ code as it does ',
333 'not drain the autorelease pool at the end of the test. Use ',
334 'PlatformTest instead.'
335 ),
336 True,
337 ),
Ewann2ecc8d72022-07-18 07:41:23338 BanRule(
339 ' systemImageNamed:',
340 (
341 '+[UIImage systemImageNamed:] should not be used to create symbols.',
342 'Instead use a wrapper defined in:',
343 'ios/chrome/browser/ui/icons/chrome_symbol.h'
344 ),
345 True,
Ewann450a2ef2022-07-19 14:38:23346 excluded_paths=(
347 'ios/chrome/browser/ui/icons/chrome_symbol.mm',
348 ),
Ewann2ecc8d72022-07-18 07:41:23349 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54350)
351
Daniel Cheng917ce542022-03-15 20:46:57352_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15353 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05354 r'/\bEXPECT_OCMOCK_VERIFY\b',
355 (
356 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
357 'it is meant for GTests. Use [mock verify] instead.'
358 ),
359 True,
360 ),
361)
362
Daniel Cheng917ce542022-03-15 20:46:57363_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15364 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04365 r'/\busing namespace ',
366 (
367 'Using directives ("using namespace x") are banned by the Google Style',
368 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
369 'Explicitly qualify symbols or use using declarations ("using x::foo").',
370 ),
371 True,
372 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
373 ),
Antonio Gomes07300d02019-03-13 20:59:57374 # Make sure that gtest's FRIEND_TEST() macro is not used; the
375 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
376 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15377 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20378 'FRIEND_TEST(',
379 (
[email protected]e3c945502012-06-26 20:01:49380 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20381 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
382 ),
383 False,
[email protected]7345da02012-11-27 14:31:49384 (),
[email protected]23e6cbc2012-06-16 18:51:20385 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15386 BanRule(
tomhudsone2c14d552016-05-26 17:07:46387 'setMatrixClip',
388 (
389 'Overriding setMatrixClip() is prohibited; ',
390 'the base function is deprecated. ',
391 ),
392 True,
393 (),
394 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15395 BanRule(
[email protected]52657f62013-05-20 05:30:31396 'SkRefPtr',
397 (
398 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22399 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31400 ),
401 True,
402 (),
403 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15404 BanRule(
[email protected]52657f62013-05-20 05:30:31405 'SkAutoRef',
406 (
407 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22408 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31409 ),
410 True,
411 (),
412 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15413 BanRule(
[email protected]52657f62013-05-20 05:30:31414 'SkAutoTUnref',
415 (
416 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22417 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31418 ),
419 True,
420 (),
421 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15422 BanRule(
[email protected]52657f62013-05-20 05:30:31423 'SkAutoUnref',
424 (
425 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
426 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22427 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31428 ),
429 True,
430 (),
431 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15432 BanRule(
[email protected]d89eec82013-12-03 14:10:59433 r'/HANDLE_EINTR\(.*close',
434 (
435 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
436 'descriptor will be closed, and it is incorrect to retry the close.',
437 'Either call close directly and ignore its return value, or wrap close',
438 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
439 ),
440 True,
441 (),
442 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15443 BanRule(
[email protected]d89eec82013-12-03 14:10:59444 r'/IGNORE_EINTR\((?!.*close)',
445 (
446 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
447 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
448 ),
449 True,
450 (
451 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04452 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
453 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59454 ),
455 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15456 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43457 r'/v8::Extension\(',
458 (
459 'Do not introduce new v8::Extensions into the code base, use',
460 'gin::Wrappable instead. See http://crbug.com/334679',
461 ),
462 True,
[email protected]f55c90ee62014-04-12 00:50:03463 (
Egor Paskoce145c42018-09-28 19:31:04464 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03465 ),
[email protected]ec5b3f02014-04-04 18:43:43466 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15467 BanRule(
jame2d1a952016-04-02 00:27:10468 '#pragma comment(lib,',
469 (
470 'Specify libraries to link with in build files and not in the source.',
471 ),
472 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41473 (
tzik3f295992018-12-04 20:32:23474 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04475 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41476 ),
jame2d1a952016-04-02 00:27:10477 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15478 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02479 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59480 (
481 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
482 ),
483 False,
484 (),
485 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15486 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02487 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59488 (
489 'Consider using THREAD_CHECKER macros instead of the class directly.',
490 ),
491 False,
492 (),
493 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15494 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06495 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
496 (
497 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
498 'deprecated (http://crbug.com/634507). Please avoid converting away',
499 'from the Time types in Chromium code, especially if any math is',
500 'being done on time values. For interfacing with platform/library',
501 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
502 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48503 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06504 'other use cases, please contact base/time/OWNERS.',
505 ),
506 False,
507 (),
508 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15509 BanRule(
dbeamb6f4fde2017-06-15 04:03:06510 'CallJavascriptFunctionUnsafe',
511 (
512 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
513 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
514 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
515 ),
516 False,
517 (
Egor Paskoce145c42018-09-28 19:31:04518 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
519 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
520 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06521 ),
522 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15523 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24524 'leveldb::DB::Open',
525 (
526 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
527 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
528 "Chrome's tracing, making their memory usage visible.",
529 ),
530 True,
531 (
532 r'^third_party/leveldatabase/.*\.(cc|h)$',
533 ),
Gabriel Charette0592c3a2017-07-26 12:02:04534 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15535 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08536 'leveldb::NewMemEnv',
537 (
538 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58539 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
540 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08541 ),
542 True,
543 (
544 r'^third_party/leveldatabase/.*\.(cc|h)$',
545 ),
546 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15547 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47548 'RunLoop::QuitCurrent',
549 (
Robert Liao64b7ab22017-08-04 23:03:43550 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
551 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47552 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41553 False,
Gabriel Charetted9839bc2017-07-29 14:17:47554 (),
Gabriel Charettea44975052017-08-21 23:14:04555 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15556 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04557 'base::ScopedMockTimeMessageLoopTaskRunner',
558 (
Gabriel Charette87cc1af2018-04-25 20:52:51559 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11560 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51561 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
562 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
563 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04564 ),
Gabriel Charette87cc1af2018-04-25 20:52:51565 False,
Gabriel Charettea44975052017-08-21 23:14:04566 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57567 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15568 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44569 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57570 (
571 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02572 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57573 ),
574 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16575 # Abseil's benchmarks never linked into chrome.
576 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38577 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15578 BanRule(
Peter Kasting991618a62019-06-17 22:00:09579 r'/\bstd::stoi\b',
580 (
581 'std::stoi uses exceptions to communicate results. ',
582 'Use base::StringToInt() instead.',
583 ),
584 True,
585 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
586 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15587 BanRule(
Peter Kasting991618a62019-06-17 22:00:09588 r'/\bstd::stol\b',
589 (
590 'std::stol uses exceptions to communicate results. ',
591 'Use base::StringToInt() instead.',
592 ),
593 True,
594 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
595 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15596 BanRule(
Peter Kasting991618a62019-06-17 22:00:09597 r'/\bstd::stoul\b',
598 (
599 'std::stoul uses exceptions to communicate results. ',
600 'Use base::StringToUint() instead.',
601 ),
602 True,
603 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
604 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15605 BanRule(
Peter Kasting991618a62019-06-17 22:00:09606 r'/\bstd::stoll\b',
607 (
608 'std::stoll uses exceptions to communicate results. ',
609 'Use base::StringToInt64() instead.',
610 ),
611 True,
612 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
613 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15614 BanRule(
Peter Kasting991618a62019-06-17 22:00:09615 r'/\bstd::stoull\b',
616 (
617 'std::stoull uses exceptions to communicate results. ',
618 'Use base::StringToUint64() instead.',
619 ),
620 True,
621 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
622 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15623 BanRule(
Peter Kasting991618a62019-06-17 22:00:09624 r'/\bstd::stof\b',
625 (
626 'std::stof uses exceptions to communicate results. ',
627 'For locale-independent values, e.g. reading numbers from disk',
628 'profiles, use base::StringToDouble().',
629 'For user-visible values, parse using ICU.',
630 ),
631 True,
632 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
633 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15634 BanRule(
Peter Kasting991618a62019-06-17 22:00:09635 r'/\bstd::stod\b',
636 (
637 'std::stod uses exceptions to communicate results. ',
638 'For locale-independent values, e.g. reading numbers from disk',
639 'profiles, use base::StringToDouble().',
640 'For user-visible values, parse using ICU.',
641 ),
642 True,
643 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
644 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15645 BanRule(
Peter Kasting991618a62019-06-17 22:00:09646 r'/\bstd::stold\b',
647 (
648 'std::stold uses exceptions to communicate results. ',
649 'For locale-independent values, e.g. reading numbers from disk',
650 'profiles, use base::StringToDouble().',
651 'For user-visible values, parse using ICU.',
652 ),
653 True,
654 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
655 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15656 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45657 r'/\bstd::to_string\b',
658 (
659 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09660 'For locale-independent strings, e.g. writing numbers to disk',
661 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45662 'For user-visible strings, use base::FormatNumber() and',
663 'the related functions in base/i18n/number_formatting.h.',
664 ),
Peter Kasting991618a62019-06-17 22:00:09665 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21666 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45667 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15668 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45669 r'/\bstd::shared_ptr\b',
670 (
671 'std::shared_ptr should not be used. Use scoped_refptr instead.',
672 ),
673 True,
Ulan Degenbaev947043882021-02-10 14:02:31674 [
675 # Needed for interop with third-party library.
676 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57677 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58678 '^third_party/blink/renderer/bindings/core/v8/' +
679 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58680 '^gin/array_buffer\.(cc|h)',
681 '^chrome/services/sharing/nearby/',
Meilin 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',
agrievef32bcc72016-04-04 14:57:401217]
1218
wnwenbdc444e2016-05-25 13:44:151219
agrievef32bcc72016-04-04 14:57:401220_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1221
1222
Eric Boren6fd2b932018-01-25 15:05:081223# Bypass the AUTHORS check for these accounts.
1224_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591225 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451226 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591227 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521228 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231229 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471230 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461231 'infra-try-recipes-tester', 'lacros-tracking-roller',
1232 'lacros-sdk-version-roller')
Eric Boren835d71f2018-09-07 21:09:041233 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271234 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041235 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161236 for s in ('chromium-internal-autoroll',)
1237 ) | set('%[email protected]' % s
1238 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081239
Matt Stark6ef08872021-07-29 01:21:461240_INVALID_GRD_FILE_LINE = [
1241 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1242]
Eric Boren6fd2b932018-01-25 15:05:081243
Daniel Bratell65b033262019-04-23 08:17:061244def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501245 """Returns True if this file contains C++-like code (and not Python,
1246 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061247
Sam Maiera6e76d72022-02-11 21:43:501248 ext = input_api.os_path.splitext(file_path)[1]
1249 # This list is compatible with CppChecker.IsCppFile but we should
1250 # consider adding ".c" to it. If we do that we can use this function
1251 # at more places in the code.
1252 return ext in (
1253 '.h',
1254 '.cc',
1255 '.cpp',
1256 '.m',
1257 '.mm',
1258 )
1259
Daniel Bratell65b033262019-04-23 08:17:061260
1261def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501262 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061263
1264
1265def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501266 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061267
1268
1269def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501270 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061271
Mohamed Heikal5e5b7922020-10-29 18:57:591272
Erik Staabc734cd7a2021-11-23 03:11:521273def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501274 ext = input_api.os_path.splitext(file_path)[1]
1275 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521276
1277
Mohamed Heikal5e5b7922020-10-29 18:57:591278def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501279 """Prevent additions of dependencies from the upstream repo on //clank."""
1280 # clank can depend on clank
1281 if input_api.change.RepositoryRoot().endswith('clank'):
1282 return []
1283 build_file_patterns = [
1284 r'(.+/)?BUILD\.gn',
1285 r'.+\.gni',
1286 ]
1287 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1288 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591289
Sam Maiera6e76d72022-02-11 21:43:501290 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591291
Sam Maiera6e76d72022-02-11 21:43:501292 def FilterFile(affected_file):
1293 return input_api.FilterSourceFile(affected_file,
1294 files_to_check=build_file_patterns,
1295 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591296
Sam Maiera6e76d72022-02-11 21:43:501297 problems = []
1298 for f in input_api.AffectedSourceFiles(FilterFile):
1299 local_path = f.LocalPath()
1300 for line_number, line in f.ChangedContents():
1301 if (bad_pattern.search(line)):
1302 problems.append('%s:%d\n %s' %
1303 (local_path, line_number, line.strip()))
1304 if problems:
1305 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1306 else:
1307 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591308
1309
Saagar Sanghavifceeaae2020-08-12 16:40:361310def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501311 """Attempts to prevent use of functions intended only for testing in
1312 non-testing code. For now this is just a best-effort implementation
1313 that ignores header files and may have some false positives. A
1314 better implementation would probably need a proper C++ parser.
1315 """
1316 # We only scan .cc files and the like, as the declaration of
1317 # for-testing functions in header files are hard to distinguish from
1318 # calls to such functions without a proper C++ parser.
1319 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191320
Sam Maiera6e76d72022-02-11 21:43:501321 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1322 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1323 base_function_pattern)
1324 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1325 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1326 exclusion_pattern = input_api.re.compile(
1327 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1328 (base_function_pattern, base_function_pattern))
1329 # Avoid a false positive in this case, where the method name, the ::, and
1330 # the closing { are all on different lines due to line wrapping.
1331 # HelperClassForTesting::
1332 # HelperClassForTesting(
1333 # args)
1334 # : member(0) {}
1335 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191336
Sam Maiera6e76d72022-02-11 21:43:501337 def FilterFile(affected_file):
1338 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1339 input_api.DEFAULT_FILES_TO_SKIP)
1340 return input_api.FilterSourceFile(
1341 affected_file,
1342 files_to_check=file_inclusion_pattern,
1343 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191344
Sam Maiera6e76d72022-02-11 21:43:501345 problems = []
1346 for f in input_api.AffectedSourceFiles(FilterFile):
1347 local_path = f.LocalPath()
1348 in_method_defn = False
1349 for line_number, line in f.ChangedContents():
1350 if (inclusion_pattern.search(line)
1351 and not comment_pattern.search(line)
1352 and not exclusion_pattern.search(line)
1353 and not allowlist_pattern.search(line)
1354 and not in_method_defn):
1355 problems.append('%s:%d\n %s' %
1356 (local_path, line_number, line.strip()))
1357 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191358
Sam Maiera6e76d72022-02-11 21:43:501359 if problems:
1360 return [
1361 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1362 ]
1363 else:
1364 return []
[email protected]55459852011-08-10 15:17:191365
1366
Saagar Sanghavifceeaae2020-08-12 16:40:361367def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501368 """This is a simplified version of
1369 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1370 """
1371 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1372 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1373 name_pattern = r'ForTest(s|ing)?'
1374 # Describes an occurrence of "ForTest*" inside a // comment.
1375 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1376 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1377 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1378 # Catch calls.
1379 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1380 # Ignore definitions. (Comments are ignored separately.)
1381 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231382
Sam Maiera6e76d72022-02-11 21:43:501383 problems = []
1384 sources = lambda x: input_api.FilterSourceFile(
1385 x,
1386 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1387 DEFAULT_FILES_TO_SKIP),
1388 files_to_check=[r'.*\.java$'])
1389 for f in input_api.AffectedFiles(include_deletes=False,
1390 file_filter=sources):
1391 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231392 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501393 for line_number, line in f.ChangedContents():
1394 if is_inside_javadoc and javadoc_end_re.search(line):
1395 is_inside_javadoc = False
1396 if not is_inside_javadoc and javadoc_start_re.search(line):
1397 is_inside_javadoc = True
1398 if is_inside_javadoc:
1399 continue
1400 if (inclusion_re.search(line) and not comment_re.search(line)
1401 and not annotation_re.search(line)
1402 and not exclusion_re.search(line)):
1403 problems.append('%s:%d\n %s' %
1404 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231405
Sam Maiera6e76d72022-02-11 21:43:501406 if problems:
1407 return [
1408 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1409 ]
1410 else:
1411 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231412
1413
Saagar Sanghavifceeaae2020-08-12 16:40:361414def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501415 """Checks to make sure no .h files include <iostream>."""
1416 files = []
1417 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1418 input_api.re.MULTILINE)
1419 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1420 if not f.LocalPath().endswith('.h'):
1421 continue
1422 contents = input_api.ReadFile(f)
1423 if pattern.search(contents):
1424 files.append(f)
[email protected]10689ca2011-09-02 02:31:541425
Sam Maiera6e76d72022-02-11 21:43:501426 if len(files):
1427 return [
1428 output_api.PresubmitError(
1429 'Do not #include <iostream> in header files, since it inserts static '
1430 'initialization into every file including the header. Instead, '
1431 '#include <ostream>. See http://crbug.com/94794', files)
1432 ]
1433 return []
1434
[email protected]10689ca2011-09-02 02:31:541435
Aleksey Khoroshilov9b28c032022-06-03 16:35:321436def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501437 """Checks no windows headers with StrCat redefined are included directly."""
1438 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:321439 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
1440 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
1441 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
1442 _NON_BASE_DEPENDENT_PATHS)
1443 sources_filter = lambda f: input_api.FilterSourceFile(
1444 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
1445
Sam Maiera6e76d72022-02-11 21:43:501446 pattern_deny = input_api.re.compile(
1447 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1448 input_api.re.MULTILINE)
1449 pattern_allow = input_api.re.compile(
1450 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:321451 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:501452 contents = input_api.ReadFile(f)
1453 if pattern_deny.search(
1454 contents) and not pattern_allow.search(contents):
1455 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431456
Sam Maiera6e76d72022-02-11 21:43:501457 if len(files):
1458 return [
1459 output_api.PresubmitError(
1460 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1461 'directly since they pollute code with StrCat macro. Instead, '
1462 'include matching header from base/win. See http://crbug.com/856536',
1463 files)
1464 ]
1465 return []
Danil Chapovalov3518f362018-08-11 16:13:431466
[email protected]10689ca2011-09-02 02:31:541467
Saagar Sanghavifceeaae2020-08-12 16:40:361468def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501469 """Checks to make sure no source files use UNIT_TEST."""
1470 problems = []
1471 for f in input_api.AffectedFiles():
1472 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1473 continue
[email protected]72df4e782012-06-21 16:28:181474
Sam Maiera6e76d72022-02-11 21:43:501475 for line_num, line in f.ChangedContents():
1476 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1477 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181478
Sam Maiera6e76d72022-02-11 21:43:501479 if not problems:
1480 return []
1481 return [
1482 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1483 '\n'.join(problems))
1484 ]
1485
[email protected]72df4e782012-06-21 16:28:181486
Saagar Sanghavifceeaae2020-08-12 16:40:361487def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501488 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341489
Sam Maiera6e76d72022-02-11 21:43:501490 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1491 instead of DISABLED_. To filter false positives, reports are only generated
1492 if a corresponding MAYBE_ line exists.
1493 """
1494 problems = []
Dominic Battre033531052018-09-24 15:45:341495
Sam Maiera6e76d72022-02-11 21:43:501496 # The following two patterns are looked for in tandem - is a test labeled
1497 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1498 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1499 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341500
Sam Maiera6e76d72022-02-11 21:43:501501 # This is for the case that a test is disabled on all platforms.
1502 full_disable_pattern = input_api.re.compile(
1503 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1504 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341505
Sam Maiera6e76d72022-02-11 21:43:501506 for f in input_api.AffectedFiles(False):
1507 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1508 continue
Dominic Battre033531052018-09-24 15:45:341509
Sam Maiera6e76d72022-02-11 21:43:501510 # Search for MABYE_, DISABLE_ pairs.
1511 disable_lines = {} # Maps of test name to line number.
1512 maybe_lines = {}
1513 for line_num, line in f.ChangedContents():
1514 disable_match = disable_pattern.search(line)
1515 if disable_match:
1516 disable_lines[disable_match.group(1)] = line_num
1517 maybe_match = maybe_pattern.search(line)
1518 if maybe_match:
1519 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341520
Sam Maiera6e76d72022-02-11 21:43:501521 # Search for DISABLE_ occurrences within a TEST() macro.
1522 disable_tests = set(disable_lines.keys())
1523 maybe_tests = set(maybe_lines.keys())
1524 for test in disable_tests.intersection(maybe_tests):
1525 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341526
Sam Maiera6e76d72022-02-11 21:43:501527 contents = input_api.ReadFile(f)
1528 full_disable_match = full_disable_pattern.search(contents)
1529 if full_disable_match:
1530 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341531
Sam Maiera6e76d72022-02-11 21:43:501532 if not problems:
1533 return []
1534 return [
1535 output_api.PresubmitPromptWarning(
1536 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1537 '\n'.join(problems))
1538 ]
1539
Dominic Battre033531052018-09-24 15:45:341540
Nina Satragnof7660532021-09-20 18:03:351541def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501542 """Checks to make sure tests disabled conditionally are not missing a
1543 corresponding MAYBE_ prefix.
1544 """
1545 # Expect at least a lowercase character in the test name. This helps rule out
1546 # false positives with macros wrapping the actual tests name.
1547 define_maybe_pattern = input_api.re.compile(
1548 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191549 # The test_maybe_pattern needs to handle all of these forms. The standard:
1550 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1551 # With a wrapper macro around the test name:
1552 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1553 # And the odd-ball NACL_BROWSER_TEST_f format:
1554 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1555 # The optional E2E_ENABLED-style is handled with (\w*\()?
1556 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1557 # trailing ')'.
1558 test_maybe_pattern = (
1559 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501560 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1561 warnings = []
Nina Satragnof7660532021-09-20 18:03:351562
Sam Maiera6e76d72022-02-11 21:43:501563 # Read the entire files. We can't just read the affected lines, forgetting to
1564 # add MAYBE_ on a change would not show up otherwise.
1565 for f in input_api.AffectedFiles(False):
1566 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1567 continue
1568 contents = input_api.ReadFile(f)
1569 lines = contents.splitlines(True)
1570 current_position = 0
1571 warning_test_names = set()
1572 for line_num, line in enumerate(lines, start=1):
1573 current_position += len(line)
1574 maybe_match = define_maybe_pattern.search(line)
1575 if maybe_match:
1576 test_name = maybe_match.group('test_name')
1577 # Do not warn twice for the same test.
1578 if (test_name in warning_test_names):
1579 continue
1580 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351581
Sam Maiera6e76d72022-02-11 21:43:501582 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1583 # the current position.
1584 test_match = input_api.re.compile(
1585 test_maybe_pattern.format(test_name=test_name),
1586 input_api.re.MULTILINE).search(contents, current_position)
1587 suite_match = input_api.re.compile(
1588 suite_maybe_pattern.format(test_name=test_name),
1589 input_api.re.MULTILINE).search(contents, current_position)
1590 if not test_match and not suite_match:
1591 warnings.append(
1592 output_api.PresubmitPromptWarning(
1593 '%s:%d found MAYBE_ defined without corresponding test %s'
1594 % (f.LocalPath(), line_num, test_name)))
1595 return warnings
1596
[email protected]72df4e782012-06-21 16:28:181597
Saagar Sanghavifceeaae2020-08-12 16:40:361598def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501599 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1600 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:161601 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:501602 input_api.re.MULTILINE)
1603 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1604 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1605 continue
1606 for lnum, line in f.ChangedContents():
1607 if input_api.re.search(pattern, line):
1608 errors.append(
1609 output_api.PresubmitError((
1610 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1611 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1612 (f.LocalPath(), lnum)))
1613 return errors
danakj61c1aa22015-10-26 19:55:521614
1615
Weilun Shia487fad2020-10-28 00:10:341616# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1617# more reliable way. See
1618# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191619
wnwenbdc444e2016-05-25 13:44:151620
Saagar Sanghavifceeaae2020-08-12 16:40:361621def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501622 """Check that FlakyTest annotation is our own instead of the android one"""
1623 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1624 files = []
1625 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1626 if f.LocalPath().endswith('Test.java'):
1627 if pattern.search(input_api.ReadFile(f)):
1628 files.append(f)
1629 if len(files):
1630 return [
1631 output_api.PresubmitError(
1632 'Use org.chromium.base.test.util.FlakyTest instead of '
1633 'android.test.FlakyTest', files)
1634 ]
1635 return []
mcasasb7440c282015-02-04 14:52:191636
wnwenbdc444e2016-05-25 13:44:151637
Saagar Sanghavifceeaae2020-08-12 16:40:361638def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501639 """Make sure .DEPS.git is never modified manually."""
1640 if any(f.LocalPath().endswith('.DEPS.git')
1641 for f in input_api.AffectedFiles()):
1642 return [
1643 output_api.PresubmitError(
1644 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1645 'automated system based on what\'s in DEPS and your changes will be\n'
1646 'overwritten.\n'
1647 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1648 'get-the-code#Rolling_DEPS\n'
1649 'for more information')
1650 ]
1651 return []
[email protected]2a8ac9c2011-10-19 17:20:441652
1653
Saagar Sanghavifceeaae2020-08-12 16:40:361654def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501655 """Checks that DEPS file deps are from allowed_hosts."""
1656 # Run only if DEPS file has been modified to annoy fewer bystanders.
1657 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1658 return []
1659 # Outsource work to gclient verify
1660 try:
1661 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
1662 'third_party', 'depot_tools',
1663 'gclient.py')
1664 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:321665 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:501666 stderr=input_api.subprocess.STDOUT)
1667 return []
1668 except input_api.subprocess.CalledProcessError as error:
1669 return [
1670 output_api.PresubmitError(
1671 'DEPS file must have only git dependencies.',
1672 long_text=error.output)
1673 ]
tandriief664692014-09-23 14:51:471674
1675
Mario Sanchez Prada2472cab2019-09-18 10:58:311676def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151677 ban_rule):
Sam Maiera6e76d72022-02-11 21:43:501678 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311679
Sam Maiera6e76d72022-02-11 21:43:501680 Returns an string composed of the name of the file, the line number where the
1681 match has been found and the additional text passed as |message| in case the
1682 target type name matches the text inside the line passed as parameter.
1683 """
1684 result = []
Peng Huang9c5949a02020-06-11 19:20:541685
Daniel Chenga44a1bcd2022-03-15 20:00:151686 # Ignore comments about banned types.
1687 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:501688 return result
Daniel Chenga44a1bcd2022-03-15 20:00:151689 # A // nocheck comment will bypass this error.
1690 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:501691 return result
1692
1693 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:151694 if ban_rule.pattern[0:1] == '/':
1695 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:501696 if input_api.re.search(regex, line):
1697 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:151698 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:501699 matched = True
1700
1701 if matched:
1702 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:151703 for line in ban_rule.explanation:
1704 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:501705
danakjd18e8892020-12-17 17:42:011706 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:311707
1708
Saagar Sanghavifceeaae2020-08-12 16:40:361709def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501710 """Make sure that banned functions are not used."""
1711 warnings = []
1712 errors = []
[email protected]127f18ec2012-06-16 05:05:591713
Sam Maiera6e76d72022-02-11 21:43:501714 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:151715 if not excluded_paths:
1716 return False
1717
Sam Maiera6e76d72022-02-11 21:43:501718 local_path = affected_file.LocalPath()
1719 for item in excluded_paths:
1720 if input_api.re.match(item, local_path):
1721 return True
1722 return False
wnwenbdc444e2016-05-25 13:44:151723
Sam Maiera6e76d72022-02-11 21:43:501724 def IsIosObjcFile(affected_file):
1725 local_path = affected_file.LocalPath()
1726 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
1727 '.h'):
1728 return False
1729 basename = input_api.os_path.basename(local_path)
1730 if 'ios' in basename.split('_'):
1731 return True
1732 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1733 if sep and 'ios' in local_path.split(sep):
1734 return True
1735 return False
Sylvain Defresnea8b73d252018-02-28 15:45:541736
Daniel Chenga44a1bcd2022-03-15 20:00:151737 def CheckForMatch(affected_file, line_num: int, line: str,
1738 ban_rule: BanRule):
1739 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
1740 return
1741
Sam Maiera6e76d72022-02-11 21:43:501742 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151743 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501744 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:151745 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:501746 errors.extend(problems)
1747 else:
1748 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151749
Sam Maiera6e76d72022-02-11 21:43:501750 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1751 for f in input_api.AffectedFiles(file_filter=file_filter):
1752 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151753 for ban_rule in _BANNED_JAVA_FUNCTIONS:
1754 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:411755
Sam Maiera6e76d72022-02-11 21:43:501756 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1757 for f in input_api.AffectedFiles(file_filter=file_filter):
1758 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151759 for ban_rule in _BANNED_OBJC_FUNCTIONS:
1760 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591761
Sam Maiera6e76d72022-02-11 21:43:501762 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
1763 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151764 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
1765 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:541766
Sam Maiera6e76d72022-02-11 21:43:501767 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1768 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1769 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151770 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
1771 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:051772
Sam Maiera6e76d72022-02-11 21:43:501773 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1774 for f in input_api.AffectedFiles(file_filter=file_filter):
1775 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151776 for ban_rule in _BANNED_CPP_FUNCTIONS:
1777 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591778
Daniel Cheng92c15e32022-03-16 17:48:221779 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
1780 for f in input_api.AffectedFiles(file_filter=file_filter):
1781 for line_num, line in f.ChangedContents():
1782 for ban_rule in _BANNED_MOJOM_PATTERNS:
1783 CheckForMatch(f, line_num, line, ban_rule)
1784
1785
Sam Maiera6e76d72022-02-11 21:43:501786 result = []
1787 if (warnings):
1788 result.append(
1789 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
1790 '\n'.join(warnings)))
1791 if (errors):
1792 result.append(
1793 output_api.PresubmitError('Banned functions were used.\n' +
1794 '\n'.join(errors)))
1795 return result
[email protected]127f18ec2012-06-16 05:05:591796
1797
Michael Thiessen44457642020-02-06 00:24:151798def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501799 """Make sure that banned java imports are not used."""
1800 errors = []
Michael Thiessen44457642020-02-06 00:24:151801
Sam Maiera6e76d72022-02-11 21:43:501802 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1803 for f in input_api.AffectedFiles(file_filter=file_filter):
1804 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151805 for ban_rule in _BANNED_JAVA_IMPORTS:
1806 # Consider merging this into the above function. There is no
1807 # real difference anymore other than helping with a little
1808 # bit of boilerplate text. Doing so means things like
1809 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:501810 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:151811 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501812 if problems:
1813 errors.extend(problems)
1814 result = []
1815 if (errors):
1816 result.append(
1817 output_api.PresubmitError('Banned imports were used.\n' +
1818 '\n'.join(errors)))
1819 return result
Michael Thiessen44457642020-02-06 00:24:151820
1821
Saagar Sanghavifceeaae2020-08-12 16:40:361822def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501823 """Make sure that banned functions are not used."""
1824 files = []
1825 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
1826 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1827 if not f.LocalPath().endswith('.h'):
1828 continue
Bruce Dawson4c4c2922022-05-02 18:07:331829 if f.LocalPath().endswith('com_imported_mstscax.h'):
1830 continue
Sam Maiera6e76d72022-02-11 21:43:501831 contents = input_api.ReadFile(f)
1832 if pattern.search(contents):
1833 files.append(f)
[email protected]6c063c62012-07-11 19:11:061834
Sam Maiera6e76d72022-02-11 21:43:501835 if files:
1836 return [
1837 output_api.PresubmitError(
1838 'Do not use #pragma once in header files.\n'
1839 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1840 files)
1841 ]
1842 return []
[email protected]6c063c62012-07-11 19:11:061843
[email protected]127f18ec2012-06-16 05:05:591844
Saagar Sanghavifceeaae2020-08-12 16:40:361845def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501846 """Checks to make sure we don't introduce use of foo ? true : false."""
1847 problems = []
1848 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1849 for f in input_api.AffectedFiles():
1850 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1851 continue
[email protected]e7479052012-09-19 00:26:121852
Sam Maiera6e76d72022-02-11 21:43:501853 for line_num, line in f.ChangedContents():
1854 if pattern.match(line):
1855 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:121856
Sam Maiera6e76d72022-02-11 21:43:501857 if not problems:
1858 return []
1859 return [
1860 output_api.PresubmitPromptWarning(
1861 'Please consider avoiding the "? true : false" pattern if possible.\n'
1862 + '\n'.join(problems))
1863 ]
[email protected]e7479052012-09-19 00:26:121864
1865
Saagar Sanghavifceeaae2020-08-12 16:40:361866def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501867 """Runs checkdeps on #include and import statements added in this
1868 change. Breaking - rules is an error, breaking ! rules is a
1869 warning.
1870 """
1871 # Return early if no relevant file types were modified.
1872 for f in input_api.AffectedFiles():
1873 path = f.LocalPath()
1874 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
1875 or _IsJavaFile(input_api, path)):
1876 break
[email protected]55f9f382012-07-31 11:02:181877 else:
Sam Maiera6e76d72022-02-11 21:43:501878 return []
rhalavati08acd232017-04-03 07:23:281879
Sam Maiera6e76d72022-02-11 21:43:501880 import sys
1881 # We need to wait until we have an input_api object and use this
1882 # roundabout construct to import checkdeps because this file is
1883 # eval-ed and thus doesn't have __file__.
1884 original_sys_path = sys.path
1885 try:
1886 sys.path = sys.path + [
1887 input_api.os_path.join(input_api.PresubmitLocalPath(),
1888 'buildtools', 'checkdeps')
1889 ]
1890 import checkdeps
1891 from rules import Rule
1892 finally:
1893 # Restore sys.path to what it was before.
1894 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:181895
Sam Maiera6e76d72022-02-11 21:43:501896 added_includes = []
1897 added_imports = []
1898 added_java_imports = []
1899 for f in input_api.AffectedFiles():
1900 if _IsCPlusPlusFile(input_api, f.LocalPath()):
1901 changed_lines = [line for _, line in f.ChangedContents()]
1902 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
1903 elif _IsProtoFile(input_api, f.LocalPath()):
1904 changed_lines = [line for _, line in f.ChangedContents()]
1905 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
1906 elif _IsJavaFile(input_api, f.LocalPath()):
1907 changed_lines = [line for _, line in f.ChangedContents()]
1908 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241909
Sam Maiera6e76d72022-02-11 21:43:501910 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
1911
1912 error_descriptions = []
1913 warning_descriptions = []
1914 error_subjects = set()
1915 warning_subjects = set()
1916
1917 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1918 added_includes):
1919 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1920 description_with_path = '%s\n %s' % (path, rule_description)
1921 if rule_type == Rule.DISALLOW:
1922 error_descriptions.append(description_with_path)
1923 error_subjects.add("#includes")
1924 else:
1925 warning_descriptions.append(description_with_path)
1926 warning_subjects.add("#includes")
1927
1928 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1929 added_imports):
1930 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1931 description_with_path = '%s\n %s' % (path, rule_description)
1932 if rule_type == Rule.DISALLOW:
1933 error_descriptions.append(description_with_path)
1934 error_subjects.add("imports")
1935 else:
1936 warning_descriptions.append(description_with_path)
1937 warning_subjects.add("imports")
1938
1939 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
1940 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
1941 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1942 description_with_path = '%s\n %s' % (path, rule_description)
1943 if rule_type == Rule.DISALLOW:
1944 error_descriptions.append(description_with_path)
1945 error_subjects.add("imports")
1946 else:
1947 warning_descriptions.append(description_with_path)
1948 warning_subjects.add("imports")
1949
1950 results = []
1951 if error_descriptions:
1952 results.append(
1953 output_api.PresubmitError(
1954 'You added one or more %s that violate checkdeps rules.' %
1955 " and ".join(error_subjects), error_descriptions))
1956 if warning_descriptions:
1957 results.append(
1958 output_api.PresubmitPromptOrNotify(
1959 'You added one or more %s of files that are temporarily\n'
1960 'allowed but being removed. Can you avoid introducing the\n'
1961 '%s? See relevant DEPS file(s) for details and contacts.' %
1962 (" and ".join(warning_subjects), "/".join(warning_subjects)),
1963 warning_descriptions))
1964 return results
[email protected]55f9f382012-07-31 11:02:181965
1966
Saagar Sanghavifceeaae2020-08-12 16:40:361967def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501968 """Check that all files have their permissions properly set."""
1969 if input_api.platform == 'win32':
1970 return []
1971 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
1972 'tools', 'checkperms',
1973 'checkperms.py')
1974 args = [
Bruce Dawson8a43cf72022-05-13 17:10:321975 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:501976 input_api.change.RepositoryRoot()
1977 ]
1978 with input_api.CreateTemporaryFile() as file_list:
1979 for f in input_api.AffectedFiles():
1980 # checkperms.py file/directory arguments must be relative to the
1981 # repository.
1982 file_list.write((f.LocalPath() + '\n').encode('utf8'))
1983 file_list.close()
1984 args += ['--file-list', file_list.name]
1985 try:
1986 input_api.subprocess.check_output(args)
1987 return []
1988 except input_api.subprocess.CalledProcessError as error:
1989 return [
1990 output_api.PresubmitError('checkperms.py failed:',
1991 long_text=error.output.decode(
1992 'utf-8', 'ignore'))
1993 ]
[email protected]fbcafe5a2012-08-08 15:31:221994
1995
Saagar Sanghavifceeaae2020-08-12 16:40:361996def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501997 """Makes sure we don't include ui/aura/window_property.h
1998 in header files.
1999 """
2000 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2001 errors = []
2002 for f in input_api.AffectedFiles():
2003 if not f.LocalPath().endswith('.h'):
2004 continue
2005 for line_num, line in f.ChangedContents():
2006 if pattern.match(line):
2007 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:492008
Sam Maiera6e76d72022-02-11 21:43:502009 results = []
2010 if errors:
2011 results.append(
2012 output_api.PresubmitError(
2013 'Header files should not include ui/aura/window_property.h',
2014 errors))
2015 return results
[email protected]c8278b32012-10-30 20:35:492016
2017
Omer Katzcc77ea92021-04-26 10:23:282018def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502019 """Makes sure we don't include any headers from
2020 third_party/blink/renderer/platform/heap/impl or
2021 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2022 third_party/blink/renderer/platform/heap
2023 """
2024 impl_pattern = input_api.re.compile(
2025 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2026 v8_wrapper_pattern = input_api.re.compile(
2027 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2028 )
2029 file_filter = lambda f: not input_api.re.match(
2030 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
2031 f.LocalPath())
2032 errors = []
Omer Katzcc77ea92021-04-26 10:23:282033
Sam Maiera6e76d72022-02-11 21:43:502034 for f in input_api.AffectedFiles(file_filter=file_filter):
2035 for line_num, line in f.ChangedContents():
2036 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2037 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282038
Sam Maiera6e76d72022-02-11 21:43:502039 results = []
2040 if errors:
2041 results.append(
2042 output_api.PresubmitError(
2043 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2044 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2045 'relevant counterparts from third_party/blink/renderer/platform/heap',
2046 errors))
2047 return results
Omer Katzcc77ea92021-04-26 10:23:282048
2049
[email protected]70ca77752012-11-20 03:45:032050def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502051 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2052 errors = []
2053 for line_num, line in f.ChangedContents():
2054 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2055 # First-level headers in markdown look a lot like version control
2056 # conflict markers. http://daringfireball.net/projects/markdown/basics
2057 continue
2058 if pattern.match(line):
2059 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2060 return errors
[email protected]70ca77752012-11-20 03:45:032061
2062
Saagar Sanghavifceeaae2020-08-12 16:40:362063def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502064 """Usually this is not intentional and will cause a compile failure."""
2065 errors = []
2066 for f in input_api.AffectedFiles():
2067 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032068
Sam Maiera6e76d72022-02-11 21:43:502069 results = []
2070 if errors:
2071 results.append(
2072 output_api.PresubmitError(
2073 'Version control conflict markers found, please resolve.',
2074 errors))
2075 return results
[email protected]70ca77752012-11-20 03:45:032076
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202077
Saagar Sanghavifceeaae2020-08-12 16:40:362078def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502079 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2080 errors = []
2081 for f in input_api.AffectedFiles():
2082 for line_num, line in f.ChangedContents():
2083 if pattern.search(line):
2084 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162085
Sam Maiera6e76d72022-02-11 21:43:502086 results = []
2087 if errors:
2088 results.append(
2089 output_api.PresubmitPromptWarning(
2090 'Found Google support URL addressed by answer number. Please replace '
2091 'with a p= identifier instead. See crbug.com/679462\n',
2092 errors))
2093 return results
estadee17314a02017-01-12 16:22:162094
[email protected]70ca77752012-11-20 03:45:032095
Saagar Sanghavifceeaae2020-08-12 16:40:362096def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502097 def FilterFile(affected_file):
2098 """Filter function for use with input_api.AffectedSourceFiles,
2099 below. This filters out everything except non-test files from
2100 top-level directories that generally speaking should not hard-code
2101 service URLs (e.g. src/android_webview/, src/content/ and others).
2102 """
2103 return input_api.FilterSourceFile(
2104 affected_file,
2105 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2106 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2107 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442108
Sam Maiera6e76d72022-02-11 21:43:502109 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2110 '\.(com|net)[^"]*"')
2111 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2112 pattern = input_api.re.compile(base_pattern)
2113 problems = [] # items are (filename, line_number, line)
2114 for f in input_api.AffectedSourceFiles(FilterFile):
2115 for line_num, line in f.ChangedContents():
2116 if not comment_pattern.search(line) and pattern.search(line):
2117 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442118
Sam Maiera6e76d72022-02-11 21:43:502119 if problems:
2120 return [
2121 output_api.PresubmitPromptOrNotify(
2122 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2123 'Are you sure this is correct?', [
2124 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2125 for problem in problems
2126 ])
2127 ]
2128 else:
2129 return []
[email protected]06e6d0ff2012-12-11 01:36:442130
2131
Saagar Sanghavifceeaae2020-08-12 16:40:362132def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502133 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292134
Sam Maiera6e76d72022-02-11 21:43:502135 def FileFilter(affected_file):
2136 """Includes directories known to be Chrome OS only."""
2137 return input_api.FilterSourceFile(
2138 affected_file,
2139 files_to_check=(
2140 '^ash/',
2141 '^chromeos/', # Top-level src/chromeos.
2142 '.*/chromeos/', # Any path component.
2143 '^components/arc',
2144 '^components/exo'),
2145 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292146
Sam Maiera6e76d72022-02-11 21:43:502147 prefs = []
2148 priority_prefs = []
2149 for f in input_api.AffectedFiles(file_filter=FileFilter):
2150 for line_num, line in f.ChangedContents():
2151 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2152 line):
2153 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2154 prefs.append(' %s' % line)
2155 if input_api.re.search(
2156 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2157 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2158 priority_prefs.append(' %s' % line)
2159
2160 results = []
2161 if (prefs):
2162 results.append(
2163 output_api.PresubmitPromptWarning(
2164 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2165 'by browser sync settings. If these prefs should be controlled by OS '
2166 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2167 '\n'.join(prefs)))
2168 if (priority_prefs):
2169 results.append(
2170 output_api.PresubmitPromptWarning(
2171 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2172 'controlled by browser sync settings. If these prefs should be '
2173 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2174 'instead.\n' + '\n'.join(prefs)))
2175 return results
James Cook6b6597c2019-11-06 22:05:292176
2177
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492178# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362179def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502180 """Makes sure there are no abbreviations in the name of PNG files.
2181 The native_client_sdk directory is excluded because it has auto-generated PNG
2182 files for documentation.
2183 """
2184 errors = []
2185 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Bruce Dawson3db456212022-05-02 05:34:182186 files_to_skip = [r'^native_client_sdk[\\/]',
2187 r'^services[\\/]test[\\/]',
2188 r'^third_party[\\/]blink[\\/]web_tests[\\/]',
2189 ]
Sam Maiera6e76d72022-02-11 21:43:502190 file_filter = lambda f: input_api.FilterSourceFile(
2191 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2192 for f in input_api.AffectedFiles(include_deletes=False,
2193 file_filter=file_filter):
2194 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272195
Sam Maiera6e76d72022-02-11 21:43:502196 results = []
2197 if errors:
2198 results.append(
2199 output_api.PresubmitError(
2200 'The name of PNG files should not have abbreviations. \n'
2201 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2202 'Contact [email protected] if you have questions.', errors))
2203 return results
[email protected]d2530012013-01-25 16:39:272204
2205
Daniel Cheng4dcdb6b2017-04-13 08:30:172206def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502207 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172208
Sam Maiera6e76d72022-02-11 21:43:502209 Args:
2210 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2211 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172212 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502213 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172214 if rule.startswith('+') or rule.startswith('!')
2215 ])
Sam Maiera6e76d72022-02-11 21:43:502216 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2217 add_rules.update([
2218 rule[1:] for rule in rules
2219 if rule.startswith('+') or rule.startswith('!')
2220 ])
2221 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172222
2223
2224def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502225 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172226
Sam Maiera6e76d72022-02-11 21:43:502227 # Stubs for handling special syntax in the root DEPS file.
2228 class _VarImpl:
2229 def __init__(self, local_scope):
2230 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172231
Sam Maiera6e76d72022-02-11 21:43:502232 def Lookup(self, var_name):
2233 """Implements the Var syntax."""
2234 try:
2235 return self._local_scope['vars'][var_name]
2236 except KeyError:
2237 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172238
Sam Maiera6e76d72022-02-11 21:43:502239 local_scope = {}
2240 global_scope = {
2241 'Var': _VarImpl(local_scope).Lookup,
2242 'Str': str,
2243 }
Dirk Pranke1b9e06382021-05-14 01:16:222244
Sam Maiera6e76d72022-02-11 21:43:502245 exec(contents, global_scope, local_scope)
2246 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172247
2248
2249def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502250 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2251 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412252
Sam Maiera6e76d72022-02-11 21:43:502253 For a directory (rather than a specific filename) we fake a path to
2254 a specific filename by adding /DEPS. This is chosen as a file that
2255 will seldom or never be subject to per-file include_rules.
2256 """
2257 # We ignore deps entries on auto-generated directories.
2258 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082259
Sam Maiera6e76d72022-02-11 21:43:502260 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2261 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172262
Sam Maiera6e76d72022-02-11 21:43:502263 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172264
Sam Maiera6e76d72022-02-11 21:43:502265 results = set()
2266 for added_dep in added_deps:
2267 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2268 continue
2269 # Assume that a rule that ends in .h is a rule for a specific file.
2270 if added_dep.endswith('.h'):
2271 results.add(added_dep)
2272 else:
2273 results.add(os_path.join(added_dep, 'DEPS'))
2274 return results
[email protected]f32e2d1e2013-07-26 21:39:082275
2276
Saagar Sanghavifceeaae2020-08-12 16:40:362277def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502278 """When a dependency prefixed with + is added to a DEPS file, we
2279 want to make sure that the change is reviewed by an OWNER of the
2280 target file or directory, to avoid layering violations from being
2281 introduced. This check verifies that this happens.
2282 """
2283 # We rely on Gerrit's code-owners to check approvals.
2284 # input_api.gerrit is always set for Chromium, but other projects
2285 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102286 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502287 return []
2288 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2289 input_api.change.issue)):
2290 # Skip OWNERS check when Owners-Override label is approved. This is intended
2291 # for global owners, trusted bots, and on-call sheriffs. Review is still
2292 # required for these changes.
2293 return []
Edward Lesmes6fba51082021-01-20 04:20:232294
Sam Maiera6e76d72022-02-11 21:43:502295 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242296
Sam Maiera6e76d72022-02-11 21:43:502297 file_filter = lambda f: not input_api.re.match(
2298 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
2299 for f in input_api.AffectedFiles(include_deletes=False,
2300 file_filter=file_filter):
2301 filename = input_api.os_path.basename(f.LocalPath())
2302 if filename == 'DEPS':
2303 virtual_depended_on_files.update(
2304 _CalculateAddedDeps(input_api.os_path,
2305 '\n'.join(f.OldContents()),
2306 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552307
Sam Maiera6e76d72022-02-11 21:43:502308 if not virtual_depended_on_files:
2309 return []
[email protected]e871964c2013-05-13 14:14:552310
Sam Maiera6e76d72022-02-11 21:43:502311 if input_api.is_committing:
2312 if input_api.tbr:
2313 return [
2314 output_api.PresubmitNotifyResult(
2315 '--tbr was specified, skipping OWNERS check for DEPS additions'
2316 )
2317 ]
Daniel Cheng3008dc12022-05-13 04:02:112318 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2319 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502320 if input_api.dry_run:
2321 return [
2322 output_api.PresubmitNotifyResult(
2323 'This is a dry run, skipping OWNERS check for DEPS additions'
2324 )
2325 ]
2326 if not input_api.change.issue:
2327 return [
2328 output_api.PresubmitError(
2329 "DEPS approval by OWNERS check failed: this change has "
2330 "no change number, so we can't check it for approvals.")
2331 ]
2332 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412333 else:
Sam Maiera6e76d72022-02-11 21:43:502334 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552335
Sam Maiera6e76d72022-02-11 21:43:502336 owner_email, reviewers = (
2337 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2338 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552339
Sam Maiera6e76d72022-02-11 21:43:502340 owner_email = owner_email or input_api.change.author_email
2341
2342 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2343 virtual_depended_on_files, reviewers.union([owner_email]), [])
2344 missing_files = [
2345 f for f in virtual_depended_on_files
2346 if approval_status[f] != input_api.owners_client.APPROVED
2347 ]
2348
2349 # We strip the /DEPS part that was added by
2350 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2351 # directory.
2352 def StripDeps(path):
2353 start_deps = path.rfind('/DEPS')
2354 if start_deps != -1:
2355 return path[:start_deps]
2356 else:
2357 return path
2358
2359 unapproved_dependencies = [
2360 "'+%s'," % StripDeps(path) for path in missing_files
2361 ]
2362
2363 if unapproved_dependencies:
2364 output_list = [
2365 output(
2366 'You need LGTM from owners of depends-on paths in DEPS that were '
2367 'modified in this CL:\n %s' %
2368 '\n '.join(sorted(unapproved_dependencies)))
2369 ]
2370 suggested_owners = input_api.owners_client.SuggestOwners(
2371 missing_files, exclude=[owner_email])
2372 output_list.append(
2373 output('Suggested missing target path OWNERS:\n %s' %
2374 '\n '.join(suggested_owners or [])))
2375 return output_list
2376
2377 return []
[email protected]e871964c2013-05-13 14:14:552378
2379
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492380# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362381def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502382 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2383 files_to_skip = (
2384 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2385 input_api.DEFAULT_FILES_TO_SKIP + (
2386 r"^base[\\/]logging\.h$",
2387 r"^base[\\/]logging\.cc$",
2388 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2389 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2390 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2391 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2392 r"startup_browser_creator\.cc$",
2393 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2394 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2395 r"diagnostics_writer\.cc$",
2396 r"^chrome[\\/]chrome_cleaner[\\/].*",
2397 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2398 r"dll_hash_main\.cc$",
2399 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2400 r"^chromecast[\\/]",
Sam Maiera6e76d72022-02-11 21:43:502401 r"^components[\\/]browser_watcher[\\/]"
Joseph Wang668ab202022-07-26 16:24:492402 r"dump_stability_report_main_win\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502403 r"^components[\\/]media_control[\\/]renderer[\\/]"
2404 r"media_playback_options\.cc$",
2405 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2406 r"overlay_strategy_underlay_cast\.cc$",
2407 r"^components[\\/]zucchini[\\/].*",
2408 # TODO(peter): Remove exception. https://crbug.com/534537
2409 r"^content[\\/]browser[\\/]notifications[\\/]"
2410 r"notification_event_dispatcher_impl\.cc$",
2411 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2412 r"gl_helper_benchmark\.cc$",
2413 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2414 r"^courgette[\\/]courgette_tool\.cc$",
2415 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Joseph Wang668ab202022-07-26 16:24:492416 r"^fuchsia_web[\\/]common[\\/]init_logging\.cc$",
2417 r"^fuchsia_web[\\/]runners[\\/]common[\\/]web_component\.cc$",
2418 r"^fuchsia_web[\\/]shell[\\/].*_shell\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502419 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2420 r"^ipc[\\/]ipc_logging\.cc$",
2421 r"^native_client_sdk[\\/]",
2422 r"^remoting[\\/]base[\\/]logging\.h$",
2423 r"^remoting[\\/]host[\\/].*",
2424 r"^sandbox[\\/]linux[\\/].*",
2425 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Joseph Wang668ab202022-07-26 16:24:492426 r"dump_file_system\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502427 r"^tools[\\/]",
Joseph Wang668ab202022-07-26 16:24:492428 r"^ui[\\/]base[\\/]resource[\\/]data_pack\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502429 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2430 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2431 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2432 r"xwmstartupcheck\.cc$"))
2433 source_file_filter = lambda x: input_api.FilterSourceFile(
2434 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402435
Sam Maiera6e76d72022-02-11 21:43:502436 log_info = set([])
2437 printf = set([])
[email protected]85218562013-11-22 07:41:402438
Sam Maiera6e76d72022-02-11 21:43:502439 for f in input_api.AffectedSourceFiles(source_file_filter):
2440 for _, line in f.ChangedContents():
2441 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2442 log_info.add(f.LocalPath())
2443 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2444 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372445
Sam Maiera6e76d72022-02-11 21:43:502446 if input_api.re.search(r"\bprintf\(", line):
2447 printf.add(f.LocalPath())
2448 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2449 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402450
Sam Maiera6e76d72022-02-11 21:43:502451 if log_info:
2452 return [
2453 output_api.PresubmitError(
2454 'These files spam the console log with LOG(INFO):',
2455 items=log_info)
2456 ]
2457 if printf:
2458 return [
2459 output_api.PresubmitError(
2460 'These files spam the console log with printf/fprintf:',
2461 items=printf)
2462 ]
2463 return []
[email protected]85218562013-11-22 07:41:402464
2465
Saagar Sanghavifceeaae2020-08-12 16:40:362466def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502467 """These types are all expected to hold locks while in scope and
2468 so should never be anonymous (which causes them to be immediately
2469 destroyed)."""
2470 they_who_must_be_named = [
2471 'base::AutoLock',
2472 'base::AutoReset',
2473 'base::AutoUnlock',
2474 'SkAutoAlphaRestore',
2475 'SkAutoBitmapShaderInstall',
2476 'SkAutoBlitterChoose',
2477 'SkAutoBounderCommit',
2478 'SkAutoCallProc',
2479 'SkAutoCanvasRestore',
2480 'SkAutoCommentBlock',
2481 'SkAutoDescriptor',
2482 'SkAutoDisableDirectionCheck',
2483 'SkAutoDisableOvalCheck',
2484 'SkAutoFree',
2485 'SkAutoGlyphCache',
2486 'SkAutoHDC',
2487 'SkAutoLockColors',
2488 'SkAutoLockPixels',
2489 'SkAutoMalloc',
2490 'SkAutoMaskFreeImage',
2491 'SkAutoMutexAcquire',
2492 'SkAutoPathBoundsUpdate',
2493 'SkAutoPDFRelease',
2494 'SkAutoRasterClipValidate',
2495 'SkAutoRef',
2496 'SkAutoTime',
2497 'SkAutoTrace',
2498 'SkAutoUnref',
2499 ]
2500 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2501 # bad: base::AutoLock(lock.get());
2502 # not bad: base::AutoLock lock(lock.get());
2503 bad_pattern = input_api.re.compile(anonymous)
2504 # good: new base::AutoLock(lock.get())
2505 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2506 errors = []
[email protected]49aa76a2013-12-04 06:59:162507
Sam Maiera6e76d72022-02-11 21:43:502508 for f in input_api.AffectedFiles():
2509 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2510 continue
2511 for linenum, line in f.ChangedContents():
2512 if bad_pattern.search(line) and not good_pattern.search(line):
2513 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162514
Sam Maiera6e76d72022-02-11 21:43:502515 if errors:
2516 return [
2517 output_api.PresubmitError(
2518 'These lines create anonymous variables that need to be named:',
2519 items=errors)
2520 ]
2521 return []
[email protected]49aa76a2013-12-04 06:59:162522
2523
Saagar Sanghavifceeaae2020-08-12 16:40:362524def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502525 # Returns whether |template_str| is of the form <T, U...> for some types T
2526 # and U. Assumes that |template_str| is already in the form <...>.
2527 def HasMoreThanOneArg(template_str):
2528 # Level of <...> nesting.
2529 nesting = 0
2530 for c in template_str:
2531 if c == '<':
2532 nesting += 1
2533 elif c == '>':
2534 nesting -= 1
2535 elif c == ',' and nesting == 1:
2536 return True
2537 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532538
Sam Maiera6e76d72022-02-11 21:43:502539 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2540 sources = lambda affected_file: input_api.FilterSourceFile(
2541 affected_file,
2542 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2543 DEFAULT_FILES_TO_SKIP),
2544 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552545
Sam Maiera6e76d72022-02-11 21:43:502546 # Pattern to capture a single "<...>" block of template arguments. It can
2547 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2548 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2549 # latter would likely require counting that < and > match, which is not
2550 # expressible in regular languages. Should the need arise, one can introduce
2551 # limited counting (matching up to a total number of nesting depth), which
2552 # should cover all practical cases for already a low nesting limit.
2553 template_arg_pattern = (
2554 r'<[^>]*' # Opening block of <.
2555 r'>([^<]*>)?') # Closing block of >.
2556 # Prefix expressing that whatever follows is not already inside a <...>
2557 # block.
2558 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2559 null_construct_pattern = input_api.re.compile(
2560 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2561 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552562
Sam Maiera6e76d72022-02-11 21:43:502563 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2564 template_arg_no_array_pattern = (
2565 r'<[^>]*[^]]' # Opening block of <.
2566 r'>([^(<]*[^]]>)?') # Closing block of >.
2567 # Prefix saying that what follows is the start of an expression.
2568 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2569 # Suffix saying that what follows are call parentheses with a non-empty list
2570 # of arguments.
2571 nonempty_arg_list_pattern = r'\(([^)]|$)'
2572 # Put the template argument into a capture group for deeper examination later.
2573 return_construct_pattern = input_api.re.compile(
2574 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2575 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552576
Sam Maiera6e76d72022-02-11 21:43:502577 problems_constructor = []
2578 problems_nullptr = []
2579 for f in input_api.AffectedSourceFiles(sources):
2580 for line_number, line in f.ChangedContents():
2581 # Disallow:
2582 # return std::unique_ptr<T>(foo);
2583 # bar = std::unique_ptr<T>(foo);
2584 # But allow:
2585 # return std::unique_ptr<T[]>(foo);
2586 # bar = std::unique_ptr<T[]>(foo);
2587 # And also allow cases when the second template argument is present. Those
2588 # cases cannot be handled by std::make_unique:
2589 # return std::unique_ptr<T, U>(foo);
2590 # bar = std::unique_ptr<T, U>(foo);
2591 local_path = f.LocalPath()
2592 return_construct_result = return_construct_pattern.search(line)
2593 if return_construct_result and not HasMoreThanOneArg(
2594 return_construct_result.group('template_arg')):
2595 problems_constructor.append(
2596 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2597 # Disallow:
2598 # std::unique_ptr<T>()
2599 if null_construct_pattern.search(line):
2600 problems_nullptr.append(
2601 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052602
Sam Maiera6e76d72022-02-11 21:43:502603 errors = []
2604 if problems_nullptr:
2605 errors.append(
2606 output_api.PresubmitPromptWarning(
2607 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2608 problems_nullptr))
2609 if problems_constructor:
2610 errors.append(
2611 output_api.PresubmitError(
2612 'The following files use explicit std::unique_ptr constructor. '
2613 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2614 'std::make_unique is not an option.', problems_constructor))
2615 return errors
Peter Kasting4844e46e2018-02-23 07:27:102616
2617
Saagar Sanghavifceeaae2020-08-12 16:40:362618def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502619 """Checks if any new user action has been added."""
2620 if any('actions.xml' == input_api.os_path.basename(f)
2621 for f in input_api.LocalPaths()):
2622 # If actions.xml is already included in the changelist, the PRESUBMIT
2623 # for actions.xml will do a more complete presubmit check.
2624 return []
2625
2626 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2627 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2628 input_api.DEFAULT_FILES_TO_SKIP)
2629 file_filter = lambda f: input_api.FilterSourceFile(
2630 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2631
2632 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2633 current_actions = None
2634 for f in input_api.AffectedFiles(file_filter=file_filter):
2635 for line_num, line in f.ChangedContents():
2636 match = input_api.re.search(action_re, line)
2637 if match:
2638 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2639 # loaded only once.
2640 if not current_actions:
2641 with open(
2642 'tools/metrics/actions/actions.xml') as actions_f:
2643 current_actions = actions_f.read()
2644 # Search for the matched user action name in |current_actions|.
2645 for action_name in match.groups():
2646 action = 'name="{0}"'.format(action_name)
2647 if action not in current_actions:
2648 return [
2649 output_api.PresubmitPromptWarning(
2650 'File %s line %d: %s is missing in '
2651 'tools/metrics/actions/actions.xml. Please run '
2652 'tools/metrics/actions/extract_actions.py to update.'
2653 % (f.LocalPath(), line_num, action_name))
2654 ]
[email protected]999261d2014-03-03 20:08:082655 return []
2656
[email protected]999261d2014-03-03 20:08:082657
Daniel Cheng13ca61a882017-08-25 15:11:252658def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502659 import sys
2660 sys.path = sys.path + [
2661 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2662 'json_comment_eater')
2663 ]
2664 import json_comment_eater
2665 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252666
2667
[email protected]99171a92014-06-03 08:44:472668def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172669 try:
Sam Maiera6e76d72022-02-11 21:43:502670 contents = input_api.ReadFile(filename)
2671 if eat_comments:
2672 json_comment_eater = _ImportJSONCommentEater(input_api)
2673 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172674
Sam Maiera6e76d72022-02-11 21:43:502675 input_api.json.loads(contents)
2676 except ValueError as e:
2677 return e
Andrew Grieve4deedb12022-02-03 21:34:502678 return None
2679
2680
Sam Maiera6e76d72022-02-11 21:43:502681def _GetIDLParseError(input_api, filename):
2682 try:
2683 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:282684 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:342685 if not char.isascii():
2686 return (
2687 'Non-ascii character "%s" (ord %d) found at offset %d.' %
2688 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:502689 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2690 'tools', 'json_schema_compiler',
2691 'idl_schema.py')
2692 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282693 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502694 stdin=input_api.subprocess.PIPE,
2695 stdout=input_api.subprocess.PIPE,
2696 stderr=input_api.subprocess.PIPE,
2697 universal_newlines=True)
2698 (_, error) = process.communicate(input=contents)
2699 return error or None
2700 except ValueError as e:
2701 return e
agrievef32bcc72016-04-04 14:57:402702
agrievef32bcc72016-04-04 14:57:402703
Sam Maiera6e76d72022-02-11 21:43:502704def CheckParseErrors(input_api, output_api):
2705 """Check that IDL and JSON files do not contain syntax errors."""
2706 actions = {
2707 '.idl': _GetIDLParseError,
2708 '.json': _GetJSONParseError,
2709 }
2710 # Most JSON files are preprocessed and support comments, but these do not.
2711 json_no_comments_patterns = [
2712 r'^testing[\\/]',
2713 ]
2714 # Only run IDL checker on files in these directories.
2715 idl_included_patterns = [
2716 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2717 r'^extensions[\\/]common[\\/]api[\\/]',
2718 ]
agrievef32bcc72016-04-04 14:57:402719
Sam Maiera6e76d72022-02-11 21:43:502720 def get_action(affected_file):
2721 filename = affected_file.LocalPath()
2722 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:402723
Sam Maiera6e76d72022-02-11 21:43:502724 def FilterFile(affected_file):
2725 action = get_action(affected_file)
2726 if not action:
2727 return False
2728 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:402729
Sam Maiera6e76d72022-02-11 21:43:502730 if _MatchesFile(input_api,
2731 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
2732 return False
2733
2734 if (action == _GetIDLParseError
2735 and not _MatchesFile(input_api, idl_included_patterns, path)):
2736 return False
2737 return True
2738
2739 results = []
2740 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
2741 include_deletes=False):
2742 action = get_action(affected_file)
2743 kwargs = {}
2744 if (action == _GetJSONParseError
2745 and _MatchesFile(input_api, json_no_comments_patterns,
2746 affected_file.LocalPath())):
2747 kwargs['eat_comments'] = False
2748 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
2749 **kwargs)
2750 if parse_error:
2751 results.append(
2752 output_api.PresubmitError(
2753 '%s could not be parsed: %s' %
2754 (affected_file.LocalPath(), parse_error)))
2755 return results
2756
2757
2758def CheckJavaStyle(input_api, output_api):
2759 """Runs checkstyle on changed java files and returns errors if any exist."""
2760
2761 # Return early if no java files were modified.
2762 if not any(
2763 _IsJavaFile(input_api, f.LocalPath())
2764 for f in input_api.AffectedFiles()):
2765 return []
2766
2767 import sys
2768 original_sys_path = sys.path
2769 try:
2770 sys.path = sys.path + [
2771 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2772 'android', 'checkstyle')
2773 ]
2774 import checkstyle
2775 finally:
2776 # Restore sys.path to what it was before.
2777 sys.path = original_sys_path
2778
2779 return checkstyle.RunCheckstyle(
2780 input_api,
2781 output_api,
2782 'tools/android/checkstyle/chromium-style-5.0.xml',
2783 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
2784
2785
2786def CheckPythonDevilInit(input_api, output_api):
2787 """Checks to make sure devil is initialized correctly in python scripts."""
2788 script_common_initialize_pattern = input_api.re.compile(
2789 r'script_common\.InitializeEnvironment\(')
2790 devil_env_config_initialize = input_api.re.compile(
2791 r'devil_env\.config\.Initialize\(')
2792
2793 errors = []
2794
2795 sources = lambda affected_file: input_api.FilterSourceFile(
2796 affected_file,
2797 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
2798 r'^build[\\/]android[\\/]devil_chromium\.py',
2799 r'^third_party[\\/].*',
2800 )),
2801 files_to_check=[r'.*\.py$'])
2802
2803 for f in input_api.AffectedSourceFiles(sources):
2804 for line_num, line in f.ChangedContents():
2805 if (script_common_initialize_pattern.search(line)
2806 or devil_env_config_initialize.search(line)):
2807 errors.append("%s:%d" % (f.LocalPath(), line_num))
2808
2809 results = []
2810
2811 if errors:
2812 results.append(
2813 output_api.PresubmitError(
2814 'Devil initialization should always be done using '
2815 'devil_chromium.Initialize() in the chromium project, to use better '
2816 'defaults for dependencies (ex. up-to-date version of adb).',
2817 errors))
2818
2819 return results
2820
2821
2822def _MatchesFile(input_api, patterns, path):
2823 for pattern in patterns:
2824 if input_api.re.search(pattern, path):
2825 return True
2826 return False
2827
2828
Daniel Chenga37c03db2022-05-12 17:20:342829def _ChangeHasSecurityReviewer(input_api, owners_file):
2830 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:502831
Daniel Chenga37c03db2022-05-12 17:20:342832 Args:
2833 input_api: The presubmit input API.
2834 owners_file: OWNERS file with required reviewers. Typically, this is
2835 something like ipc/SECURITY_OWNERS.
2836
2837 Note: if the presubmit is running for commit rather than for upload, this
2838 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:502839 """
Daniel Chengd88244472022-05-16 09:08:472840 # Owners-Override should bypass all additional OWNERS enforcement checks.
2841 # A CR+1 vote will still be required to land this change.
2842 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2843 input_api.change.issue)):
2844 return True
2845
Daniel Chenga37c03db2022-05-12 17:20:342846 owner_email, reviewers = (
2847 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:112848 input_api,
2849 None,
2850 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:502851
Daniel Chenga37c03db2022-05-12 17:20:342852 security_owners = input_api.owners_client.ListOwners(owners_file)
2853 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:502854
Daniel Chenga37c03db2022-05-12 17:20:342855
2856@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:252857class _SecurityProblemWithItems:
2858 problem: str
2859 items: Sequence[str]
2860
2861
2862@dataclass
Daniel Chenga37c03db2022-05-12 17:20:342863class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:252864 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:342865 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:252866 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:342867
2868
2869def _FindMissingSecurityOwners(input_api,
2870 output_api,
2871 file_patterns: Sequence[str],
2872 excluded_patterns: Sequence[str],
2873 required_owners_file: str,
2874 custom_rule_function: Optional[Callable] = None
2875 ) -> _MissingSecurityOwnersResult:
2876 """Find OWNERS files missing per-file rules for security-sensitive files.
2877
2878 Args:
2879 input_api: the PRESUBMIT input API object.
2880 output_api: the PRESUBMIT output API object.
2881 file_patterns: basename patterns that require a corresponding per-file
2882 security restriction.
2883 excluded_patterns: path patterns that should be exempted from
2884 requiring a security restriction.
2885 required_owners_file: path to the required OWNERS file, e.g.
2886 ipc/SECURITY_OWNERS
2887 cc_alias: If not None, email that will be CCed automatically if the
2888 change contains security-sensitive files, as determined by
2889 `file_patterns` and `excluded_patterns`.
2890 custom_rule_function: If not None, will be called with `input_api` and
2891 the current file under consideration. Returning True will add an
2892 exact match per-file rule check for the current file.
2893 """
2894
2895 # `to_check` is a mapping of an OWNERS file path to Patterns.
2896 #
2897 # Patterns is a dictionary mapping glob patterns (suitable for use in
2898 # per-file rules) to a PatternEntry.
2899 #
Sam Maiera6e76d72022-02-11 21:43:502900 # PatternEntry is a dictionary with two keys:
2901 # - 'files': the files that are matched by this pattern
2902 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:342903 #
Sam Maiera6e76d72022-02-11 21:43:502904 # For example, if we expect OWNERS file to contain rules for *.mojom and
2905 # *_struct_traits*.*, Patterns might look like this:
2906 # {
2907 # '*.mojom': {
2908 # 'files': ...,
2909 # 'rules': [
2910 # 'per-file *.mojom=set noparent',
2911 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2912 # ],
2913 # },
2914 # '*_struct_traits*.*': {
2915 # 'files': ...,
2916 # 'rules': [
2917 # 'per-file *_struct_traits*.*=set noparent',
2918 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2919 # ],
2920 # },
2921 # }
2922 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:342923 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:502924
Daniel Chenga37c03db2022-05-12 17:20:342925 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:502926 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:472927 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:502928 if owners_file not in to_check:
2929 to_check[owners_file] = {}
2930 if pattern not in to_check[owners_file]:
2931 to_check[owners_file][pattern] = {
2932 'files': [],
2933 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:342934 f'per-file {pattern}=set noparent',
2935 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:502936 ]
2937 }
Daniel Chenged57a162022-05-25 02:56:342938 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:342939 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:502940
Daniel Chenga37c03db2022-05-12 17:20:342941 # Only enforce security OWNERS rules for a directory if that directory has a
2942 # file that matches `file_patterns`. For example, if a directory only
2943 # contains *.mojom files and no *_messages*.h files, the check should only
2944 # ensure that rules for *.mojom files are present.
2945 for file in input_api.AffectedFiles(include_deletes=False):
2946 file_basename = input_api.os_path.basename(file.LocalPath())
2947 if custom_rule_function is not None and custom_rule_function(
2948 input_api, file):
2949 AddPatternToCheck(file, file_basename)
2950 continue
Sam Maiera6e76d72022-02-11 21:43:502951
Daniel Chenga37c03db2022-05-12 17:20:342952 if any(
2953 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
2954 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:502955 continue
2956
2957 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:342958 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
2959 # file's basename.
2960 if input_api.fnmatch.fnmatch(file_basename, pattern):
2961 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:502962 break
2963
Daniel Chenga37c03db2022-05-12 17:20:342964 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:252965
2966 # Check if any newly added lines in OWNERS files intersect with required
2967 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
2968 # This is a hack, but is needed because the OWNERS check (by design) ignores
2969 # new OWNERS entries; otherwise, a non-owner could add someone as a new
2970 # OWNER and have that newly-added OWNER self-approve their own addition.
2971 newly_covered_files = []
2972 for file in input_api.AffectedFiles(include_deletes=False):
2973 if not file.LocalPath() in to_check:
2974 continue
2975 for _, line in file.ChangedContents():
2976 for _, entry in to_check[file.LocalPath()].items():
2977 if line in entry['rules']:
2978 newly_covered_files.extend(entry['files'])
2979
2980 missing_reviewer_problems = None
2981 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:342982 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:252983 missing_reviewer_problems = _SecurityProblemWithItems(
2984 f'Review from an owner in {required_owners_file} is required for '
2985 'the following newly-added files:',
2986 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:502987
2988 # Go through the OWNERS files to check, filtering out rules that are already
2989 # present in that OWNERS file.
2990 for owners_file, patterns in to_check.items():
2991 try:
Daniel Cheng171dad8d2022-05-21 00:40:252992 lines = set(
2993 input_api.ReadFile(
2994 input_api.os_path.join(input_api.change.RepositoryRoot(),
2995 owners_file)).splitlines())
2996 for entry in patterns.values():
2997 entry['rules'] = [
2998 rule for rule in entry['rules'] if rule not in lines
2999 ]
Sam Maiera6e76d72022-02-11 21:43:503000 except IOError:
3001 # No OWNERS file, so all the rules are definitely missing.
3002 continue
3003
3004 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253005 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343006
Sam Maiera6e76d72022-02-11 21:43:503007 for owners_file, patterns in to_check.items():
3008 missing_lines = []
3009 files = []
3010 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343011 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503012 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503013 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253014 joined_missing_lines = '\n'.join(line for line in missing_lines)
3015 owners_file_problems.append(
3016 _SecurityProblemWithItems(
3017 'Found missing OWNERS lines for security-sensitive files. '
3018 f'Please add the following lines to {owners_file}:\n'
3019 f'{joined_missing_lines}\n\nTo ensure security review for:',
3020 files))
Daniel Chenga37c03db2022-05-12 17:20:343021
Daniel Cheng171dad8d2022-05-21 00:40:253022 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343023 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253024 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343025
3026
3027def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3028 # Whether or not a file affects IPC is (mostly) determined by a simple list
3029 # of filename patterns.
3030 file_patterns = [
3031 # Legacy IPC:
3032 '*_messages.cc',
3033 '*_messages*.h',
3034 '*_param_traits*.*',
3035 # Mojo IPC:
3036 '*.mojom',
3037 '*_mojom_traits*.*',
3038 '*_type_converter*.*',
3039 # Android native IPC:
3040 '*.aidl',
3041 ]
3042
Daniel Chenga37c03db2022-05-12 17:20:343043 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463044 # These third_party directories do not contain IPCs, but contain files
3045 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343046 'third_party/crashpad/*',
3047 'third_party/blink/renderer/platform/bindings/*',
3048 'third_party/protobuf/benchmarks/python/*',
3049 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473050 # Enum-only mojoms used for web metrics, so no security review needed.
3051 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343052 # These files are just used to communicate between class loaders running
3053 # in the same process.
3054 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3055 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3056 ]
3057
3058 def IsMojoServiceManifestFile(input_api, file):
3059 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3060 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3061 if not manifest_pattern.search(file.LocalPath()):
3062 return False
3063
3064 if test_manifest_pattern.search(file.LocalPath()):
3065 return False
3066
3067 # All actual service manifest files should contain at least one
3068 # qualified reference to service_manager::Manifest.
3069 return any('service_manager::Manifest' in line
3070 for line in file.NewContents())
3071
3072 return _FindMissingSecurityOwners(
3073 input_api,
3074 output_api,
3075 file_patterns,
3076 excluded_patterns,
3077 'ipc/SECURITY_OWNERS',
3078 custom_rule_function=IsMojoServiceManifestFile)
3079
3080
3081def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3082 file_patterns = [
3083 # Component specifications.
3084 '*.cml', # Component Framework v2.
3085 '*.cmx', # Component Framework v1.
3086
3087 # Fuchsia IDL protocol specifications.
3088 '*.fidl',
3089 ]
3090
3091 # Don't check for owners files for changes in these directories.
3092 excluded_patterns = [
3093 'third_party/crashpad/*',
3094 ]
3095
3096 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3097 excluded_patterns,
3098 'build/fuchsia/SECURITY_OWNERS')
3099
3100
3101def CheckSecurityOwners(input_api, output_api):
3102 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3103 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3104 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3105 input_api, output_api)
3106
3107 if ipc_results.has_security_sensitive_files:
3108 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503109
3110 results = []
Daniel Chenga37c03db2022-05-12 17:20:343111
Daniel Cheng171dad8d2022-05-21 00:40:253112 missing_reviewer_problems = []
3113 if ipc_results.missing_reviewer_problem:
3114 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3115 if fuchsia_results.missing_reviewer_problem:
3116 missing_reviewer_problems.append(
3117 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343118
Daniel Cheng171dad8d2022-05-21 00:40:253119 # Missing reviewers are an error unless there's no issue number
3120 # associated with this branch; in that case, the presubmit is being run
3121 # with --all or --files.
3122 #
3123 # Note that upload should never be an error; otherwise, it would be
3124 # impossible to upload changes at all.
3125 if input_api.is_committing and input_api.change.issue:
3126 make_presubmit_message = output_api.PresubmitError
3127 else:
3128 make_presubmit_message = output_api.PresubmitNotifyResult
3129 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503130 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253131 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343132
Daniel Cheng171dad8d2022-05-21 00:40:253133 owners_file_problems = []
3134 owners_file_problems.extend(ipc_results.owners_file_problems)
3135 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343136
Daniel Cheng171dad8d2022-05-21 00:40:253137 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113138 # Missing per-file rules are always an error. While swarming and caching
3139 # means that uploading a patchset with updated OWNERS files and sending
3140 # it to the CQ again should not have a large incremental cost, it is
3141 # still frustrating to discover the error only after the change has
3142 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343143 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253144 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503145
3146 return results
3147
3148
3149def _GetFilesUsingSecurityCriticalFunctions(input_api):
3150 """Checks affected files for changes to security-critical calls. This
3151 function checks the full change diff, to catch both additions/changes
3152 and removals.
3153
3154 Returns a dict keyed by file name, and the value is a set of detected
3155 functions.
3156 """
3157 # Map of function pretty name (displayed in an error) to the pattern to
3158 # match it with.
3159 _PATTERNS_TO_CHECK = {
3160 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3161 }
3162 _PATTERNS_TO_CHECK = {
3163 k: input_api.re.compile(v)
3164 for k, v in _PATTERNS_TO_CHECK.items()
3165 }
3166
Sam Maiera6e76d72022-02-11 21:43:503167 # We don't want to trigger on strings within this file.
3168 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343169 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503170
3171 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3172 files_to_functions = {}
3173 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3174 diff = f.GenerateScmDiff()
3175 for line in diff.split('\n'):
3176 # Not using just RightHandSideLines() because removing a
3177 # call to a security-critical function can be just as important
3178 # as adding or changing the arguments.
3179 if line.startswith('-') or (line.startswith('+')
3180 and not line.startswith('++')):
3181 for name, pattern in _PATTERNS_TO_CHECK.items():
3182 if pattern.search(line):
3183 path = f.LocalPath()
3184 if not path in files_to_functions:
3185 files_to_functions[path] = set()
3186 files_to_functions[path].add(name)
3187 return files_to_functions
3188
3189
3190def CheckSecurityChanges(input_api, output_api):
3191 """Checks that changes involving security-critical functions are reviewed
3192 by the security team.
3193 """
3194 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3195 if not len(files_to_functions):
3196 return []
3197
Sam Maiera6e76d72022-02-11 21:43:503198 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343199 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503200 return []
3201
Daniel Chenga37c03db2022-05-12 17:20:343202 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503203 'that need to be reviewed by {}.\n'.format(owners_file)
3204 for path, names in files_to_functions.items():
3205 msg += ' {}\n'.format(path)
3206 for name in names:
3207 msg += ' {}\n'.format(name)
3208 msg += '\n'
3209
3210 if input_api.is_committing:
3211 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033212 else:
Sam Maiera6e76d72022-02-11 21:43:503213 output = output_api.PresubmitNotifyResult
3214 return [output(msg)]
3215
3216
3217def CheckSetNoParent(input_api, output_api):
3218 """Checks that set noparent is only used together with an OWNERS file in
3219 //build/OWNERS.setnoparent (see also
3220 //docs/code_reviews.md#owners-files-details)
3221 """
3222 # Return early if no OWNERS files were modified.
3223 if not any(f.LocalPath().endswith('OWNERS')
3224 for f in input_api.AffectedFiles(include_deletes=False)):
3225 return []
3226
3227 errors = []
3228
3229 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3230 allowed_owners_files = set()
3231 with open(allowed_owners_files_file, 'r') as f:
3232 for line in f:
3233 line = line.strip()
3234 if not line or line.startswith('#'):
3235 continue
3236 allowed_owners_files.add(line)
3237
3238 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3239
3240 for f in input_api.AffectedFiles(include_deletes=False):
3241 if not f.LocalPath().endswith('OWNERS'):
3242 continue
3243
3244 found_owners_files = set()
3245 found_set_noparent_lines = dict()
3246
3247 # Parse the OWNERS file.
3248 for lineno, line in enumerate(f.NewContents(), 1):
3249 line = line.strip()
3250 if line.startswith('set noparent'):
3251 found_set_noparent_lines[''] = lineno
3252 if line.startswith('file://'):
3253 if line in allowed_owners_files:
3254 found_owners_files.add('')
3255 if line.startswith('per-file'):
3256 match = per_file_pattern.match(line)
3257 if match:
3258 glob = match.group(1).strip()
3259 directive = match.group(2).strip()
3260 if directive == 'set noparent':
3261 found_set_noparent_lines[glob] = lineno
3262 if directive.startswith('file://'):
3263 if directive in allowed_owners_files:
3264 found_owners_files.add(glob)
3265
3266 # Check that every set noparent line has a corresponding file:// line
3267 # listed in build/OWNERS.setnoparent. An exception is made for top level
3268 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493269 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3270 if (linux_path.count('/') != 1
3271 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503272 for set_noparent_line in found_set_noparent_lines:
3273 if set_noparent_line in found_owners_files:
3274 continue
3275 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493276 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503277 found_set_noparent_lines[set_noparent_line]))
3278
3279 results = []
3280 if errors:
3281 if input_api.is_committing:
3282 output = output_api.PresubmitError
3283 else:
3284 output = output_api.PresubmitPromptWarning
3285 results.append(
3286 output(
3287 'Found the following "set noparent" restrictions in OWNERS files that '
3288 'do not include owners from build/OWNERS.setnoparent:',
3289 long_text='\n\n'.join(errors)))
3290 return results
3291
3292
3293def CheckUselessForwardDeclarations(input_api, output_api):
3294 """Checks that added or removed lines in non third party affected
3295 header files do not lead to new useless class or struct forward
3296 declaration.
3297 """
3298 results = []
3299 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3300 input_api.re.MULTILINE)
3301 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3302 input_api.re.MULTILINE)
3303 for f in input_api.AffectedFiles(include_deletes=False):
3304 if (f.LocalPath().startswith('third_party')
3305 and not f.LocalPath().startswith('third_party/blink')
3306 and not f.LocalPath().startswith('third_party\\blink')):
3307 continue
3308
3309 if not f.LocalPath().endswith('.h'):
3310 continue
3311
3312 contents = input_api.ReadFile(f)
3313 fwd_decls = input_api.re.findall(class_pattern, contents)
3314 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3315
3316 useless_fwd_decls = []
3317 for decl in fwd_decls:
3318 count = sum(1 for _ in input_api.re.finditer(
3319 r'\b%s\b' % input_api.re.escape(decl), contents))
3320 if count == 1:
3321 useless_fwd_decls.append(decl)
3322
3323 if not useless_fwd_decls:
3324 continue
3325
3326 for line in f.GenerateScmDiff().splitlines():
3327 if (line.startswith('-') and not line.startswith('--')
3328 or line.startswith('+') and not line.startswith('++')):
3329 for decl in useless_fwd_decls:
3330 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3331 results.append(
3332 output_api.PresubmitPromptWarning(
3333 '%s: %s forward declaration is no longer needed'
3334 % (f.LocalPath(), decl)))
3335 useless_fwd_decls.remove(decl)
3336
3337 return results
3338
3339
3340def _CheckAndroidDebuggableBuild(input_api, output_api):
3341 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3342 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3343 this is a debuggable build of Android.
3344 """
3345 build_type_check_pattern = input_api.re.compile(
3346 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3347
3348 errors = []
3349
3350 sources = lambda affected_file: input_api.FilterSourceFile(
3351 affected_file,
3352 files_to_skip=(
3353 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3354 DEFAULT_FILES_TO_SKIP + (
3355 r"^android_webview[\\/]support_library[\\/]"
3356 "boundary_interfaces[\\/]",
3357 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3358 r'^third_party[\\/].*',
3359 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3360 r"webview[\\/]chromium[\\/]License.*",
3361 )),
3362 files_to_check=[r'.*\.java$'])
3363
3364 for f in input_api.AffectedSourceFiles(sources):
3365 for line_num, line in f.ChangedContents():
3366 if build_type_check_pattern.search(line):
3367 errors.append("%s:%d" % (f.LocalPath(), line_num))
3368
3369 results = []
3370
3371 if errors:
3372 results.append(
3373 output_api.PresubmitPromptWarning(
3374 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3375 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3376
3377 return results
3378
3379# TODO: add unit tests
3380def _CheckAndroidToastUsage(input_api, output_api):
3381 """Checks that code uses org.chromium.ui.widget.Toast instead of
3382 android.widget.Toast (Chromium Toast doesn't force hardware
3383 acceleration on low-end devices, saving memory).
3384 """
3385 toast_import_pattern = input_api.re.compile(
3386 r'^import android\.widget\.Toast;$')
3387
3388 errors = []
3389
3390 sources = lambda affected_file: input_api.FilterSourceFile(
3391 affected_file,
3392 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3393 DEFAULT_FILES_TO_SKIP + (r'^chromecast[\\/].*',
3394 r'^remoting[\\/].*')),
3395 files_to_check=[r'.*\.java$'])
3396
3397 for f in input_api.AffectedSourceFiles(sources):
3398 for line_num, line in f.ChangedContents():
3399 if toast_import_pattern.search(line):
3400 errors.append("%s:%d" % (f.LocalPath(), line_num))
3401
3402 results = []
3403
3404 if errors:
3405 results.append(
3406 output_api.PresubmitError(
3407 'android.widget.Toast usage is detected. Android toasts use hardware'
3408 ' acceleration, and can be\ncostly on low-end devices. Please use'
3409 ' org.chromium.ui.widget.Toast instead.\n'
3410 'Contact [email protected] if you have any questions.',
3411 errors))
3412
3413 return results
3414
3415
3416def _CheckAndroidCrLogUsage(input_api, output_api):
3417 """Checks that new logs using org.chromium.base.Log:
3418 - Are using 'TAG' as variable name for the tags (warn)
3419 - Are using a tag that is shorter than 20 characters (error)
3420 """
3421
3422 # Do not check format of logs in the given files
3423 cr_log_check_excluded_paths = [
3424 # //chrome/android/webapk cannot depend on //base
3425 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3426 # WebView license viewer code cannot depend on //base; used in stub APK.
3427 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3428 r"webview[\\/]chromium[\\/]License.*",
3429 # The customtabs_benchmark is a small app that does not depend on Chromium
3430 # java pieces.
3431 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3432 ]
3433
3434 cr_log_import_pattern = input_api.re.compile(
3435 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3436 class_in_base_pattern = input_api.re.compile(
3437 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3438 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3439 input_api.re.MULTILINE)
3440 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3441 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3442 log_decl_pattern = input_api.re.compile(
3443 r'static final String TAG = "(?P<name>(.*))"')
3444 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3445
3446 REF_MSG = ('See docs/android_logging.md for more info.')
3447 sources = lambda x: input_api.FilterSourceFile(
3448 x,
3449 files_to_check=[r'.*\.java$'],
3450 files_to_skip=cr_log_check_excluded_paths)
3451
3452 tag_decl_errors = []
3453 tag_length_errors = []
3454 tag_errors = []
3455 tag_with_dot_errors = []
3456 util_log_errors = []
3457
3458 for f in input_api.AffectedSourceFiles(sources):
3459 file_content = input_api.ReadFile(f)
3460 has_modified_logs = False
3461 # Per line checks
3462 if (cr_log_import_pattern.search(file_content)
3463 or (class_in_base_pattern.search(file_content)
3464 and not has_some_log_import_pattern.search(file_content))):
3465 # Checks to run for files using cr log
3466 for line_num, line in f.ChangedContents():
3467 if rough_log_decl_pattern.search(line):
3468 has_modified_logs = True
3469
3470 # Check if the new line is doing some logging
3471 match = log_call_pattern.search(line)
3472 if match:
3473 has_modified_logs = True
3474
3475 # Make sure it uses "TAG"
3476 if not match.group('tag') == 'TAG':
3477 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3478 else:
3479 # Report non cr Log function calls in changed lines
3480 for line_num, line in f.ChangedContents():
3481 if log_call_pattern.search(line):
3482 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3483
3484 # Per file checks
3485 if has_modified_logs:
3486 # Make sure the tag is using the "cr" prefix and is not too long
3487 match = log_decl_pattern.search(file_content)
3488 tag_name = match.group('name') if match else None
3489 if not tag_name:
3490 tag_decl_errors.append(f.LocalPath())
3491 elif len(tag_name) > 20:
3492 tag_length_errors.append(f.LocalPath())
3493 elif '.' in tag_name:
3494 tag_with_dot_errors.append(f.LocalPath())
3495
3496 results = []
3497 if tag_decl_errors:
3498 results.append(
3499 output_api.PresubmitPromptWarning(
3500 'Please define your tags using the suggested format: .\n'
3501 '"private static final String TAG = "<package tag>".\n'
3502 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3503 tag_decl_errors))
3504
3505 if tag_length_errors:
3506 results.append(
3507 output_api.PresubmitError(
3508 'The tag length is restricted by the system to be at most '
3509 '20 characters.\n' + REF_MSG, tag_length_errors))
3510
3511 if tag_errors:
3512 results.append(
3513 output_api.PresubmitPromptWarning(
3514 'Please use a variable named "TAG" for your log tags.\n' +
3515 REF_MSG, tag_errors))
3516
3517 if util_log_errors:
3518 results.append(
3519 output_api.PresubmitPromptWarning(
3520 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3521 util_log_errors))
3522
3523 if tag_with_dot_errors:
3524 results.append(
3525 output_api.PresubmitPromptWarning(
3526 'Dot in log tags cause them to be elided in crash reports.\n' +
3527 REF_MSG, tag_with_dot_errors))
3528
3529 return results
3530
3531
3532def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3533 """Checks that junit.framework.* is no longer used."""
3534 deprecated_junit_framework_pattern = input_api.re.compile(
3535 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3536 sources = lambda x: input_api.FilterSourceFile(
3537 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3538 errors = []
3539 for f in input_api.AffectedFiles(file_filter=sources):
3540 for line_num, line in f.ChangedContents():
3541 if deprecated_junit_framework_pattern.search(line):
3542 errors.append("%s:%d" % (f.LocalPath(), line_num))
3543
3544 results = []
3545 if errors:
3546 results.append(
3547 output_api.PresubmitError(
3548 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3549 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3550 ' if you have any question.', errors))
3551 return results
3552
3553
3554def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3555 """Checks that if new Java test classes have inheritance.
3556 Either the new test class is JUnit3 test or it is a JUnit4 test class
3557 with a base class, either case is undesirable.
3558 """
3559 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3560
3561 sources = lambda x: input_api.FilterSourceFile(
3562 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3563 errors = []
3564 for f in input_api.AffectedFiles(file_filter=sources):
3565 if not f.OldContents():
3566 class_declaration_start_flag = False
3567 for line_num, line in f.ChangedContents():
3568 if class_declaration_pattern.search(line):
3569 class_declaration_start_flag = True
3570 if class_declaration_start_flag and ' extends ' in line:
3571 errors.append('%s:%d' % (f.LocalPath(), line_num))
3572 if '{' in line:
3573 class_declaration_start_flag = False
3574
3575 results = []
3576 if errors:
3577 results.append(
3578 output_api.PresubmitPromptWarning(
3579 'The newly created files include Test classes that inherits from base'
3580 ' class. Please do not use inheritance in JUnit4 tests or add new'
3581 ' JUnit3 tests. Contact [email protected] if you have any'
3582 ' questions.', errors))
3583 return results
3584
3585
3586def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3587 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3588 deprecated_annotation_import_pattern = input_api.re.compile(
3589 r'^import android\.test\.suitebuilder\.annotation\..*;',
3590 input_api.re.MULTILINE)
3591 sources = lambda x: input_api.FilterSourceFile(
3592 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3593 errors = []
3594 for f in input_api.AffectedFiles(file_filter=sources):
3595 for line_num, line in f.ChangedContents():
3596 if deprecated_annotation_import_pattern.search(line):
3597 errors.append("%s:%d" % (f.LocalPath(), line_num))
3598
3599 results = []
3600 if errors:
3601 results.append(
3602 output_api.PresubmitError(
3603 'Annotations in android.test.suitebuilder.annotation have been'
3604 ' deprecated since API level 24. Please use android.support.test.filters'
3605 ' from //third_party/android_support_test_runner:runner_java instead.'
3606 ' Contact [email protected] if you have any questions.',
3607 errors))
3608 return results
3609
3610
3611def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3612 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:513613 file_filter = lambda f: (f.LocalPath().endswith(
3614 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
3615 LocalPath() or '/res/drawable-ldrtl/'.replace(
3616 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:503617 errors = []
3618 for f in input_api.AffectedFiles(include_deletes=False,
3619 file_filter=file_filter):
3620 errors.append(' %s' % f.LocalPath())
3621
3622 results = []
3623 if errors:
3624 results.append(
3625 output_api.PresubmitError(
3626 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3627 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3628 '/res/drawable-ldrtl/.\n'
3629 'Contact [email protected] if you have questions.', errors))
3630 return results
3631
3632
3633def _CheckAndroidWebkitImports(input_api, output_api):
3634 """Checks that code uses org.chromium.base.Callback instead of
3635 android.webview.ValueCallback except in the WebView glue layer
3636 and WebLayer.
3637 """
3638 valuecallback_import_pattern = input_api.re.compile(
3639 r'^import android\.webkit\.ValueCallback;$')
3640
3641 errors = []
3642
3643 sources = lambda affected_file: input_api.FilterSourceFile(
3644 affected_file,
3645 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3646 DEFAULT_FILES_TO_SKIP + (
3647 r'^android_webview[\\/]glue[\\/].*',
3648 r'^weblayer[\\/].*',
3649 )),
3650 files_to_check=[r'.*\.java$'])
3651
3652 for f in input_api.AffectedSourceFiles(sources):
3653 for line_num, line in f.ChangedContents():
3654 if valuecallback_import_pattern.search(line):
3655 errors.append("%s:%d" % (f.LocalPath(), line_num))
3656
3657 results = []
3658
3659 if errors:
3660 results.append(
3661 output_api.PresubmitError(
3662 'android.webkit.ValueCallback usage is detected outside of the glue'
3663 ' layer. To stay compatible with the support library, android.webkit.*'
3664 ' classes should only be used inside the glue layer and'
3665 ' org.chromium.base.Callback should be used instead.', errors))
3666
3667 return results
3668
3669
3670def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3671 """Checks Android XML styles """
3672
3673 # Return early if no relevant files were modified.
3674 if not any(
3675 _IsXmlOrGrdFile(input_api, f.LocalPath())
3676 for f in input_api.AffectedFiles(include_deletes=False)):
3677 return []
3678
3679 import sys
3680 original_sys_path = sys.path
3681 try:
3682 sys.path = sys.path + [
3683 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3684 'android', 'checkxmlstyle')
3685 ]
3686 import checkxmlstyle
3687 finally:
3688 # Restore sys.path to what it was before.
3689 sys.path = original_sys_path
3690
3691 if is_check_on_upload:
3692 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3693 else:
3694 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3695
3696
3697def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3698 """Checks Android Infobar Deprecation """
3699
3700 import sys
3701 original_sys_path = sys.path
3702 try:
3703 sys.path = sys.path + [
3704 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3705 'android', 'infobar_deprecation')
3706 ]
3707 import infobar_deprecation
3708 finally:
3709 # Restore sys.path to what it was before.
3710 sys.path = original_sys_path
3711
3712 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3713
3714
3715class _PydepsCheckerResult:
3716 def __init__(self, cmd, pydeps_path, process, old_contents):
3717 self._cmd = cmd
3718 self._pydeps_path = pydeps_path
3719 self._process = process
3720 self._old_contents = old_contents
3721
3722 def GetError(self):
3723 """Returns an error message, or None."""
3724 import difflib
3725 if self._process.wait() != 0:
3726 # STDERR should already be printed.
3727 return 'Command failed: ' + self._cmd
3728 new_contents = self._process.stdout.read().splitlines()[2:]
3729 if self._old_contents != new_contents:
3730 diff = '\n'.join(
3731 difflib.context_diff(self._old_contents, new_contents))
3732 return ('File is stale: {}\n'
3733 'Diff (apply to fix):\n'
3734 '{}\n'
3735 'To regenerate, run:\n\n'
3736 ' {}').format(self._pydeps_path, diff, self._cmd)
3737 return None
3738
3739
3740class PydepsChecker:
3741 def __init__(self, input_api, pydeps_files):
3742 self._file_cache = {}
3743 self._input_api = input_api
3744 self._pydeps_files = pydeps_files
3745
3746 def _LoadFile(self, path):
3747 """Returns the list of paths within a .pydeps file relative to //."""
3748 if path not in self._file_cache:
3749 with open(path, encoding='utf-8') as f:
3750 self._file_cache[path] = f.read()
3751 return self._file_cache[path]
3752
3753 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3754 """Returns an interable of paths within the .pydep, relativized to //."""
3755 pydeps_data = self._LoadFile(pydeps_path)
3756 uses_gn_paths = '--gn-paths' in pydeps_data
3757 entries = (l for l in pydeps_data.splitlines()
3758 if not l.startswith('#'))
3759 if uses_gn_paths:
3760 # Paths look like: //foo/bar/baz
3761 return (e[2:] for e in entries)
3762 else:
3763 # Paths look like: path/relative/to/file.pydeps
3764 os_path = self._input_api.os_path
3765 pydeps_dir = os_path.dirname(pydeps_path)
3766 return (os_path.normpath(os_path.join(pydeps_dir, e))
3767 for e in entries)
3768
3769 def _CreateFilesToPydepsMap(self):
3770 """Returns a map of local_path -> list_of_pydeps."""
3771 ret = {}
3772 for pydep_local_path in self._pydeps_files:
3773 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3774 ret.setdefault(path, []).append(pydep_local_path)
3775 return ret
3776
3777 def ComputeAffectedPydeps(self):
3778 """Returns an iterable of .pydeps files that might need regenerating."""
3779 affected_pydeps = set()
3780 file_to_pydeps_map = None
3781 for f in self._input_api.AffectedFiles(include_deletes=True):
3782 local_path = f.LocalPath()
3783 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3784 # subrepositories. We can't figure out which files change, so re-check
3785 # all files.
3786 # Changes to print_python_deps.py affect all .pydeps.
3787 if local_path in ('DEPS', 'PRESUBMIT.py'
3788 ) or local_path.endswith('print_python_deps.py'):
3789 return self._pydeps_files
3790 elif local_path.endswith('.pydeps'):
3791 if local_path in self._pydeps_files:
3792 affected_pydeps.add(local_path)
3793 elif local_path.endswith('.py'):
3794 if file_to_pydeps_map is None:
3795 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3796 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3797 return affected_pydeps
3798
3799 def DetermineIfStaleAsync(self, pydeps_path):
3800 """Runs print_python_deps.py to see if the files is stale."""
3801 import os
3802
3803 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3804 if old_pydeps_data:
3805 cmd = old_pydeps_data[1][1:].strip()
3806 if '--output' not in cmd:
3807 cmd += ' --output ' + pydeps_path
3808 old_contents = old_pydeps_data[2:]
3809 else:
3810 # A default cmd that should work in most cases (as long as pydeps filename
3811 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3812 # file is empty/new.
3813 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3814 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3815 old_contents = []
3816 env = dict(os.environ)
3817 env['PYTHONDONTWRITEBYTECODE'] = '1'
3818 process = self._input_api.subprocess.Popen(
3819 cmd + ' --output ""',
3820 shell=True,
3821 env=env,
3822 stdout=self._input_api.subprocess.PIPE,
3823 encoding='utf-8')
3824 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:403825
3826
Tibor Goldschwendt360793f72019-06-25 18:23:493827def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:503828 args = {}
3829 with open('build/config/gclient_args.gni', 'r') as f:
3830 for line in f:
3831 line = line.strip()
3832 if not line or line.startswith('#'):
3833 continue
3834 attribute, value = line.split('=')
3835 args[attribute.strip()] = value.strip()
3836 return args
Tibor Goldschwendt360793f72019-06-25 18:23:493837
3838
Saagar Sanghavifceeaae2020-08-12 16:40:363839def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:503840 """Checks if a .pydeps file needs to be regenerated."""
3841 # This check is for Python dependency lists (.pydeps files), and involves
3842 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3843 # doesn't work on Windows and Mac, so skip it on other platforms.
3844 if not input_api.platform.startswith('linux'):
3845 return []
Erik Staabc734cd7a2021-11-23 03:11:523846
Sam Maiera6e76d72022-02-11 21:43:503847 results = []
3848 # First, check for new / deleted .pydeps.
3849 for f in input_api.AffectedFiles(include_deletes=True):
3850 # Check whether we are running the presubmit check for a file in src.
3851 # f.LocalPath is relative to repo (src, or internal repo).
3852 # os_path.exists is relative to src repo.
3853 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3854 # to src and we can conclude that the pydeps is in src.
3855 if f.LocalPath().endswith('.pydeps'):
3856 if input_api.os_path.exists(f.LocalPath()):
3857 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3858 results.append(
3859 output_api.PresubmitError(
3860 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3861 'remove %s' % f.LocalPath()))
3862 elif f.Action() != 'D' and f.LocalPath(
3863 ) not in _ALL_PYDEPS_FILES:
3864 results.append(
3865 output_api.PresubmitError(
3866 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3867 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403868
Sam Maiera6e76d72022-02-11 21:43:503869 if results:
3870 return results
3871
3872 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
3873 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3874 affected_pydeps = set(checker.ComputeAffectedPydeps())
3875 affected_android_pydeps = affected_pydeps.intersection(
3876 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3877 if affected_android_pydeps and not is_android:
3878 results.append(
3879 output_api.PresubmitPromptOrNotify(
3880 'You have changed python files that may affect pydeps for android\n'
3881 'specific scripts. However, the relevant presumbit check cannot be\n'
3882 'run because you are not using an Android checkout. To validate that\n'
3883 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3884 'use the android-internal-presubmit optional trybot.\n'
3885 'Possibly stale pydeps files:\n{}'.format(
3886 '\n'.join(affected_android_pydeps))))
3887
3888 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3889 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
3890 # Process these concurrently, as each one takes 1-2 seconds.
3891 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
3892 for result in pydep_results:
3893 error_msg = result.GetError()
3894 if error_msg:
3895 results.append(output_api.PresubmitError(error_msg))
3896
agrievef32bcc72016-04-04 14:57:403897 return results
3898
agrievef32bcc72016-04-04 14:57:403899
Saagar Sanghavifceeaae2020-08-12 16:40:363900def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503901 """Checks to make sure no header files have |Singleton<|."""
3902
3903 def FileFilter(affected_file):
3904 # It's ok for base/memory/singleton.h to have |Singleton<|.
3905 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
3906 (r"^base[\\/]memory[\\/]singleton\.h$",
3907 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
James Cook24a504192020-07-23 00:08:443908 r"quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:503909 return input_api.FilterSourceFile(affected_file,
3910 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433911
Sam Maiera6e76d72022-02-11 21:43:503912 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
3913 files = []
3914 for f in input_api.AffectedSourceFiles(FileFilter):
3915 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
3916 or f.LocalPath().endswith('.hpp')
3917 or f.LocalPath().endswith('.inl')):
3918 contents = input_api.ReadFile(f)
3919 for line in contents.splitlines(False):
3920 if (not line.lstrip().startswith('//')
3921 and # Strip C++ comment.
3922 pattern.search(line)):
3923 files.append(f)
3924 break
glidere61efad2015-02-18 17:39:433925
Sam Maiera6e76d72022-02-11 21:43:503926 if files:
3927 return [
3928 output_api.PresubmitError(
3929 'Found base::Singleton<T> in the following header files.\n' +
3930 'Please move them to an appropriate source file so that the ' +
3931 'template gets instantiated in a single compilation unit.',
3932 files)
3933 ]
3934 return []
glidere61efad2015-02-18 17:39:433935
3936
[email protected]fd20b902014-05-09 02:14:533937_DEPRECATED_CSS = [
3938 # Values
3939 ( "-webkit-box", "flex" ),
3940 ( "-webkit-inline-box", "inline-flex" ),
3941 ( "-webkit-flex", "flex" ),
3942 ( "-webkit-inline-flex", "inline-flex" ),
3943 ( "-webkit-min-content", "min-content" ),
3944 ( "-webkit-max-content", "max-content" ),
3945
3946 # Properties
3947 ( "-webkit-background-clip", "background-clip" ),
3948 ( "-webkit-background-origin", "background-origin" ),
3949 ( "-webkit-background-size", "background-size" ),
3950 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443951 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533952
3953 # Functions
3954 ( "-webkit-gradient", "gradient" ),
3955 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3956 ( "-webkit-linear-gradient", "linear-gradient" ),
3957 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3958 ( "-webkit-radial-gradient", "radial-gradient" ),
3959 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3960]
3961
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203962
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493963# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363964def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503965 """ Make sure that we don't use deprecated CSS
3966 properties, functions or values. Our external
3967 documentation and iOS CSS for dom distiller
3968 (reader mode) are ignored by the hooks as it
3969 needs to be consumed by WebKit. """
3970 results = []
3971 file_inclusion_pattern = [r".+\.css$"]
3972 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3973 input_api.DEFAULT_FILES_TO_SKIP +
3974 (r"^chrome/common/extensions/docs", r"^chrome/docs",
3975 r"^native_client_sdk"))
3976 file_filter = lambda f: input_api.FilterSourceFile(
3977 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3978 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3979 for line_num, line in fpath.ChangedContents():
3980 for (deprecated_value, value) in _DEPRECATED_CSS:
3981 if deprecated_value in line:
3982 results.append(
3983 output_api.PresubmitError(
3984 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3985 (fpath.LocalPath(), line_num, deprecated_value,
3986 value)))
3987 return results
[email protected]fd20b902014-05-09 02:14:533988
mohan.reddyf21db962014-10-16 12:26:473989
Saagar Sanghavifceeaae2020-08-12 16:40:363990def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503991 bad_files = {}
3992 for f in input_api.AffectedFiles(include_deletes=False):
3993 if (f.LocalPath().startswith('third_party')
3994 and not f.LocalPath().startswith('third_party/blink')
3995 and not f.LocalPath().startswith('third_party\\blink')):
3996 continue
rlanday6802cf632017-05-30 17:48:363997
Sam Maiera6e76d72022-02-11 21:43:503998 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3999 continue
rlanday6802cf632017-05-30 17:48:364000
Sam Maiera6e76d72022-02-11 21:43:504001 relative_includes = [
4002 line for _, line in f.ChangedContents()
4003 if "#include" in line and "../" in line
4004 ]
4005 if not relative_includes:
4006 continue
4007 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364008
Sam Maiera6e76d72022-02-11 21:43:504009 if not bad_files:
4010 return []
rlanday6802cf632017-05-30 17:48:364011
Sam Maiera6e76d72022-02-11 21:43:504012 error_descriptions = []
4013 for file_path, bad_lines in bad_files.items():
4014 error_description = file_path
4015 for line in bad_lines:
4016 error_description += '\n ' + line
4017 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364018
Sam Maiera6e76d72022-02-11 21:43:504019 results = []
4020 results.append(
4021 output_api.PresubmitError(
4022 'You added one or more relative #include paths (including "../").\n'
4023 'These shouldn\'t be used because they can be used to include headers\n'
4024 'from code that\'s not correctly specified as a dependency in the\n'
4025 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364026
Sam Maiera6e76d72022-02-11 21:43:504027 return results
rlanday6802cf632017-05-30 17:48:364028
Takeshi Yoshinoe387aa32017-08-02 13:16:134029
Saagar Sanghavifceeaae2020-08-12 16:40:364030def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504031 """Check that nobody tries to include a cc file. It's a relatively
4032 common error which results in duplicate symbols in object
4033 files. This may not always break the build until someone later gets
4034 very confusing linking errors."""
4035 results = []
4036 for f in input_api.AffectedFiles(include_deletes=False):
4037 # We let third_party code do whatever it wants
4038 if (f.LocalPath().startswith('third_party')
4039 and not f.LocalPath().startswith('third_party/blink')
4040 and not f.LocalPath().startswith('third_party\\blink')):
4041 continue
Daniel Bratell65b033262019-04-23 08:17:064042
Sam Maiera6e76d72022-02-11 21:43:504043 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4044 continue
Daniel Bratell65b033262019-04-23 08:17:064045
Sam Maiera6e76d72022-02-11 21:43:504046 for _, line in f.ChangedContents():
4047 if line.startswith('#include "'):
4048 included_file = line.split('"')[1]
4049 if _IsCPlusPlusFile(input_api, included_file):
4050 # The most common naming for external files with C++ code,
4051 # apart from standard headers, is to call them foo.inc, but
4052 # Chromium sometimes uses foo-inc.cc so allow that as well.
4053 if not included_file.endswith(('.h', '-inc.cc')):
4054 results.append(
4055 output_api.PresubmitError(
4056 'Only header files or .inc files should be included in other\n'
4057 'C++ files. Compiling the contents of a cc file more than once\n'
4058 'will cause duplicate information in the build which may later\n'
4059 'result in strange link_errors.\n' +
4060 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064061
Sam Maiera6e76d72022-02-11 21:43:504062 return results
Daniel Bratell65b033262019-04-23 08:17:064063
4064
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204065def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504066 if not isinstance(key, ast.Str):
4067 return 'Key at line %d must be a string literal' % key.lineno
4068 if not isinstance(value, ast.Dict):
4069 return 'Value at line %d must be a dict' % value.lineno
4070 if len(value.keys) != 1:
4071 return 'Dict at line %d must have single entry' % value.lineno
4072 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4073 return (
4074 'Entry at line %d must have a string literal \'filepath\' as key' %
4075 value.lineno)
4076 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134077
Takeshi Yoshinoe387aa32017-08-02 13:16:134078
Sergey Ulanov4af16052018-11-08 02:41:464079def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504080 if not isinstance(key, ast.Str):
4081 return 'Key at line %d must be a string literal' % key.lineno
4082 if not isinstance(value, ast.List):
4083 return 'Value at line %d must be a list' % value.lineno
4084 for element in value.elts:
4085 if not isinstance(element, ast.Str):
4086 return 'Watchlist elements on line %d is not a string' % key.lineno
4087 if not email_regex.match(element.s):
4088 return ('Watchlist element on line %d doesn\'t look like a valid '
4089 + 'email: %s') % (key.lineno, element.s)
4090 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134091
Takeshi Yoshinoe387aa32017-08-02 13:16:134092
Sergey Ulanov4af16052018-11-08 02:41:464093def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504094 mismatch_template = (
4095 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4096 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134097
Sam Maiera6e76d72022-02-11 21:43:504098 email_regex = input_api.re.compile(
4099 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464100
Sam Maiera6e76d72022-02-11 21:43:504101 ast = input_api.ast
4102 i = 0
4103 last_key = ''
4104 while True:
4105 if i >= len(wd_dict.keys):
4106 if i >= len(w_dict.keys):
4107 return None
4108 return mismatch_template % ('missing',
4109 'line %d' % w_dict.keys[i].lineno)
4110 elif i >= len(w_dict.keys):
4111 return (mismatch_template %
4112 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134113
Sam Maiera6e76d72022-02-11 21:43:504114 wd_key = wd_dict.keys[i]
4115 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134116
Sam Maiera6e76d72022-02-11 21:43:504117 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4118 wd_dict.values[i], ast)
4119 if result is not None:
4120 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134121
Sam Maiera6e76d72022-02-11 21:43:504122 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4123 email_regex)
4124 if result is not None:
4125 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204126
Sam Maiera6e76d72022-02-11 21:43:504127 if wd_key.s != w_key.s:
4128 return mismatch_template % ('%s at line %d' %
4129 (wd_key.s, wd_key.lineno),
4130 '%s at line %d' %
4131 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204132
Sam Maiera6e76d72022-02-11 21:43:504133 if wd_key.s < last_key:
4134 return (
4135 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4136 % (wd_key.lineno, w_key.lineno))
4137 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204138
Sam Maiera6e76d72022-02-11 21:43:504139 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204140
4141
Sergey Ulanov4af16052018-11-08 02:41:464142def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504143 ast = input_api.ast
4144 if not isinstance(expression, ast.Expression):
4145 return 'WATCHLISTS file must contain a valid expression'
4146 dictionary = expression.body
4147 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4148 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204149
Sam Maiera6e76d72022-02-11 21:43:504150 first_key = dictionary.keys[0]
4151 first_value = dictionary.values[0]
4152 second_key = dictionary.keys[1]
4153 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204154
Sam Maiera6e76d72022-02-11 21:43:504155 if (not isinstance(first_key, ast.Str)
4156 or first_key.s != 'WATCHLIST_DEFINITIONS'
4157 or not isinstance(first_value, ast.Dict)):
4158 return ('The first entry of the dict in WATCHLISTS file must be '
4159 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204160
Sam Maiera6e76d72022-02-11 21:43:504161 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4162 or not isinstance(second_value, ast.Dict)):
4163 return ('The second entry of the dict in WATCHLISTS file must be '
4164 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204165
Sam Maiera6e76d72022-02-11 21:43:504166 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134167
4168
Saagar Sanghavifceeaae2020-08-12 16:40:364169def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504170 for f in input_api.AffectedFiles(include_deletes=False):
4171 if f.LocalPath() == 'WATCHLISTS':
4172 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134173
Sam Maiera6e76d72022-02-11 21:43:504174 try:
4175 # First, make sure that it can be evaluated.
4176 input_api.ast.literal_eval(contents)
4177 # Get an AST tree for it and scan the tree for detailed style checking.
4178 expression = input_api.ast.parse(contents,
4179 filename='WATCHLISTS',
4180 mode='eval')
4181 except ValueError as e:
4182 return [
4183 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4184 long_text=repr(e))
4185 ]
4186 except SyntaxError as e:
4187 return [
4188 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4189 long_text=repr(e))
4190 ]
4191 except TypeError as e:
4192 return [
4193 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4194 long_text=repr(e))
4195 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134196
Sam Maiera6e76d72022-02-11 21:43:504197 result = _CheckWATCHLISTSSyntax(expression, input_api)
4198 if result is not None:
4199 return [output_api.PresubmitError(result)]
4200 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134201
Sam Maiera6e76d72022-02-11 21:43:504202 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134203
4204
Andrew Grieve1b290e4a22020-11-24 20:07:014205def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504206 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014207
Sam Maiera6e76d72022-02-11 21:43:504208 As documented at //build/docs/writing_gn_templates.md
4209 """
Andrew Grieve1b290e4a22020-11-24 20:07:014210
Sam Maiera6e76d72022-02-11 21:43:504211 def gn_files(f):
4212 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014213
Sam Maiera6e76d72022-02-11 21:43:504214 problems = []
4215 for f in input_api.AffectedSourceFiles(gn_files):
4216 for line_num, line in f.ChangedContents():
4217 if 'forward_variables_from(invoker, "*")' in line:
4218 problems.append(
4219 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4220 (f.LocalPath(), line_num))
4221
4222 if problems:
4223 return [
4224 output_api.PresubmitPromptWarning(
4225 'forward_variables_from("*") without exclusions',
4226 items=sorted(problems),
4227 long_text=(
4228 'The variables "visibilty" and "test_only" should be '
4229 'explicitly listed in forward_variables_from(). For more '
4230 'details, see:\n'
4231 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4232 'build/docs/writing_gn_templates.md'
4233 '#Using-forward_variables_from'))
4234 ]
4235 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014236
4237
Saagar Sanghavifceeaae2020-08-12 16:40:364238def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504239 """Checks that newly added header files have corresponding GN changes.
4240 Note that this is only a heuristic. To be precise, run script:
4241 build/check_gn_headers.py.
4242 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194243
Sam Maiera6e76d72022-02-11 21:43:504244 def headers(f):
4245 return input_api.FilterSourceFile(
4246 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194247
Sam Maiera6e76d72022-02-11 21:43:504248 new_headers = []
4249 for f in input_api.AffectedSourceFiles(headers):
4250 if f.Action() != 'A':
4251 continue
4252 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194253
Sam Maiera6e76d72022-02-11 21:43:504254 def gn_files(f):
4255 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194256
Sam Maiera6e76d72022-02-11 21:43:504257 all_gn_changed_contents = ''
4258 for f in input_api.AffectedSourceFiles(gn_files):
4259 for _, line in f.ChangedContents():
4260 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194261
Sam Maiera6e76d72022-02-11 21:43:504262 problems = []
4263 for header in new_headers:
4264 basename = input_api.os_path.basename(header)
4265 if basename not in all_gn_changed_contents:
4266 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194267
Sam Maiera6e76d72022-02-11 21:43:504268 if problems:
4269 return [
4270 output_api.PresubmitPromptWarning(
4271 'Missing GN changes for new header files',
4272 items=sorted(problems),
4273 long_text=
4274 'Please double check whether newly added header files need '
4275 'corresponding changes in gn or gni files.\nThis checking is only a '
4276 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4277 'Read https://crbug.com/661774 for more info.')
4278 ]
4279 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194280
4281
Saagar Sanghavifceeaae2020-08-12 16:40:364282def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504283 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024284
Sam Maiera6e76d72022-02-11 21:43:504285 This assumes we won't intentionally reference one product from the other
4286 product.
4287 """
4288 all_problems = []
4289 test_cases = [{
4290 "filename_postfix": "google_chrome_strings.grd",
4291 "correct_name": "Chrome",
4292 "incorrect_name": "Chromium",
4293 }, {
4294 "filename_postfix": "chromium_strings.grd",
4295 "correct_name": "Chromium",
4296 "incorrect_name": "Chrome",
4297 }]
Michael Giuffridad3bc8672018-10-25 22:48:024298
Sam Maiera6e76d72022-02-11 21:43:504299 for test_case in test_cases:
4300 problems = []
4301 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4302 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024303
Sam Maiera6e76d72022-02-11 21:43:504304 # Check each new line. Can yield false positives in multiline comments, but
4305 # easier than trying to parse the XML because messages can have nested
4306 # children, and associating message elements with affected lines is hard.
4307 for f in input_api.AffectedSourceFiles(filename_filter):
4308 for line_num, line in f.ChangedContents():
4309 if "<message" in line or "<!--" in line or "-->" in line:
4310 continue
4311 if test_case["incorrect_name"] in line:
4312 problems.append("Incorrect product name in %s:%d" %
4313 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024314
Sam Maiera6e76d72022-02-11 21:43:504315 if problems:
4316 message = (
4317 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4318 % (test_case["correct_name"], test_case["correct_name"],
4319 test_case["incorrect_name"]))
4320 all_problems.append(
4321 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024322
Sam Maiera6e76d72022-02-11 21:43:504323 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024324
4325
Saagar Sanghavifceeaae2020-08-12 16:40:364326def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504327 """Avoid large files, especially binary files, in the repository since
4328 git doesn't scale well for those. They will be in everyone's repo
4329 clones forever, forever making Chromium slower to clone and work
4330 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364331
Sam Maiera6e76d72022-02-11 21:43:504332 # Uploading files to cloud storage is not trivial so we don't want
4333 # to set the limit too low, but the upper limit for "normal" large
4334 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4335 # anything over 20 MB is exceptional.
4336 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364337
Sam Maiera6e76d72022-02-11 21:43:504338 too_large_files = []
4339 for f in input_api.AffectedFiles():
4340 # Check both added and modified files (but not deleted files).
4341 if f.Action() in ('A', 'M'):
4342 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4343 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4344 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364345
Sam Maiera6e76d72022-02-11 21:43:504346 if too_large_files:
4347 message = (
4348 'Do not commit large files to git since git scales badly for those.\n'
4349 +
4350 'Instead put the large files in cloud storage and use DEPS to\n' +
4351 'fetch them.\n' + '\n'.join(too_large_files))
4352 return [
4353 output_api.PresubmitError('Too large files found in commit',
4354 long_text=message + '\n')
4355 ]
4356 else:
4357 return []
Daniel Bratell93eb6c62019-04-29 20:13:364358
Max Morozb47503b2019-08-08 21:03:274359
Saagar Sanghavifceeaae2020-08-12 16:40:364360def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504361 """Checks specific for fuzz target sources."""
4362 EXPORTED_SYMBOLS = [
4363 'LLVMFuzzerInitialize',
4364 'LLVMFuzzerCustomMutator',
4365 'LLVMFuzzerCustomCrossOver',
4366 'LLVMFuzzerMutate',
4367 ]
Max Morozb47503b2019-08-08 21:03:274368
Sam Maiera6e76d72022-02-11 21:43:504369 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274370
Sam Maiera6e76d72022-02-11 21:43:504371 def FilterFile(affected_file):
4372 """Ignore libFuzzer source code."""
4373 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4374 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274375
Sam Maiera6e76d72022-02-11 21:43:504376 return input_api.FilterSourceFile(affected_file,
4377 files_to_check=[files_to_check],
4378 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274379
Sam Maiera6e76d72022-02-11 21:43:504380 files_with_missing_header = []
4381 for f in input_api.AffectedSourceFiles(FilterFile):
4382 contents = input_api.ReadFile(f, 'r')
4383 if REQUIRED_HEADER in contents:
4384 continue
Max Morozb47503b2019-08-08 21:03:274385
Sam Maiera6e76d72022-02-11 21:43:504386 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4387 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274388
Sam Maiera6e76d72022-02-11 21:43:504389 if not files_with_missing_header:
4390 return []
Max Morozb47503b2019-08-08 21:03:274391
Sam Maiera6e76d72022-02-11 21:43:504392 long_text = (
4393 'If you define any of the libFuzzer optional functions (%s), it is '
4394 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4395 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4396 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4397 'to access command line arguments passed to the fuzzer. Instead, prefer '
4398 'static initialization and shared resources as documented in '
4399 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4400 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4401 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274402
Sam Maiera6e76d72022-02-11 21:43:504403 return [
4404 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4405 REQUIRED_HEADER,
4406 items=files_with_missing_header,
4407 long_text=long_text)
4408 ]
Max Morozb47503b2019-08-08 21:03:274409
4410
Mohamed Heikald048240a2019-11-12 16:57:374411def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504412 """
4413 Warns authors who add images into the repo to make sure their images are
4414 optimized before committing.
4415 """
4416 images_added = False
4417 image_paths = []
4418 errors = []
4419 filter_lambda = lambda x: input_api.FilterSourceFile(
4420 x,
4421 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4422 DEFAULT_FILES_TO_SKIP),
4423 files_to_check=[r'.*\/(drawable|mipmap)'])
4424 for f in input_api.AffectedFiles(include_deletes=False,
4425 file_filter=filter_lambda):
4426 local_path = f.LocalPath().lower()
4427 if any(
4428 local_path.endswith(extension)
4429 for extension in _IMAGE_EXTENSIONS):
4430 images_added = True
4431 image_paths.append(f)
4432 if images_added:
4433 errors.append(
4434 output_api.PresubmitPromptWarning(
4435 'It looks like you are trying to commit some images. If these are '
4436 'non-test-only images, please make sure to read and apply the tips in '
4437 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4438 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4439 'FYI only and will not block your CL on the CQ.', image_paths))
4440 return errors
Mohamed Heikald048240a2019-11-12 16:57:374441
4442
Saagar Sanghavifceeaae2020-08-12 16:40:364443def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504444 """Groups upload checks that target android code."""
4445 results = []
4446 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4447 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4448 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4449 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4450 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4451 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4452 input_api, output_api))
4453 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4454 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4455 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4456 results.extend(_CheckNewImagesWarning(input_api, output_api))
4457 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4458 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4459 return results
4460
Becky Zhou7c69b50992018-12-10 19:37:574461
Saagar Sanghavifceeaae2020-08-12 16:40:364462def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504463 """Groups commit checks that target android code."""
4464 results = []
4465 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4466 return results
dgnaa68d5e2015-06-10 10:08:224467
Chris Hall59f8d0c72020-05-01 07:31:194468# TODO(chrishall): could we additionally match on any path owned by
4469# ui/accessibility/OWNERS ?
4470_ACCESSIBILITY_PATHS = (
4471 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4472 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4473 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4474 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4475 r"^content[\\/]browser[\\/]accessibility[\\/]",
4476 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4477 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4478 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4479 r"^ui[\\/]accessibility[\\/]",
4480 r"^ui[\\/]views[\\/]accessibility[\\/]",
4481)
4482
Saagar Sanghavifceeaae2020-08-12 16:40:364483def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504484 """Checks that commits to accessibility code contain an AX-Relnotes field in
4485 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194486
Sam Maiera6e76d72022-02-11 21:43:504487 def FileFilter(affected_file):
4488 paths = _ACCESSIBILITY_PATHS
4489 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194490
Sam Maiera6e76d72022-02-11 21:43:504491 # Only consider changes affecting accessibility paths.
4492 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4493 return []
Akihiro Ota08108e542020-05-20 15:30:534494
Sam Maiera6e76d72022-02-11 21:43:504495 # AX-Relnotes can appear in either the description or the footer.
4496 # When searching the description, require 'AX-Relnotes:' to appear at the
4497 # beginning of a line.
4498 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4499 description_has_relnotes = any(
4500 ax_regex.match(line)
4501 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194502
Sam Maiera6e76d72022-02-11 21:43:504503 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4504 'AX-Relnotes', [])
4505 if description_has_relnotes or footer_relnotes:
4506 return []
Chris Hall59f8d0c72020-05-01 07:31:194507
Sam Maiera6e76d72022-02-11 21:43:504508 # TODO(chrishall): link to Relnotes documentation in message.
4509 message = (
4510 "Missing 'AX-Relnotes:' field required for accessibility changes"
4511 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4512 "user-facing changes"
4513 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4514 "user-facing effects"
4515 "\n if this is confusing or annoying then please contact members "
4516 "of ui/accessibility/OWNERS.")
4517
4518 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224519
Mark Schillacie5a0be22022-01-19 00:38:394520
4521_ACCESSIBILITY_EVENTS_TEST_PATH = (
4522 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]event[\\/].*\.html",
4523)
4524
4525_ACCESSIBILITY_TREE_TEST_PATH = (
4526 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]accname[\\/].*\.html",
4527 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]aria[\\/].*\.html",
4528 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]css[\\/].*\.html",
4529 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]html[\\/].*\.html",
4530)
4531
4532_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
4533 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4534)
4535
4536_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Mark Schillaci6f568a52022-02-17 18:41:444537 r"^.*[\\/]WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394538)
4539
4540def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504541 """Checks that commits that include a newly added, renamed/moved, or deleted
4542 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4543 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394544
Sam Maiera6e76d72022-02-11 21:43:504545 def FilePathFilter(affected_file):
4546 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4547 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394548
Sam Maiera6e76d72022-02-11 21:43:504549 def AndroidFilePathFilter(affected_file):
4550 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4551 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394552
Sam Maiera6e76d72022-02-11 21:43:504553 # Only consider changes in the events test data path with html type.
4554 if not any(
4555 input_api.AffectedFiles(include_deletes=True,
4556 file_filter=FilePathFilter)):
4557 return []
Mark Schillacie5a0be22022-01-19 00:38:394558
Sam Maiera6e76d72022-02-11 21:43:504559 # If the commit contains any change to the Android test file, ignore.
4560 if any(
4561 input_api.AffectedFiles(include_deletes=True,
4562 file_filter=AndroidFilePathFilter)):
4563 return []
Mark Schillacie5a0be22022-01-19 00:38:394564
Sam Maiera6e76d72022-02-11 21:43:504565 # Only consider changes that are adding/renaming or deleting a file
4566 message = []
4567 for f in input_api.AffectedFiles(include_deletes=True,
4568 file_filter=FilePathFilter):
4569 if f.Action() == 'A' or f.Action() == 'D':
4570 message = (
4571 "It appears that you are adding, renaming or deleting"
4572 "\na dump_accessibility_events* test, but have not included"
4573 "\na corresponding change for Android."
4574 "\nPlease include (or remove) the test from:"
4575 "\n content/public/android/javatests/src/org/chromium/"
4576 "content/browser/accessibility/"
4577 "WebContentsAccessibilityEventsTest.java"
4578 "\nIf this message is confusing or annoying, please contact"
4579 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394580
Sam Maiera6e76d72022-02-11 21:43:504581 # If no message was set, return empty.
4582 if not len(message):
4583 return []
4584
4585 return [output_api.PresubmitPromptWarning(message)]
4586
Mark Schillacie5a0be22022-01-19 00:38:394587
4588def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504589 """Checks that commits that include a newly added, renamed/moved, or deleted
4590 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4591 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394592
Sam Maiera6e76d72022-02-11 21:43:504593 def FilePathFilter(affected_file):
4594 paths = _ACCESSIBILITY_TREE_TEST_PATH
4595 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394596
Sam Maiera6e76d72022-02-11 21:43:504597 def AndroidFilePathFilter(affected_file):
4598 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4599 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394600
Sam Maiera6e76d72022-02-11 21:43:504601 # Only consider changes in the various tree test data paths with html type.
4602 if not any(
4603 input_api.AffectedFiles(include_deletes=True,
4604 file_filter=FilePathFilter)):
4605 return []
Mark Schillacie5a0be22022-01-19 00:38:394606
Sam Maiera6e76d72022-02-11 21:43:504607 # If the commit contains any change to the Android test file, ignore.
4608 if any(
4609 input_api.AffectedFiles(include_deletes=True,
4610 file_filter=AndroidFilePathFilter)):
4611 return []
Mark Schillacie5a0be22022-01-19 00:38:394612
Sam Maiera6e76d72022-02-11 21:43:504613 # Only consider changes that are adding/renaming or deleting a file
4614 message = []
4615 for f in input_api.AffectedFiles(include_deletes=True,
4616 file_filter=FilePathFilter):
4617 if f.Action() == 'A' or f.Action() == 'D':
4618 message = (
4619 "It appears that you are adding, renaming or deleting"
4620 "\na dump_accessibility_tree* test, but have not included"
4621 "\na corresponding change for Android."
4622 "\nPlease include (or remove) the test from:"
4623 "\n content/public/android/javatests/src/org/chromium/"
4624 "content/browser/accessibility/"
4625 "WebContentsAccessibilityTreeTest.java"
4626 "\nIf this message is confusing or annoying, please contact"
4627 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394628
Sam Maiera6e76d72022-02-11 21:43:504629 # If no message was set, return empty.
4630 if not len(message):
4631 return []
4632
4633 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394634
4635
seanmccullough4a9356252021-04-08 19:54:094636# string pattern, sequence of strings to show when pattern matches,
4637# error flag. True if match is a presubmit error, otherwise it's a warning.
4638_NON_INCLUSIVE_TERMS = (
4639 (
4640 # Note that \b pattern in python re is pretty particular. In this
4641 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4642 # ...' will not. This may require some tweaking to catch these cases
4643 # without triggering a lot of false positives. Leaving it naive and
4644 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324645 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094646 (
4647 'Please don\'t use blacklist, whitelist, ' # nocheck
4648 'or slave in your', # nocheck
4649 'code and make every effort to use other terms. Using "// nocheck"',
4650 '"# nocheck" or "<!-- nocheck -->"',
4651 'at the end of the offending line will bypass this PRESUBMIT error',
4652 'but avoid using this whenever possible. Reach out to',
4653 '[email protected] if you have questions'),
4654 True),)
4655
Saagar Sanghavifceeaae2020-08-12 16:40:364656def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504657 """Checks common to both upload and commit."""
4658 results = []
Eric Boren6fd2b932018-01-25 15:05:084659 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504660 input_api.canned_checks.PanProjectChecks(
4661 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084662
Sam Maiera6e76d72022-02-11 21:43:504663 author = input_api.change.author_email
4664 if author and author not in _KNOWN_ROBOTS:
4665 results.extend(
4666 input_api.canned_checks.CheckAuthorizedAuthor(
4667 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244668
Sam Maiera6e76d72022-02-11 21:43:504669 results.extend(
4670 input_api.canned_checks.CheckChangeHasNoTabs(
4671 input_api,
4672 output_api,
4673 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
4674 results.extend(
4675 input_api.RunTests(
4676 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:174677
Bruce Dawsonc8054482022-03-28 15:33:374678 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:504679 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:374680 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:504681 results.extend(
4682 input_api.RunTests(
4683 input_api.canned_checks.CheckDirMetadataFormat(
4684 input_api, output_api, dirmd_bin)))
4685 results.extend(
4686 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4687 input_api, output_api))
4688 results.extend(
4689 input_api.canned_checks.CheckNoNewMetadataInOwners(
4690 input_api, output_api))
4691 results.extend(
4692 input_api.canned_checks.CheckInclusiveLanguage(
4693 input_api,
4694 output_api,
4695 excluded_directories_relative_path=[
4696 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
4697 ],
4698 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:594699
Aleksey Khoroshilov2978c942022-06-13 16:14:124700 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
4701 f, files_to_check=[r'PRESUBMIT\.py$'])
4702 for f in input_api.AffectedFiles(include_deletes=False,
4703 file_filter=presubmit_py_filter):
4704 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
4705 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
4706 # The PRESUBMIT.py file (and the directory containing it) might have
4707 # been affected by being moved or removed, so only try to run the tests
4708 # if they still exist.
4709 if not input_api.os_path.exists(test_file):
4710 continue
Sam Maiera6e76d72022-02-11 21:43:504711
Aleksey Khoroshilov2978c942022-06-13 16:14:124712 use_python3 = False
4713 with open(f.LocalPath()) as fp:
4714 use_python3 = any(
4715 line.startswith('USE_PYTHON3 = True')
4716 for line in fp.readlines())
4717
4718 results.extend(
4719 input_api.canned_checks.RunUnitTestsInDirectory(
4720 input_api,
4721 output_api,
4722 full_path,
4723 files_to_check=[r'^PRESUBMIT_test\.py$'],
4724 run_on_python2=not use_python3,
4725 run_on_python3=use_python3,
4726 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:504727 return results
[email protected]1f7b4172010-01-28 01:17:344728
[email protected]b337cb5b2011-01-23 21:24:054729
Saagar Sanghavifceeaae2020-08-12 16:40:364730def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504731 problems = [
4732 f.LocalPath() for f in input_api.AffectedFiles()
4733 if f.LocalPath().endswith(('.orig', '.rej'))
4734 ]
4735 # Cargo.toml.orig files are part of third-party crates downloaded from
4736 # crates.io and should be included.
4737 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
4738 if problems:
4739 return [
4740 output_api.PresubmitError("Don't commit .rej and .orig files.",
4741 problems)
4742 ]
4743 else:
4744 return []
[email protected]b8079ae4a2012-12-05 19:56:494745
4746
Saagar Sanghavifceeaae2020-08-12 16:40:364747def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504748 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4749 macro_re = input_api.re.compile(
4750 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
4751 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
4752 input_api.re.MULTILINE)
4753 extension_re = input_api.re.compile(r'\.[a-z]+$')
4754 errors = []
4755 for f in input_api.AffectedFiles(include_deletes=False):
4756 if not f.LocalPath().endswith(
4757 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4758 continue
4759 found_line_number = None
4760 found_macro = None
4761 all_lines = input_api.ReadFile(f, 'r').splitlines()
4762 for line_num, line in enumerate(all_lines):
4763 match = macro_re.search(line)
4764 if match:
4765 found_line_number = line_num
4766 found_macro = match.group(2)
4767 break
4768 if not found_line_number:
4769 continue
Kent Tamura5a8755d2017-06-29 23:37:074770
Sam Maiera6e76d72022-02-11 21:43:504771 found_include_line = -1
4772 for line_num, line in enumerate(all_lines):
4773 if include_re.search(line):
4774 found_include_line = line_num
4775 break
4776 if found_include_line >= 0 and found_include_line < found_line_number:
4777 continue
Kent Tamura5a8755d2017-06-29 23:37:074778
Sam Maiera6e76d72022-02-11 21:43:504779 if not f.LocalPath().endswith('.h'):
4780 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4781 try:
4782 content = input_api.ReadFile(primary_header_path, 'r')
4783 if include_re.search(content):
4784 continue
4785 except IOError:
4786 pass
4787 errors.append('%s:%d %s macro is used without first including build/'
4788 'build_config.h.' %
4789 (f.LocalPath(), found_line_number, found_macro))
4790 if errors:
4791 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4792 return []
Kent Tamura5a8755d2017-06-29 23:37:074793
4794
Lei Zhang1c12a22f2021-05-12 11:28:454795def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504796 stl_include_re = input_api.re.compile(r'^#include\s+<('
4797 r'algorithm|'
4798 r'array|'
4799 r'limits|'
4800 r'list|'
4801 r'map|'
4802 r'memory|'
4803 r'queue|'
4804 r'set|'
4805 r'string|'
4806 r'unordered_map|'
4807 r'unordered_set|'
4808 r'utility|'
4809 r'vector)>')
4810 std_namespace_re = input_api.re.compile(r'std::')
4811 errors = []
4812 for f in input_api.AffectedFiles():
4813 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4814 continue
Lei Zhang1c12a22f2021-05-12 11:28:454815
Sam Maiera6e76d72022-02-11 21:43:504816 uses_std_namespace = False
4817 has_stl_include = False
4818 for line in f.NewContents():
4819 if has_stl_include and uses_std_namespace:
4820 break
Lei Zhang1c12a22f2021-05-12 11:28:454821
Sam Maiera6e76d72022-02-11 21:43:504822 if not has_stl_include and stl_include_re.search(line):
4823 has_stl_include = True
4824 continue
Lei Zhang1c12a22f2021-05-12 11:28:454825
Bruce Dawson4a5579a2022-04-08 17:11:364826 if not uses_std_namespace and (std_namespace_re.search(line)
4827 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504828 uses_std_namespace = True
4829 continue
Lei Zhang1c12a22f2021-05-12 11:28:454830
Sam Maiera6e76d72022-02-11 21:43:504831 if has_stl_include and not uses_std_namespace:
4832 errors.append(
4833 '%s: Includes STL header(s) but does not reference std::' %
4834 f.LocalPath())
4835 if errors:
4836 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4837 return []
Lei Zhang1c12a22f2021-05-12 11:28:454838
4839
Xiaohan Wang42d96c22022-01-20 17:23:114840def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504841 """Check for sensible looking, totally invalid OS macros."""
4842 preprocessor_statement = input_api.re.compile(r'^\s*#')
4843 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
4844 results = []
4845 for lnum, line in f.ChangedContents():
4846 if preprocessor_statement.search(line):
4847 for match in os_macro.finditer(line):
4848 results.append(
4849 ' %s:%d: %s' %
4850 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
4851 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
4852 return results
[email protected]b00342e7f2013-03-26 16:21:544853
4854
Xiaohan Wang42d96c22022-01-20 17:23:114855def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504856 """Check all affected files for invalid OS macros."""
4857 bad_macros = []
4858 for f in input_api.AffectedSourceFiles(None):
4859 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
4860 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:544861
Sam Maiera6e76d72022-02-11 21:43:504862 if not bad_macros:
4863 return []
[email protected]b00342e7f2013-03-26 16:21:544864
Sam Maiera6e76d72022-02-11 21:43:504865 return [
4866 output_api.PresubmitError(
4867 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
4868 'defined in build_config.h):', bad_macros)
4869 ]
[email protected]b00342e7f2013-03-26 16:21:544870
lliabraa35bab3932014-10-01 12:16:444871
4872def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504873 """Check all affected files for invalid "if defined" macros."""
4874 ALWAYS_DEFINED_MACROS = (
4875 "TARGET_CPU_PPC",
4876 "TARGET_CPU_PPC64",
4877 "TARGET_CPU_68K",
4878 "TARGET_CPU_X86",
4879 "TARGET_CPU_ARM",
4880 "TARGET_CPU_MIPS",
4881 "TARGET_CPU_SPARC",
4882 "TARGET_CPU_ALPHA",
4883 "TARGET_IPHONE_SIMULATOR",
4884 "TARGET_OS_EMBEDDED",
4885 "TARGET_OS_IPHONE",
4886 "TARGET_OS_MAC",
4887 "TARGET_OS_UNIX",
4888 "TARGET_OS_WIN32",
4889 )
4890 ifdef_macro = input_api.re.compile(
4891 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4892 results = []
4893 for lnum, line in f.ChangedContents():
4894 for match in ifdef_macro.finditer(line):
4895 if match.group(1) in ALWAYS_DEFINED_MACROS:
4896 always_defined = ' %s is always defined. ' % match.group(1)
4897 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4898 results.append(
4899 ' %s:%d %s\n\t%s' %
4900 (f.LocalPath(), lnum, always_defined, did_you_mean))
4901 return results
lliabraa35bab3932014-10-01 12:16:444902
4903
Saagar Sanghavifceeaae2020-08-12 16:40:364904def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504905 """Check all affected files for invalid "if defined" macros."""
4906 bad_macros = []
4907 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
4908 for f in input_api.AffectedFiles():
4909 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
4910 continue
4911 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4912 bad_macros.extend(
4913 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:444914
Sam Maiera6e76d72022-02-11 21:43:504915 if not bad_macros:
4916 return []
lliabraa35bab3932014-10-01 12:16:444917
Sam Maiera6e76d72022-02-11 21:43:504918 return [
4919 output_api.PresubmitError(
4920 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4921 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4922 bad_macros)
4923 ]
lliabraa35bab3932014-10-01 12:16:444924
4925
Saagar Sanghavifceeaae2020-08-12 16:40:364926def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504927 """Check for same IPC rules described in
4928 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4929 """
4930 base_pattern = r'IPC_ENUM_TRAITS\('
4931 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4932 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:044933
Sam Maiera6e76d72022-02-11 21:43:504934 problems = []
4935 for f in input_api.AffectedSourceFiles(None):
4936 local_path = f.LocalPath()
4937 if not local_path.endswith('.h'):
4938 continue
4939 for line_number, line in f.ChangedContents():
4940 if inclusion_pattern.search(
4941 line) and not comment_pattern.search(line):
4942 problems.append('%s:%d\n %s' %
4943 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:044944
Sam Maiera6e76d72022-02-11 21:43:504945 if problems:
4946 return [
4947 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
4948 problems)
4949 ]
4950 else:
4951 return []
mlamouria82272622014-09-16 18:45:044952
[email protected]b00342e7f2013-03-26 16:21:544953
Saagar Sanghavifceeaae2020-08-12 16:40:364954def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504955 """Check to make sure no files being submitted have long paths.
4956 This causes issues on Windows.
4957 """
4958 problems = []
4959 for f in input_api.AffectedTestableFiles():
4960 local_path = f.LocalPath()
4961 # Windows has a path limit of 260 characters. Limit path length to 200 so
4962 # that we have some extra for the prefix on dev machines and the bots.
4963 if len(local_path) > 200:
4964 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:054965
Sam Maiera6e76d72022-02-11 21:43:504966 if problems:
4967 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4968 else:
4969 return []
Stephen Martinis97a394142018-06-07 23:06:054970
4971
Saagar Sanghavifceeaae2020-08-12 16:40:364972def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504973 """Check that header files have proper guards against multiple inclusion.
4974 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:364975 should include the string "no-include-guard-because-multiply-included" or
4976 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:504977 """
Daniel Bratell8ba52722018-03-02 16:06:144978
Sam Maiera6e76d72022-02-11 21:43:504979 def is_chromium_header_file(f):
4980 # We only check header files under the control of the Chromium
4981 # project. That is, those outside third_party apart from
4982 # third_party/blink.
4983 # We also exclude *_message_generator.h headers as they use
4984 # include guards in a special, non-typical way.
4985 file_with_path = input_api.os_path.normpath(f.LocalPath())
4986 return (file_with_path.endswith('.h')
4987 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:334988 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:504989 and (not file_with_path.startswith('third_party')
4990 or file_with_path.startswith(
4991 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144992
Sam Maiera6e76d72022-02-11 21:43:504993 def replace_special_with_underscore(string):
4994 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144995
Sam Maiera6e76d72022-02-11 21:43:504996 errors = []
Daniel Bratell8ba52722018-03-02 16:06:144997
Sam Maiera6e76d72022-02-11 21:43:504998 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
4999 guard_name = None
5000 guard_line_number = None
5001 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145002
Sam Maiera6e76d72022-02-11 21:43:505003 file_with_path = input_api.os_path.normpath(f.LocalPath())
5004 base_file_name = input_api.os_path.splitext(
5005 input_api.os_path.basename(file_with_path))[0]
5006 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145007
Sam Maiera6e76d72022-02-11 21:43:505008 expected_guard = replace_special_with_underscore(
5009 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145010
Sam Maiera6e76d72022-02-11 21:43:505011 # For "path/elem/file_name.h" we should really only accept
5012 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5013 # are too many (1000+) files with slight deviations from the
5014 # coding style. The most important part is that the include guard
5015 # is there, and that it's unique, not the name so this check is
5016 # forgiving for existing files.
5017 #
5018 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145019
Sam Maiera6e76d72022-02-11 21:43:505020 guard_name_pattern_list = [
5021 # Anything with the right suffix (maybe with an extra _).
5022 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145023
Sam Maiera6e76d72022-02-11 21:43:505024 # To cover include guards with old Blink style.
5025 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145026
Sam Maiera6e76d72022-02-11 21:43:505027 # Anything including the uppercase name of the file.
5028 r'\w*' + input_api.re.escape(
5029 replace_special_with_underscore(upper_base_file_name)) +
5030 r'\w*',
5031 ]
5032 guard_name_pattern = '|'.join(guard_name_pattern_list)
5033 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5034 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145035
Sam Maiera6e76d72022-02-11 21:43:505036 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365037 if ('no-include-guard-because-multiply-included' in line
5038 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505039 guard_name = 'DUMMY' # To not trigger check outside the loop.
5040 break
Daniel Bratell8ba52722018-03-02 16:06:145041
Sam Maiera6e76d72022-02-11 21:43:505042 if guard_name is None:
5043 match = guard_pattern.match(line)
5044 if match:
5045 guard_name = match.group(1)
5046 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145047
Sam Maiera6e76d72022-02-11 21:43:505048 # We allow existing files to use include guards whose names
5049 # don't match the chromium style guide, but new files should
5050 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495051 if guard_name != expected_guard:
5052 if not f.OldContents():
Sam Maiera6e76d72022-02-11 21:43:505053 errors.append(
5054 output_api.PresubmitPromptWarning(
5055 'Header using the wrong include guard name %s'
5056 % guard_name, [
5057 '%s:%d' %
5058 (f.LocalPath(), line_number + 1)
5059 ], 'Expected: %r\nFound: %r' %
5060 (expected_guard, guard_name)))
5061 else:
5062 # The line after #ifndef should have a #define of the same name.
5063 if line_number == guard_line_number + 1:
5064 expected_line = '#define %s' % guard_name
5065 if line != expected_line:
5066 errors.append(
5067 output_api.PresubmitPromptWarning(
5068 'Missing "%s" for include guard' %
5069 expected_line,
5070 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5071 'Expected: %r\nGot: %r' %
5072 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145073
Sam Maiera6e76d72022-02-11 21:43:505074 if not seen_guard_end and line == '#endif // %s' % guard_name:
5075 seen_guard_end = True
5076 elif seen_guard_end:
5077 if line.strip() != '':
5078 errors.append(
5079 output_api.PresubmitPromptWarning(
5080 'Include guard %s not covering the whole file'
5081 % (guard_name), [f.LocalPath()]))
5082 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145083
Sam Maiera6e76d72022-02-11 21:43:505084 if guard_name is None:
5085 errors.append(
5086 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495087 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505088 'Recommended name: %s\n'
5089 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365090 '"no-include-guard-because-multiply-included" or\n'
5091 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505092 % (f.LocalPath(), expected_guard)))
5093
5094 return errors
Daniel Bratell8ba52722018-03-02 16:06:145095
5096
Saagar Sanghavifceeaae2020-08-12 16:40:365097def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505098 """Check source code and known ascii text files for Windows style line
5099 endings.
5100 """
Bruce Dawson5efbdc652022-04-11 19:29:515101 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235102
Sam Maiera6e76d72022-02-11 21:43:505103 file_inclusion_pattern = (known_text_files,
5104 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5105 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235106
Sam Maiera6e76d72022-02-11 21:43:505107 problems = []
5108 source_file_filter = lambda f: input_api.FilterSourceFile(
5109 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5110 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515111 # Ignore test files that contain crlf intentionally.
5112 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345113 continue
Sam Maiera6e76d72022-02-11 21:43:505114 include_file = False
5115 for line in input_api.ReadFile(f, 'r').splitlines(True):
5116 if line.endswith('\r\n'):
5117 include_file = True
5118 if include_file:
5119 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235120
Sam Maiera6e76d72022-02-11 21:43:505121 if problems:
5122 return [
5123 output_api.PresubmitPromptWarning(
5124 'Are you sure that you want '
5125 'these files to contain Windows style line endings?\n' +
5126 '\n'.join(problems))
5127 ]
mostynbb639aca52015-01-07 20:31:235128
Sam Maiera6e76d72022-02-11 21:43:505129 return []
5130
mostynbb639aca52015-01-07 20:31:235131
Evan Stade6cfc964c12021-05-18 20:21:165132def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505133 """Check that .icon files (which are fragments of C++) have license headers.
5134 """
Evan Stade6cfc964c12021-05-18 20:21:165135
Sam Maiera6e76d72022-02-11 21:43:505136 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165137
Sam Maiera6e76d72022-02-11 21:43:505138 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5139 return input_api.canned_checks.CheckLicense(input_api,
5140 output_api,
5141 source_file_filter=icons)
5142
Evan Stade6cfc964c12021-05-18 20:21:165143
Jose Magana2b456f22021-03-09 23:26:405144def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505145 """Check source code for use of Chrome App technologies being
5146 deprecated.
5147 """
Jose Magana2b456f22021-03-09 23:26:405148
Sam Maiera6e76d72022-02-11 21:43:505149 def _CheckForDeprecatedTech(input_api,
5150 output_api,
5151 detection_list,
5152 files_to_check=None,
5153 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405154
Sam Maiera6e76d72022-02-11 21:43:505155 if (files_to_check or files_to_skip):
5156 source_file_filter = lambda f: input_api.FilterSourceFile(
5157 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5158 else:
5159 source_file_filter = None
5160
5161 problems = []
5162
5163 for f in input_api.AffectedSourceFiles(source_file_filter):
5164 if f.Action() == 'D':
5165 continue
5166 for _, line in f.ChangedContents():
5167 if any(detect in line for detect in detection_list):
5168 problems.append(f.LocalPath())
5169
5170 return problems
5171
5172 # to avoid this presubmit script triggering warnings
5173 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405174
5175 problems = []
5176
Sam Maiera6e76d72022-02-11 21:43:505177 # NMF: any files with extensions .nmf or NMF
5178 _NMF_FILES = r'\.(nmf|NMF)$'
5179 problems += _CheckForDeprecatedTech(
5180 input_api,
5181 output_api,
5182 detection_list=[''], # any change to the file will trigger warning
5183 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405184
Sam Maiera6e76d72022-02-11 21:43:505185 # MANIFEST: any manifest.json that in its diff includes "app":
5186 _MANIFEST_FILES = r'(manifest\.json)$'
5187 problems += _CheckForDeprecatedTech(
5188 input_api,
5189 output_api,
5190 detection_list=['"app":'],
5191 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405192
Sam Maiera6e76d72022-02-11 21:43:505193 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5194 problems += _CheckForDeprecatedTech(
5195 input_api,
5196 output_api,
5197 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
5198 files_to_skip=files_to_skip + [r"^native_client_sdk[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405199
Sam Maiera6e76d72022-02-11 21:43:505200 # PPAPI: any C/C++ file that in its diff includes a ppappi library
5201 problems += _CheckForDeprecatedTech(
5202 input_api,
5203 output_api,
5204 detection_list=['#include "ppapi', '#include <ppapi'],
5205 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5206 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
5207 files_to_skip=[r"^ppapi[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405208
Sam Maiera6e76d72022-02-11 21:43:505209 if problems:
5210 return [
5211 output_api.PresubmitPromptWarning(
5212 'You are adding/modifying code'
5213 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5214 ' PNaCl, PPAPI). See this blog post for more details:\n'
5215 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5216 'and this documentation for options to replace these technologies:\n'
5217 'https://developer.chrome.com/docs/apps/migration/\n' +
5218 '\n'.join(problems))
5219 ]
Jose Magana2b456f22021-03-09 23:26:405220
Sam Maiera6e76d72022-02-11 21:43:505221 return []
Jose Magana2b456f22021-03-09 23:26:405222
mostynbb639aca52015-01-07 20:31:235223
Saagar Sanghavifceeaae2020-08-12 16:40:365224def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505225 """Checks that all source files use SYSLOG properly."""
5226 syslog_files = []
5227 for f in input_api.AffectedSourceFiles(src_file_filter):
5228 for line_number, line in f.ChangedContents():
5229 if 'SYSLOG' in line:
5230 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565231
Sam Maiera6e76d72022-02-11 21:43:505232 if syslog_files:
5233 return [
5234 output_api.PresubmitPromptWarning(
5235 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5236 ' calls.\nFiles to check:\n',
5237 items=syslog_files)
5238 ]
5239 return []
pastarmovj89f7ee12016-09-20 14:58:135240
5241
[email protected]1f7b4172010-01-28 01:17:345242def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505243 if input_api.version < [2, 0, 0]:
5244 return [
5245 output_api.PresubmitError(
5246 "Your depot_tools is out of date. "
5247 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5248 "but your version is %d.%d.%d" % tuple(input_api.version))
5249 ]
5250 results = []
5251 results.extend(
5252 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5253 return results
[email protected]ca8d19842009-02-19 16:33:125254
5255
5256def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505257 if input_api.version < [2, 0, 0]:
5258 return [
5259 output_api.PresubmitError(
5260 "Your depot_tools is out of date. "
5261 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5262 "but your version is %d.%d.%d" % tuple(input_api.version))
5263 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365264
Sam Maiera6e76d72022-02-11 21:43:505265 results = []
5266 # Make sure the tree is 'open'.
5267 results.extend(
5268 input_api.canned_checks.CheckTreeIsOpen(
5269 input_api,
5270 output_api,
5271 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275272
Sam Maiera6e76d72022-02-11 21:43:505273 results.extend(
5274 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5275 results.extend(
5276 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5277 results.extend(
5278 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5279 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505280 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145281
5282
Saagar Sanghavifceeaae2020-08-12 16:40:365283def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505284 """Check string ICU syntax validity and if translation screenshots exist."""
5285 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5286 # footer is set to true.
5287 git_footers = input_api.change.GitFootersFromDescription()
5288 skip_screenshot_check_footer = [
5289 footer.lower() for footer in git_footers.get(
5290 u'Skip-Translation-Screenshots-Check', [])
5291 ]
5292 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025293
Sam Maiera6e76d72022-02-11 21:43:505294 import os
5295 import re
5296 import sys
5297 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145298
Sam Maiera6e76d72022-02-11 21:43:505299 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5300 if (f.Action() == 'A' or f.Action() == 'M'))
5301 removed_paths = set(f.LocalPath()
5302 for f in input_api.AffectedFiles(include_deletes=True)
5303 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145304
Sam Maiera6e76d72022-02-11 21:43:505305 affected_grds = [
5306 f for f in input_api.AffectedFiles()
5307 if f.LocalPath().endswith(('.grd', '.grdp'))
5308 ]
5309 affected_grds = [
5310 f for f in affected_grds if not 'testdata' in f.LocalPath()
5311 ]
5312 if not affected_grds:
5313 return []
meacer8c0d3832019-12-26 21:46:165314
Sam Maiera6e76d72022-02-11 21:43:505315 affected_png_paths = [
5316 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5317 if (f.LocalPath().endswith('.png'))
5318 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145319
Sam Maiera6e76d72022-02-11 21:43:505320 # Check for screenshots. Developers can upload screenshots using
5321 # tools/translation/upload_screenshots.py which finds and uploads
5322 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5323 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5324 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5325 #
5326 # The logic here is as follows:
5327 #
5328 # - If the CL has a .png file under the screenshots directory for a grd
5329 # file, warn the developer. Actual images should never be checked into the
5330 # Chrome repo.
5331 #
5332 # - If the CL contains modified or new messages in grd files and doesn't
5333 # contain the corresponding .sha1 files, warn the developer to add images
5334 # and upload them via tools/translation/upload_screenshots.py.
5335 #
5336 # - If the CL contains modified or new messages in grd files and the
5337 # corresponding .sha1 files, everything looks good.
5338 #
5339 # - If the CL contains removed messages in grd files but the corresponding
5340 # .sha1 files aren't removed, warn the developer to remove them.
5341 unnecessary_screenshots = []
5342 missing_sha1 = []
5343 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145344
Sam Maiera6e76d72022-02-11 21:43:505345 # This checks verifies that the ICU syntax of messages this CL touched is
5346 # valid, and reports any found syntax errors.
5347 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5348 # without developers being aware of them. Later on, such ICU syntax errors
5349 # break message extraction for translation, hence would block Chromium
5350 # translations until they are fixed.
5351 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145352
Sam Maiera6e76d72022-02-11 21:43:505353 def _CheckScreenshotAdded(screenshots_dir, message_id):
5354 sha1_path = input_api.os_path.join(screenshots_dir,
5355 message_id + '.png.sha1')
5356 if sha1_path not in new_or_added_paths:
5357 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145358
Sam Maiera6e76d72022-02-11 21:43:505359 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5360 sha1_path = input_api.os_path.join(screenshots_dir,
5361 message_id + '.png.sha1')
5362 if input_api.os_path.exists(
5363 sha1_path) and sha1_path not in removed_paths:
5364 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145365
Sam Maiera6e76d72022-02-11 21:43:505366 def _ValidateIcuSyntax(text, level, signatures):
5367 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145368
Sam Maiera6e76d72022-02-11 21:43:505369 Check if text looks similar to ICU and checks for ICU syntax correctness
5370 in this case. Reports various issues with ICU syntax and values of
5371 variants. Supports checking of nested messages. Accumulate information of
5372 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265373
Sam Maiera6e76d72022-02-11 21:43:505374 Args:
5375 text: a string to check.
5376 level: a number of current nesting level.
5377 signatures: an accumulator, a list of tuple of (level, variable,
5378 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265379
Sam Maiera6e76d72022-02-11 21:43:505380 Returns:
5381 None if a string is not ICU or no issue detected.
5382 A tuple of (message, start index, end index) if an issue detected.
5383 """
5384 valid_types = {
5385 'plural': (frozenset(
5386 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5387 'other']), frozenset(['=1', 'other'])),
5388 'selectordinal': (frozenset(
5389 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5390 'other']), frozenset(['one', 'other'])),
5391 'select': (frozenset(), frozenset(['other'])),
5392 }
Rainhard Findlingfc31844c52020-05-15 09:58:265393
Sam Maiera6e76d72022-02-11 21:43:505394 # Check if the message looks like an attempt to use ICU
5395 # plural. If yes - check if its syntax strictly matches ICU format.
5396 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5397 text)
5398 if not like:
5399 signatures.append((level, None, None, None))
5400 return
Rainhard Findlingfc31844c52020-05-15 09:58:265401
Sam Maiera6e76d72022-02-11 21:43:505402 # Check for valid prefix and suffix
5403 m = re.match(
5404 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5405 r'(plural|selectordinal|select),\s*'
5406 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5407 if not m:
5408 return (('This message looks like an ICU plural, '
5409 'but does not follow ICU syntax.'), like.start(),
5410 like.end())
5411 starting, variable, kind, variant_pairs = m.groups()
5412 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5413 m.start(4))
5414 if depth:
5415 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5416 len(text))
5417 first = text[0]
5418 ending = text[last_pos:]
5419 if not starting:
5420 return ('Invalid ICU format. No initial opening bracket',
5421 last_pos - 1, last_pos)
5422 if not ending or '}' not in ending:
5423 return ('Invalid ICU format. No final closing bracket',
5424 last_pos - 1, last_pos)
5425 elif first != '{':
5426 return ((
5427 'Invalid ICU format. Extra characters at the start of a complex '
5428 'message (go/icu-message-migration): "%s"') % starting, 0,
5429 len(starting))
5430 elif ending != '}':
5431 return ((
5432 'Invalid ICU format. Extra characters at the end of a complex '
5433 'message (go/icu-message-migration): "%s"') % ending,
5434 last_pos - 1, len(text) - 1)
5435 if kind not in valid_types:
5436 return (('Unknown ICU message type %s. '
5437 'Valid types are: plural, select, selectordinal') % kind,
5438 0, 0)
5439 known, required = valid_types[kind]
5440 defined_variants = set()
5441 for variant, variant_range, value, value_range in variants:
5442 start, end = variant_range
5443 if variant in defined_variants:
5444 return ('Variant "%s" is defined more than once' % variant,
5445 start, end)
5446 elif known and variant not in known:
5447 return ('Variant "%s" is not valid for %s message' %
5448 (variant, kind), start, end)
5449 defined_variants.add(variant)
5450 # Check for nested structure
5451 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5452 if res:
5453 return (res[0], res[1] + value_range[0] + 1,
5454 res[2] + value_range[0] + 1)
5455 missing = required - defined_variants
5456 if missing:
5457 return ('Required variants missing: %s' % ', '.join(missing), 0,
5458 len(text))
5459 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265460
Sam Maiera6e76d72022-02-11 21:43:505461 def _ParseIcuVariants(text, offset=0):
5462 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265463
Sam Maiera6e76d72022-02-11 21:43:505464 Builds a tuple of variant names and values, as well as
5465 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265466
Sam Maiera6e76d72022-02-11 21:43:505467 Args:
5468 text: a string to parse
5469 offset: additional offset to add to positions in the text to get correct
5470 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265471
Sam Maiera6e76d72022-02-11 21:43:505472 Returns:
5473 List of tuples, each tuple consist of four fields: variant name,
5474 variant name span (tuple of two integers), variant value, value
5475 span (tuple of two integers).
5476 """
5477 depth, start, end = 0, -1, -1
5478 variants = []
5479 key = None
5480 for idx, char in enumerate(text):
5481 if char == '{':
5482 if not depth:
5483 start = idx
5484 chunk = text[end + 1:start]
5485 key = chunk.strip()
5486 pos = offset + end + 1 + chunk.find(key)
5487 span = (pos, pos + len(key))
5488 depth += 1
5489 elif char == '}':
5490 if not depth:
5491 return variants, depth, offset + idx
5492 depth -= 1
5493 if not depth:
5494 end = idx
5495 variants.append((key, span, text[start:end + 1],
5496 (offset + start, offset + end + 1)))
5497 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265498
Sam Maiera6e76d72022-02-11 21:43:505499 try:
5500 old_sys_path = sys.path
5501 sys.path = sys.path + [
5502 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5503 'translation')
5504 ]
5505 from helper import grd_helper
5506 finally:
5507 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265508
Sam Maiera6e76d72022-02-11 21:43:505509 for f in affected_grds:
5510 file_path = f.LocalPath()
5511 old_id_to_msg_map = {}
5512 new_id_to_msg_map = {}
5513 # Note that this code doesn't check if the file has been deleted. This is
5514 # OK because it only uses the old and new file contents and doesn't load
5515 # the file via its path.
5516 # It's also possible that a file's content refers to a renamed or deleted
5517 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5518 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5519 # .grdp files.
5520 if file_path.endswith('.grdp'):
5521 if f.OldContents():
5522 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5523 '\n'.join(f.OldContents()))
5524 if f.NewContents():
5525 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5526 '\n'.join(f.NewContents()))
5527 else:
5528 file_dir = input_api.os_path.dirname(file_path) or '.'
5529 if f.OldContents():
5530 old_id_to_msg_map = grd_helper.GetGrdMessages(
5531 StringIO('\n'.join(f.OldContents())), file_dir)
5532 if f.NewContents():
5533 new_id_to_msg_map = grd_helper.GetGrdMessages(
5534 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265535
Sam Maiera6e76d72022-02-11 21:43:505536 grd_name, ext = input_api.os_path.splitext(
5537 input_api.os_path.basename(file_path))
5538 screenshots_dir = input_api.os_path.join(
5539 input_api.os_path.dirname(file_path),
5540 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265541
Sam Maiera6e76d72022-02-11 21:43:505542 # Compute added, removed and modified message IDs.
5543 old_ids = set(old_id_to_msg_map)
5544 new_ids = set(new_id_to_msg_map)
5545 added_ids = new_ids - old_ids
5546 removed_ids = old_ids - new_ids
5547 modified_ids = set([])
5548 for key in old_ids.intersection(new_ids):
5549 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5550 new_id_to_msg_map[key].ContentsAsXml('', True)):
5551 # The message content itself changed. Require an updated screenshot.
5552 modified_ids.add(key)
5553 elif old_id_to_msg_map[key].attrs['meaning'] != \
5554 new_id_to_msg_map[key].attrs['meaning']:
5555 # The message meaning changed. Ensure there is a screenshot for it.
5556 sha1_path = input_api.os_path.join(screenshots_dir,
5557 key + '.png.sha1')
5558 if sha1_path not in new_or_added_paths and not \
5559 input_api.os_path.exists(sha1_path):
5560 # There is neither a previous screenshot nor is a new one added now.
5561 # Require a screenshot.
5562 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145563
Sam Maiera6e76d72022-02-11 21:43:505564 if run_screenshot_check:
5565 # Check the screenshot directory for .png files. Warn if there is any.
5566 for png_path in affected_png_paths:
5567 if png_path.startswith(screenshots_dir):
5568 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145569
Sam Maiera6e76d72022-02-11 21:43:505570 for added_id in added_ids:
5571 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095572
Sam Maiera6e76d72022-02-11 21:43:505573 for modified_id in modified_ids:
5574 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145575
Sam Maiera6e76d72022-02-11 21:43:505576 for removed_id in removed_ids:
5577 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5578
5579 # Check new and changed strings for ICU syntax errors.
5580 for key in added_ids.union(modified_ids):
5581 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5582 err = _ValidateIcuSyntax(msg, 0, [])
5583 if err is not None:
5584 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5585
5586 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265587 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505588 if unnecessary_screenshots:
5589 results.append(
5590 output_api.PresubmitError(
5591 'Do not include actual screenshots in the changelist. Run '
5592 'tools/translate/upload_screenshots.py to upload them instead:',
5593 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145594
Sam Maiera6e76d72022-02-11 21:43:505595 if missing_sha1:
5596 results.append(
5597 output_api.PresubmitError(
5598 'You are adding or modifying UI strings.\n'
5599 'To ensure the best translations, take screenshots of the relevant UI '
5600 '(https://g.co/chrome/translation) and add these files to your '
5601 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145602
Sam Maiera6e76d72022-02-11 21:43:505603 if unnecessary_sha1_files:
5604 results.append(
5605 output_api.PresubmitError(
5606 'You removed strings associated with these files. Remove:',
5607 sorted(unnecessary_sha1_files)))
5608 else:
5609 results.append(
5610 output_api.PresubmitPromptOrNotify('Skipping translation '
5611 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145612
Sam Maiera6e76d72022-02-11 21:43:505613 if icu_syntax_errors:
5614 results.append(
5615 output_api.PresubmitPromptWarning(
5616 'ICU syntax errors were found in the following strings (problems or '
5617 'feedback? Contact [email protected]):',
5618 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265619
Sam Maiera6e76d72022-02-11 21:43:505620 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125621
5622
Saagar Sanghavifceeaae2020-08-12 16:40:365623def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125624 repo_root=None,
5625 translation_expectations_path=None,
5626 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505627 import sys
5628 affected_grds = [
5629 f for f in input_api.AffectedFiles()
5630 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5631 ]
5632 if not affected_grds:
5633 return []
5634
5635 try:
5636 old_sys_path = sys.path
5637 sys.path = sys.path + [
5638 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5639 'translation')
5640 ]
5641 from helper import git_helper
5642 from helper import translation_helper
5643 finally:
5644 sys.path = old_sys_path
5645
5646 # Check that translation expectations can be parsed and we can get a list of
5647 # translatable grd files. |repo_root| and |translation_expectations_path| are
5648 # only passed by tests.
5649 if not repo_root:
5650 repo_root = input_api.PresubmitLocalPath()
5651 if not translation_expectations_path:
5652 translation_expectations_path = input_api.os_path.join(
5653 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5654 if not grd_files:
5655 grd_files = git_helper.list_grds_in_repository(repo_root)
5656
5657 # Ignore bogus grd files used only for testing
5658 # ui/webui/resoucres/tools/generate_grd.py.
5659 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
5660 'tests')
5661 grd_files = [p for p in grd_files if ignore_path not in p]
5662
5663 try:
5664 translation_helper.get_translatable_grds(
5665 repo_root, grd_files, translation_expectations_path)
5666 except Exception as e:
5667 return [
5668 output_api.PresubmitNotifyResult(
5669 'Failed to get a list of translatable grd files. This happens when:\n'
5670 ' - One of the modified grd or grdp files cannot be parsed or\n'
5671 ' - %s is not updated.\n'
5672 'Stack:\n%s' % (translation_expectations_path, str(e)))
5673 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:125674 return []
5675
Ken Rockotc31f4832020-05-29 18:58:515676
Saagar Sanghavifceeaae2020-08-12 16:40:365677def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505678 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5679 changed_mojoms = input_api.AffectedFiles(
5680 include_deletes=True,
5681 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525682
Bruce Dawson344ab262022-06-04 11:35:105683 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:505684 return []
5685
5686 delta = []
5687 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:505688 delta.append({
5689 'filename': mojom.LocalPath(),
5690 'old': '\n'.join(mojom.OldContents()) or None,
5691 'new': '\n'.join(mojom.NewContents()) or None,
5692 })
5693
5694 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:215695 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:505696 input_api.os_path.join(
5697 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
5698 'check_stable_mojom_compatibility.py'), '--src-root',
5699 input_api.PresubmitLocalPath()
5700 ],
5701 stdin=input_api.subprocess.PIPE,
5702 stdout=input_api.subprocess.PIPE,
5703 stderr=input_api.subprocess.PIPE,
5704 universal_newlines=True)
5705 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5706 if process.returncode:
5707 return [
5708 output_api.PresubmitError(
5709 'One or more [Stable] mojom definitions appears to have been changed '
5710 'in a way that is not backward-compatible.',
5711 long_text=error)
5712 ]
Erik Staabc734cd7a2021-11-23 03:11:525713 return []
5714
Dominic Battre645d42342020-12-04 16:14:105715def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505716 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:105717
Sam Maiera6e76d72022-02-11 21:43:505718 def FilterFile(affected_file):
5719 """Accept only .cc files and the like."""
5720 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5721 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5722 input_api.DEFAULT_FILES_TO_SKIP)
5723 return input_api.FilterSourceFile(
5724 affected_file,
5725 files_to_check=file_inclusion_pattern,
5726 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:105727
Sam Maiera6e76d72022-02-11 21:43:505728 def ModifiedLines(affected_file):
5729 """Returns a list of tuples (line number, line text) of added and removed
5730 lines.
Dominic Battre645d42342020-12-04 16:14:105731
Sam Maiera6e76d72022-02-11 21:43:505732 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:105733
Sam Maiera6e76d72022-02-11 21:43:505734 This relies on the scm diff output describing each changed code section
5735 with a line of the form
Dominic Battre645d42342020-12-04 16:14:105736
Sam Maiera6e76d72022-02-11 21:43:505737 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5738 """
5739 line_num = 0
5740 modified_lines = []
5741 for line in affected_file.GenerateScmDiff().splitlines():
5742 # Extract <new line num> of the patch fragment (see format above).
5743 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
5744 line)
5745 if m:
5746 line_num = int(m.groups(1)[0])
5747 continue
5748 if ((line.startswith('+') and not line.startswith('++'))
5749 or (line.startswith('-') and not line.startswith('--'))):
5750 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:105751
Sam Maiera6e76d72022-02-11 21:43:505752 if not line.startswith('-'):
5753 line_num += 1
5754 return modified_lines
Dominic Battre645d42342020-12-04 16:14:105755
Sam Maiera6e76d72022-02-11 21:43:505756 def FindLineWith(lines, needle):
5757 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:105758
Sam Maiera6e76d72022-02-11 21:43:505759 If 0 or >1 lines contain `needle`, -1 is returned.
5760 """
5761 matching_line_numbers = [
5762 # + 1 for 1-based counting of line numbers.
5763 i + 1 for i, line in enumerate(lines) if needle in line
5764 ]
5765 return matching_line_numbers[0] if len(
5766 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:105767
Sam Maiera6e76d72022-02-11 21:43:505768 def ModifiedPrefMigration(affected_file):
5769 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5770 # Determine first and last lines of MigrateObsolete.*Pref functions.
5771 new_contents = affected_file.NewContents()
5772 range_1 = (FindLineWith(new_contents,
5773 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5774 FindLineWith(new_contents,
5775 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5776 range_2 = (FindLineWith(new_contents,
5777 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5778 FindLineWith(new_contents,
5779 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5780 if (-1 in range_1 + range_2):
5781 raise Exception(
5782 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
5783 )
Dominic Battre645d42342020-12-04 16:14:105784
Sam Maiera6e76d72022-02-11 21:43:505785 # Check whether any of the modified lines are part of the
5786 # MigrateObsolete.*Pref functions.
5787 for line_nr, line in ModifiedLines(affected_file):
5788 if (range_1[0] <= line_nr <= range_1[1]
5789 or range_2[0] <= line_nr <= range_2[1]):
5790 return True
5791 return False
Dominic Battre645d42342020-12-04 16:14:105792
Sam Maiera6e76d72022-02-11 21:43:505793 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5794 browser_prefs_file_pattern = input_api.re.compile(
5795 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:105796
Sam Maiera6e76d72022-02-11 21:43:505797 changes = input_api.AffectedFiles(include_deletes=True,
5798 file_filter=FilterFile)
5799 potential_problems = []
5800 for f in changes:
5801 for line in f.GenerateScmDiff().splitlines():
5802 # Check deleted lines for pref registrations.
5803 if (line.startswith('-') and not line.startswith('--')
5804 and register_pref_pattern.search(line)):
5805 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:105806
Sam Maiera6e76d72022-02-11 21:43:505807 if browser_prefs_file_pattern.search(f.LocalPath()):
5808 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5809 # assume that they knew that they have to deprecate preferences and don't
5810 # warn.
5811 try:
5812 if ModifiedPrefMigration(f):
5813 return []
5814 except Exception as e:
5815 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:105816
Sam Maiera6e76d72022-02-11 21:43:505817 if potential_problems:
5818 return [
5819 output_api.PresubmitPromptWarning(
5820 'Discovered possible removal of preference registrations.\n\n'
5821 'Please make sure to properly deprecate preferences by clearing their\n'
5822 'value for a couple of milestones before finally removing the code.\n'
5823 'Otherwise data may stay in the preferences files forever. See\n'
5824 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5825 'chrome/browser/prefs/README.md for examples.\n'
5826 'This may be a false positive warning (e.g. if you move preference\n'
5827 'registrations to a different place).\n', potential_problems)
5828 ]
5829 return []
5830
Matt Stark6ef08872021-07-29 01:21:465831
5832def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505833 """Changes to GRD files must be consistent for tools to read them."""
5834 changed_grds = input_api.AffectedFiles(
5835 include_deletes=False,
5836 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5837 errors = []
5838 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5839 for matcher, msg in _INVALID_GRD_FILE_LINE]
5840 for grd in changed_grds:
5841 for i, line in enumerate(grd.NewContents()):
5842 for matcher, msg in invalid_file_regexes:
5843 if matcher.search(line):
5844 errors.append(
5845 output_api.PresubmitError(
5846 'Problem on {grd}:{i} - {msg}'.format(
5847 grd=grd.LocalPath(), i=i + 1, msg=msg)))
5848 return errors
5849
Kevin McNee967dd2d22021-11-15 16:09:295850
5851def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505852 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5853 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5854 """
Kevin McNee967dd2d22021-11-15 16:09:295855
Ian Vollickdba956c2022-04-20 23:53:455856 # Only consider top-level directories that (1) can use content APIs or
5857 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
5858 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:505859 files_to_check = (
Ian Vollickdba956c2022-04-20 23:53:455860 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Kevin McNee967dd2d22021-11-15 16:09:295861 _IMPLEMENTATION_EXTENSIONS,
Ian Vollickdba956c2022-04-20 23:53:455862 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Sam Maiera6e76d72022-02-11 21:43:505863 _HEADER_EXTENSIONS,
5864 )
5865 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5866 input_api.DEFAULT_FILES_TO_SKIP)
5867 source_file_filter = lambda f: input_api.FilterSourceFile(
5868 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:295869
Sam Maiera6e76d72022-02-11 21:43:505870 # Note that since these are are just regular expressions and we don't have
5871 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5872 # could have a method named IsInMainFrame).
5873 concerning_class_pattern = input_api.re.compile(
5874 r'WebContentsObserver|WebContentsUserData')
5875 # A subset of WebContentsObserver overrides where there's particular risk for
5876 # confusing tab and page level operations and data (e.g. incorrectly
5877 # resetting page state in DidFinishNavigation).
5878 concerning_wco_methods = [
5879 'DidStartNavigation',
5880 'ReadyToCommitNavigation',
5881 'DidFinishNavigation',
5882 'RenderViewReady',
5883 'RenderViewDeleted',
5884 'RenderViewHostChanged',
5885 'PrimaryMainDocumentElementAvailable',
5886 'DocumentOnLoadCompletedInPrimaryMainFrame',
5887 'DOMContentLoaded',
5888 'DidFinishLoad',
5889 ]
5890 concerning_nav_handle_methods = [
5891 'IsInMainFrame',
5892 ]
5893 concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:505894 'FromRenderFrameHost',
5895 'FromRenderViewHost',
Sam Maiera6e76d72022-02-11 21:43:505896 'GetRenderViewHost',
5897 ]
5898 concerning_rfh_methods = [
5899 'GetParent',
5900 'GetMainFrame',
5901 'GetFrameTreeNodeId',
5902 ]
Ian Vollickc825b1f2022-04-19 14:30:155903 concerning_rfhi_methods = [
5904 'is_main_frame',
5905 ]
Ian Vollicka77a73ea2022-04-06 18:08:015906 concerning_ftn_methods = [
5907 'IsMainFrame',
5908 ]
Ian Vollickdba956c2022-04-20 23:53:455909 concerning_blink_frame_methods = [
Ian Vollick4d785d22022-06-18 00:10:025910 'IsCrossOriginToNearestMainFrame',
Ian Vollickdba956c2022-04-20 23:53:455911 ]
Sam Maiera6e76d72022-02-11 21:43:505912 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5913 item for sublist in [
5914 concerning_wco_methods, concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:015915 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:155916 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:455917 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:505918 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:295919
Kevin McNee4eeec792022-02-14 20:02:045920 used_apis = set()
Sam Maiera6e76d72022-02-11 21:43:505921 for f in input_api.AffectedFiles(include_deletes=False,
5922 file_filter=source_file_filter):
5923 for line_num, line in f.ChangedContents():
Kevin McNee4eeec792022-02-14 20:02:045924 class_match = concerning_class_pattern.search(line)
5925 if class_match:
5926 used_apis.add(class_match[0])
5927 method_match = concerning_method_pattern.search(line)
5928 if method_match:
5929 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:505930
Kevin McNee4eeec792022-02-14 20:02:045931 if not used_apis:
5932 return []
Kevin McNee967dd2d22021-11-15 16:09:295933
Kevin McNee4eeec792022-02-14 20:02:045934 output_api.AppendCC('[email protected]')
5935 message = ('This change uses API(s) that are ambiguous in the presence of '
5936 'MPArch features such as bfcache, prerendering, and fenced '
5937 'frames.')
5938 explaination = (
5939 'Please double check whether new code assumes that a WebContents only '
5940 'contains a single page at a time. For example, it is discouraged to '
5941 'reset per-document state in response to the observation of a '
5942 'navigation. See this doc [1] and the comments on the individual APIs '
5943 'for guidance and this doc [2] for context. The MPArch review '
5944 'watchlist has been CC\'d on this change to help identify any issues.\n'
5945 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
5946 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
5947 )
5948 return [
5949 output_api.PresubmitNotifyResult(message,
5950 items=list(used_apis),
5951 long_text=explaination)
5952 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:365953
5954
5955def CheckAssertAshOnlyCode(input_api, output_api):
5956 """Errors if a BUILD.gn file in an ash/ directory doesn't include
5957 assert(is_chromeos_ash).
5958 """
5959
5960 def FileFilter(affected_file):
5961 """Includes directories known to be Ash only."""
5962 return input_api.FilterSourceFile(
5963 affected_file,
5964 files_to_check=(
5965 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
5966 r'.*/ash/.*BUILD\.gn'), # Any path component.
5967 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
5968
5969 errors = []
5970 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:565971 for f in input_api.AffectedFiles(include_deletes=False,
5972 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:365973 if (not pattern.search(input_api.ReadFile(f))):
5974 errors.append(
5975 output_api.PresubmitError(
5976 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
5977 'possible, please create and issue and add a comment such '
5978 'as:\n # TODO(https://crbug.com/XXX): add '
5979 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
5980 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:275981
5982
5983def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:505984 path = affected_file.LocalPath()
5985 if not _IsCPlusPlusFile(input_api, path):
5986 return False
5987
5988 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
5989 if "/renderer/" in path:
5990 return True
5991
5992 # Blink's public/web API is only used/included by Renderer-only code. Note
5993 # that public/platform API may be used in non-Renderer processes (e.g. there
5994 # are some includes in code used by Utility, PDF, or Plugin processes).
5995 if "/blink/public/web/" in path:
5996 return True
5997
5998 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:275999 return False
6000
Lukasz Anforowicz7016d05e2021-11-30 03:56:276001# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6002# by the Chromium Clang Plugin (which will be preferable because it will
6003# 1) report errors earlier - at compile-time and 2) cover more rules).
6004def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506005 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6006 errors = []
6007 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6008 # C++ comment.
6009 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6010 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6011 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6012 if raw_ptr_matcher.search(line):
6013 errors.append(
6014 output_api.PresubmitError(
6015 'Problem on {path}:{line} - '\
6016 'raw_ptr<T> should not be used in Renderer-only code '\
6017 '(as documented in the "Pointers to unprotected memory" '\
6018 'section in //base/memory/raw_ptr.md)'.format(
6019 path=f.LocalPath(), line=line_num)))
6020 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566021
6022
6023def CheckPythonShebang(input_api, output_api):
6024 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6025 system-wide python.
6026 """
6027 errors = []
6028 sources = lambda affected_file: input_api.FilterSourceFile(
6029 affected_file,
6030 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6031 r'third_party/blink/web_tests/external/') + input_api.
6032 DEFAULT_FILES_TO_SKIP),
6033 files_to_check=[r'.*\.py$'])
6034 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276035 for line_num, line in f.ChangedContents():
6036 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6037 errors.append(f.LocalPath())
6038 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566039
6040 result = []
6041 for file in errors:
6042 result.append(
6043 output_api.PresubmitError(
6044 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6045 file))
6046 return result
James Shen81cc0e22022-06-15 21:10:456047
6048
6049def CheckBatchAnnotation(input_api, output_api):
6050 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6051 is not an instrumentation test, disregard."""
6052
6053 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6054 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6055 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6056 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6057 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6058
ckitagawae8fd23b2022-06-17 15:29:386059 missing_annotation_errors = []
6060 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456061
6062 def _FilterFile(affected_file):
6063 return input_api.FilterSourceFile(
6064 affected_file,
6065 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6066 files_to_check=[r'.*Test\.java$'])
6067
6068 for f in input_api.AffectedSourceFiles(_FilterFile):
6069 batch_matched = None
6070 do_not_batch_matched = None
6071 is_instrumentation_test = True
6072 for line in f.NewContents():
6073 if robolectric_test.search(line) or uiautomator_test.search(line):
6074 # Skip Robolectric and UiAutomator tests.
6075 is_instrumentation_test = False
6076 break
6077 if not batch_matched:
6078 batch_matched = batch_annotation.search(line)
6079 if not do_not_batch_matched:
6080 do_not_batch_matched = do_not_batch_annotation.search(line)
6081 test_class_declaration_matched = test_class_declaration.search(
6082 line)
6083 if test_class_declaration_matched:
6084 break
6085 if (is_instrumentation_test and
6086 not batch_matched and
6087 not do_not_batch_matched):
ckitagawae8fd23b2022-06-17 15:29:386088 missing_annotation_errors.append(str(f.LocalPath()))
6089 if (not is_instrumentation_test and
6090 (batch_matched or
6091 do_not_batch_matched)):
6092 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456093
6094 results = []
6095
ckitagawae8fd23b2022-06-17 15:29:386096 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456097 results.append(
6098 output_api.PresubmitPromptWarning(
6099 """
6100Instrumentation tests should use either @Batch or @DoNotBatch. If tests are not
6101safe to run in batch, please use @DoNotBatch with reasons.
ckitagawae8fd23b2022-06-17 15:29:386102""", missing_annotation_errors))
6103 if extra_annotation_errors:
6104 results.append(
6105 output_api.PresubmitPromptWarning(
6106 """
6107Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6108""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456109
6110 return results