blob: 22a6de9ec138e8ce2257aaadcffc4aa03e89b7de [file] [log] [blame]
wez@chromium.orga18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
maruel@chromium.orgca8d19842009-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.
maruel@chromium.orgca8d19842009-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'
joi@chromium.orgeea609a2011-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
maruel@chromium.org379e7dd2010-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[\\/].*",
maruel@chromium.org3e4eb112011-01-18 03:29:5443 r".*MakeFile$",
gman@chromium.org1084ccc2012-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.*",
maruel@chromium.org4306417642009-06-11 00:33:4053)
maruel@chromium.orgca8d19842009-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
joi@chromium.org06e6d0ff2012-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
joi@chromium.org06e6d0ff2012-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,
joi@chromium.org06e6d0ff2012-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' %
danakj@chromium.orge2d7e6f2013-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[\\/].*',
darin@chromium.org7b054982013-11-27 00:44:4798 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0499 r'mojo[\\/]examples[\\/].*',
lliabraa@chromium.org8176de12014-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[\\/]*'
joi@chromium.org06e6d0ff2012-12-11 01:36:44108)
maruel@chromium.orgca8d19842009-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
joi@chromium.orgeea609a2011-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.')
joi@chromium.orgeea609a2011-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
marja@chromium.orgcf9b78f2012-11-14 11:40:28140
Daniel Chenga44a1bcd2022-03-15 20:00:15141
Daniel Cheng917ce542022-03-15 20:46:57142_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15143 BanRule(
144 'import java.net.URI;',
145 (
146 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
147 ),
148 excluded_paths=(
149 (r'net/android/javatests/src/org/chromium/net/'
150 'AndroidProxySelectorTest\.java'),
151 r'components/cronet/',
152 r'third_party/robolectric/local/',
153 ),
Michael Thiessen44457642020-02-06 00:24:15154 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15155 BanRule(
156 'import android.annotation.TargetApi;',
157 (
158 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
159 'RequiresApi ensures that any calls are guarded by the appropriate '
160 'SDK_INT check. See https://crbug.com/1116486.',
161 ),
162 ),
163 BanRule(
164 'import android.support.test.rule.UiThreadTestRule;',
165 (
166 'Do not use UiThreadTestRule, just use '
167 '@org.chromium.base.test.UiThreadTest on test methods that should run '
168 'on the UI thread. See https://crbug.com/1111893.',
169 ),
170 ),
171 BanRule(
172 'import android.support.test.annotation.UiThreadTest;',
173 ('Do not use android.support.test.annotation.UiThreadTest, use '
174 'org.chromium.base.test.UiThreadTest instead. See '
175 'https://crbug.com/1111893.',
176 ),
177 ),
178 BanRule(
179 'import android.support.test.rule.ActivityTestRule;',
180 (
181 'Do not use ActivityTestRule, use '
182 'org.chromium.base.test.BaseActivityTestRule instead.',
183 ),
184 excluded_paths=(
185 'components/cronet/',
186 ),
187 ),
188)
wnwenbdc444e2016-05-25 13:44:15189
Daniel Cheng917ce542022-03-15 20:46:57190_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15191 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41192 'StrictMode.allowThreadDiskReads()',
193 (
194 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
195 'directly.',
196 ),
197 False,
198 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15199 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41200 'StrictMode.allowThreadDiskWrites()',
201 (
202 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
203 'directly.',
204 ),
205 False,
206 ),
Daniel Cheng917ce542022-03-15 20:46:57207 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36208 '.waitForIdleSync()',
209 (
210 'Do not use waitForIdleSync as it masks underlying issues. There is '
211 'almost always something else you should wait on instead.',
212 ),
213 False,
214 ),
Eric Stevensona9a980972017-09-23 00:04:41215)
216
Daniel Cheng917ce542022-03-15 20:46:57217_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15218 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59219 'addTrackingRect:',
avi@chromium.org23e6cbc2012-06-16 18:51:20220 (
221 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
avi@chromium.org127f18ec2012-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(
leng@chromium.orgeaae1972014-04-16 04:17:26228 r'/NSTrackingArea\W',
avi@chromium.org23e6cbc2012-06-16 18:51:20229 (
230 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59237 'convertPointFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20238 (
239 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59246 'convertPointToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20247 (
248 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59255 'convertRectFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20256 (
257 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59264 'convertRectToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20265 (
266 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59273 'convertSizeFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20274 (
275 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59282 'convertSizeToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20283 (
284 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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 ),
avi@chromium.org127f18ec2012-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(
avi@chromium.org23e6cbc2012-06-16 18:51:20378 'FRIEND_TEST(',
379 (
jam@chromium.orge3c945502012-06-26 20:01:49380 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
avi@chromium.org23e6cbc2012-06-16 18:51:20381 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
382 ),
383 False,
jochen@chromium.org7345da02012-11-27 14:31:49384 (),
avi@chromium.org23e6cbc2012-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(
enne@chromium.org52657f62013-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.'
enne@chromium.org52657f62013-05-20 05:30:31400 ),
401 True,
402 (),
403 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15404 BanRule(
enne@chromium.org52657f62013-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.'
enne@chromium.org52657f62013-05-20 05:30:31409 ),
410 True,
411 (),
412 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15413 BanRule(
enne@chromium.org52657f62013-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.'
enne@chromium.org52657f62013-05-20 05:30:31418 ),
419 True,
420 (),
421 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15422 BanRule(
enne@chromium.org52657f62013-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.'
enne@chromium.org52657f62013-05-20 05:30:31428 ),
429 True,
430 (),
431 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15432 BanRule(
mark@chromium.orgd89eec82013-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(
mark@chromium.orgd89eec82013-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$',
mark@chromium.orgd89eec82013-12-03 14:10:59454 ),
455 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15456 BanRule(
jochen@chromium.orgec5b3f02014-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,
rockot@chromium.orgf55c90ee62014-04-12 00:50:03463 (
Egor Paskoce145c42018-09-28 19:31:04464 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
rockot@chromium.orgf55c90ee62014-04-12 00:50:03465 ),
jochen@chromium.orgec5b3f02014-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 ),
avi@chromium.org127f18ec2012-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]
avi@chromium.org127f18ec2012-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',
Yuki Shiino38eeaad12022-08-11 06:40:251210 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421211 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131212 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501213 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411214 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1215 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061216 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221217 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451218 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401219]
1220
wnwenbdc444e2016-05-25 13:44:151221
agrievef32bcc72016-04-04 14:57:401222_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1223
1224
Eric Boren6fd2b932018-01-25 15:05:081225# Bypass the AUTHORS check for these accounts.
1226_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591227 ) | set('%s@appspot.gserviceaccount.com' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451228 ) | set('%s@developer.gserviceaccount.com' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591229 ) | set('%s@chops-service-accounts.iam.gserviceaccount.com' % s
smutde797052019-12-04 02:03:521230 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231231 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471232 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461233 'infra-try-recipes-tester', 'lacros-tracking-roller',
1234 'lacros-sdk-version-roller')
Eric Boren835d71f2018-09-07 21:09:041235 ) | set('%s@skia-public.iam.gserviceaccount.com' % s
Eric Boren66150e52020-01-08 11:20:271236 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041237 ) | set('%s@skia-corp.google.com.iam.gserviceaccount.com' % s
Yulan Lineb0cfba2021-04-09 18:43:161238 for s in ('chromium-internal-autoroll',)
1239 ) | set('%s@owners-cleanup-prod.google.com.iam.gserviceaccount.com' % s
1240 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081241
Matt Stark6ef08872021-07-29 01:21:461242_INVALID_GRD_FILE_LINE = [
1243 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1244]
Eric Boren6fd2b932018-01-25 15:05:081245
Daniel Bratell65b033262019-04-23 08:17:061246def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501247 """Returns True if this file contains C++-like code (and not Python,
1248 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061249
Sam Maiera6e76d72022-02-11 21:43:501250 ext = input_api.os_path.splitext(file_path)[1]
1251 # This list is compatible with CppChecker.IsCppFile but we should
1252 # consider adding ".c" to it. If we do that we can use this function
1253 # at more places in the code.
1254 return ext in (
1255 '.h',
1256 '.cc',
1257 '.cpp',
1258 '.m',
1259 '.mm',
1260 )
1261
Daniel Bratell65b033262019-04-23 08:17:061262
1263def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501264 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061265
1266
1267def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501268 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061269
1270
1271def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501272 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061273
Mohamed Heikal5e5b7922020-10-29 18:57:591274
Erik Staabc734cd7a2021-11-23 03:11:521275def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501276 ext = input_api.os_path.splitext(file_path)[1]
1277 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521278
1279
Mohamed Heikal5e5b7922020-10-29 18:57:591280def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501281 """Prevent additions of dependencies from the upstream repo on //clank."""
1282 # clank can depend on clank
1283 if input_api.change.RepositoryRoot().endswith('clank'):
1284 return []
1285 build_file_patterns = [
1286 r'(.+/)?BUILD\.gn',
1287 r'.+\.gni',
1288 ]
1289 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1290 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591291
Sam Maiera6e76d72022-02-11 21:43:501292 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591293
Sam Maiera6e76d72022-02-11 21:43:501294 def FilterFile(affected_file):
1295 return input_api.FilterSourceFile(affected_file,
1296 files_to_check=build_file_patterns,
1297 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591298
Sam Maiera6e76d72022-02-11 21:43:501299 problems = []
1300 for f in input_api.AffectedSourceFiles(FilterFile):
1301 local_path = f.LocalPath()
1302 for line_number, line in f.ChangedContents():
1303 if (bad_pattern.search(line)):
1304 problems.append('%s:%d\n %s' %
1305 (local_path, line_number, line.strip()))
1306 if problems:
1307 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1308 else:
1309 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591310
1311
Saagar Sanghavifceeaae2020-08-12 16:40:361312def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501313 """Attempts to prevent use of functions intended only for testing in
1314 non-testing code. For now this is just a best-effort implementation
1315 that ignores header files and may have some false positives. A
1316 better implementation would probably need a proper C++ parser.
1317 """
1318 # We only scan .cc files and the like, as the declaration of
1319 # for-testing functions in header files are hard to distinguish from
1320 # calls to such functions without a proper C++ parser.
1321 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
joi@chromium.org55459852011-08-10 15:17:191322
Sam Maiera6e76d72022-02-11 21:43:501323 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1324 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1325 base_function_pattern)
1326 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1327 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1328 exclusion_pattern = input_api.re.compile(
1329 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1330 (base_function_pattern, base_function_pattern))
1331 # Avoid a false positive in this case, where the method name, the ::, and
1332 # the closing { are all on different lines due to line wrapping.
1333 # HelperClassForTesting::
1334 # HelperClassForTesting(
1335 # args)
1336 # : member(0) {}
1337 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
joi@chromium.org55459852011-08-10 15:17:191338
Sam Maiera6e76d72022-02-11 21:43:501339 def FilterFile(affected_file):
1340 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1341 input_api.DEFAULT_FILES_TO_SKIP)
1342 return input_api.FilterSourceFile(
1343 affected_file,
1344 files_to_check=file_inclusion_pattern,
1345 files_to_skip=files_to_skip)
joi@chromium.org55459852011-08-10 15:17:191346
Sam Maiera6e76d72022-02-11 21:43:501347 problems = []
1348 for f in input_api.AffectedSourceFiles(FilterFile):
1349 local_path = f.LocalPath()
1350 in_method_defn = False
1351 for line_number, line in f.ChangedContents():
1352 if (inclusion_pattern.search(line)
1353 and not comment_pattern.search(line)
1354 and not exclusion_pattern.search(line)
1355 and not allowlist_pattern.search(line)
1356 and not in_method_defn):
1357 problems.append('%s:%d\n %s' %
1358 (local_path, line_number, line.strip()))
1359 in_method_defn = method_defn_pattern.search(line)
joi@chromium.org55459852011-08-10 15:17:191360
Sam Maiera6e76d72022-02-11 21:43:501361 if problems:
1362 return [
1363 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1364 ]
1365 else:
1366 return []
joi@chromium.org55459852011-08-10 15:17:191367
1368
Saagar Sanghavifceeaae2020-08-12 16:40:361369def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501370 """This is a simplified version of
1371 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1372 """
1373 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1374 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1375 name_pattern = r'ForTest(s|ing)?'
1376 # Describes an occurrence of "ForTest*" inside a // comment.
1377 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1378 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1379 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1380 # Catch calls.
1381 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1382 # Ignore definitions. (Comments are ignored separately.)
1383 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231384
Sam Maiera6e76d72022-02-11 21:43:501385 problems = []
1386 sources = lambda x: input_api.FilterSourceFile(
1387 x,
1388 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1389 DEFAULT_FILES_TO_SKIP),
1390 files_to_check=[r'.*\.java$'])
1391 for f in input_api.AffectedFiles(include_deletes=False,
1392 file_filter=sources):
1393 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231394 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501395 for line_number, line in f.ChangedContents():
1396 if is_inside_javadoc and javadoc_end_re.search(line):
1397 is_inside_javadoc = False
1398 if not is_inside_javadoc and javadoc_start_re.search(line):
1399 is_inside_javadoc = True
1400 if is_inside_javadoc:
1401 continue
1402 if (inclusion_re.search(line) and not comment_re.search(line)
1403 and not annotation_re.search(line)
1404 and not exclusion_re.search(line)):
1405 problems.append('%s:%d\n %s' %
1406 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231407
Sam Maiera6e76d72022-02-11 21:43:501408 if problems:
1409 return [
1410 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1411 ]
1412 else:
1413 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231414
1415
Saagar Sanghavifceeaae2020-08-12 16:40:361416def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501417 """Checks to make sure no .h files include <iostream>."""
1418 files = []
1419 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1420 input_api.re.MULTILINE)
1421 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1422 if not f.LocalPath().endswith('.h'):
1423 continue
1424 contents = input_api.ReadFile(f)
1425 if pattern.search(contents):
1426 files.append(f)
thakis@chromium.org10689ca2011-09-02 02:31:541427
Sam Maiera6e76d72022-02-11 21:43:501428 if len(files):
1429 return [
1430 output_api.PresubmitError(
1431 'Do not #include <iostream> in header files, since it inserts static '
1432 'initialization into every file including the header. Instead, '
1433 '#include <ostream>. See http://crbug.com/94794', files)
1434 ]
1435 return []
1436
thakis@chromium.org10689ca2011-09-02 02:31:541437
Aleksey Khoroshilov9b28c032022-06-03 16:35:321438def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501439 """Checks no windows headers with StrCat redefined are included directly."""
1440 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:321441 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
1442 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
1443 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
1444 _NON_BASE_DEPENDENT_PATHS)
1445 sources_filter = lambda f: input_api.FilterSourceFile(
1446 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
1447
Sam Maiera6e76d72022-02-11 21:43:501448 pattern_deny = input_api.re.compile(
1449 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1450 input_api.re.MULTILINE)
1451 pattern_allow = input_api.re.compile(
1452 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:321453 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:501454 contents = input_api.ReadFile(f)
1455 if pattern_deny.search(
1456 contents) and not pattern_allow.search(contents):
1457 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431458
Sam Maiera6e76d72022-02-11 21:43:501459 if len(files):
1460 return [
1461 output_api.PresubmitError(
1462 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1463 'directly since they pollute code with StrCat macro. Instead, '
1464 'include matching header from base/win. See http://crbug.com/856536',
1465 files)
1466 ]
1467 return []
Danil Chapovalov3518f362018-08-11 16:13:431468
thakis@chromium.org10689ca2011-09-02 02:31:541469
Saagar Sanghavifceeaae2020-08-12 16:40:361470def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501471 """Checks to make sure no source files use UNIT_TEST."""
1472 problems = []
1473 for f in input_api.AffectedFiles():
1474 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1475 continue
jam@chromium.org72df4e782012-06-21 16:28:181476
Sam Maiera6e76d72022-02-11 21:43:501477 for line_num, line in f.ChangedContents():
1478 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1479 problems.append(' %s:%d' % (f.LocalPath(), line_num))
jam@chromium.org72df4e782012-06-21 16:28:181480
Sam Maiera6e76d72022-02-11 21:43:501481 if not problems:
1482 return []
1483 return [
1484 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1485 '\n'.join(problems))
1486 ]
1487
jam@chromium.org72df4e782012-06-21 16:28:181488
Saagar Sanghavifceeaae2020-08-12 16:40:361489def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501490 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341491
Sam Maiera6e76d72022-02-11 21:43:501492 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1493 instead of DISABLED_. To filter false positives, reports are only generated
1494 if a corresponding MAYBE_ line exists.
1495 """
1496 problems = []
Dominic Battre033531052018-09-24 15:45:341497
Sam Maiera6e76d72022-02-11 21:43:501498 # The following two patterns are looked for in tandem - is a test labeled
1499 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1500 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1501 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341502
Sam Maiera6e76d72022-02-11 21:43:501503 # This is for the case that a test is disabled on all platforms.
1504 full_disable_pattern = input_api.re.compile(
1505 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1506 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341507
Sam Maiera6e76d72022-02-11 21:43:501508 for f in input_api.AffectedFiles(False):
1509 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1510 continue
Dominic Battre033531052018-09-24 15:45:341511
Sam Maiera6e76d72022-02-11 21:43:501512 # Search for MABYE_, DISABLE_ pairs.
1513 disable_lines = {} # Maps of test name to line number.
1514 maybe_lines = {}
1515 for line_num, line in f.ChangedContents():
1516 disable_match = disable_pattern.search(line)
1517 if disable_match:
1518 disable_lines[disable_match.group(1)] = line_num
1519 maybe_match = maybe_pattern.search(line)
1520 if maybe_match:
1521 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341522
Sam Maiera6e76d72022-02-11 21:43:501523 # Search for DISABLE_ occurrences within a TEST() macro.
1524 disable_tests = set(disable_lines.keys())
1525 maybe_tests = set(maybe_lines.keys())
1526 for test in disable_tests.intersection(maybe_tests):
1527 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341528
Sam Maiera6e76d72022-02-11 21:43:501529 contents = input_api.ReadFile(f)
1530 full_disable_match = full_disable_pattern.search(contents)
1531 if full_disable_match:
1532 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341533
Sam Maiera6e76d72022-02-11 21:43:501534 if not problems:
1535 return []
1536 return [
1537 output_api.PresubmitPromptWarning(
1538 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1539 '\n'.join(problems))
1540 ]
1541
Dominic Battre033531052018-09-24 15:45:341542
Nina Satragnof7660532021-09-20 18:03:351543def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501544 """Checks to make sure tests disabled conditionally are not missing a
1545 corresponding MAYBE_ prefix.
1546 """
1547 # Expect at least a lowercase character in the test name. This helps rule out
1548 # false positives with macros wrapping the actual tests name.
1549 define_maybe_pattern = input_api.re.compile(
1550 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191551 # The test_maybe_pattern needs to handle all of these forms. The standard:
1552 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1553 # With a wrapper macro around the test name:
1554 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1555 # And the odd-ball NACL_BROWSER_TEST_f format:
1556 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1557 # The optional E2E_ENABLED-style is handled with (\w*\()?
1558 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1559 # trailing ')'.
1560 test_maybe_pattern = (
1561 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501562 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1563 warnings = []
Nina Satragnof7660532021-09-20 18:03:351564
Sam Maiera6e76d72022-02-11 21:43:501565 # Read the entire files. We can't just read the affected lines, forgetting to
1566 # add MAYBE_ on a change would not show up otherwise.
1567 for f in input_api.AffectedFiles(False):
1568 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1569 continue
1570 contents = input_api.ReadFile(f)
1571 lines = contents.splitlines(True)
1572 current_position = 0
1573 warning_test_names = set()
1574 for line_num, line in enumerate(lines, start=1):
1575 current_position += len(line)
1576 maybe_match = define_maybe_pattern.search(line)
1577 if maybe_match:
1578 test_name = maybe_match.group('test_name')
1579 # Do not warn twice for the same test.
1580 if (test_name in warning_test_names):
1581 continue
1582 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351583
Sam Maiera6e76d72022-02-11 21:43:501584 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1585 # the current position.
1586 test_match = input_api.re.compile(
1587 test_maybe_pattern.format(test_name=test_name),
1588 input_api.re.MULTILINE).search(contents, current_position)
1589 suite_match = input_api.re.compile(
1590 suite_maybe_pattern.format(test_name=test_name),
1591 input_api.re.MULTILINE).search(contents, current_position)
1592 if not test_match and not suite_match:
1593 warnings.append(
1594 output_api.PresubmitPromptWarning(
1595 '%s:%d found MAYBE_ defined without corresponding test %s'
1596 % (f.LocalPath(), line_num, test_name)))
1597 return warnings
1598
jam@chromium.org72df4e782012-06-21 16:28:181599
Saagar Sanghavifceeaae2020-08-12 16:40:361600def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501601 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1602 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:161603 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:501604 input_api.re.MULTILINE)
1605 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1606 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1607 continue
1608 for lnum, line in f.ChangedContents():
1609 if input_api.re.search(pattern, line):
1610 errors.append(
1611 output_api.PresubmitError((
1612 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1613 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1614 (f.LocalPath(), lnum)))
1615 return errors
danakj61c1aa22015-10-26 19:55:521616
1617
Weilun Shia487fad2020-10-28 00:10:341618# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1619# more reliable way. See
1620# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191621
wnwenbdc444e2016-05-25 13:44:151622
Saagar Sanghavifceeaae2020-08-12 16:40:361623def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501624 """Check that FlakyTest annotation is our own instead of the android one"""
1625 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1626 files = []
1627 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1628 if f.LocalPath().endswith('Test.java'):
1629 if pattern.search(input_api.ReadFile(f)):
1630 files.append(f)
1631 if len(files):
1632 return [
1633 output_api.PresubmitError(
1634 'Use org.chromium.base.test.util.FlakyTest instead of '
1635 'android.test.FlakyTest', files)
1636 ]
1637 return []
mcasasb7440c282015-02-04 14:52:191638
wnwenbdc444e2016-05-25 13:44:151639
Saagar Sanghavifceeaae2020-08-12 16:40:361640def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501641 """Make sure .DEPS.git is never modified manually."""
1642 if any(f.LocalPath().endswith('.DEPS.git')
1643 for f in input_api.AffectedFiles()):
1644 return [
1645 output_api.PresubmitError(
1646 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1647 'automated system based on what\'s in DEPS and your changes will be\n'
1648 'overwritten.\n'
1649 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1650 'get-the-code#Rolling_DEPS\n'
1651 'for more information')
1652 ]
1653 return []
maruel@chromium.org2a8ac9c2011-10-19 17:20:441654
1655
Saagar Sanghavifceeaae2020-08-12 16:40:361656def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501657 """Checks that DEPS file deps are from allowed_hosts."""
1658 # Run only if DEPS file has been modified to annoy fewer bystanders.
1659 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1660 return []
1661 # Outsource work to gclient verify
1662 try:
1663 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
1664 'third_party', 'depot_tools',
1665 'gclient.py')
1666 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:321667 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:501668 stderr=input_api.subprocess.STDOUT)
1669 return []
1670 except input_api.subprocess.CalledProcessError as error:
1671 return [
1672 output_api.PresubmitError(
1673 'DEPS file must have only git dependencies.',
1674 long_text=error.output)
1675 ]
tandriief664692014-09-23 14:51:471676
1677
Mario Sanchez Prada2472cab2019-09-18 10:58:311678def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151679 ban_rule):
Sam Maiera6e76d72022-02-11 21:43:501680 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311681
Sam Maiera6e76d72022-02-11 21:43:501682 Returns an string composed of the name of the file, the line number where the
1683 match has been found and the additional text passed as |message| in case the
1684 target type name matches the text inside the line passed as parameter.
1685 """
1686 result = []
Peng Huang9c5949a02020-06-11 19:20:541687
Daniel Chenga44a1bcd2022-03-15 20:00:151688 # Ignore comments about banned types.
1689 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:501690 return result
Daniel Chenga44a1bcd2022-03-15 20:00:151691 # A // nocheck comment will bypass this error.
1692 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:501693 return result
1694
1695 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:151696 if ban_rule.pattern[0:1] == '/':
1697 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:501698 if input_api.re.search(regex, line):
1699 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:151700 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:501701 matched = True
1702
1703 if matched:
1704 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:151705 for line in ban_rule.explanation:
1706 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:501707
danakjd18e8892020-12-17 17:42:011708 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:311709
1710
Saagar Sanghavifceeaae2020-08-12 16:40:361711def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501712 """Make sure that banned functions are not used."""
1713 warnings = []
1714 errors = []
avi@chromium.org127f18ec2012-06-16 05:05:591715
Sam Maiera6e76d72022-02-11 21:43:501716 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:151717 if not excluded_paths:
1718 return False
1719
Sam Maiera6e76d72022-02-11 21:43:501720 local_path = affected_file.LocalPath()
1721 for item in excluded_paths:
1722 if input_api.re.match(item, local_path):
1723 return True
1724 return False
wnwenbdc444e2016-05-25 13:44:151725
Sam Maiera6e76d72022-02-11 21:43:501726 def IsIosObjcFile(affected_file):
1727 local_path = affected_file.LocalPath()
1728 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
1729 '.h'):
1730 return False
1731 basename = input_api.os_path.basename(local_path)
1732 if 'ios' in basename.split('_'):
1733 return True
1734 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1735 if sep and 'ios' in local_path.split(sep):
1736 return True
1737 return False
Sylvain Defresnea8b73d252018-02-28 15:45:541738
Daniel Chenga44a1bcd2022-03-15 20:00:151739 def CheckForMatch(affected_file, line_num: int, line: str,
1740 ban_rule: BanRule):
1741 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
1742 return
1743
Sam Maiera6e76d72022-02-11 21:43:501744 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151745 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501746 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:151747 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:501748 errors.extend(problems)
1749 else:
1750 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151751
Sam Maiera6e76d72022-02-11 21:43:501752 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1753 for f in input_api.AffectedFiles(file_filter=file_filter):
1754 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151755 for ban_rule in _BANNED_JAVA_FUNCTIONS:
1756 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:411757
Sam Maiera6e76d72022-02-11 21:43:501758 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1759 for f in input_api.AffectedFiles(file_filter=file_filter):
1760 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151761 for ban_rule in _BANNED_OBJC_FUNCTIONS:
1762 CheckForMatch(f, line_num, line, ban_rule)
avi@chromium.org127f18ec2012-06-16 05:05:591763
Sam Maiera6e76d72022-02-11 21:43:501764 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
1765 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151766 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
1767 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:541768
Sam Maiera6e76d72022-02-11 21:43:501769 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1770 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1771 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151772 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
1773 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:051774
Sam Maiera6e76d72022-02-11 21:43:501775 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1776 for f in input_api.AffectedFiles(file_filter=file_filter):
1777 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151778 for ban_rule in _BANNED_CPP_FUNCTIONS:
1779 CheckForMatch(f, line_num, line, ban_rule)
avi@chromium.org127f18ec2012-06-16 05:05:591780
Daniel Cheng92c15e32022-03-16 17:48:221781 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
1782 for f in input_api.AffectedFiles(file_filter=file_filter):
1783 for line_num, line in f.ChangedContents():
1784 for ban_rule in _BANNED_MOJOM_PATTERNS:
1785 CheckForMatch(f, line_num, line, ban_rule)
1786
1787
Sam Maiera6e76d72022-02-11 21:43:501788 result = []
1789 if (warnings):
1790 result.append(
1791 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
1792 '\n'.join(warnings)))
1793 if (errors):
1794 result.append(
1795 output_api.PresubmitError('Banned functions were used.\n' +
1796 '\n'.join(errors)))
1797 return result
avi@chromium.org127f18ec2012-06-16 05:05:591798
1799
Michael Thiessen44457642020-02-06 00:24:151800def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501801 """Make sure that banned java imports are not used."""
1802 errors = []
Michael Thiessen44457642020-02-06 00:24:151803
Sam Maiera6e76d72022-02-11 21:43:501804 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1805 for f in input_api.AffectedFiles(file_filter=file_filter):
1806 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151807 for ban_rule in _BANNED_JAVA_IMPORTS:
1808 # Consider merging this into the above function. There is no
1809 # real difference anymore other than helping with a little
1810 # bit of boilerplate text. Doing so means things like
1811 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:501812 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:151813 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501814 if problems:
1815 errors.extend(problems)
1816 result = []
1817 if (errors):
1818 result.append(
1819 output_api.PresubmitError('Banned imports were used.\n' +
1820 '\n'.join(errors)))
1821 return result
Michael Thiessen44457642020-02-06 00:24:151822
1823
Saagar Sanghavifceeaae2020-08-12 16:40:361824def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501825 """Make sure that banned functions are not used."""
1826 files = []
1827 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
1828 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1829 if not f.LocalPath().endswith('.h'):
1830 continue
Bruce Dawson4c4c2922022-05-02 18:07:331831 if f.LocalPath().endswith('com_imported_mstscax.h'):
1832 continue
Sam Maiera6e76d72022-02-11 21:43:501833 contents = input_api.ReadFile(f)
1834 if pattern.search(contents):
1835 files.append(f)
dcheng@chromium.org6c063c62012-07-11 19:11:061836
Sam Maiera6e76d72022-02-11 21:43:501837 if files:
1838 return [
1839 output_api.PresubmitError(
1840 'Do not use #pragma once in header files.\n'
1841 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1842 files)
1843 ]
1844 return []
dcheng@chromium.org6c063c62012-07-11 19:11:061845
avi@chromium.org127f18ec2012-06-16 05:05:591846
Saagar Sanghavifceeaae2020-08-12 16:40:361847def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501848 """Checks to make sure we don't introduce use of foo ? true : false."""
1849 problems = []
1850 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1851 for f in input_api.AffectedFiles():
1852 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1853 continue
thestig@chromium.orge7479052012-09-19 00:26:121854
Sam Maiera6e76d72022-02-11 21:43:501855 for line_num, line in f.ChangedContents():
1856 if pattern.match(line):
1857 problems.append(' %s:%d' % (f.LocalPath(), line_num))
thestig@chromium.orge7479052012-09-19 00:26:121858
Sam Maiera6e76d72022-02-11 21:43:501859 if not problems:
1860 return []
1861 return [
1862 output_api.PresubmitPromptWarning(
1863 'Please consider avoiding the "? true : false" pattern if possible.\n'
1864 + '\n'.join(problems))
1865 ]
thestig@chromium.orge7479052012-09-19 00:26:121866
1867
Saagar Sanghavifceeaae2020-08-12 16:40:361868def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501869 """Runs checkdeps on #include and import statements added in this
1870 change. Breaking - rules is an error, breaking ! rules is a
1871 warning.
1872 """
1873 # Return early if no relevant file types were modified.
1874 for f in input_api.AffectedFiles():
1875 path = f.LocalPath()
1876 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
1877 or _IsJavaFile(input_api, path)):
1878 break
joi@chromium.org55f9f382012-07-31 11:02:181879 else:
Sam Maiera6e76d72022-02-11 21:43:501880 return []
rhalavati08acd232017-04-03 07:23:281881
Sam Maiera6e76d72022-02-11 21:43:501882 import sys
1883 # We need to wait until we have an input_api object and use this
1884 # roundabout construct to import checkdeps because this file is
1885 # eval-ed and thus doesn't have __file__.
1886 original_sys_path = sys.path
1887 try:
1888 sys.path = sys.path + [
1889 input_api.os_path.join(input_api.PresubmitLocalPath(),
1890 'buildtools', 'checkdeps')
1891 ]
1892 import checkdeps
1893 from rules import Rule
1894 finally:
1895 # Restore sys.path to what it was before.
1896 sys.path = original_sys_path
joi@chromium.org55f9f382012-07-31 11:02:181897
Sam Maiera6e76d72022-02-11 21:43:501898 added_includes = []
1899 added_imports = []
1900 added_java_imports = []
1901 for f in input_api.AffectedFiles():
1902 if _IsCPlusPlusFile(input_api, f.LocalPath()):
1903 changed_lines = [line for _, line in f.ChangedContents()]
1904 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
1905 elif _IsProtoFile(input_api, f.LocalPath()):
1906 changed_lines = [line for _, line in f.ChangedContents()]
1907 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
1908 elif _IsJavaFile(input_api, f.LocalPath()):
1909 changed_lines = [line for _, line in f.ChangedContents()]
1910 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241911
Sam Maiera6e76d72022-02-11 21:43:501912 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
1913
1914 error_descriptions = []
1915 warning_descriptions = []
1916 error_subjects = set()
1917 warning_subjects = set()
1918
1919 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1920 added_includes):
1921 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1922 description_with_path = '%s\n %s' % (path, rule_description)
1923 if rule_type == Rule.DISALLOW:
1924 error_descriptions.append(description_with_path)
1925 error_subjects.add("#includes")
1926 else:
1927 warning_descriptions.append(description_with_path)
1928 warning_subjects.add("#includes")
1929
1930 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1931 added_imports):
1932 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1933 description_with_path = '%s\n %s' % (path, rule_description)
1934 if rule_type == Rule.DISALLOW:
1935 error_descriptions.append(description_with_path)
1936 error_subjects.add("imports")
1937 else:
1938 warning_descriptions.append(description_with_path)
1939 warning_subjects.add("imports")
1940
1941 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
1942 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
1943 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1944 description_with_path = '%s\n %s' % (path, rule_description)
1945 if rule_type == Rule.DISALLOW:
1946 error_descriptions.append(description_with_path)
1947 error_subjects.add("imports")
1948 else:
1949 warning_descriptions.append(description_with_path)
1950 warning_subjects.add("imports")
1951
1952 results = []
1953 if error_descriptions:
1954 results.append(
1955 output_api.PresubmitError(
1956 'You added one or more %s that violate checkdeps rules.' %
1957 " and ".join(error_subjects), error_descriptions))
1958 if warning_descriptions:
1959 results.append(
1960 output_api.PresubmitPromptOrNotify(
1961 'You added one or more %s of files that are temporarily\n'
1962 'allowed but being removed. Can you avoid introducing the\n'
1963 '%s? See relevant DEPS file(s) for details and contacts.' %
1964 (" and ".join(warning_subjects), "/".join(warning_subjects)),
1965 warning_descriptions))
1966 return results
joi@chromium.org55f9f382012-07-31 11:02:181967
1968
Saagar Sanghavifceeaae2020-08-12 16:40:361969def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501970 """Check that all files have their permissions properly set."""
1971 if input_api.platform == 'win32':
1972 return []
1973 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
1974 'tools', 'checkperms',
1975 'checkperms.py')
1976 args = [
Bruce Dawson8a43cf72022-05-13 17:10:321977 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:501978 input_api.change.RepositoryRoot()
1979 ]
1980 with input_api.CreateTemporaryFile() as file_list:
1981 for f in input_api.AffectedFiles():
1982 # checkperms.py file/directory arguments must be relative to the
1983 # repository.
1984 file_list.write((f.LocalPath() + '\n').encode('utf8'))
1985 file_list.close()
1986 args += ['--file-list', file_list.name]
1987 try:
1988 input_api.subprocess.check_output(args)
1989 return []
1990 except input_api.subprocess.CalledProcessError as error:
1991 return [
1992 output_api.PresubmitError('checkperms.py failed:',
1993 long_text=error.output.decode(
1994 'utf-8', 'ignore'))
1995 ]
csharp@chromium.orgfbcafe5a2012-08-08 15:31:221996
1997
Saagar Sanghavifceeaae2020-08-12 16:40:361998def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501999 """Makes sure we don't include ui/aura/window_property.h
2000 in header files.
2001 """
2002 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2003 errors = []
2004 for f in input_api.AffectedFiles():
2005 if not f.LocalPath().endswith('.h'):
2006 continue
2007 for line_num, line in f.ChangedContents():
2008 if pattern.match(line):
2009 errors.append(' %s:%d' % (f.LocalPath(), line_num))
oshima@chromium.orgc8278b32012-10-30 20:35:492010
Sam Maiera6e76d72022-02-11 21:43:502011 results = []
2012 if errors:
2013 results.append(
2014 output_api.PresubmitError(
2015 'Header files should not include ui/aura/window_property.h',
2016 errors))
2017 return results
oshima@chromium.orgc8278b32012-10-30 20:35:492018
2019
Omer Katzcc77ea92021-04-26 10:23:282020def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502021 """Makes sure we don't include any headers from
2022 third_party/blink/renderer/platform/heap/impl or
2023 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2024 third_party/blink/renderer/platform/heap
2025 """
2026 impl_pattern = input_api.re.compile(
2027 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2028 v8_wrapper_pattern = input_api.re.compile(
2029 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2030 )
2031 file_filter = lambda f: not input_api.re.match(
2032 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
2033 f.LocalPath())
2034 errors = []
Omer Katzcc77ea92021-04-26 10:23:282035
Sam Maiera6e76d72022-02-11 21:43:502036 for f in input_api.AffectedFiles(file_filter=file_filter):
2037 for line_num, line in f.ChangedContents():
2038 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2039 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282040
Sam Maiera6e76d72022-02-11 21:43:502041 results = []
2042 if errors:
2043 results.append(
2044 output_api.PresubmitError(
2045 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2046 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2047 'relevant counterparts from third_party/blink/renderer/platform/heap',
2048 errors))
2049 return results
Omer Katzcc77ea92021-04-26 10:23:282050
2051
dbeam@chromium.org70ca77752012-11-20 03:45:032052def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502053 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2054 errors = []
2055 for line_num, line in f.ChangedContents():
2056 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2057 # First-level headers in markdown look a lot like version control
2058 # conflict markers. http://daringfireball.net/projects/markdown/basics
2059 continue
2060 if pattern.match(line):
2061 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2062 return errors
dbeam@chromium.org70ca77752012-11-20 03:45:032063
2064
Saagar Sanghavifceeaae2020-08-12 16:40:362065def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502066 """Usually this is not intentional and will cause a compile failure."""
2067 errors = []
2068 for f in input_api.AffectedFiles():
2069 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
dbeam@chromium.org70ca77752012-11-20 03:45:032070
Sam Maiera6e76d72022-02-11 21:43:502071 results = []
2072 if errors:
2073 results.append(
2074 output_api.PresubmitError(
2075 'Version control conflict markers found, please resolve.',
2076 errors))
2077 return results
dbeam@chromium.org70ca77752012-11-20 03:45:032078
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202079
Saagar Sanghavifceeaae2020-08-12 16:40:362080def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502081 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2082 errors = []
2083 for f in input_api.AffectedFiles():
2084 for line_num, line in f.ChangedContents():
2085 if pattern.search(line):
2086 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162087
Sam Maiera6e76d72022-02-11 21:43:502088 results = []
2089 if errors:
2090 results.append(
2091 output_api.PresubmitPromptWarning(
2092 'Found Google support URL addressed by answer number. Please replace '
2093 'with a p= identifier instead. See crbug.com/679462\n',
2094 errors))
2095 return results
estadee17314a02017-01-12 16:22:162096
dbeam@chromium.org70ca77752012-11-20 03:45:032097
Saagar Sanghavifceeaae2020-08-12 16:40:362098def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502099 def FilterFile(affected_file):
2100 """Filter function for use with input_api.AffectedSourceFiles,
2101 below. This filters out everything except non-test files from
2102 top-level directories that generally speaking should not hard-code
2103 service URLs (e.g. src/android_webview/, src/content/ and others).
2104 """
2105 return input_api.FilterSourceFile(
2106 affected_file,
2107 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2108 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2109 input_api.DEFAULT_FILES_TO_SKIP))
joi@chromium.org06e6d0ff2012-12-11 01:36:442110
Sam Maiera6e76d72022-02-11 21:43:502111 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2112 '\.(com|net)[^"]*"')
2113 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2114 pattern = input_api.re.compile(base_pattern)
2115 problems = [] # items are (filename, line_number, line)
2116 for f in input_api.AffectedSourceFiles(FilterFile):
2117 for line_num, line in f.ChangedContents():
2118 if not comment_pattern.search(line) and pattern.search(line):
2119 problems.append((f.LocalPath(), line_num, line))
joi@chromium.org06e6d0ff2012-12-11 01:36:442120
Sam Maiera6e76d72022-02-11 21:43:502121 if problems:
2122 return [
2123 output_api.PresubmitPromptOrNotify(
2124 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2125 'Are you sure this is correct?', [
2126 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2127 for problem in problems
2128 ])
2129 ]
2130 else:
2131 return []
joi@chromium.org06e6d0ff2012-12-11 01:36:442132
2133
Saagar Sanghavifceeaae2020-08-12 16:40:362134def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502135 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292136
Sam Maiera6e76d72022-02-11 21:43:502137 def FileFilter(affected_file):
2138 """Includes directories known to be Chrome OS only."""
2139 return input_api.FilterSourceFile(
2140 affected_file,
2141 files_to_check=(
2142 '^ash/',
2143 '^chromeos/', # Top-level src/chromeos.
2144 '.*/chromeos/', # Any path component.
2145 '^components/arc',
2146 '^components/exo'),
2147 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292148
Sam Maiera6e76d72022-02-11 21:43:502149 prefs = []
2150 priority_prefs = []
2151 for f in input_api.AffectedFiles(file_filter=FileFilter):
2152 for line_num, line in f.ChangedContents():
2153 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2154 line):
2155 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2156 prefs.append(' %s' % line)
2157 if input_api.re.search(
2158 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2159 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2160 priority_prefs.append(' %s' % line)
2161
2162 results = []
2163 if (prefs):
2164 results.append(
2165 output_api.PresubmitPromptWarning(
2166 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2167 'by browser sync settings. If these prefs should be controlled by OS '
2168 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2169 '\n'.join(prefs)))
2170 if (priority_prefs):
2171 results.append(
2172 output_api.PresubmitPromptWarning(
2173 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2174 'controlled by browser sync settings. If these prefs should be '
2175 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2176 'instead.\n' + '\n'.join(prefs)))
2177 return results
James Cook6b6597c2019-11-06 22:05:292178
2179
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492180# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362181def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502182 """Makes sure there are no abbreviations in the name of PNG files.
2183 The native_client_sdk directory is excluded because it has auto-generated PNG
2184 files for documentation.
2185 """
2186 errors = []
2187 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Bruce Dawson3db456212022-05-02 05:34:182188 files_to_skip = [r'^native_client_sdk[\\/]',
2189 r'^services[\\/]test[\\/]',
2190 r'^third_party[\\/]blink[\\/]web_tests[\\/]',
2191 ]
Sam Maiera6e76d72022-02-11 21:43:502192 file_filter = lambda f: input_api.FilterSourceFile(
2193 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2194 for f in input_api.AffectedFiles(include_deletes=False,
2195 file_filter=file_filter):
2196 errors.append(' %s' % f.LocalPath())
oshima@chromium.orgd2530012013-01-25 16:39:272197
Sam Maiera6e76d72022-02-11 21:43:502198 results = []
2199 if errors:
2200 results.append(
2201 output_api.PresubmitError(
2202 'The name of PNG files should not have abbreviations. \n'
2203 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2204 'Contact oshima@chromium.org if you have questions.', errors))
2205 return results
oshima@chromium.orgd2530012013-01-25 16:39:272206
Evan Stade7cd4a2c2022-08-04 23:37:252207def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2208 """Heuristically identifies product icons based on their file name and reminds
2209 contributors not to add them to the Chromium repository.
2210 """
2211 errors = []
2212 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2213 file_filter = lambda f: input_api.FilterSourceFile(
2214 f, files_to_check=files_to_check)
2215 for f in input_api.AffectedFiles(include_deletes=False,
2216 file_filter=file_filter):
2217 errors.append(' %s' % f.LocalPath())
2218
2219 results = []
2220 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082221 # Give warnings instead of errors on presubmit --all and presubmit
2222 # --files.
2223 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2224 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252225 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082226 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252227 'Trademarked images should not be added to the public repo. '
2228 'See crbug.com/944754', errors))
2229 return results
2230
oshima@chromium.orgd2530012013-01-25 16:39:272231
Daniel Cheng4dcdb6b2017-04-13 08:30:172232def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502233 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172234
Sam Maiera6e76d72022-02-11 21:43:502235 Args:
2236 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2237 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172238 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502239 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172240 if rule.startswith('+') or rule.startswith('!')
2241 ])
Sam Maiera6e76d72022-02-11 21:43:502242 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2243 add_rules.update([
2244 rule[1:] for rule in rules
2245 if rule.startswith('+') or rule.startswith('!')
2246 ])
2247 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172248
2249
2250def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502251 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172252
Sam Maiera6e76d72022-02-11 21:43:502253 # Stubs for handling special syntax in the root DEPS file.
2254 class _VarImpl:
2255 def __init__(self, local_scope):
2256 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172257
Sam Maiera6e76d72022-02-11 21:43:502258 def Lookup(self, var_name):
2259 """Implements the Var syntax."""
2260 try:
2261 return self._local_scope['vars'][var_name]
2262 except KeyError:
2263 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172264
Sam Maiera6e76d72022-02-11 21:43:502265 local_scope = {}
2266 global_scope = {
2267 'Var': _VarImpl(local_scope).Lookup,
2268 'Str': str,
2269 }
Dirk Pranke1b9e06382021-05-14 01:16:222270
Sam Maiera6e76d72022-02-11 21:43:502271 exec(contents, global_scope, local_scope)
2272 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172273
2274
2275def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502276 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2277 a set of DEPS entries that we should look up.
joi@chromium.org14a6131c2014-01-08 01:15:412278
Sam Maiera6e76d72022-02-11 21:43:502279 For a directory (rather than a specific filename) we fake a path to
2280 a specific filename by adding /DEPS. This is chosen as a file that
2281 will seldom or never be subject to per-file include_rules.
2282 """
2283 # We ignore deps entries on auto-generated directories.
2284 AUTO_GENERATED_DIRS = ['grit', 'jni']
tony@chromium.orgf32e2d1e2013-07-26 21:39:082285
Sam Maiera6e76d72022-02-11 21:43:502286 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2287 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172288
Sam Maiera6e76d72022-02-11 21:43:502289 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172290
Sam Maiera6e76d72022-02-11 21:43:502291 results = set()
2292 for added_dep in added_deps:
2293 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2294 continue
2295 # Assume that a rule that ends in .h is a rule for a specific file.
2296 if added_dep.endswith('.h'):
2297 results.add(added_dep)
2298 else:
2299 results.add(os_path.join(added_dep, 'DEPS'))
2300 return results
tony@chromium.orgf32e2d1e2013-07-26 21:39:082301
2302
Saagar Sanghavifceeaae2020-08-12 16:40:362303def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502304 """When a dependency prefixed with + is added to a DEPS file, we
2305 want to make sure that the change is reviewed by an OWNER of the
2306 target file or directory, to avoid layering violations from being
2307 introduced. This check verifies that this happens.
2308 """
2309 # We rely on Gerrit's code-owners to check approvals.
2310 # input_api.gerrit is always set for Chromium, but other projects
2311 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102312 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502313 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302314 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502315 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302316 try:
2317 if (input_api.change.issue and
2318 input_api.gerrit.IsOwnersOverrideApproved(
2319 input_api.change.issue)):
2320 # Skip OWNERS check when Owners-Override label is approved. This is
2321 # intended for global owners, trusted bots, and on-call sheriffs.
2322 # Review is still required for these changes.
2323 return []
2324 except Exception as e:
2325 return [output_api.PresubmitPromptWarning(
2326 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232327
Sam Maiera6e76d72022-02-11 21:43:502328 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242329
Sam Maiera6e76d72022-02-11 21:43:502330 file_filter = lambda f: not input_api.re.match(
2331 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
2332 for f in input_api.AffectedFiles(include_deletes=False,
2333 file_filter=file_filter):
2334 filename = input_api.os_path.basename(f.LocalPath())
2335 if filename == 'DEPS':
2336 virtual_depended_on_files.update(
2337 _CalculateAddedDeps(input_api.os_path,
2338 '\n'.join(f.OldContents()),
2339 '\n'.join(f.NewContents())))
joi@chromium.orge871964c2013-05-13 14:14:552340
Sam Maiera6e76d72022-02-11 21:43:502341 if not virtual_depended_on_files:
2342 return []
joi@chromium.orge871964c2013-05-13 14:14:552343
Sam Maiera6e76d72022-02-11 21:43:502344 if input_api.is_committing:
2345 if input_api.tbr:
2346 return [
2347 output_api.PresubmitNotifyResult(
2348 '--tbr was specified, skipping OWNERS check for DEPS additions'
2349 )
2350 ]
Daniel Cheng3008dc12022-05-13 04:02:112351 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2352 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502353 if input_api.dry_run:
2354 return [
2355 output_api.PresubmitNotifyResult(
2356 'This is a dry run, skipping OWNERS check for DEPS additions'
2357 )
2358 ]
2359 if not input_api.change.issue:
2360 return [
2361 output_api.PresubmitError(
2362 "DEPS approval by OWNERS check failed: this change has "
2363 "no change number, so we can't check it for approvals.")
2364 ]
2365 output = output_api.PresubmitError
joi@chromium.org14a6131c2014-01-08 01:15:412366 else:
Sam Maiera6e76d72022-02-11 21:43:502367 output = output_api.PresubmitNotifyResult
joi@chromium.orge871964c2013-05-13 14:14:552368
Sam Maiera6e76d72022-02-11 21:43:502369 owner_email, reviewers = (
2370 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2371 input_api, None, approval_needed=input_api.is_committing))
joi@chromium.orge871964c2013-05-13 14:14:552372
Sam Maiera6e76d72022-02-11 21:43:502373 owner_email = owner_email or input_api.change.author_email
2374
2375 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2376 virtual_depended_on_files, reviewers.union([owner_email]), [])
2377 missing_files = [
2378 f for f in virtual_depended_on_files
2379 if approval_status[f] != input_api.owners_client.APPROVED
2380 ]
2381
2382 # We strip the /DEPS part that was added by
2383 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2384 # directory.
2385 def StripDeps(path):
2386 start_deps = path.rfind('/DEPS')
2387 if start_deps != -1:
2388 return path[:start_deps]
2389 else:
2390 return path
2391
2392 unapproved_dependencies = [
2393 "'+%s'," % StripDeps(path) for path in missing_files
2394 ]
2395
2396 if unapproved_dependencies:
2397 output_list = [
2398 output(
2399 'You need LGTM from owners of depends-on paths in DEPS that were '
2400 'modified in this CL:\n %s' %
2401 '\n '.join(sorted(unapproved_dependencies)))
2402 ]
2403 suggested_owners = input_api.owners_client.SuggestOwners(
2404 missing_files, exclude=[owner_email])
2405 output_list.append(
2406 output('Suggested missing target path OWNERS:\n %s' %
2407 '\n '.join(suggested_owners or [])))
2408 return output_list
2409
2410 return []
joi@chromium.orge871964c2013-05-13 14:14:552411
2412
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492413# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362414def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502415 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2416 files_to_skip = (
2417 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2418 input_api.DEFAULT_FILES_TO_SKIP + (
2419 r"^base[\\/]logging\.h$",
2420 r"^base[\\/]logging\.cc$",
2421 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2422 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2423 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2424 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2425 r"startup_browser_creator\.cc$",
2426 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2427 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2428 r"diagnostics_writer\.cc$",
2429 r"^chrome[\\/]chrome_cleaner[\\/].*",
2430 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2431 r"dll_hash_main\.cc$",
2432 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2433 r"^chromecast[\\/]",
Sam Maiera6e76d72022-02-11 21:43:502434 r"^components[\\/]browser_watcher[\\/]"
Joseph Wang668ab202022-07-26 16:24:492435 r"dump_stability_report_main_win\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502436 r"^components[\\/]media_control[\\/]renderer[\\/]"
2437 r"media_playback_options\.cc$",
2438 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2439 r"overlay_strategy_underlay_cast\.cc$",
2440 r"^components[\\/]zucchini[\\/].*",
2441 # TODO(peter): Remove exception. https://crbug.com/534537
2442 r"^content[\\/]browser[\\/]notifications[\\/]"
2443 r"notification_event_dispatcher_impl\.cc$",
2444 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2445 r"gl_helper_benchmark\.cc$",
2446 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2447 r"^courgette[\\/]courgette_tool\.cc$",
2448 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Joseph Wang668ab202022-07-26 16:24:492449 r"^fuchsia_web[\\/]common[\\/]init_logging\.cc$",
2450 r"^fuchsia_web[\\/]runners[\\/]common[\\/]web_component\.cc$",
2451 r"^fuchsia_web[\\/]shell[\\/].*_shell\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502452 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2453 r"^ipc[\\/]ipc_logging\.cc$",
2454 r"^native_client_sdk[\\/]",
2455 r"^remoting[\\/]base[\\/]logging\.h$",
2456 r"^remoting[\\/]host[\\/].*",
2457 r"^sandbox[\\/]linux[\\/].*",
2458 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Joseph Wang668ab202022-07-26 16:24:492459 r"dump_file_system\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502460 r"^tools[\\/]",
Joseph Wang668ab202022-07-26 16:24:492461 r"^ui[\\/]base[\\/]resource[\\/]data_pack\.cc$",
Sam Maiera6e76d72022-02-11 21:43:502462 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2463 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2464 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2465 r"xwmstartupcheck\.cc$"))
2466 source_file_filter = lambda x: input_api.FilterSourceFile(
2467 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
thakis@chromium.org85218562013-11-22 07:41:402468
Sam Maiera6e76d72022-02-11 21:43:502469 log_info = set([])
2470 printf = set([])
thakis@chromium.org85218562013-11-22 07:41:402471
Sam Maiera6e76d72022-02-11 21:43:502472 for f in input_api.AffectedSourceFiles(source_file_filter):
2473 for _, line in f.ChangedContents():
2474 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2475 log_info.add(f.LocalPath())
2476 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2477 log_info.add(f.LocalPath())
jln@chromium.org18b466b2013-12-02 22:01:372478
Sam Maiera6e76d72022-02-11 21:43:502479 if input_api.re.search(r"\bprintf\(", line):
2480 printf.add(f.LocalPath())
2481 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2482 printf.add(f.LocalPath())
thakis@chromium.org85218562013-11-22 07:41:402483
Sam Maiera6e76d72022-02-11 21:43:502484 if log_info:
2485 return [
2486 output_api.PresubmitError(
2487 'These files spam the console log with LOG(INFO):',
2488 items=log_info)
2489 ]
2490 if printf:
2491 return [
2492 output_api.PresubmitError(
2493 'These files spam the console log with printf/fprintf:',
2494 items=printf)
2495 ]
2496 return []
thakis@chromium.org85218562013-11-22 07:41:402497
2498
Saagar Sanghavifceeaae2020-08-12 16:40:362499def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502500 """These types are all expected to hold locks while in scope and
2501 so should never be anonymous (which causes them to be immediately
2502 destroyed)."""
2503 they_who_must_be_named = [
2504 'base::AutoLock',
2505 'base::AutoReset',
2506 'base::AutoUnlock',
2507 'SkAutoAlphaRestore',
2508 'SkAutoBitmapShaderInstall',
2509 'SkAutoBlitterChoose',
2510 'SkAutoBounderCommit',
2511 'SkAutoCallProc',
2512 'SkAutoCanvasRestore',
2513 'SkAutoCommentBlock',
2514 'SkAutoDescriptor',
2515 'SkAutoDisableDirectionCheck',
2516 'SkAutoDisableOvalCheck',
2517 'SkAutoFree',
2518 'SkAutoGlyphCache',
2519 'SkAutoHDC',
2520 'SkAutoLockColors',
2521 'SkAutoLockPixels',
2522 'SkAutoMalloc',
2523 'SkAutoMaskFreeImage',
2524 'SkAutoMutexAcquire',
2525 'SkAutoPathBoundsUpdate',
2526 'SkAutoPDFRelease',
2527 'SkAutoRasterClipValidate',
2528 'SkAutoRef',
2529 'SkAutoTime',
2530 'SkAutoTrace',
2531 'SkAutoUnref',
2532 ]
2533 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2534 # bad: base::AutoLock(lock.get());
2535 # not bad: base::AutoLock lock(lock.get());
2536 bad_pattern = input_api.re.compile(anonymous)
2537 # good: new base::AutoLock(lock.get())
2538 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2539 errors = []
enne@chromium.org49aa76a2013-12-04 06:59:162540
Sam Maiera6e76d72022-02-11 21:43:502541 for f in input_api.AffectedFiles():
2542 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2543 continue
2544 for linenum, line in f.ChangedContents():
2545 if bad_pattern.search(line) and not good_pattern.search(line):
2546 errors.append('%s:%d' % (f.LocalPath(), linenum))
enne@chromium.org49aa76a2013-12-04 06:59:162547
Sam Maiera6e76d72022-02-11 21:43:502548 if errors:
2549 return [
2550 output_api.PresubmitError(
2551 'These lines create anonymous variables that need to be named:',
2552 items=errors)
2553 ]
2554 return []
enne@chromium.org49aa76a2013-12-04 06:59:162555
2556
Saagar Sanghavifceeaae2020-08-12 16:40:362557def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502558 # Returns whether |template_str| is of the form <T, U...> for some types T
2559 # and U. Assumes that |template_str| is already in the form <...>.
2560 def HasMoreThanOneArg(template_str):
2561 # Level of <...> nesting.
2562 nesting = 0
2563 for c in template_str:
2564 if c == '<':
2565 nesting += 1
2566 elif c == '>':
2567 nesting -= 1
2568 elif c == ',' and nesting == 1:
2569 return True
2570 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532571
Sam Maiera6e76d72022-02-11 21:43:502572 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2573 sources = lambda affected_file: input_api.FilterSourceFile(
2574 affected_file,
2575 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2576 DEFAULT_FILES_TO_SKIP),
2577 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552578
Sam Maiera6e76d72022-02-11 21:43:502579 # Pattern to capture a single "<...>" block of template arguments. It can
2580 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2581 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2582 # latter would likely require counting that < and > match, which is not
2583 # expressible in regular languages. Should the need arise, one can introduce
2584 # limited counting (matching up to a total number of nesting depth), which
2585 # should cover all practical cases for already a low nesting limit.
2586 template_arg_pattern = (
2587 r'<[^>]*' # Opening block of <.
2588 r'>([^<]*>)?') # Closing block of >.
2589 # Prefix expressing that whatever follows is not already inside a <...>
2590 # block.
2591 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2592 null_construct_pattern = input_api.re.compile(
2593 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2594 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552595
Sam Maiera6e76d72022-02-11 21:43:502596 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2597 template_arg_no_array_pattern = (
2598 r'<[^>]*[^]]' # Opening block of <.
2599 r'>([^(<]*[^]]>)?') # Closing block of >.
2600 # Prefix saying that what follows is the start of an expression.
2601 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2602 # Suffix saying that what follows are call parentheses with a non-empty list
2603 # of arguments.
2604 nonempty_arg_list_pattern = r'\(([^)]|$)'
2605 # Put the template argument into a capture group for deeper examination later.
2606 return_construct_pattern = input_api.re.compile(
2607 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2608 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552609
Sam Maiera6e76d72022-02-11 21:43:502610 problems_constructor = []
2611 problems_nullptr = []
2612 for f in input_api.AffectedSourceFiles(sources):
2613 for line_number, line in f.ChangedContents():
2614 # Disallow:
2615 # return std::unique_ptr<T>(foo);
2616 # bar = std::unique_ptr<T>(foo);
2617 # But allow:
2618 # return std::unique_ptr<T[]>(foo);
2619 # bar = std::unique_ptr<T[]>(foo);
2620 # And also allow cases when the second template argument is present. Those
2621 # cases cannot be handled by std::make_unique:
2622 # return std::unique_ptr<T, U>(foo);
2623 # bar = std::unique_ptr<T, U>(foo);
2624 local_path = f.LocalPath()
2625 return_construct_result = return_construct_pattern.search(line)
2626 if return_construct_result and not HasMoreThanOneArg(
2627 return_construct_result.group('template_arg')):
2628 problems_constructor.append(
2629 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2630 # Disallow:
2631 # std::unique_ptr<T>()
2632 if null_construct_pattern.search(line):
2633 problems_nullptr.append(
2634 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052635
Sam Maiera6e76d72022-02-11 21:43:502636 errors = []
2637 if problems_nullptr:
2638 errors.append(
2639 output_api.PresubmitPromptWarning(
2640 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2641 problems_nullptr))
2642 if problems_constructor:
2643 errors.append(
2644 output_api.PresubmitError(
2645 'The following files use explicit std::unique_ptr constructor. '
2646 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2647 'std::make_unique is not an option.', problems_constructor))
2648 return errors
Peter Kasting4844e46e2018-02-23 07:27:102649
2650
Saagar Sanghavifceeaae2020-08-12 16:40:362651def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502652 """Checks if any new user action has been added."""
2653 if any('actions.xml' == input_api.os_path.basename(f)
2654 for f in input_api.LocalPaths()):
2655 # If actions.xml is already included in the changelist, the PRESUBMIT
2656 # for actions.xml will do a more complete presubmit check.
2657 return []
2658
2659 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2660 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2661 input_api.DEFAULT_FILES_TO_SKIP)
2662 file_filter = lambda f: input_api.FilterSourceFile(
2663 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2664
2665 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2666 current_actions = None
2667 for f in input_api.AffectedFiles(file_filter=file_filter):
2668 for line_num, line in f.ChangedContents():
2669 match = input_api.re.search(action_re, line)
2670 if match:
2671 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2672 # loaded only once.
2673 if not current_actions:
2674 with open(
2675 'tools/metrics/actions/actions.xml') as actions_f:
2676 current_actions = actions_f.read()
2677 # Search for the matched user action name in |current_actions|.
2678 for action_name in match.groups():
2679 action = 'name="{0}"'.format(action_name)
2680 if action not in current_actions:
2681 return [
2682 output_api.PresubmitPromptWarning(
2683 'File %s line %d: %s is missing in '
2684 'tools/metrics/actions/actions.xml. Please run '
2685 'tools/metrics/actions/extract_actions.py to update.'
2686 % (f.LocalPath(), line_num, action_name))
2687 ]
yiyaoliu@chromium.org999261d2014-03-03 20:08:082688 return []
2689
yiyaoliu@chromium.org999261d2014-03-03 20:08:082690
Daniel Cheng13ca61a882017-08-25 15:11:252691def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502692 import sys
2693 sys.path = sys.path + [
2694 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2695 'json_comment_eater')
2696 ]
2697 import json_comment_eater
2698 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252699
2700
yoz@chromium.org99171a92014-06-03 08:44:472701def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172702 try:
Sam Maiera6e76d72022-02-11 21:43:502703 contents = input_api.ReadFile(filename)
2704 if eat_comments:
2705 json_comment_eater = _ImportJSONCommentEater(input_api)
2706 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172707
Sam Maiera6e76d72022-02-11 21:43:502708 input_api.json.loads(contents)
2709 except ValueError as e:
2710 return e
Andrew Grieve4deedb12022-02-03 21:34:502711 return None
2712
2713
Sam Maiera6e76d72022-02-11 21:43:502714def _GetIDLParseError(input_api, filename):
2715 try:
2716 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:282717 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:342718 if not char.isascii():
2719 return (
2720 'Non-ascii character "%s" (ord %d) found at offset %d.' %
2721 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:502722 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2723 'tools', 'json_schema_compiler',
2724 'idl_schema.py')
2725 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282726 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502727 stdin=input_api.subprocess.PIPE,
2728 stdout=input_api.subprocess.PIPE,
2729 stderr=input_api.subprocess.PIPE,
2730 universal_newlines=True)
2731 (_, error) = process.communicate(input=contents)
2732 return error or None
2733 except ValueError as e:
2734 return e
agrievef32bcc72016-04-04 14:57:402735
agrievef32bcc72016-04-04 14:57:402736
Sam Maiera6e76d72022-02-11 21:43:502737def CheckParseErrors(input_api, output_api):
2738 """Check that IDL and JSON files do not contain syntax errors."""
2739 actions = {
2740 '.idl': _GetIDLParseError,
2741 '.json': _GetJSONParseError,
2742 }
2743 # Most JSON files are preprocessed and support comments, but these do not.
2744 json_no_comments_patterns = [
2745 r'^testing[\\/]',
2746 ]
2747 # Only run IDL checker on files in these directories.
2748 idl_included_patterns = [
2749 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2750 r'^extensions[\\/]common[\\/]api[\\/]',
2751 ]
agrievef32bcc72016-04-04 14:57:402752
Sam Maiera6e76d72022-02-11 21:43:502753 def get_action(affected_file):
2754 filename = affected_file.LocalPath()
2755 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:402756
Sam Maiera6e76d72022-02-11 21:43:502757 def FilterFile(affected_file):
2758 action = get_action(affected_file)
2759 if not action:
2760 return False
2761 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:402762
Sam Maiera6e76d72022-02-11 21:43:502763 if _MatchesFile(input_api,
2764 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
2765 return False
2766
2767 if (action == _GetIDLParseError
2768 and not _MatchesFile(input_api, idl_included_patterns, path)):
2769 return False
2770 return True
2771
2772 results = []
2773 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
2774 include_deletes=False):
2775 action = get_action(affected_file)
2776 kwargs = {}
2777 if (action == _GetJSONParseError
2778 and _MatchesFile(input_api, json_no_comments_patterns,
2779 affected_file.LocalPath())):
2780 kwargs['eat_comments'] = False
2781 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
2782 **kwargs)
2783 if parse_error:
2784 results.append(
2785 output_api.PresubmitError(
2786 '%s could not be parsed: %s' %
2787 (affected_file.LocalPath(), parse_error)))
2788 return results
2789
2790
2791def CheckJavaStyle(input_api, output_api):
2792 """Runs checkstyle on changed java files and returns errors if any exist."""
2793
2794 # Return early if no java files were modified.
2795 if not any(
2796 _IsJavaFile(input_api, f.LocalPath())
2797 for f in input_api.AffectedFiles()):
2798 return []
2799
2800 import sys
2801 original_sys_path = sys.path
2802 try:
2803 sys.path = sys.path + [
2804 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2805 'android', 'checkstyle')
2806 ]
2807 import checkstyle
2808 finally:
2809 # Restore sys.path to what it was before.
2810 sys.path = original_sys_path
2811
2812 return checkstyle.RunCheckstyle(
2813 input_api,
2814 output_api,
2815 'tools/android/checkstyle/chromium-style-5.0.xml',
2816 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
2817
2818
2819def CheckPythonDevilInit(input_api, output_api):
2820 """Checks to make sure devil is initialized correctly in python scripts."""
2821 script_common_initialize_pattern = input_api.re.compile(
2822 r'script_common\.InitializeEnvironment\(')
2823 devil_env_config_initialize = input_api.re.compile(
2824 r'devil_env\.config\.Initialize\(')
2825
2826 errors = []
2827
2828 sources = lambda affected_file: input_api.FilterSourceFile(
2829 affected_file,
2830 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
2831 r'^build[\\/]android[\\/]devil_chromium\.py',
2832 r'^third_party[\\/].*',
2833 )),
2834 files_to_check=[r'.*\.py$'])
2835
2836 for f in input_api.AffectedSourceFiles(sources):
2837 for line_num, line in f.ChangedContents():
2838 if (script_common_initialize_pattern.search(line)
2839 or devil_env_config_initialize.search(line)):
2840 errors.append("%s:%d" % (f.LocalPath(), line_num))
2841
2842 results = []
2843
2844 if errors:
2845 results.append(
2846 output_api.PresubmitError(
2847 'Devil initialization should always be done using '
2848 'devil_chromium.Initialize() in the chromium project, to use better '
2849 'defaults for dependencies (ex. up-to-date version of adb).',
2850 errors))
2851
2852 return results
2853
2854
2855def _MatchesFile(input_api, patterns, path):
2856 for pattern in patterns:
2857 if input_api.re.search(pattern, path):
2858 return True
2859 return False
2860
2861
Daniel Chenga37c03db2022-05-12 17:20:342862def _ChangeHasSecurityReviewer(input_api, owners_file):
2863 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:502864
Daniel Chenga37c03db2022-05-12 17:20:342865 Args:
2866 input_api: The presubmit input API.
2867 owners_file: OWNERS file with required reviewers. Typically, this is
2868 something like ipc/SECURITY_OWNERS.
2869
2870 Note: if the presubmit is running for commit rather than for upload, this
2871 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:502872 """
Daniel Chengd88244472022-05-16 09:08:472873 # Owners-Override should bypass all additional OWNERS enforcement checks.
2874 # A CR+1 vote will still be required to land this change.
2875 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2876 input_api.change.issue)):
2877 return True
2878
Daniel Chenga37c03db2022-05-12 17:20:342879 owner_email, reviewers = (
2880 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:112881 input_api,
2882 None,
2883 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:502884
Daniel Chenga37c03db2022-05-12 17:20:342885 security_owners = input_api.owners_client.ListOwners(owners_file)
2886 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:502887
Daniel Chenga37c03db2022-05-12 17:20:342888
2889@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:252890class _SecurityProblemWithItems:
2891 problem: str
2892 items: Sequence[str]
2893
2894
2895@dataclass
Daniel Chenga37c03db2022-05-12 17:20:342896class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:252897 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:342898 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:252899 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:342900
2901
2902def _FindMissingSecurityOwners(input_api,
2903 output_api,
2904 file_patterns: Sequence[str],
2905 excluded_patterns: Sequence[str],
2906 required_owners_file: str,
2907 custom_rule_function: Optional[Callable] = None
2908 ) -> _MissingSecurityOwnersResult:
2909 """Find OWNERS files missing per-file rules for security-sensitive files.
2910
2911 Args:
2912 input_api: the PRESUBMIT input API object.
2913 output_api: the PRESUBMIT output API object.
2914 file_patterns: basename patterns that require a corresponding per-file
2915 security restriction.
2916 excluded_patterns: path patterns that should be exempted from
2917 requiring a security restriction.
2918 required_owners_file: path to the required OWNERS file, e.g.
2919 ipc/SECURITY_OWNERS
2920 cc_alias: If not None, email that will be CCed automatically if the
2921 change contains security-sensitive files, as determined by
2922 `file_patterns` and `excluded_patterns`.
2923 custom_rule_function: If not None, will be called with `input_api` and
2924 the current file under consideration. Returning True will add an
2925 exact match per-file rule check for the current file.
2926 """
2927
2928 # `to_check` is a mapping of an OWNERS file path to Patterns.
2929 #
2930 # Patterns is a dictionary mapping glob patterns (suitable for use in
2931 # per-file rules) to a PatternEntry.
2932 #
Sam Maiera6e76d72022-02-11 21:43:502933 # PatternEntry is a dictionary with two keys:
2934 # - 'files': the files that are matched by this pattern
2935 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:342936 #
Sam Maiera6e76d72022-02-11 21:43:502937 # For example, if we expect OWNERS file to contain rules for *.mojom and
2938 # *_struct_traits*.*, Patterns might look like this:
2939 # {
2940 # '*.mojom': {
2941 # 'files': ...,
2942 # 'rules': [
2943 # 'per-file *.mojom=set noparent',
2944 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2945 # ],
2946 # },
2947 # '*_struct_traits*.*': {
2948 # 'files': ...,
2949 # 'rules': [
2950 # 'per-file *_struct_traits*.*=set noparent',
2951 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2952 # ],
2953 # },
2954 # }
2955 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:342956 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:502957
Daniel Chenga37c03db2022-05-12 17:20:342958 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:502959 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:472960 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:502961 if owners_file not in to_check:
2962 to_check[owners_file] = {}
2963 if pattern not in to_check[owners_file]:
2964 to_check[owners_file][pattern] = {
2965 'files': [],
2966 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:342967 f'per-file {pattern}=set noparent',
2968 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:502969 ]
2970 }
Daniel Chenged57a162022-05-25 02:56:342971 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:342972 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:502973
Daniel Chenga37c03db2022-05-12 17:20:342974 # Only enforce security OWNERS rules for a directory if that directory has a
2975 # file that matches `file_patterns`. For example, if a directory only
2976 # contains *.mojom files and no *_messages*.h files, the check should only
2977 # ensure that rules for *.mojom files are present.
2978 for file in input_api.AffectedFiles(include_deletes=False):
2979 file_basename = input_api.os_path.basename(file.LocalPath())
2980 if custom_rule_function is not None and custom_rule_function(
2981 input_api, file):
2982 AddPatternToCheck(file, file_basename)
2983 continue
Sam Maiera6e76d72022-02-11 21:43:502984
Daniel Chenga37c03db2022-05-12 17:20:342985 if any(
2986 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
2987 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:502988 continue
2989
2990 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:342991 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
2992 # file's basename.
2993 if input_api.fnmatch.fnmatch(file_basename, pattern):
2994 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:502995 break
2996
Daniel Chenga37c03db2022-05-12 17:20:342997 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:252998
2999 # Check if any newly added lines in OWNERS files intersect with required
3000 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3001 # This is a hack, but is needed because the OWNERS check (by design) ignores
3002 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3003 # OWNER and have that newly-added OWNER self-approve their own addition.
3004 newly_covered_files = []
3005 for file in input_api.AffectedFiles(include_deletes=False):
3006 if not file.LocalPath() in to_check:
3007 continue
3008 for _, line in file.ChangedContents():
3009 for _, entry in to_check[file.LocalPath()].items():
3010 if line in entry['rules']:
3011 newly_covered_files.extend(entry['files'])
3012
3013 missing_reviewer_problems = None
3014 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343015 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253016 missing_reviewer_problems = _SecurityProblemWithItems(
3017 f'Review from an owner in {required_owners_file} is required for '
3018 'the following newly-added files:',
3019 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503020
3021 # Go through the OWNERS files to check, filtering out rules that are already
3022 # present in that OWNERS file.
3023 for owners_file, patterns in to_check.items():
3024 try:
Daniel Cheng171dad8d2022-05-21 00:40:253025 lines = set(
3026 input_api.ReadFile(
3027 input_api.os_path.join(input_api.change.RepositoryRoot(),
3028 owners_file)).splitlines())
3029 for entry in patterns.values():
3030 entry['rules'] = [
3031 rule for rule in entry['rules'] if rule not in lines
3032 ]
Sam Maiera6e76d72022-02-11 21:43:503033 except IOError:
3034 # No OWNERS file, so all the rules are definitely missing.
3035 continue
3036
3037 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253038 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343039
Sam Maiera6e76d72022-02-11 21:43:503040 for owners_file, patterns in to_check.items():
3041 missing_lines = []
3042 files = []
3043 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343044 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503045 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503046 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253047 joined_missing_lines = '\n'.join(line for line in missing_lines)
3048 owners_file_problems.append(
3049 _SecurityProblemWithItems(
3050 'Found missing OWNERS lines for security-sensitive files. '
3051 f'Please add the following lines to {owners_file}:\n'
3052 f'{joined_missing_lines}\n\nTo ensure security review for:',
3053 files))
Daniel Chenga37c03db2022-05-12 17:20:343054
Daniel Cheng171dad8d2022-05-21 00:40:253055 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343056 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253057 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343058
3059
3060def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3061 # Whether or not a file affects IPC is (mostly) determined by a simple list
3062 # of filename patterns.
3063 file_patterns = [
3064 # Legacy IPC:
3065 '*_messages.cc',
3066 '*_messages*.h',
3067 '*_param_traits*.*',
3068 # Mojo IPC:
3069 '*.mojom',
3070 '*_mojom_traits*.*',
3071 '*_type_converter*.*',
3072 # Android native IPC:
3073 '*.aidl',
3074 ]
3075
Daniel Chenga37c03db2022-05-12 17:20:343076 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463077 # These third_party directories do not contain IPCs, but contain files
3078 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343079 'third_party/crashpad/*',
3080 'third_party/blink/renderer/platform/bindings/*',
3081 'third_party/protobuf/benchmarks/python/*',
3082 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473083 # Enum-only mojoms used for web metrics, so no security review needed.
3084 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343085 # These files are just used to communicate between class loaders running
3086 # in the same process.
3087 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3088 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3089 ]
3090
3091 def IsMojoServiceManifestFile(input_api, file):
3092 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3093 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3094 if not manifest_pattern.search(file.LocalPath()):
3095 return False
3096
3097 if test_manifest_pattern.search(file.LocalPath()):
3098 return False
3099
3100 # All actual service manifest files should contain at least one
3101 # qualified reference to service_manager::Manifest.
3102 return any('service_manager::Manifest' in line
3103 for line in file.NewContents())
3104
3105 return _FindMissingSecurityOwners(
3106 input_api,
3107 output_api,
3108 file_patterns,
3109 excluded_patterns,
3110 'ipc/SECURITY_OWNERS',
3111 custom_rule_function=IsMojoServiceManifestFile)
3112
3113
3114def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3115 file_patterns = [
3116 # Component specifications.
3117 '*.cml', # Component Framework v2.
3118 '*.cmx', # Component Framework v1.
3119
3120 # Fuchsia IDL protocol specifications.
3121 '*.fidl',
3122 ]
3123
3124 # Don't check for owners files for changes in these directories.
3125 excluded_patterns = [
3126 'third_party/crashpad/*',
3127 ]
3128
3129 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3130 excluded_patterns,
3131 'build/fuchsia/SECURITY_OWNERS')
3132
3133
3134def CheckSecurityOwners(input_api, output_api):
3135 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3136 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3137 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3138 input_api, output_api)
3139
3140 if ipc_results.has_security_sensitive_files:
3141 output_api.AppendCC('ipc-security-reviews@chromium.org')
Sam Maiera6e76d72022-02-11 21:43:503142
3143 results = []
Daniel Chenga37c03db2022-05-12 17:20:343144
Daniel Cheng171dad8d2022-05-21 00:40:253145 missing_reviewer_problems = []
3146 if ipc_results.missing_reviewer_problem:
3147 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3148 if fuchsia_results.missing_reviewer_problem:
3149 missing_reviewer_problems.append(
3150 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343151
Daniel Cheng171dad8d2022-05-21 00:40:253152 # Missing reviewers are an error unless there's no issue number
3153 # associated with this branch; in that case, the presubmit is being run
3154 # with --all or --files.
3155 #
3156 # Note that upload should never be an error; otherwise, it would be
3157 # impossible to upload changes at all.
3158 if input_api.is_committing and input_api.change.issue:
3159 make_presubmit_message = output_api.PresubmitError
3160 else:
3161 make_presubmit_message = output_api.PresubmitNotifyResult
3162 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503163 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253164 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343165
Daniel Cheng171dad8d2022-05-21 00:40:253166 owners_file_problems = []
3167 owners_file_problems.extend(ipc_results.owners_file_problems)
3168 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343169
Daniel Cheng171dad8d2022-05-21 00:40:253170 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113171 # Missing per-file rules are always an error. While swarming and caching
3172 # means that uploading a patchset with updated OWNERS files and sending
3173 # it to the CQ again should not have a large incremental cost, it is
3174 # still frustrating to discover the error only after the change has
3175 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343176 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253177 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503178
3179 return results
3180
3181
3182def _GetFilesUsingSecurityCriticalFunctions(input_api):
3183 """Checks affected files for changes to security-critical calls. This
3184 function checks the full change diff, to catch both additions/changes
3185 and removals.
3186
3187 Returns a dict keyed by file name, and the value is a set of detected
3188 functions.
3189 """
3190 # Map of function pretty name (displayed in an error) to the pattern to
3191 # match it with.
3192 _PATTERNS_TO_CHECK = {
3193 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3194 }
3195 _PATTERNS_TO_CHECK = {
3196 k: input_api.re.compile(v)
3197 for k, v in _PATTERNS_TO_CHECK.items()
3198 }
3199
Sam Maiera6e76d72022-02-11 21:43:503200 # We don't want to trigger on strings within this file.
3201 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343202 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503203
3204 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3205 files_to_functions = {}
3206 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3207 diff = f.GenerateScmDiff()
3208 for line in diff.split('\n'):
3209 # Not using just RightHandSideLines() because removing a
3210 # call to a security-critical function can be just as important
3211 # as adding or changing the arguments.
3212 if line.startswith('-') or (line.startswith('+')
3213 and not line.startswith('++')):
3214 for name, pattern in _PATTERNS_TO_CHECK.items():
3215 if pattern.search(line):
3216 path = f.LocalPath()
3217 if not path in files_to_functions:
3218 files_to_functions[path] = set()
3219 files_to_functions[path].add(name)
3220 return files_to_functions
3221
3222
3223def CheckSecurityChanges(input_api, output_api):
3224 """Checks that changes involving security-critical functions are reviewed
3225 by the security team.
3226 """
3227 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3228 if not len(files_to_functions):
3229 return []
3230
Sam Maiera6e76d72022-02-11 21:43:503231 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343232 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503233 return []
3234
Daniel Chenga37c03db2022-05-12 17:20:343235 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503236 'that need to be reviewed by {}.\n'.format(owners_file)
3237 for path, names in files_to_functions.items():
3238 msg += ' {}\n'.format(path)
3239 for name in names:
3240 msg += ' {}\n'.format(name)
3241 msg += '\n'
3242
3243 if input_api.is_committing:
3244 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033245 else:
Sam Maiera6e76d72022-02-11 21:43:503246 output = output_api.PresubmitNotifyResult
3247 return [output(msg)]
3248
3249
3250def CheckSetNoParent(input_api, output_api):
3251 """Checks that set noparent is only used together with an OWNERS file in
3252 //build/OWNERS.setnoparent (see also
3253 //docs/code_reviews.md#owners-files-details)
3254 """
3255 # Return early if no OWNERS files were modified.
3256 if not any(f.LocalPath().endswith('OWNERS')
3257 for f in input_api.AffectedFiles(include_deletes=False)):
3258 return []
3259
3260 errors = []
3261
3262 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3263 allowed_owners_files = set()
3264 with open(allowed_owners_files_file, 'r') as f:
3265 for line in f:
3266 line = line.strip()
3267 if not line or line.startswith('#'):
3268 continue
3269 allowed_owners_files.add(line)
3270
3271 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3272
3273 for f in input_api.AffectedFiles(include_deletes=False):
3274 if not f.LocalPath().endswith('OWNERS'):
3275 continue
3276
3277 found_owners_files = set()
3278 found_set_noparent_lines = dict()
3279
3280 # Parse the OWNERS file.
3281 for lineno, line in enumerate(f.NewContents(), 1):
3282 line = line.strip()
3283 if line.startswith('set noparent'):
3284 found_set_noparent_lines[''] = lineno
3285 if line.startswith('file://'):
3286 if line in allowed_owners_files:
3287 found_owners_files.add('')
3288 if line.startswith('per-file'):
3289 match = per_file_pattern.match(line)
3290 if match:
3291 glob = match.group(1).strip()
3292 directive = match.group(2).strip()
3293 if directive == 'set noparent':
3294 found_set_noparent_lines[glob] = lineno
3295 if directive.startswith('file://'):
3296 if directive in allowed_owners_files:
3297 found_owners_files.add(glob)
3298
3299 # Check that every set noparent line has a corresponding file:// line
3300 # listed in build/OWNERS.setnoparent. An exception is made for top level
3301 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493302 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3303 if (linux_path.count('/') != 1
3304 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503305 for set_noparent_line in found_set_noparent_lines:
3306 if set_noparent_line in found_owners_files:
3307 continue
3308 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493309 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503310 found_set_noparent_lines[set_noparent_line]))
3311
3312 results = []
3313 if errors:
3314 if input_api.is_committing:
3315 output = output_api.PresubmitError
3316 else:
3317 output = output_api.PresubmitPromptWarning
3318 results.append(
3319 output(
3320 'Found the following "set noparent" restrictions in OWNERS files that '
3321 'do not include owners from build/OWNERS.setnoparent:',
3322 long_text='\n\n'.join(errors)))
3323 return results
3324
3325
3326def CheckUselessForwardDeclarations(input_api, output_api):
3327 """Checks that added or removed lines in non third party affected
3328 header files do not lead to new useless class or struct forward
3329 declaration.
3330 """
3331 results = []
3332 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3333 input_api.re.MULTILINE)
3334 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3335 input_api.re.MULTILINE)
3336 for f in input_api.AffectedFiles(include_deletes=False):
3337 if (f.LocalPath().startswith('third_party')
3338 and not f.LocalPath().startswith('third_party/blink')
3339 and not f.LocalPath().startswith('third_party\\blink')):
3340 continue
3341
3342 if not f.LocalPath().endswith('.h'):
3343 continue
3344
3345 contents = input_api.ReadFile(f)
3346 fwd_decls = input_api.re.findall(class_pattern, contents)
3347 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3348
3349 useless_fwd_decls = []
3350 for decl in fwd_decls:
3351 count = sum(1 for _ in input_api.re.finditer(
3352 r'\b%s\b' % input_api.re.escape(decl), contents))
3353 if count == 1:
3354 useless_fwd_decls.append(decl)
3355
3356 if not useless_fwd_decls:
3357 continue
3358
3359 for line in f.GenerateScmDiff().splitlines():
3360 if (line.startswith('-') and not line.startswith('--')
3361 or line.startswith('+') and not line.startswith('++')):
3362 for decl in useless_fwd_decls:
3363 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3364 results.append(
3365 output_api.PresubmitPromptWarning(
3366 '%s: %s forward declaration is no longer needed'
3367 % (f.LocalPath(), decl)))
3368 useless_fwd_decls.remove(decl)
3369
3370 return results
3371
3372
3373def _CheckAndroidDebuggableBuild(input_api, output_api):
3374 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3375 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3376 this is a debuggable build of Android.
3377 """
3378 build_type_check_pattern = input_api.re.compile(
3379 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3380
3381 errors = []
3382
3383 sources = lambda affected_file: input_api.FilterSourceFile(
3384 affected_file,
3385 files_to_skip=(
3386 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3387 DEFAULT_FILES_TO_SKIP + (
3388 r"^android_webview[\\/]support_library[\\/]"
3389 "boundary_interfaces[\\/]",
3390 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3391 r'^third_party[\\/].*',
3392 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3393 r"webview[\\/]chromium[\\/]License.*",
3394 )),
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 build_type_check_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.PresubmitPromptWarning(
3407 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3408 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3409
3410 return results
3411
3412# TODO: add unit tests
3413def _CheckAndroidToastUsage(input_api, output_api):
3414 """Checks that code uses org.chromium.ui.widget.Toast instead of
3415 android.widget.Toast (Chromium Toast doesn't force hardware
3416 acceleration on low-end devices, saving memory).
3417 """
3418 toast_import_pattern = input_api.re.compile(
3419 r'^import android\.widget\.Toast;$')
3420
3421 errors = []
3422
3423 sources = lambda affected_file: input_api.FilterSourceFile(
3424 affected_file,
3425 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3426 DEFAULT_FILES_TO_SKIP + (r'^chromecast[\\/].*',
3427 r'^remoting[\\/].*')),
3428 files_to_check=[r'.*\.java$'])
3429
3430 for f in input_api.AffectedSourceFiles(sources):
3431 for line_num, line in f.ChangedContents():
3432 if toast_import_pattern.search(line):
3433 errors.append("%s:%d" % (f.LocalPath(), line_num))
3434
3435 results = []
3436
3437 if errors:
3438 results.append(
3439 output_api.PresubmitError(
3440 'android.widget.Toast usage is detected. Android toasts use hardware'
3441 ' acceleration, and can be\ncostly on low-end devices. Please use'
3442 ' org.chromium.ui.widget.Toast instead.\n'
3443 'Contact dskiba@chromium.org if you have any questions.',
3444 errors))
3445
3446 return results
3447
3448
3449def _CheckAndroidCrLogUsage(input_api, output_api):
3450 """Checks that new logs using org.chromium.base.Log:
3451 - Are using 'TAG' as variable name for the tags (warn)
3452 - Are using a tag that is shorter than 20 characters (error)
3453 """
3454
3455 # Do not check format of logs in the given files
3456 cr_log_check_excluded_paths = [
3457 # //chrome/android/webapk cannot depend on //base
3458 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3459 # WebView license viewer code cannot depend on //base; used in stub APK.
3460 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3461 r"webview[\\/]chromium[\\/]License.*",
3462 # The customtabs_benchmark is a small app that does not depend on Chromium
3463 # java pieces.
3464 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3465 ]
3466
3467 cr_log_import_pattern = input_api.re.compile(
3468 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3469 class_in_base_pattern = input_api.re.compile(
3470 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3471 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3472 input_api.re.MULTILINE)
3473 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3474 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3475 log_decl_pattern = input_api.re.compile(
3476 r'static final String TAG = "(?P<name>(.*))"')
3477 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3478
3479 REF_MSG = ('See docs/android_logging.md for more info.')
3480 sources = lambda x: input_api.FilterSourceFile(
3481 x,
3482 files_to_check=[r'.*\.java$'],
3483 files_to_skip=cr_log_check_excluded_paths)
3484
3485 tag_decl_errors = []
3486 tag_length_errors = []
3487 tag_errors = []
3488 tag_with_dot_errors = []
3489 util_log_errors = []
3490
3491 for f in input_api.AffectedSourceFiles(sources):
3492 file_content = input_api.ReadFile(f)
3493 has_modified_logs = False
3494 # Per line checks
3495 if (cr_log_import_pattern.search(file_content)
3496 or (class_in_base_pattern.search(file_content)
3497 and not has_some_log_import_pattern.search(file_content))):
3498 # Checks to run for files using cr log
3499 for line_num, line in f.ChangedContents():
3500 if rough_log_decl_pattern.search(line):
3501 has_modified_logs = True
3502
3503 # Check if the new line is doing some logging
3504 match = log_call_pattern.search(line)
3505 if match:
3506 has_modified_logs = True
3507
3508 # Make sure it uses "TAG"
3509 if not match.group('tag') == 'TAG':
3510 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3511 else:
3512 # Report non cr Log function calls in changed lines
3513 for line_num, line in f.ChangedContents():
3514 if log_call_pattern.search(line):
3515 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3516
3517 # Per file checks
3518 if has_modified_logs:
3519 # Make sure the tag is using the "cr" prefix and is not too long
3520 match = log_decl_pattern.search(file_content)
3521 tag_name = match.group('name') if match else None
3522 if not tag_name:
3523 tag_decl_errors.append(f.LocalPath())
3524 elif len(tag_name) > 20:
3525 tag_length_errors.append(f.LocalPath())
3526 elif '.' in tag_name:
3527 tag_with_dot_errors.append(f.LocalPath())
3528
3529 results = []
3530 if tag_decl_errors:
3531 results.append(
3532 output_api.PresubmitPromptWarning(
3533 'Please define your tags using the suggested format: .\n'
3534 '"private static final String TAG = "<package tag>".\n'
3535 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3536 tag_decl_errors))
3537
3538 if tag_length_errors:
3539 results.append(
3540 output_api.PresubmitError(
3541 'The tag length is restricted by the system to be at most '
3542 '20 characters.\n' + REF_MSG, tag_length_errors))
3543
3544 if tag_errors:
3545 results.append(
3546 output_api.PresubmitPromptWarning(
3547 'Please use a variable named "TAG" for your log tags.\n' +
3548 REF_MSG, tag_errors))
3549
3550 if util_log_errors:
3551 results.append(
3552 output_api.PresubmitPromptWarning(
3553 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3554 util_log_errors))
3555
3556 if tag_with_dot_errors:
3557 results.append(
3558 output_api.PresubmitPromptWarning(
3559 'Dot in log tags cause them to be elided in crash reports.\n' +
3560 REF_MSG, tag_with_dot_errors))
3561
3562 return results
3563
3564
3565def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3566 """Checks that junit.framework.* is no longer used."""
3567 deprecated_junit_framework_pattern = input_api.re.compile(
3568 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3569 sources = lambda x: input_api.FilterSourceFile(
3570 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3571 errors = []
3572 for f in input_api.AffectedFiles(file_filter=sources):
3573 for line_num, line in f.ChangedContents():
3574 if deprecated_junit_framework_pattern.search(line):
3575 errors.append("%s:%d" % (f.LocalPath(), line_num))
3576
3577 results = []
3578 if errors:
3579 results.append(
3580 output_api.PresubmitError(
3581 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3582 '(org.junit.*) from //third_party/junit. Contact yolandyan@chromium.org'
3583 ' if you have any question.', errors))
3584 return results
3585
3586
3587def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3588 """Checks that if new Java test classes have inheritance.
3589 Either the new test class is JUnit3 test or it is a JUnit4 test class
3590 with a base class, either case is undesirable.
3591 """
3592 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3593
3594 sources = lambda x: input_api.FilterSourceFile(
3595 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3596 errors = []
3597 for f in input_api.AffectedFiles(file_filter=sources):
3598 if not f.OldContents():
3599 class_declaration_start_flag = False
3600 for line_num, line in f.ChangedContents():
3601 if class_declaration_pattern.search(line):
3602 class_declaration_start_flag = True
3603 if class_declaration_start_flag and ' extends ' in line:
3604 errors.append('%s:%d' % (f.LocalPath(), line_num))
3605 if '{' in line:
3606 class_declaration_start_flag = False
3607
3608 results = []
3609 if errors:
3610 results.append(
3611 output_api.PresubmitPromptWarning(
3612 'The newly created files include Test classes that inherits from base'
3613 ' class. Please do not use inheritance in JUnit4 tests or add new'
3614 ' JUnit3 tests. Contact yolandyan@chromium.org if you have any'
3615 ' questions.', errors))
3616 return results
3617
3618
3619def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3620 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3621 deprecated_annotation_import_pattern = input_api.re.compile(
3622 r'^import android\.test\.suitebuilder\.annotation\..*;',
3623 input_api.re.MULTILINE)
3624 sources = lambda x: input_api.FilterSourceFile(
3625 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3626 errors = []
3627 for f in input_api.AffectedFiles(file_filter=sources):
3628 for line_num, line in f.ChangedContents():
3629 if deprecated_annotation_import_pattern.search(line):
3630 errors.append("%s:%d" % (f.LocalPath(), line_num))
3631
3632 results = []
3633 if errors:
3634 results.append(
3635 output_api.PresubmitError(
3636 'Annotations in android.test.suitebuilder.annotation have been'
3637 ' deprecated since API level 24. Please use android.support.test.filters'
3638 ' from //third_party/android_support_test_runner:runner_java instead.'
3639 ' Contact yolandyan@chromium.org if you have any questions.',
3640 errors))
3641 return results
3642
3643
3644def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3645 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:513646 file_filter = lambda f: (f.LocalPath().endswith(
3647 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
3648 LocalPath() or '/res/drawable-ldrtl/'.replace(
3649 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:503650 errors = []
3651 for f in input_api.AffectedFiles(include_deletes=False,
3652 file_filter=file_filter):
3653 errors.append(' %s' % f.LocalPath())
3654
3655 results = []
3656 if errors:
3657 results.append(
3658 output_api.PresubmitError(
3659 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3660 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3661 '/res/drawable-ldrtl/.\n'
3662 'Contact newt@chromium.org if you have questions.', errors))
3663 return results
3664
3665
3666def _CheckAndroidWebkitImports(input_api, output_api):
3667 """Checks that code uses org.chromium.base.Callback instead of
3668 android.webview.ValueCallback except in the WebView glue layer
3669 and WebLayer.
3670 """
3671 valuecallback_import_pattern = input_api.re.compile(
3672 r'^import android\.webkit\.ValueCallback;$')
3673
3674 errors = []
3675
3676 sources = lambda affected_file: input_api.FilterSourceFile(
3677 affected_file,
3678 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3679 DEFAULT_FILES_TO_SKIP + (
3680 r'^android_webview[\\/]glue[\\/].*',
3681 r'^weblayer[\\/].*',
3682 )),
3683 files_to_check=[r'.*\.java$'])
3684
3685 for f in input_api.AffectedSourceFiles(sources):
3686 for line_num, line in f.ChangedContents():
3687 if valuecallback_import_pattern.search(line):
3688 errors.append("%s:%d" % (f.LocalPath(), line_num))
3689
3690 results = []
3691
3692 if errors:
3693 results.append(
3694 output_api.PresubmitError(
3695 'android.webkit.ValueCallback usage is detected outside of the glue'
3696 ' layer. To stay compatible with the support library, android.webkit.*'
3697 ' classes should only be used inside the glue layer and'
3698 ' org.chromium.base.Callback should be used instead.', errors))
3699
3700 return results
3701
3702
3703def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3704 """Checks Android XML styles """
3705
3706 # Return early if no relevant files were modified.
3707 if not any(
3708 _IsXmlOrGrdFile(input_api, f.LocalPath())
3709 for f in input_api.AffectedFiles(include_deletes=False)):
3710 return []
3711
3712 import sys
3713 original_sys_path = sys.path
3714 try:
3715 sys.path = sys.path + [
3716 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3717 'android', 'checkxmlstyle')
3718 ]
3719 import checkxmlstyle
3720 finally:
3721 # Restore sys.path to what it was before.
3722 sys.path = original_sys_path
3723
3724 if is_check_on_upload:
3725 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3726 else:
3727 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3728
3729
3730def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3731 """Checks Android Infobar Deprecation """
3732
3733 import sys
3734 original_sys_path = sys.path
3735 try:
3736 sys.path = sys.path + [
3737 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3738 'android', 'infobar_deprecation')
3739 ]
3740 import infobar_deprecation
3741 finally:
3742 # Restore sys.path to what it was before.
3743 sys.path = original_sys_path
3744
3745 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3746
3747
3748class _PydepsCheckerResult:
3749 def __init__(self, cmd, pydeps_path, process, old_contents):
3750 self._cmd = cmd
3751 self._pydeps_path = pydeps_path
3752 self._process = process
3753 self._old_contents = old_contents
3754
3755 def GetError(self):
3756 """Returns an error message, or None."""
3757 import difflib
3758 if self._process.wait() != 0:
3759 # STDERR should already be printed.
3760 return 'Command failed: ' + self._cmd
3761 new_contents = self._process.stdout.read().splitlines()[2:]
3762 if self._old_contents != new_contents:
3763 diff = '\n'.join(
3764 difflib.context_diff(self._old_contents, new_contents))
3765 return ('File is stale: {}\n'
3766 'Diff (apply to fix):\n'
3767 '{}\n'
3768 'To regenerate, run:\n\n'
3769 ' {}').format(self._pydeps_path, diff, self._cmd)
3770 return None
3771
3772
3773class PydepsChecker:
3774 def __init__(self, input_api, pydeps_files):
3775 self._file_cache = {}
3776 self._input_api = input_api
3777 self._pydeps_files = pydeps_files
3778
3779 def _LoadFile(self, path):
3780 """Returns the list of paths within a .pydeps file relative to //."""
3781 if path not in self._file_cache:
3782 with open(path, encoding='utf-8') as f:
3783 self._file_cache[path] = f.read()
3784 return self._file_cache[path]
3785
3786 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:593787 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:503788 pydeps_data = self._LoadFile(pydeps_path)
3789 uses_gn_paths = '--gn-paths' in pydeps_data
3790 entries = (l for l in pydeps_data.splitlines()
3791 if not l.startswith('#'))
3792 if uses_gn_paths:
3793 # Paths look like: //foo/bar/baz
3794 return (e[2:] for e in entries)
3795 else:
3796 # Paths look like: path/relative/to/file.pydeps
3797 os_path = self._input_api.os_path
3798 pydeps_dir = os_path.dirname(pydeps_path)
3799 return (os_path.normpath(os_path.join(pydeps_dir, e))
3800 for e in entries)
3801
3802 def _CreateFilesToPydepsMap(self):
3803 """Returns a map of local_path -> list_of_pydeps."""
3804 ret = {}
3805 for pydep_local_path in self._pydeps_files:
3806 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3807 ret.setdefault(path, []).append(pydep_local_path)
3808 return ret
3809
3810 def ComputeAffectedPydeps(self):
3811 """Returns an iterable of .pydeps files that might need regenerating."""
3812 affected_pydeps = set()
3813 file_to_pydeps_map = None
3814 for f in self._input_api.AffectedFiles(include_deletes=True):
3815 local_path = f.LocalPath()
3816 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3817 # subrepositories. We can't figure out which files change, so re-check
3818 # all files.
3819 # Changes to print_python_deps.py affect all .pydeps.
3820 if local_path in ('DEPS', 'PRESUBMIT.py'
3821 ) or local_path.endswith('print_python_deps.py'):
3822 return self._pydeps_files
3823 elif local_path.endswith('.pydeps'):
3824 if local_path in self._pydeps_files:
3825 affected_pydeps.add(local_path)
3826 elif local_path.endswith('.py'):
3827 if file_to_pydeps_map is None:
3828 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3829 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3830 return affected_pydeps
3831
3832 def DetermineIfStaleAsync(self, pydeps_path):
3833 """Runs print_python_deps.py to see if the files is stale."""
3834 import os
3835
3836 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3837 if old_pydeps_data:
3838 cmd = old_pydeps_data[1][1:].strip()
3839 if '--output' not in cmd:
3840 cmd += ' --output ' + pydeps_path
3841 old_contents = old_pydeps_data[2:]
3842 else:
3843 # A default cmd that should work in most cases (as long as pydeps filename
3844 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3845 # file is empty/new.
3846 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3847 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3848 old_contents = []
3849 env = dict(os.environ)
3850 env['PYTHONDONTWRITEBYTECODE'] = '1'
3851 process = self._input_api.subprocess.Popen(
3852 cmd + ' --output ""',
3853 shell=True,
3854 env=env,
3855 stdout=self._input_api.subprocess.PIPE,
3856 encoding='utf-8')
3857 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:403858
3859
Tibor Goldschwendt360793f72019-06-25 18:23:493860def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:503861 args = {}
3862 with open('build/config/gclient_args.gni', 'r') as f:
3863 for line in f:
3864 line = line.strip()
3865 if not line or line.startswith('#'):
3866 continue
3867 attribute, value = line.split('=')
3868 args[attribute.strip()] = value.strip()
3869 return args
Tibor Goldschwendt360793f72019-06-25 18:23:493870
3871
Saagar Sanghavifceeaae2020-08-12 16:40:363872def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:503873 """Checks if a .pydeps file needs to be regenerated."""
3874 # This check is for Python dependency lists (.pydeps files), and involves
3875 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3876 # doesn't work on Windows and Mac, so skip it on other platforms.
3877 if not input_api.platform.startswith('linux'):
3878 return []
Erik Staabc734cd7a2021-11-23 03:11:523879
Sam Maiera6e76d72022-02-11 21:43:503880 results = []
3881 # First, check for new / deleted .pydeps.
3882 for f in input_api.AffectedFiles(include_deletes=True):
3883 # Check whether we are running the presubmit check for a file in src.
3884 # f.LocalPath is relative to repo (src, or internal repo).
3885 # os_path.exists is relative to src repo.
3886 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3887 # to src and we can conclude that the pydeps is in src.
3888 if f.LocalPath().endswith('.pydeps'):
3889 if input_api.os_path.exists(f.LocalPath()):
3890 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3891 results.append(
3892 output_api.PresubmitError(
3893 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3894 'remove %s' % f.LocalPath()))
3895 elif f.Action() != 'D' and f.LocalPath(
3896 ) not in _ALL_PYDEPS_FILES:
3897 results.append(
3898 output_api.PresubmitError(
3899 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3900 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403901
Sam Maiera6e76d72022-02-11 21:43:503902 if results:
3903 return results
3904
3905 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
3906 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3907 affected_pydeps = set(checker.ComputeAffectedPydeps())
3908 affected_android_pydeps = affected_pydeps.intersection(
3909 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3910 if affected_android_pydeps and not is_android:
3911 results.append(
3912 output_api.PresubmitPromptOrNotify(
3913 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:593914 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:503915 'run because you are not using an Android checkout. To validate that\n'
3916 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3917 'use the android-internal-presubmit optional trybot.\n'
3918 'Possibly stale pydeps files:\n{}'.format(
3919 '\n'.join(affected_android_pydeps))))
3920
3921 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3922 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
3923 # Process these concurrently, as each one takes 1-2 seconds.
3924 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
3925 for result in pydep_results:
3926 error_msg = result.GetError()
3927 if error_msg:
3928 results.append(output_api.PresubmitError(error_msg))
3929
agrievef32bcc72016-04-04 14:57:403930 return results
3931
agrievef32bcc72016-04-04 14:57:403932
Saagar Sanghavifceeaae2020-08-12 16:40:363933def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503934 """Checks to make sure no header files have |Singleton<|."""
3935
3936 def FileFilter(affected_file):
3937 # It's ok for base/memory/singleton.h to have |Singleton<|.
3938 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
3939 (r"^base[\\/]memory[\\/]singleton\.h$",
3940 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
James Cook24a504192020-07-23 00:08:443941 r"quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:503942 return input_api.FilterSourceFile(affected_file,
3943 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433944
Sam Maiera6e76d72022-02-11 21:43:503945 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
3946 files = []
3947 for f in input_api.AffectedSourceFiles(FileFilter):
3948 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
3949 or f.LocalPath().endswith('.hpp')
3950 or f.LocalPath().endswith('.inl')):
3951 contents = input_api.ReadFile(f)
3952 for line in contents.splitlines(False):
3953 if (not line.lstrip().startswith('//')
3954 and # Strip C++ comment.
3955 pattern.search(line)):
3956 files.append(f)
3957 break
glidere61efad2015-02-18 17:39:433958
Sam Maiera6e76d72022-02-11 21:43:503959 if files:
3960 return [
3961 output_api.PresubmitError(
3962 'Found base::Singleton<T> in the following header files.\n' +
3963 'Please move them to an appropriate source file so that the ' +
3964 'template gets instantiated in a single compilation unit.',
3965 files)
3966 ]
3967 return []
glidere61efad2015-02-18 17:39:433968
3969
jchaffraix@chromium.orgfd20b902014-05-09 02:14:533970_DEPRECATED_CSS = [
3971 # Values
3972 ( "-webkit-box", "flex" ),
3973 ( "-webkit-inline-box", "inline-flex" ),
3974 ( "-webkit-flex", "flex" ),
3975 ( "-webkit-inline-flex", "inline-flex" ),
3976 ( "-webkit-min-content", "min-content" ),
3977 ( "-webkit-max-content", "max-content" ),
3978
3979 # Properties
3980 ( "-webkit-background-clip", "background-clip" ),
3981 ( "-webkit-background-origin", "background-origin" ),
3982 ( "-webkit-background-size", "background-size" ),
3983 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443984 ( "-webkit-user-select", "user-select" ),
jchaffraix@chromium.orgfd20b902014-05-09 02:14:533985
3986 # Functions
3987 ( "-webkit-gradient", "gradient" ),
3988 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3989 ( "-webkit-linear-gradient", "linear-gradient" ),
3990 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3991 ( "-webkit-radial-gradient", "radial-gradient" ),
3992 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3993]
3994
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203995
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493996# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363997def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503998 """ Make sure that we don't use deprecated CSS
3999 properties, functions or values. Our external
4000 documentation and iOS CSS for dom distiller
4001 (reader mode) are ignored by the hooks as it
4002 needs to be consumed by WebKit. """
4003 results = []
4004 file_inclusion_pattern = [r".+\.css$"]
4005 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4006 input_api.DEFAULT_FILES_TO_SKIP +
4007 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4008 r"^native_client_sdk"))
4009 file_filter = lambda f: input_api.FilterSourceFile(
4010 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4011 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4012 for line_num, line in fpath.ChangedContents():
4013 for (deprecated_value, value) in _DEPRECATED_CSS:
4014 if deprecated_value in line:
4015 results.append(
4016 output_api.PresubmitError(
4017 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4018 (fpath.LocalPath(), line_num, deprecated_value,
4019 value)))
4020 return results
jchaffraix@chromium.orgfd20b902014-05-09 02:14:534021
mohan.reddyf21db962014-10-16 12:26:474022
Saagar Sanghavifceeaae2020-08-12 16:40:364023def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504024 bad_files = {}
4025 for f in input_api.AffectedFiles(include_deletes=False):
4026 if (f.LocalPath().startswith('third_party')
4027 and not f.LocalPath().startswith('third_party/blink')
4028 and not f.LocalPath().startswith('third_party\\blink')):
4029 continue
rlanday6802cf632017-05-30 17:48:364030
Sam Maiera6e76d72022-02-11 21:43:504031 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4032 continue
rlanday6802cf632017-05-30 17:48:364033
Sam Maiera6e76d72022-02-11 21:43:504034 relative_includes = [
4035 line for _, line in f.ChangedContents()
4036 if "#include" in line and "../" in line
4037 ]
4038 if not relative_includes:
4039 continue
4040 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364041
Sam Maiera6e76d72022-02-11 21:43:504042 if not bad_files:
4043 return []
rlanday6802cf632017-05-30 17:48:364044
Sam Maiera6e76d72022-02-11 21:43:504045 error_descriptions = []
4046 for file_path, bad_lines in bad_files.items():
4047 error_description = file_path
4048 for line in bad_lines:
4049 error_description += '\n ' + line
4050 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364051
Sam Maiera6e76d72022-02-11 21:43:504052 results = []
4053 results.append(
4054 output_api.PresubmitError(
4055 'You added one or more relative #include paths (including "../").\n'
4056 'These shouldn\'t be used because they can be used to include headers\n'
4057 'from code that\'s not correctly specified as a dependency in the\n'
4058 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364059
Sam Maiera6e76d72022-02-11 21:43:504060 return results
rlanday6802cf632017-05-30 17:48:364061
Takeshi Yoshinoe387aa32017-08-02 13:16:134062
Saagar Sanghavifceeaae2020-08-12 16:40:364063def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504064 """Check that nobody tries to include a cc file. It's a relatively
4065 common error which results in duplicate symbols in object
4066 files. This may not always break the build until someone later gets
4067 very confusing linking errors."""
4068 results = []
4069 for f in input_api.AffectedFiles(include_deletes=False):
4070 # We let third_party code do whatever it wants
4071 if (f.LocalPath().startswith('third_party')
4072 and not f.LocalPath().startswith('third_party/blink')
4073 and not f.LocalPath().startswith('third_party\\blink')):
4074 continue
Daniel Bratell65b033262019-04-23 08:17:064075
Sam Maiera6e76d72022-02-11 21:43:504076 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4077 continue
Daniel Bratell65b033262019-04-23 08:17:064078
Sam Maiera6e76d72022-02-11 21:43:504079 for _, line in f.ChangedContents():
4080 if line.startswith('#include "'):
4081 included_file = line.split('"')[1]
4082 if _IsCPlusPlusFile(input_api, included_file):
4083 # The most common naming for external files with C++ code,
4084 # apart from standard headers, is to call them foo.inc, but
4085 # Chromium sometimes uses foo-inc.cc so allow that as well.
4086 if not included_file.endswith(('.h', '-inc.cc')):
4087 results.append(
4088 output_api.PresubmitError(
4089 'Only header files or .inc files should be included in other\n'
4090 'C++ files. Compiling the contents of a cc file more than once\n'
4091 'will cause duplicate information in the build which may later\n'
4092 'result in strange link_errors.\n' +
4093 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064094
Sam Maiera6e76d72022-02-11 21:43:504095 return results
Daniel Bratell65b033262019-04-23 08:17:064096
4097
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204098def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504099 if not isinstance(key, ast.Str):
4100 return 'Key at line %d must be a string literal' % key.lineno
4101 if not isinstance(value, ast.Dict):
4102 return 'Value at line %d must be a dict' % value.lineno
4103 if len(value.keys) != 1:
4104 return 'Dict at line %d must have single entry' % value.lineno
4105 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4106 return (
4107 'Entry at line %d must have a string literal \'filepath\' as key' %
4108 value.lineno)
4109 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134110
Takeshi Yoshinoe387aa32017-08-02 13:16:134111
Sergey Ulanov4af16052018-11-08 02:41:464112def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504113 if not isinstance(key, ast.Str):
4114 return 'Key at line %d must be a string literal' % key.lineno
4115 if not isinstance(value, ast.List):
4116 return 'Value at line %d must be a list' % value.lineno
4117 for element in value.elts:
4118 if not isinstance(element, ast.Str):
4119 return 'Watchlist elements on line %d is not a string' % key.lineno
4120 if not email_regex.match(element.s):
4121 return ('Watchlist element on line %d doesn\'t look like a valid '
4122 + 'email: %s') % (key.lineno, element.s)
4123 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134124
Takeshi Yoshinoe387aa32017-08-02 13:16:134125
Sergey Ulanov4af16052018-11-08 02:41:464126def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504127 mismatch_template = (
4128 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4129 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134130
Sam Maiera6e76d72022-02-11 21:43:504131 email_regex = input_api.re.compile(
4132 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464133
Sam Maiera6e76d72022-02-11 21:43:504134 ast = input_api.ast
4135 i = 0
4136 last_key = ''
4137 while True:
4138 if i >= len(wd_dict.keys):
4139 if i >= len(w_dict.keys):
4140 return None
4141 return mismatch_template % ('missing',
4142 'line %d' % w_dict.keys[i].lineno)
4143 elif i >= len(w_dict.keys):
4144 return (mismatch_template %
4145 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134146
Sam Maiera6e76d72022-02-11 21:43:504147 wd_key = wd_dict.keys[i]
4148 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134149
Sam Maiera6e76d72022-02-11 21:43:504150 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4151 wd_dict.values[i], ast)
4152 if result is not None:
4153 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134154
Sam Maiera6e76d72022-02-11 21:43:504155 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4156 email_regex)
4157 if result is not None:
4158 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204159
Sam Maiera6e76d72022-02-11 21:43:504160 if wd_key.s != w_key.s:
4161 return mismatch_template % ('%s at line %d' %
4162 (wd_key.s, wd_key.lineno),
4163 '%s at line %d' %
4164 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204165
Sam Maiera6e76d72022-02-11 21:43:504166 if wd_key.s < last_key:
4167 return (
4168 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4169 % (wd_key.lineno, w_key.lineno))
4170 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204171
Sam Maiera6e76d72022-02-11 21:43:504172 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204173
4174
Sergey Ulanov4af16052018-11-08 02:41:464175def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504176 ast = input_api.ast
4177 if not isinstance(expression, ast.Expression):
4178 return 'WATCHLISTS file must contain a valid expression'
4179 dictionary = expression.body
4180 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4181 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204182
Sam Maiera6e76d72022-02-11 21:43:504183 first_key = dictionary.keys[0]
4184 first_value = dictionary.values[0]
4185 second_key = dictionary.keys[1]
4186 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204187
Sam Maiera6e76d72022-02-11 21:43:504188 if (not isinstance(first_key, ast.Str)
4189 or first_key.s != 'WATCHLIST_DEFINITIONS'
4190 or not isinstance(first_value, ast.Dict)):
4191 return ('The first entry of the dict in WATCHLISTS file must be '
4192 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204193
Sam Maiera6e76d72022-02-11 21:43:504194 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4195 or not isinstance(second_value, ast.Dict)):
4196 return ('The second entry of the dict in WATCHLISTS file must be '
4197 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204198
Sam Maiera6e76d72022-02-11 21:43:504199 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134200
4201
Saagar Sanghavifceeaae2020-08-12 16:40:364202def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504203 for f in input_api.AffectedFiles(include_deletes=False):
4204 if f.LocalPath() == 'WATCHLISTS':
4205 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134206
Sam Maiera6e76d72022-02-11 21:43:504207 try:
4208 # First, make sure that it can be evaluated.
4209 input_api.ast.literal_eval(contents)
4210 # Get an AST tree for it and scan the tree for detailed style checking.
4211 expression = input_api.ast.parse(contents,
4212 filename='WATCHLISTS',
4213 mode='eval')
4214 except ValueError as e:
4215 return [
4216 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4217 long_text=repr(e))
4218 ]
4219 except SyntaxError as e:
4220 return [
4221 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4222 long_text=repr(e))
4223 ]
4224 except TypeError as e:
4225 return [
4226 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4227 long_text=repr(e))
4228 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134229
Sam Maiera6e76d72022-02-11 21:43:504230 result = _CheckWATCHLISTSSyntax(expression, input_api)
4231 if result is not None:
4232 return [output_api.PresubmitError(result)]
4233 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134234
Sam Maiera6e76d72022-02-11 21:43:504235 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134236
4237
Andrew Grieve1b290e4a22020-11-24 20:07:014238def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504239 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014240
Sam Maiera6e76d72022-02-11 21:43:504241 As documented at //build/docs/writing_gn_templates.md
4242 """
Andrew Grieve1b290e4a22020-11-24 20:07:014243
Sam Maiera6e76d72022-02-11 21:43:504244 def gn_files(f):
4245 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014246
Sam Maiera6e76d72022-02-11 21:43:504247 problems = []
4248 for f in input_api.AffectedSourceFiles(gn_files):
4249 for line_num, line in f.ChangedContents():
4250 if 'forward_variables_from(invoker, "*")' in line:
4251 problems.append(
4252 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4253 (f.LocalPath(), line_num))
4254
4255 if problems:
4256 return [
4257 output_api.PresubmitPromptWarning(
4258 'forward_variables_from("*") without exclusions',
4259 items=sorted(problems),
4260 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594261 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504262 'explicitly listed in forward_variables_from(). For more '
4263 'details, see:\n'
4264 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4265 'build/docs/writing_gn_templates.md'
4266 '#Using-forward_variables_from'))
4267 ]
4268 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014269
4270
Saagar Sanghavifceeaae2020-08-12 16:40:364271def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504272 """Checks that newly added header files have corresponding GN changes.
4273 Note that this is only a heuristic. To be precise, run script:
4274 build/check_gn_headers.py.
4275 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194276
Sam Maiera6e76d72022-02-11 21:43:504277 def headers(f):
4278 return input_api.FilterSourceFile(
4279 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194280
Sam Maiera6e76d72022-02-11 21:43:504281 new_headers = []
4282 for f in input_api.AffectedSourceFiles(headers):
4283 if f.Action() != 'A':
4284 continue
4285 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194286
Sam Maiera6e76d72022-02-11 21:43:504287 def gn_files(f):
4288 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194289
Sam Maiera6e76d72022-02-11 21:43:504290 all_gn_changed_contents = ''
4291 for f in input_api.AffectedSourceFiles(gn_files):
4292 for _, line in f.ChangedContents():
4293 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194294
Sam Maiera6e76d72022-02-11 21:43:504295 problems = []
4296 for header in new_headers:
4297 basename = input_api.os_path.basename(header)
4298 if basename not in all_gn_changed_contents:
4299 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194300
Sam Maiera6e76d72022-02-11 21:43:504301 if problems:
4302 return [
4303 output_api.PresubmitPromptWarning(
4304 'Missing GN changes for new header files',
4305 items=sorted(problems),
4306 long_text=
4307 'Please double check whether newly added header files need '
4308 'corresponding changes in gn or gni files.\nThis checking is only a '
4309 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4310 'Read https://crbug.com/661774 for more info.')
4311 ]
4312 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194313
4314
Saagar Sanghavifceeaae2020-08-12 16:40:364315def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504316 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024317
Sam Maiera6e76d72022-02-11 21:43:504318 This assumes we won't intentionally reference one product from the other
4319 product.
4320 """
4321 all_problems = []
4322 test_cases = [{
4323 "filename_postfix": "google_chrome_strings.grd",
4324 "correct_name": "Chrome",
4325 "incorrect_name": "Chromium",
4326 }, {
4327 "filename_postfix": "chromium_strings.grd",
4328 "correct_name": "Chromium",
4329 "incorrect_name": "Chrome",
4330 }]
Michael Giuffridad3bc8672018-10-25 22:48:024331
Sam Maiera6e76d72022-02-11 21:43:504332 for test_case in test_cases:
4333 problems = []
4334 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4335 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024336
Sam Maiera6e76d72022-02-11 21:43:504337 # Check each new line. Can yield false positives in multiline comments, but
4338 # easier than trying to parse the XML because messages can have nested
4339 # children, and associating message elements with affected lines is hard.
4340 for f in input_api.AffectedSourceFiles(filename_filter):
4341 for line_num, line in f.ChangedContents():
4342 if "<message" in line or "<!--" in line or "-->" in line:
4343 continue
4344 if test_case["incorrect_name"] in line:
4345 problems.append("Incorrect product name in %s:%d" %
4346 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024347
Sam Maiera6e76d72022-02-11 21:43:504348 if problems:
4349 message = (
4350 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4351 % (test_case["correct_name"], test_case["correct_name"],
4352 test_case["incorrect_name"]))
4353 all_problems.append(
4354 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024355
Sam Maiera6e76d72022-02-11 21:43:504356 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024357
4358
Saagar Sanghavifceeaae2020-08-12 16:40:364359def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504360 """Avoid large files, especially binary files, in the repository since
4361 git doesn't scale well for those. They will be in everyone's repo
4362 clones forever, forever making Chromium slower to clone and work
4363 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364364
Sam Maiera6e76d72022-02-11 21:43:504365 # Uploading files to cloud storage is not trivial so we don't want
4366 # to set the limit too low, but the upper limit for "normal" large
4367 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4368 # anything over 20 MB is exceptional.
4369 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364370
Sam Maiera6e76d72022-02-11 21:43:504371 too_large_files = []
4372 for f in input_api.AffectedFiles():
4373 # Check both added and modified files (but not deleted files).
4374 if f.Action() in ('A', 'M'):
4375 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4376 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4377 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364378
Sam Maiera6e76d72022-02-11 21:43:504379 if too_large_files:
4380 message = (
4381 'Do not commit large files to git since git scales badly for those.\n'
4382 +
4383 'Instead put the large files in cloud storage and use DEPS to\n' +
4384 'fetch them.\n' + '\n'.join(too_large_files))
4385 return [
4386 output_api.PresubmitError('Too large files found in commit',
4387 long_text=message + '\n')
4388 ]
4389 else:
4390 return []
Daniel Bratell93eb6c62019-04-29 20:13:364391
Max Morozb47503b2019-08-08 21:03:274392
Saagar Sanghavifceeaae2020-08-12 16:40:364393def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504394 """Checks specific for fuzz target sources."""
4395 EXPORTED_SYMBOLS = [
4396 'LLVMFuzzerInitialize',
4397 'LLVMFuzzerCustomMutator',
4398 'LLVMFuzzerCustomCrossOver',
4399 'LLVMFuzzerMutate',
4400 ]
Max Morozb47503b2019-08-08 21:03:274401
Sam Maiera6e76d72022-02-11 21:43:504402 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274403
Sam Maiera6e76d72022-02-11 21:43:504404 def FilterFile(affected_file):
4405 """Ignore libFuzzer source code."""
4406 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4407 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274408
Sam Maiera6e76d72022-02-11 21:43:504409 return input_api.FilterSourceFile(affected_file,
4410 files_to_check=[files_to_check],
4411 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274412
Sam Maiera6e76d72022-02-11 21:43:504413 files_with_missing_header = []
4414 for f in input_api.AffectedSourceFiles(FilterFile):
4415 contents = input_api.ReadFile(f, 'r')
4416 if REQUIRED_HEADER in contents:
4417 continue
Max Morozb47503b2019-08-08 21:03:274418
Sam Maiera6e76d72022-02-11 21:43:504419 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4420 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274421
Sam Maiera6e76d72022-02-11 21:43:504422 if not files_with_missing_header:
4423 return []
Max Morozb47503b2019-08-08 21:03:274424
Sam Maiera6e76d72022-02-11 21:43:504425 long_text = (
4426 'If you define any of the libFuzzer optional functions (%s), it is '
4427 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4428 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4429 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4430 'to access command line arguments passed to the fuzzer. Instead, prefer '
4431 'static initialization and shared resources as documented in '
4432 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4433 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4434 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274435
Sam Maiera6e76d72022-02-11 21:43:504436 return [
4437 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4438 REQUIRED_HEADER,
4439 items=files_with_missing_header,
4440 long_text=long_text)
4441 ]
Max Morozb47503b2019-08-08 21:03:274442
4443
Mohamed Heikald048240a2019-11-12 16:57:374444def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504445 """
4446 Warns authors who add images into the repo to make sure their images are
4447 optimized before committing.
4448 """
4449 images_added = False
4450 image_paths = []
4451 errors = []
4452 filter_lambda = lambda x: input_api.FilterSourceFile(
4453 x,
4454 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4455 DEFAULT_FILES_TO_SKIP),
4456 files_to_check=[r'.*\/(drawable|mipmap)'])
4457 for f in input_api.AffectedFiles(include_deletes=False,
4458 file_filter=filter_lambda):
4459 local_path = f.LocalPath().lower()
4460 if any(
4461 local_path.endswith(extension)
4462 for extension in _IMAGE_EXTENSIONS):
4463 images_added = True
4464 image_paths.append(f)
4465 if images_added:
4466 errors.append(
4467 output_api.PresubmitPromptWarning(
4468 'It looks like you are trying to commit some images. If these are '
4469 'non-test-only images, please make sure to read and apply the tips in '
4470 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4471 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4472 'FYI only and will not block your CL on the CQ.', image_paths))
4473 return errors
Mohamed Heikald048240a2019-11-12 16:57:374474
4475
Saagar Sanghavifceeaae2020-08-12 16:40:364476def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504477 """Groups upload checks that target android code."""
4478 results = []
4479 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4480 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4481 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4482 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4483 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4484 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4485 input_api, output_api))
4486 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4487 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4488 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4489 results.extend(_CheckNewImagesWarning(input_api, output_api))
4490 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4491 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4492 return results
4493
Becky Zhou7c69b50992018-12-10 19:37:574494
Saagar Sanghavifceeaae2020-08-12 16:40:364495def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504496 """Groups commit checks that target android code."""
4497 results = []
4498 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4499 return results
dgnaa68d5e2015-06-10 10:08:224500
Chris Hall59f8d0c72020-05-01 07:31:194501# TODO(chrishall): could we additionally match on any path owned by
4502# ui/accessibility/OWNERS ?
4503_ACCESSIBILITY_PATHS = (
4504 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4505 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4506 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4507 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4508 r"^content[\\/]browser[\\/]accessibility[\\/]",
4509 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4510 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4511 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4512 r"^ui[\\/]accessibility[\\/]",
4513 r"^ui[\\/]views[\\/]accessibility[\\/]",
4514)
4515
Saagar Sanghavifceeaae2020-08-12 16:40:364516def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504517 """Checks that commits to accessibility code contain an AX-Relnotes field in
4518 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194519
Sam Maiera6e76d72022-02-11 21:43:504520 def FileFilter(affected_file):
4521 paths = _ACCESSIBILITY_PATHS
4522 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194523
Sam Maiera6e76d72022-02-11 21:43:504524 # Only consider changes affecting accessibility paths.
4525 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4526 return []
Akihiro Ota08108e542020-05-20 15:30:534527
Sam Maiera6e76d72022-02-11 21:43:504528 # AX-Relnotes can appear in either the description or the footer.
4529 # When searching the description, require 'AX-Relnotes:' to appear at the
4530 # beginning of a line.
4531 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4532 description_has_relnotes = any(
4533 ax_regex.match(line)
4534 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194535
Sam Maiera6e76d72022-02-11 21:43:504536 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4537 'AX-Relnotes', [])
4538 if description_has_relnotes or footer_relnotes:
4539 return []
Chris Hall59f8d0c72020-05-01 07:31:194540
Sam Maiera6e76d72022-02-11 21:43:504541 # TODO(chrishall): link to Relnotes documentation in message.
4542 message = (
4543 "Missing 'AX-Relnotes:' field required for accessibility changes"
4544 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4545 "user-facing changes"
4546 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4547 "user-facing effects"
4548 "\n if this is confusing or annoying then please contact members "
4549 "of ui/accessibility/OWNERS.")
4550
4551 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224552
Mark Schillacie5a0be22022-01-19 00:38:394553
4554_ACCESSIBILITY_EVENTS_TEST_PATH = (
4555 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]event[\\/].*\.html",
4556)
4557
4558_ACCESSIBILITY_TREE_TEST_PATH = (
4559 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]accname[\\/].*\.html",
4560 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]aria[\\/].*\.html",
4561 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]css[\\/].*\.html",
4562 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]html[\\/].*\.html",
4563)
4564
4565_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
4566 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4567)
4568
4569_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Mark Schillaci6f568a52022-02-17 18:41:444570 r"^.*[\\/]WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394571)
4572
4573def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504574 """Checks that commits that include a newly added, renamed/moved, or deleted
4575 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4576 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394577
Sam Maiera6e76d72022-02-11 21:43:504578 def FilePathFilter(affected_file):
4579 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4580 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394581
Sam Maiera6e76d72022-02-11 21:43:504582 def AndroidFilePathFilter(affected_file):
4583 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4584 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394585
Sam Maiera6e76d72022-02-11 21:43:504586 # Only consider changes in the events test data path with html type.
4587 if not any(
4588 input_api.AffectedFiles(include_deletes=True,
4589 file_filter=FilePathFilter)):
4590 return []
Mark Schillacie5a0be22022-01-19 00:38:394591
Sam Maiera6e76d72022-02-11 21:43:504592 # If the commit contains any change to the Android test file, ignore.
4593 if any(
4594 input_api.AffectedFiles(include_deletes=True,
4595 file_filter=AndroidFilePathFilter)):
4596 return []
Mark Schillacie5a0be22022-01-19 00:38:394597
Sam Maiera6e76d72022-02-11 21:43:504598 # Only consider changes that are adding/renaming or deleting a file
4599 message = []
4600 for f in input_api.AffectedFiles(include_deletes=True,
4601 file_filter=FilePathFilter):
4602 if f.Action() == 'A' or f.Action() == 'D':
4603 message = (
4604 "It appears that you are adding, renaming or deleting"
4605 "\na dump_accessibility_events* test, but have not included"
4606 "\na corresponding change for Android."
4607 "\nPlease include (or remove) the test from:"
4608 "\n content/public/android/javatests/src/org/chromium/"
4609 "content/browser/accessibility/"
4610 "WebContentsAccessibilityEventsTest.java"
4611 "\nIf this message is confusing or annoying, please contact"
4612 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394613
Sam Maiera6e76d72022-02-11 21:43:504614 # If no message was set, return empty.
4615 if not len(message):
4616 return []
4617
4618 return [output_api.PresubmitPromptWarning(message)]
4619
Mark Schillacie5a0be22022-01-19 00:38:394620
4621def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504622 """Checks that commits that include a newly added, renamed/moved, or deleted
4623 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4624 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394625
Sam Maiera6e76d72022-02-11 21:43:504626 def FilePathFilter(affected_file):
4627 paths = _ACCESSIBILITY_TREE_TEST_PATH
4628 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394629
Sam Maiera6e76d72022-02-11 21:43:504630 def AndroidFilePathFilter(affected_file):
4631 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4632 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394633
Sam Maiera6e76d72022-02-11 21:43:504634 # Only consider changes in the various tree test data paths with html type.
4635 if not any(
4636 input_api.AffectedFiles(include_deletes=True,
4637 file_filter=FilePathFilter)):
4638 return []
Mark Schillacie5a0be22022-01-19 00:38:394639
Sam Maiera6e76d72022-02-11 21:43:504640 # If the commit contains any change to the Android test file, ignore.
4641 if any(
4642 input_api.AffectedFiles(include_deletes=True,
4643 file_filter=AndroidFilePathFilter)):
4644 return []
Mark Schillacie5a0be22022-01-19 00:38:394645
Sam Maiera6e76d72022-02-11 21:43:504646 # Only consider changes that are adding/renaming or deleting a file
4647 message = []
4648 for f in input_api.AffectedFiles(include_deletes=True,
4649 file_filter=FilePathFilter):
4650 if f.Action() == 'A' or f.Action() == 'D':
4651 message = (
4652 "It appears that you are adding, renaming or deleting"
4653 "\na dump_accessibility_tree* test, but have not included"
4654 "\na corresponding change for Android."
4655 "\nPlease include (or remove) the test from:"
4656 "\n content/public/android/javatests/src/org/chromium/"
4657 "content/browser/accessibility/"
4658 "WebContentsAccessibilityTreeTest.java"
4659 "\nIf this message is confusing or annoying, please contact"
4660 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394661
Sam Maiera6e76d72022-02-11 21:43:504662 # If no message was set, return empty.
4663 if not len(message):
4664 return []
4665
4666 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394667
4668
seanmccullough4a9356252021-04-08 19:54:094669# string pattern, sequence of strings to show when pattern matches,
4670# error flag. True if match is a presubmit error, otherwise it's a warning.
4671_NON_INCLUSIVE_TERMS = (
4672 (
4673 # Note that \b pattern in python re is pretty particular. In this
4674 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4675 # ...' will not. This may require some tweaking to catch these cases
4676 # without triggering a lot of false positives. Leaving it naive and
4677 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324678 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094679 (
4680 'Please don\'t use blacklist, whitelist, ' # nocheck
4681 'or slave in your', # nocheck
4682 'code and make every effort to use other terms. Using "// nocheck"',
4683 '"# nocheck" or "<!-- nocheck -->"',
4684 'at the end of the offending line will bypass this PRESUBMIT error',
4685 'but avoid using this whenever possible. Reach out to',
4686 'community@chromium.org if you have questions'),
4687 True),)
4688
Saagar Sanghavifceeaae2020-08-12 16:40:364689def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504690 """Checks common to both upload and commit."""
4691 results = []
Eric Boren6fd2b932018-01-25 15:05:084692 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504693 input_api.canned_checks.PanProjectChecks(
4694 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084695
Sam Maiera6e76d72022-02-11 21:43:504696 author = input_api.change.author_email
4697 if author and author not in _KNOWN_ROBOTS:
4698 results.extend(
4699 input_api.canned_checks.CheckAuthorizedAuthor(
4700 input_api, output_api))
marja@chromium.org2299dcf2012-11-15 19:56:244701
Sam Maiera6e76d72022-02-11 21:43:504702 results.extend(
4703 input_api.canned_checks.CheckChangeHasNoTabs(
4704 input_api,
4705 output_api,
4706 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
4707 results.extend(
4708 input_api.RunTests(
4709 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:174710
Bruce Dawsonc8054482022-03-28 15:33:374711 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:504712 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:374713 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:504714 results.extend(
4715 input_api.RunTests(
4716 input_api.canned_checks.CheckDirMetadataFormat(
4717 input_api, output_api, dirmd_bin)))
4718 results.extend(
4719 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4720 input_api, output_api))
4721 results.extend(
4722 input_api.canned_checks.CheckNoNewMetadataInOwners(
4723 input_api, output_api))
4724 results.extend(
4725 input_api.canned_checks.CheckInclusiveLanguage(
4726 input_api,
4727 output_api,
4728 excluded_directories_relative_path=[
4729 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
4730 ],
4731 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:594732
Aleksey Khoroshilov2978c942022-06-13 16:14:124733 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
4734 f, files_to_check=[r'PRESUBMIT\.py$'])
4735 for f in input_api.AffectedFiles(include_deletes=False,
4736 file_filter=presubmit_py_filter):
4737 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
4738 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
4739 # The PRESUBMIT.py file (and the directory containing it) might have
4740 # been affected by being moved or removed, so only try to run the tests
4741 # if they still exist.
4742 if not input_api.os_path.exists(test_file):
4743 continue
Sam Maiera6e76d72022-02-11 21:43:504744
Aleksey Khoroshilov2978c942022-06-13 16:14:124745 use_python3 = False
4746 with open(f.LocalPath()) as fp:
4747 use_python3 = any(
4748 line.startswith('USE_PYTHON3 = True')
4749 for line in fp.readlines())
4750
4751 results.extend(
4752 input_api.canned_checks.RunUnitTestsInDirectory(
4753 input_api,
4754 output_api,
4755 full_path,
4756 files_to_check=[r'^PRESUBMIT_test\.py$'],
4757 run_on_python2=not use_python3,
4758 run_on_python3=use_python3,
4759 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:504760 return results
maruel@chromium.org1f7b4172010-01-28 01:17:344761
maruel@chromium.orgb337cb5b2011-01-23 21:24:054762
Saagar Sanghavifceeaae2020-08-12 16:40:364763def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504764 problems = [
4765 f.LocalPath() for f in input_api.AffectedFiles()
4766 if f.LocalPath().endswith(('.orig', '.rej'))
4767 ]
4768 # Cargo.toml.orig files are part of third-party crates downloaded from
4769 # crates.io and should be included.
4770 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
4771 if problems:
4772 return [
4773 output_api.PresubmitError("Don't commit .rej and .orig files.",
4774 problems)
4775 ]
4776 else:
4777 return []
enne@chromium.orgb8079ae4a2012-12-05 19:56:494778
4779
Saagar Sanghavifceeaae2020-08-12 16:40:364780def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504781 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4782 macro_re = input_api.re.compile(
4783 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
4784 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
4785 input_api.re.MULTILINE)
4786 extension_re = input_api.re.compile(r'\.[a-z]+$')
4787 errors = []
Bruce Dawsonf7679202022-08-09 20:24:004788 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:504789 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:004790 # The build-config macros are allowed to be used in build_config.h
4791 # without including itself.
4792 if f.LocalPath() == config_h_file:
4793 continue
Sam Maiera6e76d72022-02-11 21:43:504794 if not f.LocalPath().endswith(
4795 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4796 continue
4797 found_line_number = None
4798 found_macro = None
4799 all_lines = input_api.ReadFile(f, 'r').splitlines()
4800 for line_num, line in enumerate(all_lines):
4801 match = macro_re.search(line)
4802 if match:
4803 found_line_number = line_num
4804 found_macro = match.group(2)
4805 break
4806 if not found_line_number:
4807 continue
Kent Tamura5a8755d2017-06-29 23:37:074808
Sam Maiera6e76d72022-02-11 21:43:504809 found_include_line = -1
4810 for line_num, line in enumerate(all_lines):
4811 if include_re.search(line):
4812 found_include_line = line_num
4813 break
4814 if found_include_line >= 0 and found_include_line < found_line_number:
4815 continue
Kent Tamura5a8755d2017-06-29 23:37:074816
Sam Maiera6e76d72022-02-11 21:43:504817 if not f.LocalPath().endswith('.h'):
4818 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4819 try:
4820 content = input_api.ReadFile(primary_header_path, 'r')
4821 if include_re.search(content):
4822 continue
4823 except IOError:
4824 pass
4825 errors.append('%s:%d %s macro is used without first including build/'
4826 'build_config.h.' %
4827 (f.LocalPath(), found_line_number, found_macro))
4828 if errors:
4829 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4830 return []
Kent Tamura5a8755d2017-06-29 23:37:074831
4832
Lei Zhang1c12a22f2021-05-12 11:28:454833def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504834 stl_include_re = input_api.re.compile(r'^#include\s+<('
4835 r'algorithm|'
4836 r'array|'
4837 r'limits|'
4838 r'list|'
4839 r'map|'
4840 r'memory|'
4841 r'queue|'
4842 r'set|'
4843 r'string|'
4844 r'unordered_map|'
4845 r'unordered_set|'
4846 r'utility|'
4847 r'vector)>')
4848 std_namespace_re = input_api.re.compile(r'std::')
4849 errors = []
4850 for f in input_api.AffectedFiles():
4851 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4852 continue
Lei Zhang1c12a22f2021-05-12 11:28:454853
Sam Maiera6e76d72022-02-11 21:43:504854 uses_std_namespace = False
4855 has_stl_include = False
4856 for line in f.NewContents():
4857 if has_stl_include and uses_std_namespace:
4858 break
Lei Zhang1c12a22f2021-05-12 11:28:454859
Sam Maiera6e76d72022-02-11 21:43:504860 if not has_stl_include and stl_include_re.search(line):
4861 has_stl_include = True
4862 continue
Lei Zhang1c12a22f2021-05-12 11:28:454863
Bruce Dawson4a5579a2022-04-08 17:11:364864 if not uses_std_namespace and (std_namespace_re.search(line)
4865 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504866 uses_std_namespace = True
4867 continue
Lei Zhang1c12a22f2021-05-12 11:28:454868
Sam Maiera6e76d72022-02-11 21:43:504869 if has_stl_include and not uses_std_namespace:
4870 errors.append(
4871 '%s: Includes STL header(s) but does not reference std::' %
4872 f.LocalPath())
4873 if errors:
4874 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4875 return []
Lei Zhang1c12a22f2021-05-12 11:28:454876
4877
Xiaohan Wang42d96c22022-01-20 17:23:114878def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504879 """Check for sensible looking, totally invalid OS macros."""
4880 preprocessor_statement = input_api.re.compile(r'^\s*#')
4881 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
4882 results = []
4883 for lnum, line in f.ChangedContents():
4884 if preprocessor_statement.search(line):
4885 for match in os_macro.finditer(line):
4886 results.append(
4887 ' %s:%d: %s' %
4888 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
4889 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
4890 return results
dbeam@chromium.orgb00342e7f2013-03-26 16:21:544891
4892
Xiaohan Wang42d96c22022-01-20 17:23:114893def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504894 """Check all affected files for invalid OS macros."""
4895 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:004896 # The OS_ macros are allowed to be used in build/build_config.h.
4897 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:504898 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:004899 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
4900 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:504901 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
dbeam@chromium.orgb00342e7f2013-03-26 16:21:544902
Sam Maiera6e76d72022-02-11 21:43:504903 if not bad_macros:
4904 return []
dbeam@chromium.orgb00342e7f2013-03-26 16:21:544905
Sam Maiera6e76d72022-02-11 21:43:504906 return [
4907 output_api.PresubmitError(
4908 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
4909 'defined in build_config.h):', bad_macros)
4910 ]
dbeam@chromium.orgb00342e7f2013-03-26 16:21:544911
lliabraa35bab3932014-10-01 12:16:444912
4913def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504914 """Check all affected files for invalid "if defined" macros."""
4915 ALWAYS_DEFINED_MACROS = (
4916 "TARGET_CPU_PPC",
4917 "TARGET_CPU_PPC64",
4918 "TARGET_CPU_68K",
4919 "TARGET_CPU_X86",
4920 "TARGET_CPU_ARM",
4921 "TARGET_CPU_MIPS",
4922 "TARGET_CPU_SPARC",
4923 "TARGET_CPU_ALPHA",
4924 "TARGET_IPHONE_SIMULATOR",
4925 "TARGET_OS_EMBEDDED",
4926 "TARGET_OS_IPHONE",
4927 "TARGET_OS_MAC",
4928 "TARGET_OS_UNIX",
4929 "TARGET_OS_WIN32",
4930 )
4931 ifdef_macro = input_api.re.compile(
4932 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4933 results = []
4934 for lnum, line in f.ChangedContents():
4935 for match in ifdef_macro.finditer(line):
4936 if match.group(1) in ALWAYS_DEFINED_MACROS:
4937 always_defined = ' %s is always defined. ' % match.group(1)
4938 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4939 results.append(
4940 ' %s:%d %s\n\t%s' %
4941 (f.LocalPath(), lnum, always_defined, did_you_mean))
4942 return results
lliabraa35bab3932014-10-01 12:16:444943
4944
Saagar Sanghavifceeaae2020-08-12 16:40:364945def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504946 """Check all affected files for invalid "if defined" macros."""
4947 bad_macros = []
4948 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
4949 for f in input_api.AffectedFiles():
4950 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
4951 continue
4952 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4953 bad_macros.extend(
4954 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:444955
Sam Maiera6e76d72022-02-11 21:43:504956 if not bad_macros:
4957 return []
lliabraa35bab3932014-10-01 12:16:444958
Sam Maiera6e76d72022-02-11 21:43:504959 return [
4960 output_api.PresubmitError(
4961 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4962 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4963 bad_macros)
4964 ]
lliabraa35bab3932014-10-01 12:16:444965
4966
Saagar Sanghavifceeaae2020-08-12 16:40:364967def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504968 """Check for same IPC rules described in
4969 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4970 """
4971 base_pattern = r'IPC_ENUM_TRAITS\('
4972 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4973 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:044974
Sam Maiera6e76d72022-02-11 21:43:504975 problems = []
4976 for f in input_api.AffectedSourceFiles(None):
4977 local_path = f.LocalPath()
4978 if not local_path.endswith('.h'):
4979 continue
4980 for line_number, line in f.ChangedContents():
4981 if inclusion_pattern.search(
4982 line) and not comment_pattern.search(line):
4983 problems.append('%s:%d\n %s' %
4984 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:044985
Sam Maiera6e76d72022-02-11 21:43:504986 if problems:
4987 return [
4988 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
4989 problems)
4990 ]
4991 else:
4992 return []
mlamouria82272622014-09-16 18:45:044993
dbeam@chromium.orgb00342e7f2013-03-26 16:21:544994
Saagar Sanghavifceeaae2020-08-12 16:40:364995def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504996 """Check to make sure no files being submitted have long paths.
4997 This causes issues on Windows.
4998 """
4999 problems = []
5000 for f in input_api.AffectedTestableFiles():
5001 local_path = f.LocalPath()
5002 # Windows has a path limit of 260 characters. Limit path length to 200 so
5003 # that we have some extra for the prefix on dev machines and the bots.
5004 if len(local_path) > 200:
5005 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055006
Sam Maiera6e76d72022-02-11 21:43:505007 if problems:
5008 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5009 else:
5010 return []
Stephen Martinis97a394142018-06-07 23:06:055011
5012
Saagar Sanghavifceeaae2020-08-12 16:40:365013def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505014 """Check that header files have proper guards against multiple inclusion.
5015 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365016 should include the string "no-include-guard-because-multiply-included" or
5017 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505018 """
Daniel Bratell8ba52722018-03-02 16:06:145019
Sam Maiera6e76d72022-02-11 21:43:505020 def is_chromium_header_file(f):
5021 # We only check header files under the control of the Chromium
5022 # project. That is, those outside third_party apart from
5023 # third_party/blink.
5024 # We also exclude *_message_generator.h headers as they use
5025 # include guards in a special, non-typical way.
5026 file_with_path = input_api.os_path.normpath(f.LocalPath())
5027 return (file_with_path.endswith('.h')
5028 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335029 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505030 and (not file_with_path.startswith('third_party')
5031 or file_with_path.startswith(
5032 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145033
Sam Maiera6e76d72022-02-11 21:43:505034 def replace_special_with_underscore(string):
5035 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145036
Sam Maiera6e76d72022-02-11 21:43:505037 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145038
Sam Maiera6e76d72022-02-11 21:43:505039 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5040 guard_name = None
5041 guard_line_number = None
5042 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145043
Sam Maiera6e76d72022-02-11 21:43:505044 file_with_path = input_api.os_path.normpath(f.LocalPath())
5045 base_file_name = input_api.os_path.splitext(
5046 input_api.os_path.basename(file_with_path))[0]
5047 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145048
Sam Maiera6e76d72022-02-11 21:43:505049 expected_guard = replace_special_with_underscore(
5050 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145051
Sam Maiera6e76d72022-02-11 21:43:505052 # For "path/elem/file_name.h" we should really only accept
5053 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5054 # are too many (1000+) files with slight deviations from the
5055 # coding style. The most important part is that the include guard
5056 # is there, and that it's unique, not the name so this check is
5057 # forgiving for existing files.
5058 #
5059 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145060
Sam Maiera6e76d72022-02-11 21:43:505061 guard_name_pattern_list = [
5062 # Anything with the right suffix (maybe with an extra _).
5063 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145064
Sam Maiera6e76d72022-02-11 21:43:505065 # To cover include guards with old Blink style.
5066 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145067
Sam Maiera6e76d72022-02-11 21:43:505068 # Anything including the uppercase name of the file.
5069 r'\w*' + input_api.re.escape(
5070 replace_special_with_underscore(upper_base_file_name)) +
5071 r'\w*',
5072 ]
5073 guard_name_pattern = '|'.join(guard_name_pattern_list)
5074 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5075 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145076
Sam Maiera6e76d72022-02-11 21:43:505077 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365078 if ('no-include-guard-because-multiply-included' in line
5079 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505080 guard_name = 'DUMMY' # To not trigger check outside the loop.
5081 break
Daniel Bratell8ba52722018-03-02 16:06:145082
Sam Maiera6e76d72022-02-11 21:43:505083 if guard_name is None:
5084 match = guard_pattern.match(line)
5085 if match:
5086 guard_name = match.group(1)
5087 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145088
Sam Maiera6e76d72022-02-11 21:43:505089 # We allow existing files to use include guards whose names
5090 # don't match the chromium style guide, but new files should
5091 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495092 if guard_name != expected_guard:
5093 if not f.OldContents():
Sam Maiera6e76d72022-02-11 21:43:505094 errors.append(
5095 output_api.PresubmitPromptWarning(
5096 'Header using the wrong include guard name %s'
5097 % guard_name, [
5098 '%s:%d' %
5099 (f.LocalPath(), line_number + 1)
5100 ], 'Expected: %r\nFound: %r' %
5101 (expected_guard, guard_name)))
5102 else:
5103 # The line after #ifndef should have a #define of the same name.
5104 if line_number == guard_line_number + 1:
5105 expected_line = '#define %s' % guard_name
5106 if line != expected_line:
5107 errors.append(
5108 output_api.PresubmitPromptWarning(
5109 'Missing "%s" for include guard' %
5110 expected_line,
5111 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5112 'Expected: %r\nGot: %r' %
5113 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145114
Sam Maiera6e76d72022-02-11 21:43:505115 if not seen_guard_end and line == '#endif // %s' % guard_name:
5116 seen_guard_end = True
5117 elif seen_guard_end:
5118 if line.strip() != '':
5119 errors.append(
5120 output_api.PresubmitPromptWarning(
5121 'Include guard %s not covering the whole file'
5122 % (guard_name), [f.LocalPath()]))
5123 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145124
Sam Maiera6e76d72022-02-11 21:43:505125 if guard_name is None:
5126 errors.append(
5127 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495128 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505129 'Recommended name: %s\n'
5130 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365131 '"no-include-guard-because-multiply-included" or\n'
5132 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505133 % (f.LocalPath(), expected_guard)))
5134
5135 return errors
Daniel Bratell8ba52722018-03-02 16:06:145136
5137
Saagar Sanghavifceeaae2020-08-12 16:40:365138def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505139 """Check source code and known ascii text files for Windows style line
5140 endings.
5141 """
Bruce Dawson5efbdc652022-04-11 19:29:515142 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235143
Sam Maiera6e76d72022-02-11 21:43:505144 file_inclusion_pattern = (known_text_files,
5145 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5146 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235147
Sam Maiera6e76d72022-02-11 21:43:505148 problems = []
5149 source_file_filter = lambda f: input_api.FilterSourceFile(
5150 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5151 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515152 # Ignore test files that contain crlf intentionally.
5153 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345154 continue
Sam Maiera6e76d72022-02-11 21:43:505155 include_file = False
5156 for line in input_api.ReadFile(f, 'r').splitlines(True):
5157 if line.endswith('\r\n'):
5158 include_file = True
5159 if include_file:
5160 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235161
Sam Maiera6e76d72022-02-11 21:43:505162 if problems:
5163 return [
5164 output_api.PresubmitPromptWarning(
5165 'Are you sure that you want '
5166 'these files to contain Windows style line endings?\n' +
5167 '\n'.join(problems))
5168 ]
mostynbb639aca52015-01-07 20:31:235169
Sam Maiera6e76d72022-02-11 21:43:505170 return []
5171
mostynbb639aca52015-01-07 20:31:235172
Evan Stade6cfc964c12021-05-18 20:21:165173def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505174 """Check that .icon files (which are fragments of C++) have license headers.
5175 """
Evan Stade6cfc964c12021-05-18 20:21:165176
Sam Maiera6e76d72022-02-11 21:43:505177 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165178
Sam Maiera6e76d72022-02-11 21:43:505179 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5180 return input_api.canned_checks.CheckLicense(input_api,
5181 output_api,
5182 source_file_filter=icons)
5183
Evan Stade6cfc964c12021-05-18 20:21:165184
Jose Magana2b456f22021-03-09 23:26:405185def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505186 """Check source code for use of Chrome App technologies being
5187 deprecated.
5188 """
Jose Magana2b456f22021-03-09 23:26:405189
Sam Maiera6e76d72022-02-11 21:43:505190 def _CheckForDeprecatedTech(input_api,
5191 output_api,
5192 detection_list,
5193 files_to_check=None,
5194 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405195
Sam Maiera6e76d72022-02-11 21:43:505196 if (files_to_check or files_to_skip):
5197 source_file_filter = lambda f: input_api.FilterSourceFile(
5198 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5199 else:
5200 source_file_filter = None
5201
5202 problems = []
5203
5204 for f in input_api.AffectedSourceFiles(source_file_filter):
5205 if f.Action() == 'D':
5206 continue
5207 for _, line in f.ChangedContents():
5208 if any(detect in line for detect in detection_list):
5209 problems.append(f.LocalPath())
5210
5211 return problems
5212
5213 # to avoid this presubmit script triggering warnings
5214 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405215
5216 problems = []
5217
Sam Maiera6e76d72022-02-11 21:43:505218 # NMF: any files with extensions .nmf or NMF
5219 _NMF_FILES = r'\.(nmf|NMF)$'
5220 problems += _CheckForDeprecatedTech(
5221 input_api,
5222 output_api,
5223 detection_list=[''], # any change to the file will trigger warning
5224 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405225
Sam Maiera6e76d72022-02-11 21:43:505226 # MANIFEST: any manifest.json that in its diff includes "app":
5227 _MANIFEST_FILES = r'(manifest\.json)$'
5228 problems += _CheckForDeprecatedTech(
5229 input_api,
5230 output_api,
5231 detection_list=['"app":'],
5232 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405233
Sam Maiera6e76d72022-02-11 21:43:505234 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5235 problems += _CheckForDeprecatedTech(
5236 input_api,
5237 output_api,
5238 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
5239 files_to_skip=files_to_skip + [r"^native_client_sdk[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405240
Gao Shenga79ebd42022-08-08 17:25:595241 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505242 problems += _CheckForDeprecatedTech(
5243 input_api,
5244 output_api,
5245 detection_list=['#include "ppapi', '#include <ppapi'],
5246 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5247 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
5248 files_to_skip=[r"^ppapi[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405249
Sam Maiera6e76d72022-02-11 21:43:505250 if problems:
5251 return [
5252 output_api.PresubmitPromptWarning(
5253 'You are adding/modifying code'
5254 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5255 ' PNaCl, PPAPI). See this blog post for more details:\n'
5256 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5257 'and this documentation for options to replace these technologies:\n'
5258 'https://developer.chrome.com/docs/apps/migration/\n' +
5259 '\n'.join(problems))
5260 ]
Jose Magana2b456f22021-03-09 23:26:405261
Sam Maiera6e76d72022-02-11 21:43:505262 return []
Jose Magana2b456f22021-03-09 23:26:405263
mostynbb639aca52015-01-07 20:31:235264
Saagar Sanghavifceeaae2020-08-12 16:40:365265def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505266 """Checks that all source files use SYSLOG properly."""
5267 syslog_files = []
5268 for f in input_api.AffectedSourceFiles(src_file_filter):
5269 for line_number, line in f.ChangedContents():
5270 if 'SYSLOG' in line:
5271 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565272
Sam Maiera6e76d72022-02-11 21:43:505273 if syslog_files:
5274 return [
5275 output_api.PresubmitPromptWarning(
5276 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5277 ' calls.\nFiles to check:\n',
5278 items=syslog_files)
5279 ]
5280 return []
pastarmovj89f7ee12016-09-20 14:58:135281
5282
maruel@chromium.org1f7b4172010-01-28 01:17:345283def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505284 if input_api.version < [2, 0, 0]:
5285 return [
5286 output_api.PresubmitError(
5287 "Your depot_tools is out of date. "
5288 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5289 "but your version is %d.%d.%d" % tuple(input_api.version))
5290 ]
5291 results = []
5292 results.extend(
5293 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5294 return results
maruel@chromium.orgca8d19842009-02-19 16:33:125295
5296
5297def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505298 if input_api.version < [2, 0, 0]:
5299 return [
5300 output_api.PresubmitError(
5301 "Your depot_tools is out of date. "
5302 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5303 "but your version is %d.%d.%d" % tuple(input_api.version))
5304 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365305
Sam Maiera6e76d72022-02-11 21:43:505306 results = []
5307 # Make sure the tree is 'open'.
5308 results.extend(
5309 input_api.canned_checks.CheckTreeIsOpen(
5310 input_api,
5311 output_api,
5312 json_url='http://chromium-status.appspot.com/current?format=json'))
maruel@chromium.org806e98e2010-03-19 17:49:275313
Sam Maiera6e76d72022-02-11 21:43:505314 results.extend(
5315 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5316 results.extend(
5317 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5318 results.extend(
5319 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5320 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505321 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145322
5323
Saagar Sanghavifceeaae2020-08-12 16:40:365324def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505325 """Check string ICU syntax validity and if translation screenshots exist."""
5326 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5327 # footer is set to true.
5328 git_footers = input_api.change.GitFootersFromDescription()
5329 skip_screenshot_check_footer = [
5330 footer.lower() for footer in git_footers.get(
5331 u'Skip-Translation-Screenshots-Check', [])
5332 ]
5333 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025334
Sam Maiera6e76d72022-02-11 21:43:505335 import os
5336 import re
5337 import sys
5338 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145339
Sam Maiera6e76d72022-02-11 21:43:505340 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5341 if (f.Action() == 'A' or f.Action() == 'M'))
5342 removed_paths = set(f.LocalPath()
5343 for f in input_api.AffectedFiles(include_deletes=True)
5344 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145345
Sam Maiera6e76d72022-02-11 21:43:505346 affected_grds = [
5347 f for f in input_api.AffectedFiles()
5348 if f.LocalPath().endswith(('.grd', '.grdp'))
5349 ]
5350 affected_grds = [
5351 f for f in affected_grds if not 'testdata' in f.LocalPath()
5352 ]
5353 if not affected_grds:
5354 return []
meacer8c0d3832019-12-26 21:46:165355
Sam Maiera6e76d72022-02-11 21:43:505356 affected_png_paths = [
5357 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5358 if (f.LocalPath().endswith('.png'))
5359 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145360
Sam Maiera6e76d72022-02-11 21:43:505361 # Check for screenshots. Developers can upload screenshots using
5362 # tools/translation/upload_screenshots.py which finds and uploads
5363 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5364 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5365 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5366 #
5367 # The logic here is as follows:
5368 #
5369 # - If the CL has a .png file under the screenshots directory for a grd
5370 # file, warn the developer. Actual images should never be checked into the
5371 # Chrome repo.
5372 #
5373 # - If the CL contains modified or new messages in grd files and doesn't
5374 # contain the corresponding .sha1 files, warn the developer to add images
5375 # and upload them via tools/translation/upload_screenshots.py.
5376 #
5377 # - If the CL contains modified or new messages in grd files and the
5378 # corresponding .sha1 files, everything looks good.
5379 #
5380 # - If the CL contains removed messages in grd files but the corresponding
5381 # .sha1 files aren't removed, warn the developer to remove them.
5382 unnecessary_screenshots = []
5383 missing_sha1 = []
5384 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145385
Sam Maiera6e76d72022-02-11 21:43:505386 # This checks verifies that the ICU syntax of messages this CL touched is
5387 # valid, and reports any found syntax errors.
5388 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5389 # without developers being aware of them. Later on, such ICU syntax errors
5390 # break message extraction for translation, hence would block Chromium
5391 # translations until they are fixed.
5392 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145393
Sam Maiera6e76d72022-02-11 21:43:505394 def _CheckScreenshotAdded(screenshots_dir, message_id):
5395 sha1_path = input_api.os_path.join(screenshots_dir,
5396 message_id + '.png.sha1')
5397 if sha1_path not in new_or_added_paths:
5398 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145399
Sam Maiera6e76d72022-02-11 21:43:505400 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5401 sha1_path = input_api.os_path.join(screenshots_dir,
5402 message_id + '.png.sha1')
5403 if input_api.os_path.exists(
5404 sha1_path) and sha1_path not in removed_paths:
5405 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145406
Sam Maiera6e76d72022-02-11 21:43:505407 def _ValidateIcuSyntax(text, level, signatures):
5408 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145409
Sam Maiera6e76d72022-02-11 21:43:505410 Check if text looks similar to ICU and checks for ICU syntax correctness
5411 in this case. Reports various issues with ICU syntax and values of
5412 variants. Supports checking of nested messages. Accumulate information of
5413 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265414
Sam Maiera6e76d72022-02-11 21:43:505415 Args:
5416 text: a string to check.
5417 level: a number of current nesting level.
5418 signatures: an accumulator, a list of tuple of (level, variable,
5419 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265420
Sam Maiera6e76d72022-02-11 21:43:505421 Returns:
5422 None if a string is not ICU or no issue detected.
5423 A tuple of (message, start index, end index) if an issue detected.
5424 """
5425 valid_types = {
5426 'plural': (frozenset(
5427 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5428 'other']), frozenset(['=1', 'other'])),
5429 'selectordinal': (frozenset(
5430 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5431 'other']), frozenset(['one', 'other'])),
5432 'select': (frozenset(), frozenset(['other'])),
5433 }
Rainhard Findlingfc31844c52020-05-15 09:58:265434
Sam Maiera6e76d72022-02-11 21:43:505435 # Check if the message looks like an attempt to use ICU
5436 # plural. If yes - check if its syntax strictly matches ICU format.
5437 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5438 text)
5439 if not like:
5440 signatures.append((level, None, None, None))
5441 return
Rainhard Findlingfc31844c52020-05-15 09:58:265442
Sam Maiera6e76d72022-02-11 21:43:505443 # Check for valid prefix and suffix
5444 m = re.match(
5445 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5446 r'(plural|selectordinal|select),\s*'
5447 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5448 if not m:
5449 return (('This message looks like an ICU plural, '
5450 'but does not follow ICU syntax.'), like.start(),
5451 like.end())
5452 starting, variable, kind, variant_pairs = m.groups()
5453 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5454 m.start(4))
5455 if depth:
5456 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5457 len(text))
5458 first = text[0]
5459 ending = text[last_pos:]
5460 if not starting:
5461 return ('Invalid ICU format. No initial opening bracket',
5462 last_pos - 1, last_pos)
5463 if not ending or '}' not in ending:
5464 return ('Invalid ICU format. No final closing bracket',
5465 last_pos - 1, last_pos)
5466 elif first != '{':
5467 return ((
5468 'Invalid ICU format. Extra characters at the start of a complex '
5469 'message (go/icu-message-migration): "%s"') % starting, 0,
5470 len(starting))
5471 elif ending != '}':
5472 return ((
5473 'Invalid ICU format. Extra characters at the end of a complex '
5474 'message (go/icu-message-migration): "%s"') % ending,
5475 last_pos - 1, len(text) - 1)
5476 if kind not in valid_types:
5477 return (('Unknown ICU message type %s. '
5478 'Valid types are: plural, select, selectordinal') % kind,
5479 0, 0)
5480 known, required = valid_types[kind]
5481 defined_variants = set()
5482 for variant, variant_range, value, value_range in variants:
5483 start, end = variant_range
5484 if variant in defined_variants:
5485 return ('Variant "%s" is defined more than once' % variant,
5486 start, end)
5487 elif known and variant not in known:
5488 return ('Variant "%s" is not valid for %s message' %
5489 (variant, kind), start, end)
5490 defined_variants.add(variant)
5491 # Check for nested structure
5492 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5493 if res:
5494 return (res[0], res[1] + value_range[0] + 1,
5495 res[2] + value_range[0] + 1)
5496 missing = required - defined_variants
5497 if missing:
5498 return ('Required variants missing: %s' % ', '.join(missing), 0,
5499 len(text))
5500 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265501
Sam Maiera6e76d72022-02-11 21:43:505502 def _ParseIcuVariants(text, offset=0):
5503 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265504
Sam Maiera6e76d72022-02-11 21:43:505505 Builds a tuple of variant names and values, as well as
5506 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265507
Sam Maiera6e76d72022-02-11 21:43:505508 Args:
5509 text: a string to parse
5510 offset: additional offset to add to positions in the text to get correct
5511 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265512
Sam Maiera6e76d72022-02-11 21:43:505513 Returns:
5514 List of tuples, each tuple consist of four fields: variant name,
5515 variant name span (tuple of two integers), variant value, value
5516 span (tuple of two integers).
5517 """
5518 depth, start, end = 0, -1, -1
5519 variants = []
5520 key = None
5521 for idx, char in enumerate(text):
5522 if char == '{':
5523 if not depth:
5524 start = idx
5525 chunk = text[end + 1:start]
5526 key = chunk.strip()
5527 pos = offset + end + 1 + chunk.find(key)
5528 span = (pos, pos + len(key))
5529 depth += 1
5530 elif char == '}':
5531 if not depth:
5532 return variants, depth, offset + idx
5533 depth -= 1
5534 if not depth:
5535 end = idx
5536 variants.append((key, span, text[start:end + 1],
5537 (offset + start, offset + end + 1)))
5538 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265539
Sam Maiera6e76d72022-02-11 21:43:505540 try:
5541 old_sys_path = sys.path
5542 sys.path = sys.path + [
5543 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5544 'translation')
5545 ]
5546 from helper import grd_helper
5547 finally:
5548 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265549
Sam Maiera6e76d72022-02-11 21:43:505550 for f in affected_grds:
5551 file_path = f.LocalPath()
5552 old_id_to_msg_map = {}
5553 new_id_to_msg_map = {}
5554 # Note that this code doesn't check if the file has been deleted. This is
5555 # OK because it only uses the old and new file contents and doesn't load
5556 # the file via its path.
5557 # It's also possible that a file's content refers to a renamed or deleted
5558 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5559 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5560 # .grdp files.
5561 if file_path.endswith('.grdp'):
5562 if f.OldContents():
5563 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5564 '\n'.join(f.OldContents()))
5565 if f.NewContents():
5566 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5567 '\n'.join(f.NewContents()))
5568 else:
5569 file_dir = input_api.os_path.dirname(file_path) or '.'
5570 if f.OldContents():
5571 old_id_to_msg_map = grd_helper.GetGrdMessages(
5572 StringIO('\n'.join(f.OldContents())), file_dir)
5573 if f.NewContents():
5574 new_id_to_msg_map = grd_helper.GetGrdMessages(
5575 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265576
Sam Maiera6e76d72022-02-11 21:43:505577 grd_name, ext = input_api.os_path.splitext(
5578 input_api.os_path.basename(file_path))
5579 screenshots_dir = input_api.os_path.join(
5580 input_api.os_path.dirname(file_path),
5581 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265582
Sam Maiera6e76d72022-02-11 21:43:505583 # Compute added, removed and modified message IDs.
5584 old_ids = set(old_id_to_msg_map)
5585 new_ids = set(new_id_to_msg_map)
5586 added_ids = new_ids - old_ids
5587 removed_ids = old_ids - new_ids
5588 modified_ids = set([])
5589 for key in old_ids.intersection(new_ids):
5590 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5591 new_id_to_msg_map[key].ContentsAsXml('', True)):
5592 # The message content itself changed. Require an updated screenshot.
5593 modified_ids.add(key)
5594 elif old_id_to_msg_map[key].attrs['meaning'] != \
5595 new_id_to_msg_map[key].attrs['meaning']:
5596 # The message meaning changed. Ensure there is a screenshot for it.
5597 sha1_path = input_api.os_path.join(screenshots_dir,
5598 key + '.png.sha1')
5599 if sha1_path not in new_or_added_paths and not \
5600 input_api.os_path.exists(sha1_path):
5601 # There is neither a previous screenshot nor is a new one added now.
5602 # Require a screenshot.
5603 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145604
Sam Maiera6e76d72022-02-11 21:43:505605 if run_screenshot_check:
5606 # Check the screenshot directory for .png files. Warn if there is any.
5607 for png_path in affected_png_paths:
5608 if png_path.startswith(screenshots_dir):
5609 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145610
Sam Maiera6e76d72022-02-11 21:43:505611 for added_id in added_ids:
5612 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095613
Sam Maiera6e76d72022-02-11 21:43:505614 for modified_id in modified_ids:
5615 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145616
Sam Maiera6e76d72022-02-11 21:43:505617 for removed_id in removed_ids:
5618 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5619
5620 # Check new and changed strings for ICU syntax errors.
5621 for key in added_ids.union(modified_ids):
5622 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5623 err = _ValidateIcuSyntax(msg, 0, [])
5624 if err is not None:
5625 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5626
5627 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265628 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505629 if unnecessary_screenshots:
5630 results.append(
5631 output_api.PresubmitError(
5632 'Do not include actual screenshots in the changelist. Run '
5633 'tools/translate/upload_screenshots.py to upload them instead:',
5634 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145635
Sam Maiera6e76d72022-02-11 21:43:505636 if missing_sha1:
5637 results.append(
5638 output_api.PresubmitError(
5639 'You are adding or modifying UI strings.\n'
5640 'To ensure the best translations, take screenshots of the relevant UI '
5641 '(https://g.co/chrome/translation) and add these files to your '
5642 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145643
Sam Maiera6e76d72022-02-11 21:43:505644 if unnecessary_sha1_files:
5645 results.append(
5646 output_api.PresubmitError(
5647 'You removed strings associated with these files. Remove:',
5648 sorted(unnecessary_sha1_files)))
5649 else:
5650 results.append(
5651 output_api.PresubmitPromptOrNotify('Skipping translation '
5652 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145653
Sam Maiera6e76d72022-02-11 21:43:505654 if icu_syntax_errors:
5655 results.append(
5656 output_api.PresubmitPromptWarning(
5657 'ICU syntax errors were found in the following strings (problems or '
5658 'feedback? Contact rainhard@chromium.org):',
5659 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265660
Sam Maiera6e76d72022-02-11 21:43:505661 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125662
5663
Saagar Sanghavifceeaae2020-08-12 16:40:365664def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125665 repo_root=None,
5666 translation_expectations_path=None,
5667 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505668 import sys
5669 affected_grds = [
5670 f for f in input_api.AffectedFiles()
5671 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5672 ]
5673 if not affected_grds:
5674 return []
5675
5676 try:
5677 old_sys_path = sys.path
5678 sys.path = sys.path + [
5679 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5680 'translation')
5681 ]
5682 from helper import git_helper
5683 from helper import translation_helper
5684 finally:
5685 sys.path = old_sys_path
5686
5687 # Check that translation expectations can be parsed and we can get a list of
5688 # translatable grd files. |repo_root| and |translation_expectations_path| are
5689 # only passed by tests.
5690 if not repo_root:
5691 repo_root = input_api.PresubmitLocalPath()
5692 if not translation_expectations_path:
5693 translation_expectations_path = input_api.os_path.join(
5694 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5695 if not grd_files:
5696 grd_files = git_helper.list_grds_in_repository(repo_root)
5697
5698 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:595699 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:505700 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
5701 'tests')
5702 grd_files = [p for p in grd_files if ignore_path not in p]
5703
5704 try:
5705 translation_helper.get_translatable_grds(
5706 repo_root, grd_files, translation_expectations_path)
5707 except Exception as e:
5708 return [
5709 output_api.PresubmitNotifyResult(
5710 'Failed to get a list of translatable grd files. This happens when:\n'
5711 ' - One of the modified grd or grdp files cannot be parsed or\n'
5712 ' - %s is not updated.\n'
5713 'Stack:\n%s' % (translation_expectations_path, str(e)))
5714 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:125715 return []
5716
Ken Rockotc31f4832020-05-29 18:58:515717
Saagar Sanghavifceeaae2020-08-12 16:40:365718def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505719 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5720 changed_mojoms = input_api.AffectedFiles(
5721 include_deletes=True,
5722 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525723
Bruce Dawson344ab262022-06-04 11:35:105724 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:505725 return []
5726
5727 delta = []
5728 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:505729 delta.append({
5730 'filename': mojom.LocalPath(),
5731 'old': '\n'.join(mojom.OldContents()) or None,
5732 'new': '\n'.join(mojom.NewContents()) or None,
5733 })
5734
5735 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:215736 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:505737 input_api.os_path.join(
5738 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
5739 'check_stable_mojom_compatibility.py'), '--src-root',
5740 input_api.PresubmitLocalPath()
5741 ],
5742 stdin=input_api.subprocess.PIPE,
5743 stdout=input_api.subprocess.PIPE,
5744 stderr=input_api.subprocess.PIPE,
5745 universal_newlines=True)
5746 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5747 if process.returncode:
5748 return [
5749 output_api.PresubmitError(
5750 'One or more [Stable] mojom definitions appears to have been changed '
5751 'in a way that is not backward-compatible.',
5752 long_text=error)
5753 ]
Erik Staabc734cd7a2021-11-23 03:11:525754 return []
5755
Dominic Battre645d42342020-12-04 16:14:105756def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505757 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:105758
Sam Maiera6e76d72022-02-11 21:43:505759 def FilterFile(affected_file):
5760 """Accept only .cc files and the like."""
5761 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5762 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5763 input_api.DEFAULT_FILES_TO_SKIP)
5764 return input_api.FilterSourceFile(
5765 affected_file,
5766 files_to_check=file_inclusion_pattern,
5767 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:105768
Sam Maiera6e76d72022-02-11 21:43:505769 def ModifiedLines(affected_file):
5770 """Returns a list of tuples (line number, line text) of added and removed
5771 lines.
Dominic Battre645d42342020-12-04 16:14:105772
Sam Maiera6e76d72022-02-11 21:43:505773 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:105774
Sam Maiera6e76d72022-02-11 21:43:505775 This relies on the scm diff output describing each changed code section
5776 with a line of the form
Dominic Battre645d42342020-12-04 16:14:105777
Sam Maiera6e76d72022-02-11 21:43:505778 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5779 """
5780 line_num = 0
5781 modified_lines = []
5782 for line in affected_file.GenerateScmDiff().splitlines():
5783 # Extract <new line num> of the patch fragment (see format above).
5784 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
5785 line)
5786 if m:
5787 line_num = int(m.groups(1)[0])
5788 continue
5789 if ((line.startswith('+') and not line.startswith('++'))
5790 or (line.startswith('-') and not line.startswith('--'))):
5791 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:105792
Sam Maiera6e76d72022-02-11 21:43:505793 if not line.startswith('-'):
5794 line_num += 1
5795 return modified_lines
Dominic Battre645d42342020-12-04 16:14:105796
Sam Maiera6e76d72022-02-11 21:43:505797 def FindLineWith(lines, needle):
5798 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:105799
Sam Maiera6e76d72022-02-11 21:43:505800 If 0 or >1 lines contain `needle`, -1 is returned.
5801 """
5802 matching_line_numbers = [
5803 # + 1 for 1-based counting of line numbers.
5804 i + 1 for i, line in enumerate(lines) if needle in line
5805 ]
5806 return matching_line_numbers[0] if len(
5807 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:105808
Sam Maiera6e76d72022-02-11 21:43:505809 def ModifiedPrefMigration(affected_file):
5810 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5811 # Determine first and last lines of MigrateObsolete.*Pref functions.
5812 new_contents = affected_file.NewContents()
5813 range_1 = (FindLineWith(new_contents,
5814 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5815 FindLineWith(new_contents,
5816 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5817 range_2 = (FindLineWith(new_contents,
5818 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5819 FindLineWith(new_contents,
5820 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5821 if (-1 in range_1 + range_2):
5822 raise Exception(
5823 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
5824 )
Dominic Battre645d42342020-12-04 16:14:105825
Sam Maiera6e76d72022-02-11 21:43:505826 # Check whether any of the modified lines are part of the
5827 # MigrateObsolete.*Pref functions.
5828 for line_nr, line in ModifiedLines(affected_file):
5829 if (range_1[0] <= line_nr <= range_1[1]
5830 or range_2[0] <= line_nr <= range_2[1]):
5831 return True
5832 return False
Dominic Battre645d42342020-12-04 16:14:105833
Sam Maiera6e76d72022-02-11 21:43:505834 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5835 browser_prefs_file_pattern = input_api.re.compile(
5836 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:105837
Sam Maiera6e76d72022-02-11 21:43:505838 changes = input_api.AffectedFiles(include_deletes=True,
5839 file_filter=FilterFile)
5840 potential_problems = []
5841 for f in changes:
5842 for line in f.GenerateScmDiff().splitlines():
5843 # Check deleted lines for pref registrations.
5844 if (line.startswith('-') and not line.startswith('--')
5845 and register_pref_pattern.search(line)):
5846 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:105847
Sam Maiera6e76d72022-02-11 21:43:505848 if browser_prefs_file_pattern.search(f.LocalPath()):
5849 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5850 # assume that they knew that they have to deprecate preferences and don't
5851 # warn.
5852 try:
5853 if ModifiedPrefMigration(f):
5854 return []
5855 except Exception as e:
5856 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:105857
Sam Maiera6e76d72022-02-11 21:43:505858 if potential_problems:
5859 return [
5860 output_api.PresubmitPromptWarning(
5861 'Discovered possible removal of preference registrations.\n\n'
5862 'Please make sure to properly deprecate preferences by clearing their\n'
5863 'value for a couple of milestones before finally removing the code.\n'
5864 'Otherwise data may stay in the preferences files forever. See\n'
5865 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5866 'chrome/browser/prefs/README.md for examples.\n'
5867 'This may be a false positive warning (e.g. if you move preference\n'
5868 'registrations to a different place).\n', potential_problems)
5869 ]
5870 return []
5871
Matt Stark6ef08872021-07-29 01:21:465872
5873def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505874 """Changes to GRD files must be consistent for tools to read them."""
5875 changed_grds = input_api.AffectedFiles(
5876 include_deletes=False,
5877 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5878 errors = []
5879 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5880 for matcher, msg in _INVALID_GRD_FILE_LINE]
5881 for grd in changed_grds:
5882 for i, line in enumerate(grd.NewContents()):
5883 for matcher, msg in invalid_file_regexes:
5884 if matcher.search(line):
5885 errors.append(
5886 output_api.PresubmitError(
5887 'Problem on {grd}:{i} - {msg}'.format(
5888 grd=grd.LocalPath(), i=i + 1, msg=msg)))
5889 return errors
5890
Kevin McNee967dd2d22021-11-15 16:09:295891
5892def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505893 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5894 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5895 """
Kevin McNee967dd2d22021-11-15 16:09:295896
Ian Vollickdba956c2022-04-20 23:53:455897 # Only consider top-level directories that (1) can use content APIs or
5898 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
5899 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:505900 files_to_check = (
Ian Vollickdba956c2022-04-20 23:53:455901 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Kevin McNee967dd2d22021-11-15 16:09:295902 _IMPLEMENTATION_EXTENSIONS,
Ian Vollickdba956c2022-04-20 23:53:455903 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Sam Maiera6e76d72022-02-11 21:43:505904 _HEADER_EXTENSIONS,
5905 )
5906 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5907 input_api.DEFAULT_FILES_TO_SKIP)
5908 source_file_filter = lambda f: input_api.FilterSourceFile(
5909 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:295910
Kevin McNee29c0e8232022-08-05 15:36:095911 # Here we list the classes/methods we're monitoring. For the "fyi" cases,
5912 # we add the CL to the watchlist, but we don't omit a warning or have it be
5913 # included in the triage rotation.
Sam Maiera6e76d72022-02-11 21:43:505914 # Note that since these are are just regular expressions and we don't have
5915 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5916 # could have a method named IsInMainFrame).
Kevin McNee29c0e8232022-08-05 15:36:095917 fyi_concerning_class_pattern = input_api.re.compile(
Sam Maiera6e76d72022-02-11 21:43:505918 r'WebContentsObserver|WebContentsUserData')
5919 # A subset of WebContentsObserver overrides where there's particular risk for
5920 # confusing tab and page level operations and data (e.g. incorrectly
5921 # resetting page state in DidFinishNavigation).
Kevin McNee29c0e8232022-08-05 15:36:095922 fyi_concerning_wco_methods = [
Sam Maiera6e76d72022-02-11 21:43:505923 'DidStartNavigation',
5924 'ReadyToCommitNavigation',
5925 'DidFinishNavigation',
5926 'RenderViewReady',
5927 'RenderViewDeleted',
5928 'RenderViewHostChanged',
Sam Maiera6e76d72022-02-11 21:43:505929 'DOMContentLoaded',
5930 'DidFinishLoad',
5931 ]
5932 concerning_nav_handle_methods = [
5933 'IsInMainFrame',
5934 ]
5935 concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:505936 'FromRenderFrameHost',
5937 'FromRenderViewHost',
Kevin McNee29c0e8232022-08-05 15:36:095938 ]
5939 fyi_concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:505940 'GetRenderViewHost',
5941 ]
5942 concerning_rfh_methods = [
5943 'GetParent',
5944 'GetMainFrame',
Kevin McNee29c0e8232022-08-05 15:36:095945 ]
5946 fyi_concerning_rfh_methods = [
Sam Maiera6e76d72022-02-11 21:43:505947 'GetFrameTreeNodeId',
5948 ]
Ian Vollickc825b1f2022-04-19 14:30:155949 concerning_rfhi_methods = [
5950 'is_main_frame',
5951 ]
Ian Vollicka77a73ea2022-04-06 18:08:015952 concerning_ftn_methods = [
5953 'IsMainFrame',
5954 ]
Ian Vollickdba956c2022-04-20 23:53:455955 concerning_blink_frame_methods = [
Ian Vollick4d785d22022-06-18 00:10:025956 'IsCrossOriginToNearestMainFrame',
Ian Vollickdba956c2022-04-20 23:53:455957 ]
Sam Maiera6e76d72022-02-11 21:43:505958 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5959 item for sublist in [
Kevin McNee29c0e8232022-08-05 15:36:095960 concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:015961 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:155962 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:455963 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:505964 ] for item in sublist) + r')\(')
Kevin McNee29c0e8232022-08-05 15:36:095965 fyi_concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5966 item for sublist in [
5967 fyi_concerning_wco_methods, fyi_concerning_web_contents_methods,
5968 fyi_concerning_rfh_methods,
5969 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:295970
Kevin McNee4eeec792022-02-14 20:02:045971 used_apis = set()
Kevin McNee29c0e8232022-08-05 15:36:095972 used_fyi_methods = False
Sam Maiera6e76d72022-02-11 21:43:505973 for f in input_api.AffectedFiles(include_deletes=False,
5974 file_filter=source_file_filter):
5975 for line_num, line in f.ChangedContents():
Kevin McNee29c0e8232022-08-05 15:36:095976 fyi_class_match = fyi_concerning_class_pattern.search(line)
5977 if fyi_class_match:
5978 used_fyi_methods = True
5979 fyi_method_match = fyi_concerning_method_pattern.search(line)
5980 if fyi_method_match:
5981 used_fyi_methods = True
Kevin McNee4eeec792022-02-14 20:02:045982 method_match = concerning_method_pattern.search(line)
5983 if method_match:
5984 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:505985
Kevin McNee4eeec792022-02-14 20:02:045986 if not used_apis:
Kevin McNee29c0e8232022-08-05 15:36:095987 if used_fyi_methods:
5988 output_api.AppendCC('mparch-reviews+watchfyi@chromium.org')
5989
Kevin McNee4eeec792022-02-14 20:02:045990 return []
Kevin McNee967dd2d22021-11-15 16:09:295991
Kevin McNee4eeec792022-02-14 20:02:045992 output_api.AppendCC('mparch-reviews+watch@chromium.org')
5993 message = ('This change uses API(s) that are ambiguous in the presence of '
5994 'MPArch features such as bfcache, prerendering, and fenced '
5995 'frames.')
Kevin McNee29c0e8232022-08-05 15:36:095996 explanation = (
Kevin McNee4eeec792022-02-14 20:02:045997 'Please double check whether new code assumes that a WebContents only '
Kevin McNee29c0e8232022-08-05 15:36:095998 'contains a single page at a time. Notably, checking whether a frame '
5999 'is the \"main frame\" is not specific enough to determine whether it '
6000 'corresponds to the document reflected in the omnibox. A WebContents '
6001 'may have additional main frames for prerendered pages, bfcached '
6002 'pages, fenced frames, etc. '
6003 'See this doc [1] and the comments on the individual APIs '
Kevin McNee4eeec792022-02-14 20:02:046004 'for guidance and this doc [2] for context. The MPArch review '
6005 'watchlist has been CC\'d on this change to help identify any issues.\n'
6006 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
6007 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
6008 )
6009 return [
6010 output_api.PresubmitNotifyResult(message,
6011 items=list(used_apis),
Kevin McNee29c0e8232022-08-05 15:36:096012 long_text=explanation)
Kevin McNee4eeec792022-02-14 20:02:046013 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:366014
6015
6016def CheckAssertAshOnlyCode(input_api, output_api):
6017 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6018 assert(is_chromeos_ash).
6019 """
6020
6021 def FileFilter(affected_file):
6022 """Includes directories known to be Ash only."""
6023 return input_api.FilterSourceFile(
6024 affected_file,
6025 files_to_check=(
6026 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6027 r'.*/ash/.*BUILD\.gn'), # Any path component.
6028 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6029
6030 errors = []
6031 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566032 for f in input_api.AffectedFiles(include_deletes=False,
6033 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366034 if (not pattern.search(input_api.ReadFile(f))):
6035 errors.append(
6036 output_api.PresubmitError(
6037 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6038 'possible, please create and issue and add a comment such '
6039 'as:\n # TODO(https://crbug.com/XXX): add '
6040 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6041 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276042
6043
6044def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506045 path = affected_file.LocalPath()
6046 if not _IsCPlusPlusFile(input_api, path):
6047 return False
6048
6049 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6050 if "/renderer/" in path:
6051 return True
6052
6053 # Blink's public/web API is only used/included by Renderer-only code. Note
6054 # that public/platform API may be used in non-Renderer processes (e.g. there
6055 # are some includes in code used by Utility, PDF, or Plugin processes).
6056 if "/blink/public/web/" in path:
6057 return True
6058
6059 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276060 return False
6061
Lukasz Anforowicz7016d05e2021-11-30 03:56:276062# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6063# by the Chromium Clang Plugin (which will be preferable because it will
6064# 1) report errors earlier - at compile-time and 2) cover more rules).
6065def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506066 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6067 errors = []
6068 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6069 # C++ comment.
6070 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6071 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6072 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6073 if raw_ptr_matcher.search(line):
6074 errors.append(
6075 output_api.PresubmitError(
6076 'Problem on {path}:{line} - '\
6077 'raw_ptr<T> should not be used in Renderer-only code '\
6078 '(as documented in the "Pointers to unprotected memory" '\
6079 'section in //base/memory/raw_ptr.md)'.format(
6080 path=f.LocalPath(), line=line_num)))
6081 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566082
6083
6084def CheckPythonShebang(input_api, output_api):
6085 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6086 system-wide python.
6087 """
6088 errors = []
6089 sources = lambda affected_file: input_api.FilterSourceFile(
6090 affected_file,
6091 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6092 r'third_party/blink/web_tests/external/') + input_api.
6093 DEFAULT_FILES_TO_SKIP),
6094 files_to_check=[r'.*\.py$'])
6095 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276096 for line_num, line in f.ChangedContents():
6097 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6098 errors.append(f.LocalPath())
6099 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566100
6101 result = []
6102 for file in errors:
6103 result.append(
6104 output_api.PresubmitError(
6105 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6106 file))
6107 return result
James Shen81cc0e22022-06-15 21:10:456108
6109
6110def CheckBatchAnnotation(input_api, output_api):
6111 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6112 is not an instrumentation test, disregard."""
6113
6114 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6115 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6116 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6117 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6118 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6119
ckitagawae8fd23b2022-06-17 15:29:386120 missing_annotation_errors = []
6121 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456122
6123 def _FilterFile(affected_file):
6124 return input_api.FilterSourceFile(
6125 affected_file,
6126 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6127 files_to_check=[r'.*Test\.java$'])
6128
6129 for f in input_api.AffectedSourceFiles(_FilterFile):
6130 batch_matched = None
6131 do_not_batch_matched = None
6132 is_instrumentation_test = True
6133 for line in f.NewContents():
6134 if robolectric_test.search(line) or uiautomator_test.search(line):
6135 # Skip Robolectric and UiAutomator tests.
6136 is_instrumentation_test = False
6137 break
6138 if not batch_matched:
6139 batch_matched = batch_annotation.search(line)
6140 if not do_not_batch_matched:
6141 do_not_batch_matched = do_not_batch_annotation.search(line)
6142 test_class_declaration_matched = test_class_declaration.search(
6143 line)
6144 if test_class_declaration_matched:
6145 break
6146 if (is_instrumentation_test and
6147 not batch_matched and
6148 not do_not_batch_matched):
ckitagawae8fd23b2022-06-17 15:29:386149 missing_annotation_errors.append(str(f.LocalPath()))
6150 if (not is_instrumentation_test and
6151 (batch_matched or
6152 do_not_batch_matched)):
6153 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456154
6155 results = []
6156
ckitagawae8fd23b2022-06-17 15:29:386157 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456158 results.append(
6159 output_api.PresubmitPromptWarning(
6160 """
6161Instrumentation tests should use either @Batch or @DoNotBatch. If tests are not
6162safe to run in batch, please use @DoNotBatch with reasons.
ckitagawae8fd23b2022-06-17 15:29:386163""", missing_annotation_errors))
6164 if extra_annotation_errors:
6165 results.append(
6166 output_api.PresubmitPromptWarning(
6167 """
6168Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6169""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456170
6171 return results