blob: 0f21adf9b85ed426043376a0ec2f179300a66c2e [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
11from typing import Optional
12from typing import Sequence
13from dataclasses import dataclass
14
Saagar Sanghavifceeaae2020-08-12 16:40:3615PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1216
Dirk Prankee3c9c62d2021-05-18 18:35:5917# This line is 'magic' in that git-cl looks for it to decide whether to
18# use Python3 instead of Python2 when running the code in this file.
19USE_PYTHON3 = True
20
[email protected]379e7dd2010-01-28 17:39:2121_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1822 # Generated file
23 (r'chrome[\\/]android[\\/]webapk[\\/]shell_apk[\\/]src[\\/]org[\\/]chromium'
24 r'[\\/]webapk[\\/]lib[\\/]runtime_library[\\/]IWebApkApi.java'),
Mila Greene3aa7222021-09-07 16:34:0825 # File needs to write to stdout to emulate a tool it's replacing.
Mila Greend3fc6a42021-09-10 17:38:2326 r"chrome[\\/]updater[\\/]mac[\\/]keystone[\\/]ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4727 # Generated file.
28 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2629 r"client_variations.js"),
Mila Greene3aa7222021-09-07 16:34:0830 r"^native_client_sdksrc[\\/]build_tools[\\/]make_rules.py",
Egor Paskoce145c42018-09-28 19:31:0431 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
32 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
33 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
34 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4935 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0436 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4637 # sqlite is an imported third party dependency.
38 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0439 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5440 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5341 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1242 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0443 r".+[\\/]pnacl_shim\.c$",
44 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0445 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1446 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0447 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5448 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0449 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4050)
[email protected]ca8d1982009-02-19 16:33:1251
John Abd-El-Malek759fea62021-03-13 03:41:1452_EXCLUDED_SET_NO_PARENT_PATHS = (
53 # It's for historical reasons that blink isn't a top level directory, where
54 # it would be allowed to have "set noparent" to avoid top level owners
55 # accidentally +1ing changes.
56 'third_party/blink/OWNERS',
57)
58
wnwenbdc444e2016-05-25 13:44:1559
[email protected]06e6d0ff2012-12-11 01:36:4460# Fragment of a regular expression that matches C++ and Objective-C++
61# implementation files.
62_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
63
wnwenbdc444e2016-05-25 13:44:1564
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1965# Fragment of a regular expression that matches C++ and Objective-C++
66# header files.
67_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
68
69
[email protected]06e6d0ff2012-12-11 01:36:4470# Regular expression that matches code only used for test binaries
71# (best effort).
72_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0473 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4474 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1375 # Test suite files, like:
76 # foo_browsertest.cc
77 # bar_unittest_mac.cc (suffix)
78 # baz_unittests.cc (plural)
79 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1280 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1881 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2182 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0483 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4384 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0485 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4386 # Web test harness.
87 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4788 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0489 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0890 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0491 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4192 # EarlGrey app side code for tests.
93 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1794 # Views Examples code
95 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4196 # Chromium Codelab
97 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4498)
[email protected]ca8d1982009-02-19 16:33:1299
Daniel Bratell609102be2019-03-27 20:53:21100_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15101
[email protected]eea609a2011-11-18 13:10:12102_TEST_ONLY_WARNING = (
103 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55104 'production code. If you are doing this from inside another method\n'
105 'named as *ForTesting(), then consider exposing things to have tests\n'
106 'make that same call directly.\n'
107 'If that is not possible, you may put a comment on the same line with\n'
108 ' // IN-TEST \n'
109 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
110 'method and can be ignored. Do not do this inside production code.\n'
111 'The android-binary-size trybot will block if the method exists in the\n'
112 'release apk.')
[email protected]eea609a2011-11-18 13:10:12113
114
Daniel Chenga44a1bcd2022-03-15 20:00:15115@dataclass
116class BanRule:
117 # String pattern. If the pattern begins with a slash, the pattern will be
118 # treated as a regular expression instead.
119 pattern: str
120 # Explanation as a sequence of strings. Each string in the sequence will be
121 # printed on its own line.
122 explanation: Sequence[str]
123 # Whether or not to treat this ban as a fatal error. If unspecified, defaults
124 # to true.
125 treat_as_error: Optional[bool] = None
126 # Paths that should be excluded from the ban check. Each string is a regular
127 # expression that will be matched against the path of the file being checked
128 # relative to the root of the source tree.
129 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28130
Daniel Chenga44a1bcd2022-03-15 20:00:15131
Daniel Cheng917ce542022-03-15 20:46:57132_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15133 BanRule(
134 'import java.net.URI;',
135 (
136 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
137 ),
138 excluded_paths=(
139 (r'net/android/javatests/src/org/chromium/net/'
140 'AndroidProxySelectorTest\.java'),
141 r'components/cronet/',
142 r'third_party/robolectric/local/',
143 ),
Michael Thiessen44457642020-02-06 00:24:15144 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15145 BanRule(
146 'import android.annotation.TargetApi;',
147 (
148 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
149 'RequiresApi ensures that any calls are guarded by the appropriate '
150 'SDK_INT check. See https://crbug.com/1116486.',
151 ),
152 ),
153 BanRule(
154 'import android.support.test.rule.UiThreadTestRule;',
155 (
156 'Do not use UiThreadTestRule, just use '
157 '@org.chromium.base.test.UiThreadTest on test methods that should run '
158 'on the UI thread. See https://crbug.com/1111893.',
159 ),
160 ),
161 BanRule(
162 'import android.support.test.annotation.UiThreadTest;',
163 ('Do not use android.support.test.annotation.UiThreadTest, use '
164 'org.chromium.base.test.UiThreadTest instead. See '
165 'https://crbug.com/1111893.',
166 ),
167 ),
168 BanRule(
169 'import android.support.test.rule.ActivityTestRule;',
170 (
171 'Do not use ActivityTestRule, use '
172 'org.chromium.base.test.BaseActivityTestRule instead.',
173 ),
174 excluded_paths=(
175 'components/cronet/',
176 ),
177 ),
178)
wnwenbdc444e2016-05-25 13:44:15179
Daniel Cheng917ce542022-03-15 20:46:57180_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15181 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41182 'StrictMode.allowThreadDiskReads()',
183 (
184 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
185 'directly.',
186 ),
187 False,
188 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15189 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41190 'StrictMode.allowThreadDiskWrites()',
191 (
192 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
193 'directly.',
194 ),
195 False,
196 ),
Daniel Cheng917ce542022-03-15 20:46:57197 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36198 '.waitForIdleSync()',
199 (
200 'Do not use waitForIdleSync as it masks underlying issues. There is '
201 'almost always something else you should wait on instead.',
202 ),
203 False,
204 ),
Eric Stevensona9a980972017-09-23 00:04:41205)
206
Daniel Cheng917ce542022-03-15 20:46:57207_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15208 BanRule(
[email protected]127f18ec2012-06-16 05:05:59209 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20210 (
211 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59212 'prohibited. Please use CrTrackingArea instead.',
213 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
214 ),
215 False,
216 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15217 BanRule(
[email protected]eaae1972014-04-16 04:17:26218 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20219 (
220 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59221 'instead.',
222 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
223 ),
224 False,
225 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15226 BanRule(
[email protected]127f18ec2012-06-16 05:05:59227 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20228 (
229 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59230 'Please use |convertPoint:(point) fromView:nil| instead.',
231 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
232 ),
233 True,
234 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15235 BanRule(
[email protected]127f18ec2012-06-16 05:05:59236 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20237 (
238 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59239 'Please use |convertPoint:(point) toView:nil| instead.',
240 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
241 ),
242 True,
243 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15244 BanRule(
[email protected]127f18ec2012-06-16 05:05:59245 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20246 (
247 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59248 'Please use |convertRect:(point) fromView:nil| instead.',
249 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
250 ),
251 True,
252 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15253 BanRule(
[email protected]127f18ec2012-06-16 05:05:59254 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20255 (
256 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59257 'Please use |convertRect:(point) toView:nil| instead.',
258 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
259 ),
260 True,
261 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15262 BanRule(
[email protected]127f18ec2012-06-16 05:05:59263 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20264 (
265 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59266 'Please use |convertSize:(point) fromView:nil| instead.',
267 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
268 ),
269 True,
270 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15271 BanRule(
[email protected]127f18ec2012-06-16 05:05:59272 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20273 (
274 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59275 'Please use |convertSize:(point) toView:nil| instead.',
276 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
277 ),
278 True,
279 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15280 BanRule(
jif65398702016-10-27 10:19:48281 r"/\s+UTF8String\s*]",
282 (
283 'The use of -[NSString UTF8String] is dangerous as it can return null',
284 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
285 'Please use |SysNSStringToUTF8| instead.',
286 ),
287 True,
288 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15289 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34290 r'__unsafe_unretained',
291 (
292 'The use of __unsafe_unretained is almost certainly wrong, unless',
293 'when interacting with NSFastEnumeration or NSInvocation.',
294 'Please use __weak in files build with ARC, nothing otherwise.',
295 ),
296 False,
297 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15298 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13299 'freeWhenDone:NO',
300 (
301 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
302 'Foundation types is prohibited.',
303 ),
304 True,
305 ),
[email protected]127f18ec2012-06-16 05:05:59306)
307
Sylvain Defresnea8b73d252018-02-28 15:45:54308_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15309 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54310 r'/\bTEST[(]',
311 (
312 'TEST() macro should not be used in Objective-C++ code as it does not ',
313 'drain the autorelease pool at the end of the test. Use TEST_F() ',
314 'macro instead with a fixture inheriting from PlatformTest (or a ',
315 'typedef).'
316 ),
317 True,
318 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15319 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54320 r'/\btesting::Test\b',
321 (
322 'testing::Test should not be used in Objective-C++ code as it does ',
323 'not drain the autorelease pool at the end of the test. Use ',
324 'PlatformTest instead.'
325 ),
326 True,
327 ),
328)
329
Daniel Cheng917ce542022-03-15 20:46:57330_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15331 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05332 r'/\bEXPECT_OCMOCK_VERIFY\b',
333 (
334 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
335 'it is meant for GTests. Use [mock verify] instead.'
336 ),
337 True,
338 ),
339)
340
Daniel Cheng917ce542022-03-15 20:46:57341_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15342 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04343 r'/\busing namespace ',
344 (
345 'Using directives ("using namespace x") are banned by the Google Style',
346 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
347 'Explicitly qualify symbols or use using declarations ("using x::foo").',
348 ),
349 True,
350 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
351 ),
Antonio Gomes07300d02019-03-13 20:59:57352 # Make sure that gtest's FRIEND_TEST() macro is not used; the
353 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
354 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15355 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20356 'FRIEND_TEST(',
357 (
[email protected]e3c945502012-06-26 20:01:49358 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20359 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
360 ),
361 False,
[email protected]7345da02012-11-27 14:31:49362 (),
[email protected]23e6cbc2012-06-16 18:51:20363 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15364 BanRule(
tomhudsone2c14d552016-05-26 17:07:46365 'setMatrixClip',
366 (
367 'Overriding setMatrixClip() is prohibited; ',
368 'the base function is deprecated. ',
369 ),
370 True,
371 (),
372 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15373 BanRule(
[email protected]52657f62013-05-20 05:30:31374 'SkRefPtr',
375 (
376 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22377 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31378 ),
379 True,
380 (),
381 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15382 BanRule(
[email protected]52657f62013-05-20 05:30:31383 'SkAutoRef',
384 (
385 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22386 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31387 ),
388 True,
389 (),
390 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15391 BanRule(
[email protected]52657f62013-05-20 05:30:31392 'SkAutoTUnref',
393 (
394 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22395 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31396 ),
397 True,
398 (),
399 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15400 BanRule(
[email protected]52657f62013-05-20 05:30:31401 'SkAutoUnref',
402 (
403 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
404 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22405 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31406 ),
407 True,
408 (),
409 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15410 BanRule(
[email protected]d89eec82013-12-03 14:10:59411 r'/HANDLE_EINTR\(.*close',
412 (
413 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
414 'descriptor will be closed, and it is incorrect to retry the close.',
415 'Either call close directly and ignore its return value, or wrap close',
416 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
417 ),
418 True,
419 (),
420 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15421 BanRule(
[email protected]d89eec82013-12-03 14:10:59422 r'/IGNORE_EINTR\((?!.*close)',
423 (
424 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
425 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
426 ),
427 True,
428 (
429 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04430 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
431 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59432 ),
433 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15434 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43435 r'/v8::Extension\(',
436 (
437 'Do not introduce new v8::Extensions into the code base, use',
438 'gin::Wrappable instead. See http://crbug.com/334679',
439 ),
440 True,
[email protected]f55c90ee62014-04-12 00:50:03441 (
Egor Paskoce145c42018-09-28 19:31:04442 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03443 ),
[email protected]ec5b3f02014-04-04 18:43:43444 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15445 BanRule(
jame2d1a952016-04-02 00:27:10446 '#pragma comment(lib,',
447 (
448 'Specify libraries to link with in build files and not in the source.',
449 ),
450 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41451 (
tzik3f295992018-12-04 20:32:23452 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04453 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41454 ),
jame2d1a952016-04-02 00:27:10455 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15456 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02457 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59458 (
459 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
460 ),
461 False,
462 (),
463 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15464 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02465 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59466 (
467 'Consider using THREAD_CHECKER macros instead of the class directly.',
468 ),
469 False,
470 (),
471 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15472 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06473 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
474 (
475 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
476 'deprecated (http://crbug.com/634507). Please avoid converting away',
477 'from the Time types in Chromium code, especially if any math is',
478 'being done on time values. For interfacing with platform/library',
479 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
480 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48481 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06482 'other use cases, please contact base/time/OWNERS.',
483 ),
484 False,
485 (),
486 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15487 BanRule(
dbeamb6f4fde2017-06-15 04:03:06488 'CallJavascriptFunctionUnsafe',
489 (
490 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
491 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
492 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
493 ),
494 False,
495 (
Egor Paskoce145c42018-09-28 19:31:04496 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
497 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
498 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06499 ),
500 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15501 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24502 'leveldb::DB::Open',
503 (
504 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
505 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
506 "Chrome's tracing, making their memory usage visible.",
507 ),
508 True,
509 (
510 r'^third_party/leveldatabase/.*\.(cc|h)$',
511 ),
Gabriel Charette0592c3a2017-07-26 12:02:04512 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15513 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08514 'leveldb::NewMemEnv',
515 (
516 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58517 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
518 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08519 ),
520 True,
521 (
522 r'^third_party/leveldatabase/.*\.(cc|h)$',
523 ),
524 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15525 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47526 'RunLoop::QuitCurrent',
527 (
Robert Liao64b7ab22017-08-04 23:03:43528 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
529 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47530 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41531 False,
Gabriel Charetted9839bc2017-07-29 14:17:47532 (),
Gabriel Charettea44975052017-08-21 23:14:04533 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15534 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04535 'base::ScopedMockTimeMessageLoopTaskRunner',
536 (
Gabriel Charette87cc1af2018-04-25 20:52:51537 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11538 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51539 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
540 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
541 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04542 ),
Gabriel Charette87cc1af2018-04-25 20:52:51543 False,
Gabriel Charettea44975052017-08-21 23:14:04544 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57545 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15546 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44547 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57548 (
549 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02550 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57551 ),
552 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16553 # Abseil's benchmarks never linked into chrome.
554 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38555 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15556 BanRule(
Peter Kasting991618a62019-06-17 22:00:09557 r'/\bstd::stoi\b',
558 (
559 'std::stoi uses exceptions to communicate results. ',
560 'Use base::StringToInt() instead.',
561 ),
562 True,
563 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
564 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15565 BanRule(
Peter Kasting991618a62019-06-17 22:00:09566 r'/\bstd::stol\b',
567 (
568 'std::stol uses exceptions to communicate results. ',
569 'Use base::StringToInt() instead.',
570 ),
571 True,
572 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
573 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15574 BanRule(
Peter Kasting991618a62019-06-17 22:00:09575 r'/\bstd::stoul\b',
576 (
577 'std::stoul uses exceptions to communicate results. ',
578 'Use base::StringToUint() instead.',
579 ),
580 True,
581 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
582 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15583 BanRule(
Peter Kasting991618a62019-06-17 22:00:09584 r'/\bstd::stoll\b',
585 (
586 'std::stoll uses exceptions to communicate results. ',
587 'Use base::StringToInt64() instead.',
588 ),
589 True,
590 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
591 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15592 BanRule(
Peter Kasting991618a62019-06-17 22:00:09593 r'/\bstd::stoull\b',
594 (
595 'std::stoull uses exceptions to communicate results. ',
596 'Use base::StringToUint64() instead.',
597 ),
598 True,
599 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
600 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15601 BanRule(
Peter Kasting991618a62019-06-17 22:00:09602 r'/\bstd::stof\b',
603 (
604 'std::stof uses exceptions to communicate results. ',
605 'For locale-independent values, e.g. reading numbers from disk',
606 'profiles, use base::StringToDouble().',
607 'For user-visible values, parse using ICU.',
608 ),
609 True,
610 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
611 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15612 BanRule(
Peter Kasting991618a62019-06-17 22:00:09613 r'/\bstd::stod\b',
614 (
615 'std::stod uses exceptions to communicate results. ',
616 'For locale-independent values, e.g. reading numbers from disk',
617 'profiles, use base::StringToDouble().',
618 'For user-visible values, parse using ICU.',
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::stold\b',
625 (
626 'std::stold 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(
Daniel Bratell69334cc2019-03-26 11:07:45635 r'/\bstd::to_string\b',
636 (
637 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09638 'For locale-independent strings, e.g. writing numbers to disk',
639 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45640 'For user-visible strings, use base::FormatNumber() and',
641 'the related functions in base/i18n/number_formatting.h.',
642 ),
Peter Kasting991618a62019-06-17 22:00:09643 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21644 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45645 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15646 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45647 r'/\bstd::shared_ptr\b',
648 (
649 'std::shared_ptr should not be used. Use scoped_refptr instead.',
650 ),
651 True,
Ulan Degenbaev947043882021-02-10 14:02:31652 [
653 # Needed for interop with third-party library.
654 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57655 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58656 '^third_party/blink/renderer/bindings/core/v8/' +
657 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58658 '^gin/array_buffer\.(cc|h)',
659 '^chrome/services/sharing/nearby/',
Meilin Wang00efc7c2021-05-13 01:12:42660 # gRPC provides some C++ libraries that use std::shared_ptr<>.
661 '^chromeos/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59662 '^chromecast/cast_core/grpc',
663 '^chromecast/cast_core/runtime/browser',
Wez5f56be52021-05-04 09:30:58664 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Fabrice de Gans3b875422022-04-19 19:40:26665 '^base/fuchsia/filtered_service_directory\.(cc|h)',
666 '^base/fuchsia/service_directory_test_base\.h',
Wez5f56be52021-05-04 09:30:58667 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57668 # Needed for clang plugin tests
669 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57670 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21671 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15672 BanRule(
Peter Kasting991618a62019-06-17 22:00:09673 r'/\bstd::weak_ptr\b',
674 (
675 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
676 ),
677 True,
678 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
679 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15680 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21681 r'/\blong long\b',
682 (
683 'long long is banned. Use stdint.h if you need a 64 bit number.',
684 ),
685 False, # Only a warning since it is already used.
686 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
687 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15688 BanRule(
Daniel Chengc05fcc62022-01-12 16:54:29689 r'\b(absl|std)::any\b',
690 (
Daniel Chenga44a1bcd2022-03-15 20:00:15691 'absl::any / std::any are not safe to use in a component build.',
Daniel Chengc05fcc62022-01-12 16:54:29692 ),
693 True,
694 # Not an error in third party folders, though it probably should be :)
695 [_THIRD_PARTY_EXCEPT_BLINK],
696 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15697 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21698 r'/\bstd::bind\b',
699 (
700 'std::bind is banned because of lifetime risks.',
701 'Use base::BindOnce or base::BindRepeating instead.',
702 ),
703 True,
704 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
705 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15706 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:03707 r'/\bstd::optional\b',
708 (
709 'std::optional is banned. Use absl::optional instead.',
710 ),
711 True,
712 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
713 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15714 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21715 r'/\b#include <chrono>\b',
716 (
717 '<chrono> overlaps with Time APIs in base. Keep using',
718 'base classes.',
719 ),
720 True,
721 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
722 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15723 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21724 r'/\b#include <exception>\b',
725 (
726 'Exceptions are banned and disabled in Chromium.',
727 ),
728 True,
729 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
730 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15731 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21732 r'/\bstd::function\b',
733 (
Colin Blundellea615d422021-05-12 09:35:41734 'std::function is banned. Instead use base::OnceCallback or ',
735 'base::RepeatingCallback, which directly support Chromium\'s weak ',
736 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21737 ),
Peter Kasting991618a62019-06-17 22:00:09738 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21739 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
740 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15741 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21742 r'/\b#include <random>\b',
743 (
744 'Do not use any random number engines from <random>. Instead',
745 'use base::RandomBitGenerator.',
746 ),
747 True,
748 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
749 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15750 BanRule(
Tom Andersona95e12042020-09-09 23:08:00751 r'/\b#include <X11/',
752 (
753 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
754 ),
755 True,
756 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
757 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15758 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21759 r'/\bstd::ratio\b',
760 (
761 'std::ratio is banned by the Google Style Guide.',
762 ),
763 True,
764 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45765 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15766 BanRule(
Gabriel Charetted90bcc92021-09-21 00:23:10767 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:38768 (
Gabriel Charetted90bcc92021-09-21 00:23:10769 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:38770 ),
Gabriel Charette04b138f2018-08-06 00:03:22771 False,
Francois Doray43670e32017-09-27 12:40:38772 (),
773 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15774 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:58775 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19776 (
777 'RunMessageLoop is deprecated, use RunLoop instead.',
778 ),
779 False,
780 (),
781 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15782 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44783 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19784 (
785 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
786 ),
787 False,
788 (),
789 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15790 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44791 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19792 (
793 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
794 "if you're convinced you need this.",
795 ),
796 False,
797 (),
798 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15799 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44800 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19801 (
802 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04803 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19804 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
805 'async events instead of flushing threads.',
806 ),
807 False,
808 (),
809 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15810 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:19811 r'MessageLoopRunner',
812 (
813 'MessageLoopRunner is deprecated, use RunLoop instead.',
814 ),
815 False,
816 (),
817 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15818 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44819 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19820 (
821 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
822 "gab@ if you found a use case where this is the only solution.",
823 ),
824 False,
825 (),
826 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15827 BanRule(
Victor Costane48a2e82019-03-15 22:02:34828 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16829 (
Victor Costane48a2e82019-03-15 22:02:34830 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16831 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
832 ),
833 True,
834 (
835 r'^sql/initialization\.(cc|h)$',
836 r'^third_party/sqlite/.*\.(c|cc|h)$',
837 ),
838 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15839 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44840 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47841 (
842 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
843 'base::RandomShuffle instead.'
844 ),
845 True,
846 (),
847 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15848 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24849 'ios/web/public/test/http_server',
850 (
851 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
852 ),
853 False,
854 (),
855 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15856 BanRule(
Robert Liao764c9492019-01-24 18:46:28857 'GetAddressOf',
858 (
859 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53860 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11861 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53862 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28863 ),
864 True,
865 (),
866 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15867 BanRule(
Ben Lewisa9514602019-04-29 17:53:05868 'SHFileOperation',
869 (
870 'SHFileOperation was deprecated in Windows Vista, and there are less ',
871 'complex functions to achieve the same goals. Use IFileOperation for ',
872 'any esoteric actions instead.'
873 ),
874 True,
875 (),
876 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15877 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:51878 'StringFromGUID2',
879 (
880 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24881 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51882 ),
883 True,
884 (
Daniel Chenga44a1bcd2022-03-15 20:00:15885 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:51886 ),
887 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15888 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:51889 'StringFromCLSID',
890 (
891 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24892 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51893 ),
894 True,
895 (
Daniel Chenga44a1bcd2022-03-15 20:00:15896 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:51897 ),
898 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15899 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13900 'kCFAllocatorNull',
901 (
902 'The use of kCFAllocatorNull with the NoCopy creation of ',
903 'CoreFoundation types is prohibited.',
904 ),
905 True,
906 (),
907 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15908 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:29909 'mojo::ConvertTo',
910 (
911 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
912 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
913 'StringTraits if you would like to convert between custom types and',
914 'the wire format of mojom types.'
915 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22916 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29917 (
Wezf89dec092019-09-11 19:38:33918 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
919 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29920 r'^third_party/blink/.*\.(cc|h)$',
921 r'^content/renderer/.*\.(cc|h)$',
922 ),
923 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15924 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:16925 'GetInterfaceProvider',
926 (
927 'InterfaceProvider is deprecated.',
928 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
929 'or Platform::GetBrowserInterfaceBroker.'
930 ),
931 False,
932 (),
933 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15934 BanRule(
Robert Liao1d78df52019-11-11 20:02:01935 'CComPtr',
936 (
937 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
938 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
939 'details.'
940 ),
941 False,
942 (),
943 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15944 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:20945 r'/\b(IFACE|STD)METHOD_?\(',
946 (
947 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
948 'Instead, always use IFACEMETHODIMP in the declaration.'
949 ),
950 False,
951 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
952 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15953 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:47954 'set_owned_by_client',
955 (
956 'set_owned_by_client is deprecated.',
957 'views::View already owns the child views by default. This introduces ',
958 'a competing ownership model which makes the code difficult to reason ',
959 'about. See http://crbug.com/1044687 for more details.'
960 ),
961 False,
962 (),
963 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15964 BanRule(
Peter Boström7ff41522021-07-29 03:43:27965 'RemoveAllChildViewsWithoutDeleting',
966 (
967 'RemoveAllChildViewsWithoutDeleting is deprecated.',
968 'This method is deemed dangerous as, unless raw pointers are re-added,',
969 'calls to this method introduce memory leaks.'
970 ),
971 False,
972 (),
973 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15974 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:12975 r'/\bTRACE_EVENT_ASYNC_',
976 (
977 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
978 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
979 ),
980 False,
981 (
982 r'^base/trace_event/.*',
983 r'^base/tracing/.*',
984 ),
985 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15986 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:43987 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
988 (
989 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
990 'dumps and may spam crash reports. Consider if the throttled',
991 'variants suffice instead.',
992 ),
993 False,
994 (),
995 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15996 BanRule(
Robert Liao22f66a52021-04-10 00:57:52997 'RoInitialize',
998 (
Robert Liao48018922021-04-16 23:03:02999 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521000 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1001 'instead. See http://crbug.com/1197722 for more information.'
1002 ),
1003 True,
Robert Liao48018922021-04-16 23:03:021004 (
Daniel Chenga44a1bcd2022-03-15 20:00:151005 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021006 ),
Robert Liao22f66a52021-04-10 00:57:521007 ),
[email protected]127f18ec2012-06-16 05:05:591008)
1009
Daniel Cheng92c15e32022-03-16 17:48:221010_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1011 BanRule(
1012 'handle<shared_buffer>',
1013 (
1014 'Please use one of the more specific shared memory types instead:',
1015 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1016 ' mojo_base.mojom.WritableSharedMemoryRegion',
1017 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1018 ),
1019 True,
1020 ),
1021)
1022
mlamouria82272622014-09-16 18:45:041023_IPC_ENUM_TRAITS_DEPRECATED = (
1024 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501025 'See http://www.chromium.org/Home/chromium-security/education/'
1026 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041027
Stephen Martinis97a394142018-06-07 23:06:051028_LONG_PATH_ERROR = (
1029 'Some files included in this CL have file names that are too long (> 200'
1030 ' characters). If committed, these files will cause issues on Windows. See'
1031 ' https://crbug.com/612667 for more details.'
1032)
1033
Shenghua Zhangbfaa38b82017-11-16 21:58:021034_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041035 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041036 r".*[\\/]BuildHooksAndroidImpl\.java",
1037 r".*[\\/]LicenseContentProvider\.java",
1038 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281039 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021040]
[email protected]127f18ec2012-06-16 05:05:591041
Mohamed Heikald048240a2019-11-12 16:57:371042# List of image extensions that are used as resources in chromium.
1043_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1044
Sean Kau46e29bc2017-08-28 16:31:161045# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401046_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041047 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401048 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041049 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1050 r'^third_party[\\/]protobuf[\\/]',
Bruce Dawson49a3db522022-05-05 23:54:331051 r'^third_party[\\/]blink[\\/]perf_tests[\\/]speedometer[\\/]resources[\\/]todomvc[\\/]learn.json',
Egor Paskoce145c42018-09-28 19:31:041052 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431053 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
John Chen288dee02022-04-28 17:37:061054 r'^tools[\\/]perf[\\/]',
Bruce Dawson49a3db522022-05-05 23:54:331055 r'^tools[\\/]traceline[\\/]svgui[\\/]startup-release.json',
Sean Kau46e29bc2017-08-28 16:31:161056]
1057
Andrew Grieveb773bad2020-06-05 18:00:381058# These are not checked on the public chromium-presubmit trybot.
1059# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041060# checkouts.
agrievef32bcc72016-04-04 14:57:401061_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381062 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381063]
1064
1065
1066_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101067 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041068 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361069 'base/android/jni_generator/jni_generator.pydeps',
1070 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361071 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041072 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361073 'build/android/gyp/aar.pydeps',
1074 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271075 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361076 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381077 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361078 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021079 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221080 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111081 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361082 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361083 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361084 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111085 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041086 'build/android/gyp/create_app_bundle_apks.pydeps',
1087 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361088 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121089 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091090 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221091 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001092 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361093 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421094 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041095 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361096 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361097 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211098 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361099 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361100 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361101 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581102 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361103 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141104 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261105 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471106 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011107 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041108 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361109 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361110 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101111 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361112 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221113 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361114 'build/android/gyp/proguard.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101115 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461116 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301117 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241118 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361119 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461120 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561121 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361122 'build/android/incremental_install/generate_android_manifest.pydeps',
1123 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041124 'build/android/resource_sizes.pydeps',
1125 'build/android/test_runner.pydeps',
1126 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361127 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361128 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321129 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271130 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1131 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041132 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001133 'components/cronet/tools/generate_javadoc.pydeps',
1134 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381135 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001136 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381137 'net/tools/testserver/testserver.pydeps',
Jonathan Lee10c06dea2022-05-02 23:13:321138 'testing/scripts/run_wpt_tests.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181139 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411140 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1141 'testing/merge_scripts/standard_gtest_merge.pydeps',
1142 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1143 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041144 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421145 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1146 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131147 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501148 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411149 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1150 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061151 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221152 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401153]
1154
wnwenbdc444e2016-05-25 13:44:151155
agrievef32bcc72016-04-04 14:57:401156_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1157
1158
Eric Boren6fd2b932018-01-25 15:05:081159# Bypass the AUTHORS check for these accounts.
1160_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591161 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451162 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591163 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521164 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231165 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471166 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Jieting Yang668bde92022-01-27 18:40:431167 'infra-try-recipes-tester', 'lacros-tracking-roller')
Eric Boren835d71f2018-09-07 21:09:041168 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271169 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041170 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161171 for s in ('chromium-internal-autoroll',)
1172 ) | set('%[email protected]' % s
1173 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081174
Matt Stark6ef08872021-07-29 01:21:461175_INVALID_GRD_FILE_LINE = [
1176 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1177]
Eric Boren6fd2b932018-01-25 15:05:081178
Daniel Bratell65b033262019-04-23 08:17:061179def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501180 """Returns True if this file contains C++-like code (and not Python,
1181 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061182
Sam Maiera6e76d72022-02-11 21:43:501183 ext = input_api.os_path.splitext(file_path)[1]
1184 # This list is compatible with CppChecker.IsCppFile but we should
1185 # consider adding ".c" to it. If we do that we can use this function
1186 # at more places in the code.
1187 return ext in (
1188 '.h',
1189 '.cc',
1190 '.cpp',
1191 '.m',
1192 '.mm',
1193 )
1194
Daniel Bratell65b033262019-04-23 08:17:061195
1196def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501197 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061198
1199
1200def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501201 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061202
1203
1204def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501205 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061206
Mohamed Heikal5e5b7922020-10-29 18:57:591207
Erik Staabc734cd7a2021-11-23 03:11:521208def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501209 ext = input_api.os_path.splitext(file_path)[1]
1210 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521211
1212
Mohamed Heikal5e5b7922020-10-29 18:57:591213def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501214 """Prevent additions of dependencies from the upstream repo on //clank."""
1215 # clank can depend on clank
1216 if input_api.change.RepositoryRoot().endswith('clank'):
1217 return []
1218 build_file_patterns = [
1219 r'(.+/)?BUILD\.gn',
1220 r'.+\.gni',
1221 ]
1222 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1223 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591224
Sam Maiera6e76d72022-02-11 21:43:501225 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591226
Sam Maiera6e76d72022-02-11 21:43:501227 def FilterFile(affected_file):
1228 return input_api.FilterSourceFile(affected_file,
1229 files_to_check=build_file_patterns,
1230 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591231
Sam Maiera6e76d72022-02-11 21:43:501232 problems = []
1233 for f in input_api.AffectedSourceFiles(FilterFile):
1234 local_path = f.LocalPath()
1235 for line_number, line in f.ChangedContents():
1236 if (bad_pattern.search(line)):
1237 problems.append('%s:%d\n %s' %
1238 (local_path, line_number, line.strip()))
1239 if problems:
1240 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1241 else:
1242 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591243
1244
Saagar Sanghavifceeaae2020-08-12 16:40:361245def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501246 """Attempts to prevent use of functions intended only for testing in
1247 non-testing code. For now this is just a best-effort implementation
1248 that ignores header files and may have some false positives. A
1249 better implementation would probably need a proper C++ parser.
1250 """
1251 # We only scan .cc files and the like, as the declaration of
1252 # for-testing functions in header files are hard to distinguish from
1253 # calls to such functions without a proper C++ parser.
1254 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191255
Sam Maiera6e76d72022-02-11 21:43:501256 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1257 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1258 base_function_pattern)
1259 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1260 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1261 exclusion_pattern = input_api.re.compile(
1262 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1263 (base_function_pattern, base_function_pattern))
1264 # Avoid a false positive in this case, where the method name, the ::, and
1265 # the closing { are all on different lines due to line wrapping.
1266 # HelperClassForTesting::
1267 # HelperClassForTesting(
1268 # args)
1269 # : member(0) {}
1270 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191271
Sam Maiera6e76d72022-02-11 21:43:501272 def FilterFile(affected_file):
1273 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1274 input_api.DEFAULT_FILES_TO_SKIP)
1275 return input_api.FilterSourceFile(
1276 affected_file,
1277 files_to_check=file_inclusion_pattern,
1278 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191279
Sam Maiera6e76d72022-02-11 21:43:501280 problems = []
1281 for f in input_api.AffectedSourceFiles(FilterFile):
1282 local_path = f.LocalPath()
1283 in_method_defn = False
1284 for line_number, line in f.ChangedContents():
1285 if (inclusion_pattern.search(line)
1286 and not comment_pattern.search(line)
1287 and not exclusion_pattern.search(line)
1288 and not allowlist_pattern.search(line)
1289 and not in_method_defn):
1290 problems.append('%s:%d\n %s' %
1291 (local_path, line_number, line.strip()))
1292 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191293
Sam Maiera6e76d72022-02-11 21:43:501294 if problems:
1295 return [
1296 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1297 ]
1298 else:
1299 return []
[email protected]55459852011-08-10 15:17:191300
1301
Saagar Sanghavifceeaae2020-08-12 16:40:361302def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501303 """This is a simplified version of
1304 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1305 """
1306 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1307 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1308 name_pattern = r'ForTest(s|ing)?'
1309 # Describes an occurrence of "ForTest*" inside a // comment.
1310 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1311 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1312 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1313 # Catch calls.
1314 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1315 # Ignore definitions. (Comments are ignored separately.)
1316 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231317
Sam Maiera6e76d72022-02-11 21:43:501318 problems = []
1319 sources = lambda x: input_api.FilterSourceFile(
1320 x,
1321 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1322 DEFAULT_FILES_TO_SKIP),
1323 files_to_check=[r'.*\.java$'])
1324 for f in input_api.AffectedFiles(include_deletes=False,
1325 file_filter=sources):
1326 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231327 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501328 for line_number, line in f.ChangedContents():
1329 if is_inside_javadoc and javadoc_end_re.search(line):
1330 is_inside_javadoc = False
1331 if not is_inside_javadoc and javadoc_start_re.search(line):
1332 is_inside_javadoc = True
1333 if is_inside_javadoc:
1334 continue
1335 if (inclusion_re.search(line) and not comment_re.search(line)
1336 and not annotation_re.search(line)
1337 and not exclusion_re.search(line)):
1338 problems.append('%s:%d\n %s' %
1339 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231340
Sam Maiera6e76d72022-02-11 21:43:501341 if problems:
1342 return [
1343 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1344 ]
1345 else:
1346 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231347
1348
Saagar Sanghavifceeaae2020-08-12 16:40:361349def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501350 """Checks to make sure no .h files include <iostream>."""
1351 files = []
1352 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1353 input_api.re.MULTILINE)
1354 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1355 if not f.LocalPath().endswith('.h'):
1356 continue
1357 contents = input_api.ReadFile(f)
1358 if pattern.search(contents):
1359 files.append(f)
[email protected]10689ca2011-09-02 02:31:541360
Sam Maiera6e76d72022-02-11 21:43:501361 if len(files):
1362 return [
1363 output_api.PresubmitError(
1364 'Do not #include <iostream> in header files, since it inserts static '
1365 'initialization into every file including the header. Instead, '
1366 '#include <ostream>. See http://crbug.com/94794', files)
1367 ]
1368 return []
1369
[email protected]10689ca2011-09-02 02:31:541370
Danil Chapovalov3518f362018-08-11 16:13:431371def _CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501372 """Checks no windows headers with StrCat redefined are included directly."""
1373 files = []
1374 pattern_deny = input_api.re.compile(
1375 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1376 input_api.re.MULTILINE)
1377 pattern_allow = input_api.re.compile(
1378 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
1379 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1380 contents = input_api.ReadFile(f)
1381 if pattern_deny.search(
1382 contents) and not pattern_allow.search(contents):
1383 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431384
Sam Maiera6e76d72022-02-11 21:43:501385 if len(files):
1386 return [
1387 output_api.PresubmitError(
1388 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1389 'directly since they pollute code with StrCat macro. Instead, '
1390 'include matching header from base/win. See http://crbug.com/856536',
1391 files)
1392 ]
1393 return []
Danil Chapovalov3518f362018-08-11 16:13:431394
[email protected]10689ca2011-09-02 02:31:541395
Saagar Sanghavifceeaae2020-08-12 16:40:361396def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501397 """Checks to make sure no source files use UNIT_TEST."""
1398 problems = []
1399 for f in input_api.AffectedFiles():
1400 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1401 continue
[email protected]72df4e782012-06-21 16:28:181402
Sam Maiera6e76d72022-02-11 21:43:501403 for line_num, line in f.ChangedContents():
1404 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1405 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181406
Sam Maiera6e76d72022-02-11 21:43:501407 if not problems:
1408 return []
1409 return [
1410 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1411 '\n'.join(problems))
1412 ]
1413
[email protected]72df4e782012-06-21 16:28:181414
Saagar Sanghavifceeaae2020-08-12 16:40:361415def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501416 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341417
Sam Maiera6e76d72022-02-11 21:43:501418 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1419 instead of DISABLED_. To filter false positives, reports are only generated
1420 if a corresponding MAYBE_ line exists.
1421 """
1422 problems = []
Dominic Battre033531052018-09-24 15:45:341423
Sam Maiera6e76d72022-02-11 21:43:501424 # The following two patterns are looked for in tandem - is a test labeled
1425 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1426 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1427 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341428
Sam Maiera6e76d72022-02-11 21:43:501429 # This is for the case that a test is disabled on all platforms.
1430 full_disable_pattern = input_api.re.compile(
1431 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1432 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341433
Sam Maiera6e76d72022-02-11 21:43:501434 for f in input_api.AffectedFiles(False):
1435 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1436 continue
Dominic Battre033531052018-09-24 15:45:341437
Sam Maiera6e76d72022-02-11 21:43:501438 # Search for MABYE_, DISABLE_ pairs.
1439 disable_lines = {} # Maps of test name to line number.
1440 maybe_lines = {}
1441 for line_num, line in f.ChangedContents():
1442 disable_match = disable_pattern.search(line)
1443 if disable_match:
1444 disable_lines[disable_match.group(1)] = line_num
1445 maybe_match = maybe_pattern.search(line)
1446 if maybe_match:
1447 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341448
Sam Maiera6e76d72022-02-11 21:43:501449 # Search for DISABLE_ occurrences within a TEST() macro.
1450 disable_tests = set(disable_lines.keys())
1451 maybe_tests = set(maybe_lines.keys())
1452 for test in disable_tests.intersection(maybe_tests):
1453 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341454
Sam Maiera6e76d72022-02-11 21:43:501455 contents = input_api.ReadFile(f)
1456 full_disable_match = full_disable_pattern.search(contents)
1457 if full_disable_match:
1458 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341459
Sam Maiera6e76d72022-02-11 21:43:501460 if not problems:
1461 return []
1462 return [
1463 output_api.PresubmitPromptWarning(
1464 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1465 '\n'.join(problems))
1466 ]
1467
Dominic Battre033531052018-09-24 15:45:341468
Nina Satragnof7660532021-09-20 18:03:351469def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501470 """Checks to make sure tests disabled conditionally are not missing a
1471 corresponding MAYBE_ prefix.
1472 """
1473 # Expect at least a lowercase character in the test name. This helps rule out
1474 # false positives with macros wrapping the actual tests name.
1475 define_maybe_pattern = input_api.re.compile(
1476 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191477 # The test_maybe_pattern needs to handle all of these forms. The standard:
1478 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1479 # With a wrapper macro around the test name:
1480 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1481 # And the odd-ball NACL_BROWSER_TEST_f format:
1482 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1483 # The optional E2E_ENABLED-style is handled with (\w*\()?
1484 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1485 # trailing ')'.
1486 test_maybe_pattern = (
1487 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501488 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1489 warnings = []
Nina Satragnof7660532021-09-20 18:03:351490
Sam Maiera6e76d72022-02-11 21:43:501491 # Read the entire files. We can't just read the affected lines, forgetting to
1492 # add MAYBE_ on a change would not show up otherwise.
1493 for f in input_api.AffectedFiles(False):
1494 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1495 continue
1496 contents = input_api.ReadFile(f)
1497 lines = contents.splitlines(True)
1498 current_position = 0
1499 warning_test_names = set()
1500 for line_num, line in enumerate(lines, start=1):
1501 current_position += len(line)
1502 maybe_match = define_maybe_pattern.search(line)
1503 if maybe_match:
1504 test_name = maybe_match.group('test_name')
1505 # Do not warn twice for the same test.
1506 if (test_name in warning_test_names):
1507 continue
1508 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351509
Sam Maiera6e76d72022-02-11 21:43:501510 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1511 # the current position.
1512 test_match = input_api.re.compile(
1513 test_maybe_pattern.format(test_name=test_name),
1514 input_api.re.MULTILINE).search(contents, current_position)
1515 suite_match = input_api.re.compile(
1516 suite_maybe_pattern.format(test_name=test_name),
1517 input_api.re.MULTILINE).search(contents, current_position)
1518 if not test_match and not suite_match:
1519 warnings.append(
1520 output_api.PresubmitPromptWarning(
1521 '%s:%d found MAYBE_ defined without corresponding test %s'
1522 % (f.LocalPath(), line_num, test_name)))
1523 return warnings
1524
[email protected]72df4e782012-06-21 16:28:181525
Saagar Sanghavifceeaae2020-08-12 16:40:361526def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501527 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1528 errors = []
1529 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
1530 input_api.re.MULTILINE)
1531 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1532 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1533 continue
1534 for lnum, line in f.ChangedContents():
1535 if input_api.re.search(pattern, line):
1536 errors.append(
1537 output_api.PresubmitError((
1538 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1539 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1540 (f.LocalPath(), lnum)))
1541 return errors
danakj61c1aa22015-10-26 19:55:521542
1543
Weilun Shia487fad2020-10-28 00:10:341544# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1545# more reliable way. See
1546# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191547
wnwenbdc444e2016-05-25 13:44:151548
Saagar Sanghavifceeaae2020-08-12 16:40:361549def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501550 """Check that FlakyTest annotation is our own instead of the android one"""
1551 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1552 files = []
1553 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1554 if f.LocalPath().endswith('Test.java'):
1555 if pattern.search(input_api.ReadFile(f)):
1556 files.append(f)
1557 if len(files):
1558 return [
1559 output_api.PresubmitError(
1560 'Use org.chromium.base.test.util.FlakyTest instead of '
1561 'android.test.FlakyTest', files)
1562 ]
1563 return []
mcasasb7440c282015-02-04 14:52:191564
wnwenbdc444e2016-05-25 13:44:151565
Saagar Sanghavifceeaae2020-08-12 16:40:361566def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501567 """Make sure .DEPS.git is never modified manually."""
1568 if any(f.LocalPath().endswith('.DEPS.git')
1569 for f in input_api.AffectedFiles()):
1570 return [
1571 output_api.PresubmitError(
1572 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1573 'automated system based on what\'s in DEPS and your changes will be\n'
1574 'overwritten.\n'
1575 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1576 'get-the-code#Rolling_DEPS\n'
1577 'for more information')
1578 ]
1579 return []
[email protected]2a8ac9c2011-10-19 17:20:441580
1581
Saagar Sanghavifceeaae2020-08-12 16:40:361582def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501583 """Checks that DEPS file deps are from allowed_hosts."""
1584 # Run only if DEPS file has been modified to annoy fewer bystanders.
1585 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1586 return []
1587 # Outsource work to gclient verify
1588 try:
1589 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
1590 'third_party', 'depot_tools',
1591 'gclient.py')
1592 input_api.subprocess.check_output(
1593 [input_api.python_executable, gclient_path, 'verify'],
1594 stderr=input_api.subprocess.STDOUT)
1595 return []
1596 except input_api.subprocess.CalledProcessError as error:
1597 return [
1598 output_api.PresubmitError(
1599 'DEPS file must have only git dependencies.',
1600 long_text=error.output)
1601 ]
tandriief664692014-09-23 14:51:471602
1603
Mario Sanchez Prada2472cab2019-09-18 10:58:311604def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151605 ban_rule):
Sam Maiera6e76d72022-02-11 21:43:501606 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311607
Sam Maiera6e76d72022-02-11 21:43:501608 Returns an string composed of the name of the file, the line number where the
1609 match has been found and the additional text passed as |message| in case the
1610 target type name matches the text inside the line passed as parameter.
1611 """
1612 result = []
Peng Huang9c5949a02020-06-11 19:20:541613
Daniel Chenga44a1bcd2022-03-15 20:00:151614 # Ignore comments about banned types.
1615 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:501616 return result
Daniel Chenga44a1bcd2022-03-15 20:00:151617 # A // nocheck comment will bypass this error.
1618 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:501619 return result
1620
1621 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:151622 if ban_rule.pattern[0:1] == '/':
1623 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:501624 if input_api.re.search(regex, line):
1625 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:151626 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:501627 matched = True
1628
1629 if matched:
1630 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:151631 for line in ban_rule.explanation:
1632 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:501633
danakjd18e8892020-12-17 17:42:011634 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:311635
1636
Saagar Sanghavifceeaae2020-08-12 16:40:361637def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501638 """Make sure that banned functions are not used."""
1639 warnings = []
1640 errors = []
[email protected]127f18ec2012-06-16 05:05:591641
Sam Maiera6e76d72022-02-11 21:43:501642 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:151643 if not excluded_paths:
1644 return False
1645
Sam Maiera6e76d72022-02-11 21:43:501646 local_path = affected_file.LocalPath()
1647 for item in excluded_paths:
1648 if input_api.re.match(item, local_path):
1649 return True
1650 return False
wnwenbdc444e2016-05-25 13:44:151651
Sam Maiera6e76d72022-02-11 21:43:501652 def IsIosObjcFile(affected_file):
1653 local_path = affected_file.LocalPath()
1654 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
1655 '.h'):
1656 return False
1657 basename = input_api.os_path.basename(local_path)
1658 if 'ios' in basename.split('_'):
1659 return True
1660 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1661 if sep and 'ios' in local_path.split(sep):
1662 return True
1663 return False
Sylvain Defresnea8b73d252018-02-28 15:45:541664
Daniel Chenga44a1bcd2022-03-15 20:00:151665 def CheckForMatch(affected_file, line_num: int, line: str,
1666 ban_rule: BanRule):
1667 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
1668 return
1669
Sam Maiera6e76d72022-02-11 21:43:501670 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151671 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501672 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:151673 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:501674 errors.extend(problems)
1675 else:
1676 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151677
Sam Maiera6e76d72022-02-11 21:43:501678 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1679 for f in input_api.AffectedFiles(file_filter=file_filter):
1680 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151681 for ban_rule in _BANNED_JAVA_FUNCTIONS:
1682 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:411683
Sam Maiera6e76d72022-02-11 21:43:501684 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1685 for f in input_api.AffectedFiles(file_filter=file_filter):
1686 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151687 for ban_rule in _BANNED_OBJC_FUNCTIONS:
1688 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591689
Sam Maiera6e76d72022-02-11 21:43:501690 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
1691 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151692 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
1693 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:541694
Sam Maiera6e76d72022-02-11 21:43:501695 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1696 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1697 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151698 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
1699 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:051700
Sam Maiera6e76d72022-02-11 21:43:501701 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1702 for f in input_api.AffectedFiles(file_filter=file_filter):
1703 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151704 for ban_rule in _BANNED_CPP_FUNCTIONS:
1705 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591706
Daniel Cheng92c15e32022-03-16 17:48:221707 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
1708 for f in input_api.AffectedFiles(file_filter=file_filter):
1709 for line_num, line in f.ChangedContents():
1710 for ban_rule in _BANNED_MOJOM_PATTERNS:
1711 CheckForMatch(f, line_num, line, ban_rule)
1712
1713
Sam Maiera6e76d72022-02-11 21:43:501714 result = []
1715 if (warnings):
1716 result.append(
1717 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
1718 '\n'.join(warnings)))
1719 if (errors):
1720 result.append(
1721 output_api.PresubmitError('Banned functions were used.\n' +
1722 '\n'.join(errors)))
1723 return result
[email protected]127f18ec2012-06-16 05:05:591724
1725
Michael Thiessen44457642020-02-06 00:24:151726def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501727 """Make sure that banned java imports are not used."""
1728 errors = []
Michael Thiessen44457642020-02-06 00:24:151729
Sam Maiera6e76d72022-02-11 21:43:501730 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1731 for f in input_api.AffectedFiles(file_filter=file_filter):
1732 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151733 for ban_rule in _BANNED_JAVA_IMPORTS:
1734 # Consider merging this into the above function. There is no
1735 # real difference anymore other than helping with a little
1736 # bit of boilerplate text. Doing so means things like
1737 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:501738 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:151739 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501740 if problems:
1741 errors.extend(problems)
1742 result = []
1743 if (errors):
1744 result.append(
1745 output_api.PresubmitError('Banned imports were used.\n' +
1746 '\n'.join(errors)))
1747 return result
Michael Thiessen44457642020-02-06 00:24:151748
1749
Saagar Sanghavifceeaae2020-08-12 16:40:361750def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501751 """Make sure that banned functions are not used."""
1752 files = []
1753 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
1754 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1755 if not f.LocalPath().endswith('.h'):
1756 continue
Bruce Dawson4c4c2922022-05-02 18:07:331757 if f.LocalPath().endswith('com_imported_mstscax.h'):
1758 continue
Sam Maiera6e76d72022-02-11 21:43:501759 contents = input_api.ReadFile(f)
1760 if pattern.search(contents):
1761 files.append(f)
[email protected]6c063c62012-07-11 19:11:061762
Sam Maiera6e76d72022-02-11 21:43:501763 if files:
1764 return [
1765 output_api.PresubmitError(
1766 'Do not use #pragma once in header files.\n'
1767 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1768 files)
1769 ]
1770 return []
[email protected]6c063c62012-07-11 19:11:061771
[email protected]127f18ec2012-06-16 05:05:591772
Saagar Sanghavifceeaae2020-08-12 16:40:361773def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501774 """Checks to make sure we don't introduce use of foo ? true : false."""
1775 problems = []
1776 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1777 for f in input_api.AffectedFiles():
1778 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1779 continue
[email protected]e7479052012-09-19 00:26:121780
Sam Maiera6e76d72022-02-11 21:43:501781 for line_num, line in f.ChangedContents():
1782 if pattern.match(line):
1783 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:121784
Sam Maiera6e76d72022-02-11 21:43:501785 if not problems:
1786 return []
1787 return [
1788 output_api.PresubmitPromptWarning(
1789 'Please consider avoiding the "? true : false" pattern if possible.\n'
1790 + '\n'.join(problems))
1791 ]
[email protected]e7479052012-09-19 00:26:121792
1793
Saagar Sanghavifceeaae2020-08-12 16:40:361794def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501795 """Runs checkdeps on #include and import statements added in this
1796 change. Breaking - rules is an error, breaking ! rules is a
1797 warning.
1798 """
1799 # Return early if no relevant file types were modified.
1800 for f in input_api.AffectedFiles():
1801 path = f.LocalPath()
1802 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
1803 or _IsJavaFile(input_api, path)):
1804 break
[email protected]55f9f382012-07-31 11:02:181805 else:
Sam Maiera6e76d72022-02-11 21:43:501806 return []
rhalavati08acd232017-04-03 07:23:281807
Sam Maiera6e76d72022-02-11 21:43:501808 import sys
1809 # We need to wait until we have an input_api object and use this
1810 # roundabout construct to import checkdeps because this file is
1811 # eval-ed and thus doesn't have __file__.
1812 original_sys_path = sys.path
1813 try:
1814 sys.path = sys.path + [
1815 input_api.os_path.join(input_api.PresubmitLocalPath(),
1816 'buildtools', 'checkdeps')
1817 ]
1818 import checkdeps
1819 from rules import Rule
1820 finally:
1821 # Restore sys.path to what it was before.
1822 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:181823
Sam Maiera6e76d72022-02-11 21:43:501824 added_includes = []
1825 added_imports = []
1826 added_java_imports = []
1827 for f in input_api.AffectedFiles():
1828 if _IsCPlusPlusFile(input_api, f.LocalPath()):
1829 changed_lines = [line for _, line in f.ChangedContents()]
1830 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
1831 elif _IsProtoFile(input_api, f.LocalPath()):
1832 changed_lines = [line for _, line in f.ChangedContents()]
1833 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
1834 elif _IsJavaFile(input_api, f.LocalPath()):
1835 changed_lines = [line for _, line in f.ChangedContents()]
1836 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241837
Sam Maiera6e76d72022-02-11 21:43:501838 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
1839
1840 error_descriptions = []
1841 warning_descriptions = []
1842 error_subjects = set()
1843 warning_subjects = set()
1844
1845 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1846 added_includes):
1847 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1848 description_with_path = '%s\n %s' % (path, rule_description)
1849 if rule_type == Rule.DISALLOW:
1850 error_descriptions.append(description_with_path)
1851 error_subjects.add("#includes")
1852 else:
1853 warning_descriptions.append(description_with_path)
1854 warning_subjects.add("#includes")
1855
1856 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1857 added_imports):
1858 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1859 description_with_path = '%s\n %s' % (path, rule_description)
1860 if rule_type == Rule.DISALLOW:
1861 error_descriptions.append(description_with_path)
1862 error_subjects.add("imports")
1863 else:
1864 warning_descriptions.append(description_with_path)
1865 warning_subjects.add("imports")
1866
1867 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
1868 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
1869 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1870 description_with_path = '%s\n %s' % (path, rule_description)
1871 if rule_type == Rule.DISALLOW:
1872 error_descriptions.append(description_with_path)
1873 error_subjects.add("imports")
1874 else:
1875 warning_descriptions.append(description_with_path)
1876 warning_subjects.add("imports")
1877
1878 results = []
1879 if error_descriptions:
1880 results.append(
1881 output_api.PresubmitError(
1882 'You added one or more %s that violate checkdeps rules.' %
1883 " and ".join(error_subjects), error_descriptions))
1884 if warning_descriptions:
1885 results.append(
1886 output_api.PresubmitPromptOrNotify(
1887 'You added one or more %s of files that are temporarily\n'
1888 'allowed but being removed. Can you avoid introducing the\n'
1889 '%s? See relevant DEPS file(s) for details and contacts.' %
1890 (" and ".join(warning_subjects), "/".join(warning_subjects)),
1891 warning_descriptions))
1892 return results
[email protected]55f9f382012-07-31 11:02:181893
1894
Saagar Sanghavifceeaae2020-08-12 16:40:361895def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501896 """Check that all files have their permissions properly set."""
1897 if input_api.platform == 'win32':
1898 return []
1899 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
1900 'tools', 'checkperms',
1901 'checkperms.py')
1902 args = [
1903 input_api.python_executable, checkperms_tool, '--root',
1904 input_api.change.RepositoryRoot()
1905 ]
1906 with input_api.CreateTemporaryFile() as file_list:
1907 for f in input_api.AffectedFiles():
1908 # checkperms.py file/directory arguments must be relative to the
1909 # repository.
1910 file_list.write((f.LocalPath() + '\n').encode('utf8'))
1911 file_list.close()
1912 args += ['--file-list', file_list.name]
1913 try:
1914 input_api.subprocess.check_output(args)
1915 return []
1916 except input_api.subprocess.CalledProcessError as error:
1917 return [
1918 output_api.PresubmitError('checkperms.py failed:',
1919 long_text=error.output.decode(
1920 'utf-8', 'ignore'))
1921 ]
[email protected]fbcafe5a2012-08-08 15:31:221922
1923
Saagar Sanghavifceeaae2020-08-12 16:40:361924def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501925 """Makes sure we don't include ui/aura/window_property.h
1926 in header files.
1927 """
1928 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1929 errors = []
1930 for f in input_api.AffectedFiles():
1931 if not f.LocalPath().endswith('.h'):
1932 continue
1933 for line_num, line in f.ChangedContents():
1934 if pattern.match(line):
1935 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:491936
Sam Maiera6e76d72022-02-11 21:43:501937 results = []
1938 if errors:
1939 results.append(
1940 output_api.PresubmitError(
1941 'Header files should not include ui/aura/window_property.h',
1942 errors))
1943 return results
[email protected]c8278b32012-10-30 20:35:491944
1945
Omer Katzcc77ea92021-04-26 10:23:281946def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501947 """Makes sure we don't include any headers from
1948 third_party/blink/renderer/platform/heap/impl or
1949 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1950 third_party/blink/renderer/platform/heap
1951 """
1952 impl_pattern = input_api.re.compile(
1953 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1954 v8_wrapper_pattern = input_api.re.compile(
1955 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
1956 )
1957 file_filter = lambda f: not input_api.re.match(
1958 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1959 f.LocalPath())
1960 errors = []
Omer Katzcc77ea92021-04-26 10:23:281961
Sam Maiera6e76d72022-02-11 21:43:501962 for f in input_api.AffectedFiles(file_filter=file_filter):
1963 for line_num, line in f.ChangedContents():
1964 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1965 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:281966
Sam Maiera6e76d72022-02-11 21:43:501967 results = []
1968 if errors:
1969 results.append(
1970 output_api.PresubmitError(
1971 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1972 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1973 'relevant counterparts from third_party/blink/renderer/platform/heap',
1974 errors))
1975 return results
Omer Katzcc77ea92021-04-26 10:23:281976
1977
[email protected]70ca77752012-11-20 03:45:031978def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:501979 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1980 errors = []
1981 for line_num, line in f.ChangedContents():
1982 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
1983 # First-level headers in markdown look a lot like version control
1984 # conflict markers. http://daringfireball.net/projects/markdown/basics
1985 continue
1986 if pattern.match(line):
1987 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1988 return errors
[email protected]70ca77752012-11-20 03:45:031989
1990
Saagar Sanghavifceeaae2020-08-12 16:40:361991def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501992 """Usually this is not intentional and will cause a compile failure."""
1993 errors = []
1994 for f in input_api.AffectedFiles():
1995 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:031996
Sam Maiera6e76d72022-02-11 21:43:501997 results = []
1998 if errors:
1999 results.append(
2000 output_api.PresubmitError(
2001 'Version control conflict markers found, please resolve.',
2002 errors))
2003 return results
[email protected]70ca77752012-11-20 03:45:032004
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202005
Saagar Sanghavifceeaae2020-08-12 16:40:362006def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502007 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2008 errors = []
2009 for f in input_api.AffectedFiles():
2010 for line_num, line in f.ChangedContents():
2011 if pattern.search(line):
2012 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162013
Sam Maiera6e76d72022-02-11 21:43:502014 results = []
2015 if errors:
2016 results.append(
2017 output_api.PresubmitPromptWarning(
2018 'Found Google support URL addressed by answer number. Please replace '
2019 'with a p= identifier instead. See crbug.com/679462\n',
2020 errors))
2021 return results
estadee17314a02017-01-12 16:22:162022
[email protected]70ca77752012-11-20 03:45:032023
Saagar Sanghavifceeaae2020-08-12 16:40:362024def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502025 def FilterFile(affected_file):
2026 """Filter function for use with input_api.AffectedSourceFiles,
2027 below. This filters out everything except non-test files from
2028 top-level directories that generally speaking should not hard-code
2029 service URLs (e.g. src/android_webview/, src/content/ and others).
2030 """
2031 return input_api.FilterSourceFile(
2032 affected_file,
2033 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2034 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2035 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442036
Sam Maiera6e76d72022-02-11 21:43:502037 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2038 '\.(com|net)[^"]*"')
2039 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2040 pattern = input_api.re.compile(base_pattern)
2041 problems = [] # items are (filename, line_number, line)
2042 for f in input_api.AffectedSourceFiles(FilterFile):
2043 for line_num, line in f.ChangedContents():
2044 if not comment_pattern.search(line) and pattern.search(line):
2045 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442046
Sam Maiera6e76d72022-02-11 21:43:502047 if problems:
2048 return [
2049 output_api.PresubmitPromptOrNotify(
2050 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2051 'Are you sure this is correct?', [
2052 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2053 for problem in problems
2054 ])
2055 ]
2056 else:
2057 return []
[email protected]06e6d0ff2012-12-11 01:36:442058
2059
Saagar Sanghavifceeaae2020-08-12 16:40:362060def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502061 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292062
Sam Maiera6e76d72022-02-11 21:43:502063 def FileFilter(affected_file):
2064 """Includes directories known to be Chrome OS only."""
2065 return input_api.FilterSourceFile(
2066 affected_file,
2067 files_to_check=(
2068 '^ash/',
2069 '^chromeos/', # Top-level src/chromeos.
2070 '.*/chromeos/', # Any path component.
2071 '^components/arc',
2072 '^components/exo'),
2073 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292074
Sam Maiera6e76d72022-02-11 21:43:502075 prefs = []
2076 priority_prefs = []
2077 for f in input_api.AffectedFiles(file_filter=FileFilter):
2078 for line_num, line in f.ChangedContents():
2079 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2080 line):
2081 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2082 prefs.append(' %s' % line)
2083 if input_api.re.search(
2084 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2085 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2086 priority_prefs.append(' %s' % line)
2087
2088 results = []
2089 if (prefs):
2090 results.append(
2091 output_api.PresubmitPromptWarning(
2092 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2093 'by browser sync settings. If these prefs should be controlled by OS '
2094 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2095 '\n'.join(prefs)))
2096 if (priority_prefs):
2097 results.append(
2098 output_api.PresubmitPromptWarning(
2099 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2100 'controlled by browser sync settings. If these prefs should be '
2101 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2102 'instead.\n' + '\n'.join(prefs)))
2103 return results
James Cook6b6597c2019-11-06 22:05:292104
2105
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492106# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362107def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502108 """Makes sure there are no abbreviations in the name of PNG files.
2109 The native_client_sdk directory is excluded because it has auto-generated PNG
2110 files for documentation.
2111 """
2112 errors = []
2113 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Bruce Dawson3db456212022-05-02 05:34:182114 files_to_skip = [r'^native_client_sdk[\\/]',
2115 r'^services[\\/]test[\\/]',
2116 r'^third_party[\\/]blink[\\/]web_tests[\\/]',
2117 ]
Sam Maiera6e76d72022-02-11 21:43:502118 file_filter = lambda f: input_api.FilterSourceFile(
2119 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2120 for f in input_api.AffectedFiles(include_deletes=False,
2121 file_filter=file_filter):
2122 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272123
Sam Maiera6e76d72022-02-11 21:43:502124 results = []
2125 if errors:
2126 results.append(
2127 output_api.PresubmitError(
2128 'The name of PNG files should not have abbreviations. \n'
2129 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2130 'Contact [email protected] if you have questions.', errors))
2131 return results
[email protected]d2530012013-01-25 16:39:272132
2133
Daniel Cheng4dcdb6b2017-04-13 08:30:172134def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502135 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172136
Sam Maiera6e76d72022-02-11 21:43:502137 Args:
2138 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2139 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172140 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502141 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172142 if rule.startswith('+') or rule.startswith('!')
2143 ])
Sam Maiera6e76d72022-02-11 21:43:502144 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2145 add_rules.update([
2146 rule[1:] for rule in rules
2147 if rule.startswith('+') or rule.startswith('!')
2148 ])
2149 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172150
2151
2152def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502153 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172154
Sam Maiera6e76d72022-02-11 21:43:502155 # Stubs for handling special syntax in the root DEPS file.
2156 class _VarImpl:
2157 def __init__(self, local_scope):
2158 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172159
Sam Maiera6e76d72022-02-11 21:43:502160 def Lookup(self, var_name):
2161 """Implements the Var syntax."""
2162 try:
2163 return self._local_scope['vars'][var_name]
2164 except KeyError:
2165 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172166
Sam Maiera6e76d72022-02-11 21:43:502167 local_scope = {}
2168 global_scope = {
2169 'Var': _VarImpl(local_scope).Lookup,
2170 'Str': str,
2171 }
Dirk Pranke1b9e06382021-05-14 01:16:222172
Sam Maiera6e76d72022-02-11 21:43:502173 exec(contents, global_scope, local_scope)
2174 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172175
2176
2177def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502178 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2179 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412180
Sam Maiera6e76d72022-02-11 21:43:502181 For a directory (rather than a specific filename) we fake a path to
2182 a specific filename by adding /DEPS. This is chosen as a file that
2183 will seldom or never be subject to per-file include_rules.
2184 """
2185 # We ignore deps entries on auto-generated directories.
2186 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082187
Sam Maiera6e76d72022-02-11 21:43:502188 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2189 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172190
Sam Maiera6e76d72022-02-11 21:43:502191 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172192
Sam Maiera6e76d72022-02-11 21:43:502193 results = set()
2194 for added_dep in added_deps:
2195 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2196 continue
2197 # Assume that a rule that ends in .h is a rule for a specific file.
2198 if added_dep.endswith('.h'):
2199 results.add(added_dep)
2200 else:
2201 results.add(os_path.join(added_dep, 'DEPS'))
2202 return results
[email protected]f32e2d1e2013-07-26 21:39:082203
2204
Saagar Sanghavifceeaae2020-08-12 16:40:362205def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502206 """When a dependency prefixed with + is added to a DEPS file, we
2207 want to make sure that the change is reviewed by an OWNER of the
2208 target file or directory, to avoid layering violations from being
2209 introduced. This check verifies that this happens.
2210 """
2211 # We rely on Gerrit's code-owners to check approvals.
2212 # input_api.gerrit is always set for Chromium, but other projects
2213 # might not use Gerrit.
2214 if not input_api.gerrit:
2215 return []
2216 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2217 input_api.change.issue)):
2218 # Skip OWNERS check when Owners-Override label is approved. This is intended
2219 # for global owners, trusted bots, and on-call sheriffs. Review is still
2220 # required for these changes.
2221 return []
Edward Lesmes6fba51082021-01-20 04:20:232222
Sam Maiera6e76d72022-02-11 21:43:502223 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242224
Sam Maiera6e76d72022-02-11 21:43:502225 file_filter = lambda f: not input_api.re.match(
2226 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
2227 for f in input_api.AffectedFiles(include_deletes=False,
2228 file_filter=file_filter):
2229 filename = input_api.os_path.basename(f.LocalPath())
2230 if filename == 'DEPS':
2231 virtual_depended_on_files.update(
2232 _CalculateAddedDeps(input_api.os_path,
2233 '\n'.join(f.OldContents()),
2234 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552235
Sam Maiera6e76d72022-02-11 21:43:502236 if not virtual_depended_on_files:
2237 return []
[email protected]e871964c2013-05-13 14:14:552238
Sam Maiera6e76d72022-02-11 21:43:502239 if input_api.is_committing:
2240 if input_api.tbr:
2241 return [
2242 output_api.PresubmitNotifyResult(
2243 '--tbr was specified, skipping OWNERS check for DEPS additions'
2244 )
2245 ]
2246 if input_api.dry_run:
2247 return [
2248 output_api.PresubmitNotifyResult(
2249 'This is a dry run, skipping OWNERS check for DEPS additions'
2250 )
2251 ]
2252 if not input_api.change.issue:
2253 return [
2254 output_api.PresubmitError(
2255 "DEPS approval by OWNERS check failed: this change has "
2256 "no change number, so we can't check it for approvals.")
2257 ]
2258 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412259 else:
Sam Maiera6e76d72022-02-11 21:43:502260 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552261
Sam Maiera6e76d72022-02-11 21:43:502262 owner_email, reviewers = (
2263 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2264 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552265
Sam Maiera6e76d72022-02-11 21:43:502266 owner_email = owner_email or input_api.change.author_email
2267
2268 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2269 virtual_depended_on_files, reviewers.union([owner_email]), [])
2270 missing_files = [
2271 f for f in virtual_depended_on_files
2272 if approval_status[f] != input_api.owners_client.APPROVED
2273 ]
2274
2275 # We strip the /DEPS part that was added by
2276 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2277 # directory.
2278 def StripDeps(path):
2279 start_deps = path.rfind('/DEPS')
2280 if start_deps != -1:
2281 return path[:start_deps]
2282 else:
2283 return path
2284
2285 unapproved_dependencies = [
2286 "'+%s'," % StripDeps(path) for path in missing_files
2287 ]
2288
2289 if unapproved_dependencies:
2290 output_list = [
2291 output(
2292 'You need LGTM from owners of depends-on paths in DEPS that were '
2293 'modified in this CL:\n %s' %
2294 '\n '.join(sorted(unapproved_dependencies)))
2295 ]
2296 suggested_owners = input_api.owners_client.SuggestOwners(
2297 missing_files, exclude=[owner_email])
2298 output_list.append(
2299 output('Suggested missing target path OWNERS:\n %s' %
2300 '\n '.join(suggested_owners or [])))
2301 return output_list
2302
2303 return []
[email protected]e871964c2013-05-13 14:14:552304
2305
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492306# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362307def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502308 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2309 files_to_skip = (
2310 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2311 input_api.DEFAULT_FILES_TO_SKIP + (
2312 r"^base[\\/]logging\.h$",
2313 r"^base[\\/]logging\.cc$",
2314 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2315 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2316 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2317 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2318 r"startup_browser_creator\.cc$",
2319 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2320 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2321 r"diagnostics_writer\.cc$",
2322 r"^chrome[\\/]chrome_cleaner[\\/].*",
2323 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2324 r"dll_hash_main\.cc$",
2325 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2326 r"^chromecast[\\/]",
Sam Maiera6e76d72022-02-11 21:43:502327 r"^components[\\/]browser_watcher[\\/]"
2328 r"dump_stability_report_main_win.cc$",
2329 r"^components[\\/]media_control[\\/]renderer[\\/]"
2330 r"media_playback_options\.cc$",
2331 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2332 r"overlay_strategy_underlay_cast\.cc$",
2333 r"^components[\\/]zucchini[\\/].*",
2334 # TODO(peter): Remove exception. https://crbug.com/534537
2335 r"^content[\\/]browser[\\/]notifications[\\/]"
2336 r"notification_event_dispatcher_impl\.cc$",
2337 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2338 r"gl_helper_benchmark\.cc$",
2339 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2340 r"^courgette[\\/]courgette_tool\.cc$",
2341 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2342 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
2343 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2344 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
2345 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2346 r"^ipc[\\/]ipc_logging\.cc$",
2347 r"^native_client_sdk[\\/]",
2348 r"^remoting[\\/]base[\\/]logging\.h$",
2349 r"^remoting[\\/]host[\\/].*",
2350 r"^sandbox[\\/]linux[\\/].*",
2351 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2352 r"dump_file_system.cc$",
2353 r"^tools[\\/]",
2354 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2355 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2356 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2357 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2358 r"xwmstartupcheck\.cc$"))
2359 source_file_filter = lambda x: input_api.FilterSourceFile(
2360 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402361
Sam Maiera6e76d72022-02-11 21:43:502362 log_info = set([])
2363 printf = set([])
[email protected]85218562013-11-22 07:41:402364
Sam Maiera6e76d72022-02-11 21:43:502365 for f in input_api.AffectedSourceFiles(source_file_filter):
2366 for _, line in f.ChangedContents():
2367 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2368 log_info.add(f.LocalPath())
2369 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2370 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372371
Sam Maiera6e76d72022-02-11 21:43:502372 if input_api.re.search(r"\bprintf\(", line):
2373 printf.add(f.LocalPath())
2374 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2375 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402376
Sam Maiera6e76d72022-02-11 21:43:502377 if log_info:
2378 return [
2379 output_api.PresubmitError(
2380 'These files spam the console log with LOG(INFO):',
2381 items=log_info)
2382 ]
2383 if printf:
2384 return [
2385 output_api.PresubmitError(
2386 'These files spam the console log with printf/fprintf:',
2387 items=printf)
2388 ]
2389 return []
[email protected]85218562013-11-22 07:41:402390
2391
Saagar Sanghavifceeaae2020-08-12 16:40:362392def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502393 """These types are all expected to hold locks while in scope and
2394 so should never be anonymous (which causes them to be immediately
2395 destroyed)."""
2396 they_who_must_be_named = [
2397 'base::AutoLock',
2398 'base::AutoReset',
2399 'base::AutoUnlock',
2400 'SkAutoAlphaRestore',
2401 'SkAutoBitmapShaderInstall',
2402 'SkAutoBlitterChoose',
2403 'SkAutoBounderCommit',
2404 'SkAutoCallProc',
2405 'SkAutoCanvasRestore',
2406 'SkAutoCommentBlock',
2407 'SkAutoDescriptor',
2408 'SkAutoDisableDirectionCheck',
2409 'SkAutoDisableOvalCheck',
2410 'SkAutoFree',
2411 'SkAutoGlyphCache',
2412 'SkAutoHDC',
2413 'SkAutoLockColors',
2414 'SkAutoLockPixels',
2415 'SkAutoMalloc',
2416 'SkAutoMaskFreeImage',
2417 'SkAutoMutexAcquire',
2418 'SkAutoPathBoundsUpdate',
2419 'SkAutoPDFRelease',
2420 'SkAutoRasterClipValidate',
2421 'SkAutoRef',
2422 'SkAutoTime',
2423 'SkAutoTrace',
2424 'SkAutoUnref',
2425 ]
2426 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2427 # bad: base::AutoLock(lock.get());
2428 # not bad: base::AutoLock lock(lock.get());
2429 bad_pattern = input_api.re.compile(anonymous)
2430 # good: new base::AutoLock(lock.get())
2431 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2432 errors = []
[email protected]49aa76a2013-12-04 06:59:162433
Sam Maiera6e76d72022-02-11 21:43:502434 for f in input_api.AffectedFiles():
2435 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2436 continue
2437 for linenum, line in f.ChangedContents():
2438 if bad_pattern.search(line) and not good_pattern.search(line):
2439 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162440
Sam Maiera6e76d72022-02-11 21:43:502441 if errors:
2442 return [
2443 output_api.PresubmitError(
2444 'These lines create anonymous variables that need to be named:',
2445 items=errors)
2446 ]
2447 return []
[email protected]49aa76a2013-12-04 06:59:162448
2449
Saagar Sanghavifceeaae2020-08-12 16:40:362450def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502451 # Returns whether |template_str| is of the form <T, U...> for some types T
2452 # and U. Assumes that |template_str| is already in the form <...>.
2453 def HasMoreThanOneArg(template_str):
2454 # Level of <...> nesting.
2455 nesting = 0
2456 for c in template_str:
2457 if c == '<':
2458 nesting += 1
2459 elif c == '>':
2460 nesting -= 1
2461 elif c == ',' and nesting == 1:
2462 return True
2463 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532464
Sam Maiera6e76d72022-02-11 21:43:502465 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2466 sources = lambda affected_file: input_api.FilterSourceFile(
2467 affected_file,
2468 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2469 DEFAULT_FILES_TO_SKIP),
2470 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552471
Sam Maiera6e76d72022-02-11 21:43:502472 # Pattern to capture a single "<...>" block of template arguments. It can
2473 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2474 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2475 # latter would likely require counting that < and > match, which is not
2476 # expressible in regular languages. Should the need arise, one can introduce
2477 # limited counting (matching up to a total number of nesting depth), which
2478 # should cover all practical cases for already a low nesting limit.
2479 template_arg_pattern = (
2480 r'<[^>]*' # Opening block of <.
2481 r'>([^<]*>)?') # Closing block of >.
2482 # Prefix expressing that whatever follows is not already inside a <...>
2483 # block.
2484 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2485 null_construct_pattern = input_api.re.compile(
2486 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2487 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552488
Sam Maiera6e76d72022-02-11 21:43:502489 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2490 template_arg_no_array_pattern = (
2491 r'<[^>]*[^]]' # Opening block of <.
2492 r'>([^(<]*[^]]>)?') # Closing block of >.
2493 # Prefix saying that what follows is the start of an expression.
2494 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2495 # Suffix saying that what follows are call parentheses with a non-empty list
2496 # of arguments.
2497 nonempty_arg_list_pattern = r'\(([^)]|$)'
2498 # Put the template argument into a capture group for deeper examination later.
2499 return_construct_pattern = input_api.re.compile(
2500 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2501 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552502
Sam Maiera6e76d72022-02-11 21:43:502503 problems_constructor = []
2504 problems_nullptr = []
2505 for f in input_api.AffectedSourceFiles(sources):
2506 for line_number, line in f.ChangedContents():
2507 # Disallow:
2508 # return std::unique_ptr<T>(foo);
2509 # bar = std::unique_ptr<T>(foo);
2510 # But allow:
2511 # return std::unique_ptr<T[]>(foo);
2512 # bar = std::unique_ptr<T[]>(foo);
2513 # And also allow cases when the second template argument is present. Those
2514 # cases cannot be handled by std::make_unique:
2515 # return std::unique_ptr<T, U>(foo);
2516 # bar = std::unique_ptr<T, U>(foo);
2517 local_path = f.LocalPath()
2518 return_construct_result = return_construct_pattern.search(line)
2519 if return_construct_result and not HasMoreThanOneArg(
2520 return_construct_result.group('template_arg')):
2521 problems_constructor.append(
2522 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2523 # Disallow:
2524 # std::unique_ptr<T>()
2525 if null_construct_pattern.search(line):
2526 problems_nullptr.append(
2527 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052528
Sam Maiera6e76d72022-02-11 21:43:502529 errors = []
2530 if problems_nullptr:
2531 errors.append(
2532 output_api.PresubmitPromptWarning(
2533 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2534 problems_nullptr))
2535 if problems_constructor:
2536 errors.append(
2537 output_api.PresubmitError(
2538 'The following files use explicit std::unique_ptr constructor. '
2539 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2540 'std::make_unique is not an option.', problems_constructor))
2541 return errors
Peter Kasting4844e46e2018-02-23 07:27:102542
2543
Saagar Sanghavifceeaae2020-08-12 16:40:362544def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502545 """Checks if any new user action has been added."""
2546 if any('actions.xml' == input_api.os_path.basename(f)
2547 for f in input_api.LocalPaths()):
2548 # If actions.xml is already included in the changelist, the PRESUBMIT
2549 # for actions.xml will do a more complete presubmit check.
2550 return []
2551
2552 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2553 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2554 input_api.DEFAULT_FILES_TO_SKIP)
2555 file_filter = lambda f: input_api.FilterSourceFile(
2556 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2557
2558 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2559 current_actions = None
2560 for f in input_api.AffectedFiles(file_filter=file_filter):
2561 for line_num, line in f.ChangedContents():
2562 match = input_api.re.search(action_re, line)
2563 if match:
2564 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2565 # loaded only once.
2566 if not current_actions:
2567 with open(
2568 'tools/metrics/actions/actions.xml') as actions_f:
2569 current_actions = actions_f.read()
2570 # Search for the matched user action name in |current_actions|.
2571 for action_name in match.groups():
2572 action = 'name="{0}"'.format(action_name)
2573 if action not in current_actions:
2574 return [
2575 output_api.PresubmitPromptWarning(
2576 'File %s line %d: %s is missing in '
2577 'tools/metrics/actions/actions.xml. Please run '
2578 'tools/metrics/actions/extract_actions.py to update.'
2579 % (f.LocalPath(), line_num, action_name))
2580 ]
[email protected]999261d2014-03-03 20:08:082581 return []
2582
[email protected]999261d2014-03-03 20:08:082583
Daniel Cheng13ca61a882017-08-25 15:11:252584def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502585 import sys
2586 sys.path = sys.path + [
2587 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2588 'json_comment_eater')
2589 ]
2590 import json_comment_eater
2591 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252592
2593
[email protected]99171a92014-06-03 08:44:472594def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172595 try:
Sam Maiera6e76d72022-02-11 21:43:502596 contents = input_api.ReadFile(filename)
2597 if eat_comments:
2598 json_comment_eater = _ImportJSONCommentEater(input_api)
2599 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172600
Sam Maiera6e76d72022-02-11 21:43:502601 input_api.json.loads(contents)
2602 except ValueError as e:
2603 return e
Andrew Grieve4deedb12022-02-03 21:34:502604 return None
2605
2606
Sam Maiera6e76d72022-02-11 21:43:502607def _GetIDLParseError(input_api, filename):
2608 try:
2609 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:282610 for i, char in enumerate(contents):
2611 if not char.isascii():
2612 return ('Non-ascii character "%s" (ord %d) found at offset %d.'
2613 % (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:502614 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2615 'tools', 'json_schema_compiler',
2616 'idl_schema.py')
2617 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282618 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502619 stdin=input_api.subprocess.PIPE,
2620 stdout=input_api.subprocess.PIPE,
2621 stderr=input_api.subprocess.PIPE,
2622 universal_newlines=True)
2623 (_, error) = process.communicate(input=contents)
2624 return error or None
2625 except ValueError as e:
2626 return e
agrievef32bcc72016-04-04 14:57:402627
agrievef32bcc72016-04-04 14:57:402628
Sam Maiera6e76d72022-02-11 21:43:502629def CheckParseErrors(input_api, output_api):
2630 """Check that IDL and JSON files do not contain syntax errors."""
2631 actions = {
2632 '.idl': _GetIDLParseError,
2633 '.json': _GetJSONParseError,
2634 }
2635 # Most JSON files are preprocessed and support comments, but these do not.
2636 json_no_comments_patterns = [
2637 r'^testing[\\/]',
2638 ]
2639 # Only run IDL checker on files in these directories.
2640 idl_included_patterns = [
2641 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2642 r'^extensions[\\/]common[\\/]api[\\/]',
2643 ]
agrievef32bcc72016-04-04 14:57:402644
Sam Maiera6e76d72022-02-11 21:43:502645 def get_action(affected_file):
2646 filename = affected_file.LocalPath()
2647 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:402648
Sam Maiera6e76d72022-02-11 21:43:502649 def FilterFile(affected_file):
2650 action = get_action(affected_file)
2651 if not action:
2652 return False
2653 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:402654
Sam Maiera6e76d72022-02-11 21:43:502655 if _MatchesFile(input_api,
2656 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
2657 return False
2658
2659 if (action == _GetIDLParseError
2660 and not _MatchesFile(input_api, idl_included_patterns, path)):
2661 return False
2662 return True
2663
2664 results = []
2665 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
2666 include_deletes=False):
2667 action = get_action(affected_file)
2668 kwargs = {}
2669 if (action == _GetJSONParseError
2670 and _MatchesFile(input_api, json_no_comments_patterns,
2671 affected_file.LocalPath())):
2672 kwargs['eat_comments'] = False
2673 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
2674 **kwargs)
2675 if parse_error:
2676 results.append(
2677 output_api.PresubmitError(
2678 '%s could not be parsed: %s' %
2679 (affected_file.LocalPath(), parse_error)))
2680 return results
2681
2682
2683def CheckJavaStyle(input_api, output_api):
2684 """Runs checkstyle on changed java files and returns errors if any exist."""
2685
2686 # Return early if no java files were modified.
2687 if not any(
2688 _IsJavaFile(input_api, f.LocalPath())
2689 for f in input_api.AffectedFiles()):
2690 return []
2691
2692 import sys
2693 original_sys_path = sys.path
2694 try:
2695 sys.path = sys.path + [
2696 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2697 'android', 'checkstyle')
2698 ]
2699 import checkstyle
2700 finally:
2701 # Restore sys.path to what it was before.
2702 sys.path = original_sys_path
2703
2704 return checkstyle.RunCheckstyle(
2705 input_api,
2706 output_api,
2707 'tools/android/checkstyle/chromium-style-5.0.xml',
2708 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
2709
2710
2711def CheckPythonDevilInit(input_api, output_api):
2712 """Checks to make sure devil is initialized correctly in python scripts."""
2713 script_common_initialize_pattern = input_api.re.compile(
2714 r'script_common\.InitializeEnvironment\(')
2715 devil_env_config_initialize = input_api.re.compile(
2716 r'devil_env\.config\.Initialize\(')
2717
2718 errors = []
2719
2720 sources = lambda affected_file: input_api.FilterSourceFile(
2721 affected_file,
2722 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
2723 r'^build[\\/]android[\\/]devil_chromium\.py',
2724 r'^third_party[\\/].*',
2725 )),
2726 files_to_check=[r'.*\.py$'])
2727
2728 for f in input_api.AffectedSourceFiles(sources):
2729 for line_num, line in f.ChangedContents():
2730 if (script_common_initialize_pattern.search(line)
2731 or devil_env_config_initialize.search(line)):
2732 errors.append("%s:%d" % (f.LocalPath(), line_num))
2733
2734 results = []
2735
2736 if errors:
2737 results.append(
2738 output_api.PresubmitError(
2739 'Devil initialization should always be done using '
2740 'devil_chromium.Initialize() in the chromium project, to use better '
2741 'defaults for dependencies (ex. up-to-date version of adb).',
2742 errors))
2743
2744 return results
2745
2746
2747def _MatchesFile(input_api, patterns, path):
2748 for pattern in patterns:
2749 if input_api.re.search(pattern, path):
2750 return True
2751 return False
2752
2753
2754def _GetOwnersFilesToCheckForIpcOwners(input_api):
2755 """Gets a list of OWNERS files to check for correct security owners.
2756
2757 Returns:
2758 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2759 contain to cover IPC-related files with noparent reviewer rules.
2760 """
2761 # Whether or not a file affects IPC is (mostly) determined by a simple list
2762 # of filename patterns.
2763 file_patterns = [
2764 # Legacy IPC:
2765 '*_messages.cc',
2766 '*_messages*.h',
2767 '*_param_traits*.*',
2768 # Mojo IPC:
2769 '*.mojom',
2770 '*_mojom_traits*.*',
2771 '*_struct_traits*.*',
2772 '*_type_converter*.*',
2773 '*.typemap',
2774 # Android native IPC:
2775 '*.aidl',
2776 # Blink uses a different file naming convention:
2777 '*EnumTraits*.*',
2778 "*MojomTraits*.*",
2779 '*StructTraits*.*',
2780 '*TypeConverter*.*',
2781 ]
2782
2783 # These third_party directories do not contain IPCs, but contain files
2784 # matching the above patterns, which trigger false positives.
2785 exclude_paths = [
2786 'third_party/crashpad/*',
2787 'third_party/blink/renderer/platform/bindings/*',
2788 'third_party/protobuf/benchmarks/python/*',
2789 'third_party/win_build_output/*',
2790 # These files are just used to communicate between class loaders running
2791 # in the same process.
2792 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
2793 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2794 ]
2795
2796 # Dictionary mapping an OWNERS file path to Patterns.
2797 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2798 # rules ) to a PatternEntry.
2799 # PatternEntry is a dictionary with two keys:
2800 # - 'files': the files that are matched by this pattern
2801 # - 'rules': the per-file rules needed for this pattern
2802 # For example, if we expect OWNERS file to contain rules for *.mojom and
2803 # *_struct_traits*.*, Patterns might look like this:
2804 # {
2805 # '*.mojom': {
2806 # 'files': ...,
2807 # 'rules': [
2808 # 'per-file *.mojom=set noparent',
2809 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2810 # ],
2811 # },
2812 # '*_struct_traits*.*': {
2813 # 'files': ...,
2814 # 'rules': [
2815 # 'per-file *_struct_traits*.*=set noparent',
2816 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2817 # ],
2818 # },
2819 # }
2820 to_check = {}
2821
2822 def AddPatternToCheck(input_file, pattern):
2823 owners_file = input_api.os_path.join(
2824 input_api.os_path.dirname(input_file.AbsoluteLocalPath()),
2825 'OWNERS')
2826 if owners_file not in to_check:
2827 to_check[owners_file] = {}
2828 if pattern not in to_check[owners_file]:
2829 to_check[owners_file][pattern] = {
2830 'files': [],
2831 'rules': [
2832 'per-file %s=set noparent' % pattern,
2833 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2834 ]
2835 }
2836 to_check[owners_file][pattern]['files'].append(input_file)
2837
2838 # Iterate through the affected files to see what we actually need to check
2839 # for. We should only nag patch authors about per-file rules if a file in that
2840 # directory would match that pattern. If a directory only contains *.mojom
2841 # files and no *_messages*.h files, we should only nag about rules for
2842 # *.mojom files.
2843 for f in input_api.AffectedFiles(include_deletes=False):
2844 # Manifest files don't have a strong naming convention. Instead, try to find
2845 # affected .cc and .h files which look like they contain a manifest
2846 # definition.
2847 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2848 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2849 if (manifest_pattern.search(f.LocalPath())
2850 and not test_manifest_pattern.search(f.LocalPath())):
2851 # We expect all actual service manifest files to contain at least one
2852 # qualified reference to service_manager::Manifest.
2853 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2854 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
2855 for pattern in file_patterns:
2856 if input_api.fnmatch.fnmatch(
2857 input_api.os_path.basename(f.LocalPath()), pattern):
2858 skip = False
2859 for exclude in exclude_paths:
2860 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2861 skip = True
2862 break
2863 if skip:
2864 continue
2865 AddPatternToCheck(f, pattern)
2866 break
2867
2868 return to_check
2869
2870
2871def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2872 """Adds OWNERS files to check for correct Fuchsia security owners."""
2873
2874 file_patterns = [
2875 # Component specifications.
2876 '*.cml', # Component Framework v2.
2877 '*.cmx', # Component Framework v1.
2878
2879 # Fuchsia IDL protocol specifications.
2880 '*.fidl',
2881 ]
2882
2883 # Don't check for owners files for changes in these directories.
2884 exclude_paths = [
2885 'third_party/crashpad/*',
2886 ]
2887
2888 def AddPatternToCheck(input_file, pattern):
2889 owners_file = input_api.os_path.join(
2890 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2891 if owners_file not in to_check:
2892 to_check[owners_file] = {}
2893 if pattern not in to_check[owners_file]:
2894 to_check[owners_file][pattern] = {
2895 'files': [],
2896 'rules': [
2897 'per-file %s=set noparent' % pattern,
2898 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2899 ]
2900 }
2901 to_check[owners_file][pattern]['files'].append(input_file)
2902
2903 # Iterate through the affected files to see what we actually need to check
2904 # for. We should only nag patch authors about per-file rules if a file in that
2905 # directory would match that pattern.
2906 for f in input_api.AffectedFiles(include_deletes=False):
2907 skip = False
2908 for exclude in exclude_paths:
2909 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2910 skip = True
2911 if skip:
2912 continue
2913
2914 for pattern in file_patterns:
2915 if input_api.fnmatch.fnmatch(
2916 input_api.os_path.basename(f.LocalPath()), pattern):
2917 AddPatternToCheck(f, pattern)
2918 break
2919
2920 return to_check
2921
2922
2923def CheckSecurityOwners(input_api, output_api):
2924 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2925 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2926 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
2927
2928 if to_check:
2929 # If there are any OWNERS files to check, there are IPC-related changes in
2930 # this CL. Auto-CC the review list.
2931 output_api.AppendCC('[email protected]')
2932
2933 # Go through the OWNERS files to check, filtering out rules that are already
2934 # present in that OWNERS file.
2935 for owners_file, patterns in to_check.items():
2936 try:
2937 with open(owners_file) as f:
2938 lines = set(f.read().splitlines())
2939 for entry in patterns.values():
2940 entry['rules'] = [
2941 rule for rule in entry['rules'] if rule not in lines
2942 ]
2943 except IOError:
2944 # No OWNERS file, so all the rules are definitely missing.
2945 continue
2946
2947 # All the remaining lines weren't found in OWNERS files, so emit an error.
2948 errors = []
2949 for owners_file, patterns in to_check.items():
2950 missing_lines = []
2951 files = []
2952 for _, entry in patterns.items():
2953 missing_lines.extend(entry['rules'])
2954 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2955 if missing_lines:
2956 errors.append('Because of the presence of files:\n%s\n\n'
2957 '%s needs the following %d lines added:\n\n%s' %
2958 ('\n'.join(files), owners_file, len(missing_lines),
2959 '\n'.join(missing_lines)))
2960
2961 results = []
2962 if errors:
2963 if input_api.is_committing:
2964 output = output_api.PresubmitError
2965 else:
2966 output = output_api.PresubmitPromptWarning
2967 results.append(
2968 output(
2969 'Found OWNERS files that need to be updated for IPC security '
2970 + 'review coverage.\nPlease update the OWNERS files below:',
2971 long_text='\n\n'.join(errors)))
2972
2973 return results
2974
2975
2976def _GetFilesUsingSecurityCriticalFunctions(input_api):
2977 """Checks affected files for changes to security-critical calls. This
2978 function checks the full change diff, to catch both additions/changes
2979 and removals.
2980
2981 Returns a dict keyed by file name, and the value is a set of detected
2982 functions.
2983 """
2984 # Map of function pretty name (displayed in an error) to the pattern to
2985 # match it with.
2986 _PATTERNS_TO_CHECK = {
2987 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
2988 }
2989 _PATTERNS_TO_CHECK = {
2990 k: input_api.re.compile(v)
2991 for k, v in _PATTERNS_TO_CHECK.items()
2992 }
2993
John Budorick47ca3fe2018-02-10 00:53:102994 import os
2995
Sam Maiera6e76d72022-02-11 21:43:502996 # We don't want to trigger on strings within this file.
2997 def presubmit_file_filter(f):
2998 return 'PRESUBMIT.py' != os.path.split(f.LocalPath())[1]
2999
3000 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3001 files_to_functions = {}
3002 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3003 diff = f.GenerateScmDiff()
3004 for line in diff.split('\n'):
3005 # Not using just RightHandSideLines() because removing a
3006 # call to a security-critical function can be just as important
3007 # as adding or changing the arguments.
3008 if line.startswith('-') or (line.startswith('+')
3009 and not line.startswith('++')):
3010 for name, pattern in _PATTERNS_TO_CHECK.items():
3011 if pattern.search(line):
3012 path = f.LocalPath()
3013 if not path in files_to_functions:
3014 files_to_functions[path] = set()
3015 files_to_functions[path].add(name)
3016 return files_to_functions
3017
3018
3019def CheckSecurityChanges(input_api, output_api):
3020 """Checks that changes involving security-critical functions are reviewed
3021 by the security team.
3022 """
3023 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3024 if not len(files_to_functions):
3025 return []
3026
3027 owner_email, reviewers = (
3028 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3029 input_api, None, approval_needed=input_api.is_committing))
3030
3031 # Load the OWNERS file for security changes.
3032 owners_file = 'ipc/SECURITY_OWNERS'
3033 security_owners = input_api.owners_client.ListOwners(owners_file)
3034 has_security_owner = any([owner in reviewers for owner in security_owners])
3035 if has_security_owner:
3036 return []
3037
3038 msg = 'The following files change calls to security-sensive functions\n' \
3039 'that need to be reviewed by {}.\n'.format(owners_file)
3040 for path, names in files_to_functions.items():
3041 msg += ' {}\n'.format(path)
3042 for name in names:
3043 msg += ' {}\n'.format(name)
3044 msg += '\n'
3045
3046 if input_api.is_committing:
3047 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033048 else:
Sam Maiera6e76d72022-02-11 21:43:503049 output = output_api.PresubmitNotifyResult
3050 return [output(msg)]
3051
3052
3053def CheckSetNoParent(input_api, output_api):
3054 """Checks that set noparent is only used together with an OWNERS file in
3055 //build/OWNERS.setnoparent (see also
3056 //docs/code_reviews.md#owners-files-details)
3057 """
3058 # Return early if no OWNERS files were modified.
3059 if not any(f.LocalPath().endswith('OWNERS')
3060 for f in input_api.AffectedFiles(include_deletes=False)):
3061 return []
3062
3063 errors = []
3064
3065 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3066 allowed_owners_files = set()
3067 with open(allowed_owners_files_file, 'r') as f:
3068 for line in f:
3069 line = line.strip()
3070 if not line or line.startswith('#'):
3071 continue
3072 allowed_owners_files.add(line)
3073
3074 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3075
3076 for f in input_api.AffectedFiles(include_deletes=False):
3077 if not f.LocalPath().endswith('OWNERS'):
3078 continue
3079
3080 found_owners_files = set()
3081 found_set_noparent_lines = dict()
3082
3083 # Parse the OWNERS file.
3084 for lineno, line in enumerate(f.NewContents(), 1):
3085 line = line.strip()
3086 if line.startswith('set noparent'):
3087 found_set_noparent_lines[''] = lineno
3088 if line.startswith('file://'):
3089 if line in allowed_owners_files:
3090 found_owners_files.add('')
3091 if line.startswith('per-file'):
3092 match = per_file_pattern.match(line)
3093 if match:
3094 glob = match.group(1).strip()
3095 directive = match.group(2).strip()
3096 if directive == 'set noparent':
3097 found_set_noparent_lines[glob] = lineno
3098 if directive.startswith('file://'):
3099 if directive in allowed_owners_files:
3100 found_owners_files.add(glob)
3101
3102 # Check that every set noparent line has a corresponding file:// line
3103 # listed in build/OWNERS.setnoparent. An exception is made for top level
3104 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493105 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3106 if (linux_path.count('/') != 1
3107 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503108 for set_noparent_line in found_set_noparent_lines:
3109 if set_noparent_line in found_owners_files:
3110 continue
3111 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493112 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503113 found_set_noparent_lines[set_noparent_line]))
3114
3115 results = []
3116 if errors:
3117 if input_api.is_committing:
3118 output = output_api.PresubmitError
3119 else:
3120 output = output_api.PresubmitPromptWarning
3121 results.append(
3122 output(
3123 'Found the following "set noparent" restrictions in OWNERS files that '
3124 'do not include owners from build/OWNERS.setnoparent:',
3125 long_text='\n\n'.join(errors)))
3126 return results
3127
3128
3129def CheckUselessForwardDeclarations(input_api, output_api):
3130 """Checks that added or removed lines in non third party affected
3131 header files do not lead to new useless class or struct forward
3132 declaration.
3133 """
3134 results = []
3135 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3136 input_api.re.MULTILINE)
3137 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3138 input_api.re.MULTILINE)
3139 for f in input_api.AffectedFiles(include_deletes=False):
3140 if (f.LocalPath().startswith('third_party')
3141 and not f.LocalPath().startswith('third_party/blink')
3142 and not f.LocalPath().startswith('third_party\\blink')):
3143 continue
3144
3145 if not f.LocalPath().endswith('.h'):
3146 continue
3147
3148 contents = input_api.ReadFile(f)
3149 fwd_decls = input_api.re.findall(class_pattern, contents)
3150 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3151
3152 useless_fwd_decls = []
3153 for decl in fwd_decls:
3154 count = sum(1 for _ in input_api.re.finditer(
3155 r'\b%s\b' % input_api.re.escape(decl), contents))
3156 if count == 1:
3157 useless_fwd_decls.append(decl)
3158
3159 if not useless_fwd_decls:
3160 continue
3161
3162 for line in f.GenerateScmDiff().splitlines():
3163 if (line.startswith('-') and not line.startswith('--')
3164 or line.startswith('+') and not line.startswith('++')):
3165 for decl in useless_fwd_decls:
3166 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3167 results.append(
3168 output_api.PresubmitPromptWarning(
3169 '%s: %s forward declaration is no longer needed'
3170 % (f.LocalPath(), decl)))
3171 useless_fwd_decls.remove(decl)
3172
3173 return results
3174
3175
3176def _CheckAndroidDebuggableBuild(input_api, output_api):
3177 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3178 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3179 this is a debuggable build of Android.
3180 """
3181 build_type_check_pattern = input_api.re.compile(
3182 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3183
3184 errors = []
3185
3186 sources = lambda affected_file: input_api.FilterSourceFile(
3187 affected_file,
3188 files_to_skip=(
3189 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3190 DEFAULT_FILES_TO_SKIP + (
3191 r"^android_webview[\\/]support_library[\\/]"
3192 "boundary_interfaces[\\/]",
3193 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3194 r'^third_party[\\/].*',
3195 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3196 r"webview[\\/]chromium[\\/]License.*",
3197 )),
3198 files_to_check=[r'.*\.java$'])
3199
3200 for f in input_api.AffectedSourceFiles(sources):
3201 for line_num, line in f.ChangedContents():
3202 if build_type_check_pattern.search(line):
3203 errors.append("%s:%d" % (f.LocalPath(), line_num))
3204
3205 results = []
3206
3207 if errors:
3208 results.append(
3209 output_api.PresubmitPromptWarning(
3210 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3211 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3212
3213 return results
3214
3215# TODO: add unit tests
3216def _CheckAndroidToastUsage(input_api, output_api):
3217 """Checks that code uses org.chromium.ui.widget.Toast instead of
3218 android.widget.Toast (Chromium Toast doesn't force hardware
3219 acceleration on low-end devices, saving memory).
3220 """
3221 toast_import_pattern = input_api.re.compile(
3222 r'^import android\.widget\.Toast;$')
3223
3224 errors = []
3225
3226 sources = lambda affected_file: input_api.FilterSourceFile(
3227 affected_file,
3228 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3229 DEFAULT_FILES_TO_SKIP + (r'^chromecast[\\/].*',
3230 r'^remoting[\\/].*')),
3231 files_to_check=[r'.*\.java$'])
3232
3233 for f in input_api.AffectedSourceFiles(sources):
3234 for line_num, line in f.ChangedContents():
3235 if toast_import_pattern.search(line):
3236 errors.append("%s:%d" % (f.LocalPath(), line_num))
3237
3238 results = []
3239
3240 if errors:
3241 results.append(
3242 output_api.PresubmitError(
3243 'android.widget.Toast usage is detected. Android toasts use hardware'
3244 ' acceleration, and can be\ncostly on low-end devices. Please use'
3245 ' org.chromium.ui.widget.Toast instead.\n'
3246 'Contact [email protected] if you have any questions.',
3247 errors))
3248
3249 return results
3250
3251
3252def _CheckAndroidCrLogUsage(input_api, output_api):
3253 """Checks that new logs using org.chromium.base.Log:
3254 - Are using 'TAG' as variable name for the tags (warn)
3255 - Are using a tag that is shorter than 20 characters (error)
3256 """
3257
3258 # Do not check format of logs in the given files
3259 cr_log_check_excluded_paths = [
3260 # //chrome/android/webapk cannot depend on //base
3261 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3262 # WebView license viewer code cannot depend on //base; used in stub APK.
3263 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3264 r"webview[\\/]chromium[\\/]License.*",
3265 # The customtabs_benchmark is a small app that does not depend on Chromium
3266 # java pieces.
3267 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3268 ]
3269
3270 cr_log_import_pattern = input_api.re.compile(
3271 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3272 class_in_base_pattern = input_api.re.compile(
3273 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3274 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3275 input_api.re.MULTILINE)
3276 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3277 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3278 log_decl_pattern = input_api.re.compile(
3279 r'static final String TAG = "(?P<name>(.*))"')
3280 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3281
3282 REF_MSG = ('See docs/android_logging.md for more info.')
3283 sources = lambda x: input_api.FilterSourceFile(
3284 x,
3285 files_to_check=[r'.*\.java$'],
3286 files_to_skip=cr_log_check_excluded_paths)
3287
3288 tag_decl_errors = []
3289 tag_length_errors = []
3290 tag_errors = []
3291 tag_with_dot_errors = []
3292 util_log_errors = []
3293
3294 for f in input_api.AffectedSourceFiles(sources):
3295 file_content = input_api.ReadFile(f)
3296 has_modified_logs = False
3297 # Per line checks
3298 if (cr_log_import_pattern.search(file_content)
3299 or (class_in_base_pattern.search(file_content)
3300 and not has_some_log_import_pattern.search(file_content))):
3301 # Checks to run for files using cr log
3302 for line_num, line in f.ChangedContents():
3303 if rough_log_decl_pattern.search(line):
3304 has_modified_logs = True
3305
3306 # Check if the new line is doing some logging
3307 match = log_call_pattern.search(line)
3308 if match:
3309 has_modified_logs = True
3310
3311 # Make sure it uses "TAG"
3312 if not match.group('tag') == 'TAG':
3313 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3314 else:
3315 # Report non cr Log function calls in changed lines
3316 for line_num, line in f.ChangedContents():
3317 if log_call_pattern.search(line):
3318 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3319
3320 # Per file checks
3321 if has_modified_logs:
3322 # Make sure the tag is using the "cr" prefix and is not too long
3323 match = log_decl_pattern.search(file_content)
3324 tag_name = match.group('name') if match else None
3325 if not tag_name:
3326 tag_decl_errors.append(f.LocalPath())
3327 elif len(tag_name) > 20:
3328 tag_length_errors.append(f.LocalPath())
3329 elif '.' in tag_name:
3330 tag_with_dot_errors.append(f.LocalPath())
3331
3332 results = []
3333 if tag_decl_errors:
3334 results.append(
3335 output_api.PresubmitPromptWarning(
3336 'Please define your tags using the suggested format: .\n'
3337 '"private static final String TAG = "<package tag>".\n'
3338 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3339 tag_decl_errors))
3340
3341 if tag_length_errors:
3342 results.append(
3343 output_api.PresubmitError(
3344 'The tag length is restricted by the system to be at most '
3345 '20 characters.\n' + REF_MSG, tag_length_errors))
3346
3347 if tag_errors:
3348 results.append(
3349 output_api.PresubmitPromptWarning(
3350 'Please use a variable named "TAG" for your log tags.\n' +
3351 REF_MSG, tag_errors))
3352
3353 if util_log_errors:
3354 results.append(
3355 output_api.PresubmitPromptWarning(
3356 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3357 util_log_errors))
3358
3359 if tag_with_dot_errors:
3360 results.append(
3361 output_api.PresubmitPromptWarning(
3362 'Dot in log tags cause them to be elided in crash reports.\n' +
3363 REF_MSG, tag_with_dot_errors))
3364
3365 return results
3366
3367
3368def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3369 """Checks that junit.framework.* is no longer used."""
3370 deprecated_junit_framework_pattern = input_api.re.compile(
3371 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3372 sources = lambda x: input_api.FilterSourceFile(
3373 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3374 errors = []
3375 for f in input_api.AffectedFiles(file_filter=sources):
3376 for line_num, line in f.ChangedContents():
3377 if deprecated_junit_framework_pattern.search(line):
3378 errors.append("%s:%d" % (f.LocalPath(), line_num))
3379
3380 results = []
3381 if errors:
3382 results.append(
3383 output_api.PresubmitError(
3384 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3385 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3386 ' if you have any question.', errors))
3387 return results
3388
3389
3390def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3391 """Checks that if new Java test classes have inheritance.
3392 Either the new test class is JUnit3 test or it is a JUnit4 test class
3393 with a base class, either case is undesirable.
3394 """
3395 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3396
3397 sources = lambda x: input_api.FilterSourceFile(
3398 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3399 errors = []
3400 for f in input_api.AffectedFiles(file_filter=sources):
3401 if not f.OldContents():
3402 class_declaration_start_flag = False
3403 for line_num, line in f.ChangedContents():
3404 if class_declaration_pattern.search(line):
3405 class_declaration_start_flag = True
3406 if class_declaration_start_flag and ' extends ' in line:
3407 errors.append('%s:%d' % (f.LocalPath(), line_num))
3408 if '{' in line:
3409 class_declaration_start_flag = False
3410
3411 results = []
3412 if errors:
3413 results.append(
3414 output_api.PresubmitPromptWarning(
3415 'The newly created files include Test classes that inherits from base'
3416 ' class. Please do not use inheritance in JUnit4 tests or add new'
3417 ' JUnit3 tests. Contact [email protected] if you have any'
3418 ' questions.', errors))
3419 return results
3420
3421
3422def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3423 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3424 deprecated_annotation_import_pattern = input_api.re.compile(
3425 r'^import android\.test\.suitebuilder\.annotation\..*;',
3426 input_api.re.MULTILINE)
3427 sources = lambda x: input_api.FilterSourceFile(
3428 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3429 errors = []
3430 for f in input_api.AffectedFiles(file_filter=sources):
3431 for line_num, line in f.ChangedContents():
3432 if deprecated_annotation_import_pattern.search(line):
3433 errors.append("%s:%d" % (f.LocalPath(), line_num))
3434
3435 results = []
3436 if errors:
3437 results.append(
3438 output_api.PresubmitError(
3439 'Annotations in android.test.suitebuilder.annotation have been'
3440 ' deprecated since API level 24. Please use android.support.test.filters'
3441 ' from //third_party/android_support_test_runner:runner_java instead.'
3442 ' Contact [email protected] if you have any questions.',
3443 errors))
3444 return results
3445
3446
3447def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3448 """Checks if MDPI assets are placed in a correct directory."""
3449 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3450 ('/res/drawable/' in f.LocalPath() or
3451 '/res/drawable-ldrtl/' in f.LocalPath()))
3452 errors = []
3453 for f in input_api.AffectedFiles(include_deletes=False,
3454 file_filter=file_filter):
3455 errors.append(' %s' % f.LocalPath())
3456
3457 results = []
3458 if errors:
3459 results.append(
3460 output_api.PresubmitError(
3461 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3462 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3463 '/res/drawable-ldrtl/.\n'
3464 'Contact [email protected] if you have questions.', errors))
3465 return results
3466
3467
3468def _CheckAndroidWebkitImports(input_api, output_api):
3469 """Checks that code uses org.chromium.base.Callback instead of
3470 android.webview.ValueCallback except in the WebView glue layer
3471 and WebLayer.
3472 """
3473 valuecallback_import_pattern = input_api.re.compile(
3474 r'^import android\.webkit\.ValueCallback;$')
3475
3476 errors = []
3477
3478 sources = lambda affected_file: input_api.FilterSourceFile(
3479 affected_file,
3480 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3481 DEFAULT_FILES_TO_SKIP + (
3482 r'^android_webview[\\/]glue[\\/].*',
3483 r'^weblayer[\\/].*',
3484 )),
3485 files_to_check=[r'.*\.java$'])
3486
3487 for f in input_api.AffectedSourceFiles(sources):
3488 for line_num, line in f.ChangedContents():
3489 if valuecallback_import_pattern.search(line):
3490 errors.append("%s:%d" % (f.LocalPath(), line_num))
3491
3492 results = []
3493
3494 if errors:
3495 results.append(
3496 output_api.PresubmitError(
3497 'android.webkit.ValueCallback usage is detected outside of the glue'
3498 ' layer. To stay compatible with the support library, android.webkit.*'
3499 ' classes should only be used inside the glue layer and'
3500 ' org.chromium.base.Callback should be used instead.', errors))
3501
3502 return results
3503
3504
3505def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3506 """Checks Android XML styles """
3507
3508 # Return early if no relevant files were modified.
3509 if not any(
3510 _IsXmlOrGrdFile(input_api, f.LocalPath())
3511 for f in input_api.AffectedFiles(include_deletes=False)):
3512 return []
3513
3514 import sys
3515 original_sys_path = sys.path
3516 try:
3517 sys.path = sys.path + [
3518 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3519 'android', 'checkxmlstyle')
3520 ]
3521 import checkxmlstyle
3522 finally:
3523 # Restore sys.path to what it was before.
3524 sys.path = original_sys_path
3525
3526 if is_check_on_upload:
3527 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3528 else:
3529 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3530
3531
3532def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3533 """Checks Android Infobar Deprecation """
3534
3535 import sys
3536 original_sys_path = sys.path
3537 try:
3538 sys.path = sys.path + [
3539 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3540 'android', 'infobar_deprecation')
3541 ]
3542 import infobar_deprecation
3543 finally:
3544 # Restore sys.path to what it was before.
3545 sys.path = original_sys_path
3546
3547 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3548
3549
3550class _PydepsCheckerResult:
3551 def __init__(self, cmd, pydeps_path, process, old_contents):
3552 self._cmd = cmd
3553 self._pydeps_path = pydeps_path
3554 self._process = process
3555 self._old_contents = old_contents
3556
3557 def GetError(self):
3558 """Returns an error message, or None."""
3559 import difflib
3560 if self._process.wait() != 0:
3561 # STDERR should already be printed.
3562 return 'Command failed: ' + self._cmd
3563 new_contents = self._process.stdout.read().splitlines()[2:]
3564 if self._old_contents != new_contents:
3565 diff = '\n'.join(
3566 difflib.context_diff(self._old_contents, new_contents))
3567 return ('File is stale: {}\n'
3568 'Diff (apply to fix):\n'
3569 '{}\n'
3570 'To regenerate, run:\n\n'
3571 ' {}').format(self._pydeps_path, diff, self._cmd)
3572 return None
3573
3574
3575class PydepsChecker:
3576 def __init__(self, input_api, pydeps_files):
3577 self._file_cache = {}
3578 self._input_api = input_api
3579 self._pydeps_files = pydeps_files
3580
3581 def _LoadFile(self, path):
3582 """Returns the list of paths within a .pydeps file relative to //."""
3583 if path not in self._file_cache:
3584 with open(path, encoding='utf-8') as f:
3585 self._file_cache[path] = f.read()
3586 return self._file_cache[path]
3587
3588 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3589 """Returns an interable of paths within the .pydep, relativized to //."""
3590 pydeps_data = self._LoadFile(pydeps_path)
3591 uses_gn_paths = '--gn-paths' in pydeps_data
3592 entries = (l for l in pydeps_data.splitlines()
3593 if not l.startswith('#'))
3594 if uses_gn_paths:
3595 # Paths look like: //foo/bar/baz
3596 return (e[2:] for e in entries)
3597 else:
3598 # Paths look like: path/relative/to/file.pydeps
3599 os_path = self._input_api.os_path
3600 pydeps_dir = os_path.dirname(pydeps_path)
3601 return (os_path.normpath(os_path.join(pydeps_dir, e))
3602 for e in entries)
3603
3604 def _CreateFilesToPydepsMap(self):
3605 """Returns a map of local_path -> list_of_pydeps."""
3606 ret = {}
3607 for pydep_local_path in self._pydeps_files:
3608 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3609 ret.setdefault(path, []).append(pydep_local_path)
3610 return ret
3611
3612 def ComputeAffectedPydeps(self):
3613 """Returns an iterable of .pydeps files that might need regenerating."""
3614 affected_pydeps = set()
3615 file_to_pydeps_map = None
3616 for f in self._input_api.AffectedFiles(include_deletes=True):
3617 local_path = f.LocalPath()
3618 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3619 # subrepositories. We can't figure out which files change, so re-check
3620 # all files.
3621 # Changes to print_python_deps.py affect all .pydeps.
3622 if local_path in ('DEPS', 'PRESUBMIT.py'
3623 ) or local_path.endswith('print_python_deps.py'):
3624 return self._pydeps_files
3625 elif local_path.endswith('.pydeps'):
3626 if local_path in self._pydeps_files:
3627 affected_pydeps.add(local_path)
3628 elif local_path.endswith('.py'):
3629 if file_to_pydeps_map is None:
3630 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3631 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3632 return affected_pydeps
3633
3634 def DetermineIfStaleAsync(self, pydeps_path):
3635 """Runs print_python_deps.py to see if the files is stale."""
3636 import os
3637
3638 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3639 if old_pydeps_data:
3640 cmd = old_pydeps_data[1][1:].strip()
3641 if '--output' not in cmd:
3642 cmd += ' --output ' + pydeps_path
3643 old_contents = old_pydeps_data[2:]
3644 else:
3645 # A default cmd that should work in most cases (as long as pydeps filename
3646 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3647 # file is empty/new.
3648 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3649 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3650 old_contents = []
3651 env = dict(os.environ)
3652 env['PYTHONDONTWRITEBYTECODE'] = '1'
3653 process = self._input_api.subprocess.Popen(
3654 cmd + ' --output ""',
3655 shell=True,
3656 env=env,
3657 stdout=self._input_api.subprocess.PIPE,
3658 encoding='utf-8')
3659 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:403660
3661
Tibor Goldschwendt360793f72019-06-25 18:23:493662def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:503663 args = {}
3664 with open('build/config/gclient_args.gni', 'r') as f:
3665 for line in f:
3666 line = line.strip()
3667 if not line or line.startswith('#'):
3668 continue
3669 attribute, value = line.split('=')
3670 args[attribute.strip()] = value.strip()
3671 return args
Tibor Goldschwendt360793f72019-06-25 18:23:493672
3673
Saagar Sanghavifceeaae2020-08-12 16:40:363674def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:503675 """Checks if a .pydeps file needs to be regenerated."""
3676 # This check is for Python dependency lists (.pydeps files), and involves
3677 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3678 # doesn't work on Windows and Mac, so skip it on other platforms.
3679 if not input_api.platform.startswith('linux'):
3680 return []
Erik Staabc734cd7a2021-11-23 03:11:523681
Sam Maiera6e76d72022-02-11 21:43:503682 results = []
3683 # First, check for new / deleted .pydeps.
3684 for f in input_api.AffectedFiles(include_deletes=True):
3685 # Check whether we are running the presubmit check for a file in src.
3686 # f.LocalPath is relative to repo (src, or internal repo).
3687 # os_path.exists is relative to src repo.
3688 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3689 # to src and we can conclude that the pydeps is in src.
3690 if f.LocalPath().endswith('.pydeps'):
3691 if input_api.os_path.exists(f.LocalPath()):
3692 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3693 results.append(
3694 output_api.PresubmitError(
3695 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3696 'remove %s' % f.LocalPath()))
3697 elif f.Action() != 'D' and f.LocalPath(
3698 ) not in _ALL_PYDEPS_FILES:
3699 results.append(
3700 output_api.PresubmitError(
3701 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3702 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403703
Sam Maiera6e76d72022-02-11 21:43:503704 if results:
3705 return results
3706
3707 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
3708 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3709 affected_pydeps = set(checker.ComputeAffectedPydeps())
3710 affected_android_pydeps = affected_pydeps.intersection(
3711 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3712 if affected_android_pydeps and not is_android:
3713 results.append(
3714 output_api.PresubmitPromptOrNotify(
3715 'You have changed python files that may affect pydeps for android\n'
3716 'specific scripts. However, the relevant presumbit check cannot be\n'
3717 'run because you are not using an Android checkout. To validate that\n'
3718 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3719 'use the android-internal-presubmit optional trybot.\n'
3720 'Possibly stale pydeps files:\n{}'.format(
3721 '\n'.join(affected_android_pydeps))))
3722
3723 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3724 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
3725 # Process these concurrently, as each one takes 1-2 seconds.
3726 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
3727 for result in pydep_results:
3728 error_msg = result.GetError()
3729 if error_msg:
3730 results.append(output_api.PresubmitError(error_msg))
3731
agrievef32bcc72016-04-04 14:57:403732 return results
3733
agrievef32bcc72016-04-04 14:57:403734
Saagar Sanghavifceeaae2020-08-12 16:40:363735def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503736 """Checks to make sure no header files have |Singleton<|."""
3737
3738 def FileFilter(affected_file):
3739 # It's ok for base/memory/singleton.h to have |Singleton<|.
3740 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
3741 (r"^base[\\/]memory[\\/]singleton\.h$",
3742 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
James Cook24a504192020-07-23 00:08:443743 r"quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:503744 return input_api.FilterSourceFile(affected_file,
3745 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433746
Sam Maiera6e76d72022-02-11 21:43:503747 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
3748 files = []
3749 for f in input_api.AffectedSourceFiles(FileFilter):
3750 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
3751 or f.LocalPath().endswith('.hpp')
3752 or f.LocalPath().endswith('.inl')):
3753 contents = input_api.ReadFile(f)
3754 for line in contents.splitlines(False):
3755 if (not line.lstrip().startswith('//')
3756 and # Strip C++ comment.
3757 pattern.search(line)):
3758 files.append(f)
3759 break
glidere61efad2015-02-18 17:39:433760
Sam Maiera6e76d72022-02-11 21:43:503761 if files:
3762 return [
3763 output_api.PresubmitError(
3764 'Found base::Singleton<T> in the following header files.\n' +
3765 'Please move them to an appropriate source file so that the ' +
3766 'template gets instantiated in a single compilation unit.',
3767 files)
3768 ]
3769 return []
glidere61efad2015-02-18 17:39:433770
3771
[email protected]fd20b902014-05-09 02:14:533772_DEPRECATED_CSS = [
3773 # Values
3774 ( "-webkit-box", "flex" ),
3775 ( "-webkit-inline-box", "inline-flex" ),
3776 ( "-webkit-flex", "flex" ),
3777 ( "-webkit-inline-flex", "inline-flex" ),
3778 ( "-webkit-min-content", "min-content" ),
3779 ( "-webkit-max-content", "max-content" ),
3780
3781 # Properties
3782 ( "-webkit-background-clip", "background-clip" ),
3783 ( "-webkit-background-origin", "background-origin" ),
3784 ( "-webkit-background-size", "background-size" ),
3785 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443786 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533787
3788 # Functions
3789 ( "-webkit-gradient", "gradient" ),
3790 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3791 ( "-webkit-linear-gradient", "linear-gradient" ),
3792 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3793 ( "-webkit-radial-gradient", "radial-gradient" ),
3794 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3795]
3796
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203797
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493798# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363799def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503800 """ Make sure that we don't use deprecated CSS
3801 properties, functions or values. Our external
3802 documentation and iOS CSS for dom distiller
3803 (reader mode) are ignored by the hooks as it
3804 needs to be consumed by WebKit. """
3805 results = []
3806 file_inclusion_pattern = [r".+\.css$"]
3807 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3808 input_api.DEFAULT_FILES_TO_SKIP +
3809 (r"^chrome/common/extensions/docs", r"^chrome/docs",
3810 r"^native_client_sdk"))
3811 file_filter = lambda f: input_api.FilterSourceFile(
3812 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3813 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3814 for line_num, line in fpath.ChangedContents():
3815 for (deprecated_value, value) in _DEPRECATED_CSS:
3816 if deprecated_value in line:
3817 results.append(
3818 output_api.PresubmitError(
3819 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3820 (fpath.LocalPath(), line_num, deprecated_value,
3821 value)))
3822 return results
[email protected]fd20b902014-05-09 02:14:533823
mohan.reddyf21db962014-10-16 12:26:473824
Saagar Sanghavifceeaae2020-08-12 16:40:363825def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503826 bad_files = {}
3827 for f in input_api.AffectedFiles(include_deletes=False):
3828 if (f.LocalPath().startswith('third_party')
3829 and not f.LocalPath().startswith('third_party/blink')
3830 and not f.LocalPath().startswith('third_party\\blink')):
3831 continue
rlanday6802cf632017-05-30 17:48:363832
Sam Maiera6e76d72022-02-11 21:43:503833 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3834 continue
rlanday6802cf632017-05-30 17:48:363835
Sam Maiera6e76d72022-02-11 21:43:503836 relative_includes = [
3837 line for _, line in f.ChangedContents()
3838 if "#include" in line and "../" in line
3839 ]
3840 if not relative_includes:
3841 continue
3842 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:363843
Sam Maiera6e76d72022-02-11 21:43:503844 if not bad_files:
3845 return []
rlanday6802cf632017-05-30 17:48:363846
Sam Maiera6e76d72022-02-11 21:43:503847 error_descriptions = []
3848 for file_path, bad_lines in bad_files.items():
3849 error_description = file_path
3850 for line in bad_lines:
3851 error_description += '\n ' + line
3852 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:363853
Sam Maiera6e76d72022-02-11 21:43:503854 results = []
3855 results.append(
3856 output_api.PresubmitError(
3857 'You added one or more relative #include paths (including "../").\n'
3858 'These shouldn\'t be used because they can be used to include headers\n'
3859 'from code that\'s not correctly specified as a dependency in the\n'
3860 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:363861
Sam Maiera6e76d72022-02-11 21:43:503862 return results
rlanday6802cf632017-05-30 17:48:363863
Takeshi Yoshinoe387aa32017-08-02 13:16:133864
Saagar Sanghavifceeaae2020-08-12 16:40:363865def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503866 """Check that nobody tries to include a cc file. It's a relatively
3867 common error which results in duplicate symbols in object
3868 files. This may not always break the build until someone later gets
3869 very confusing linking errors."""
3870 results = []
3871 for f in input_api.AffectedFiles(include_deletes=False):
3872 # We let third_party code do whatever it wants
3873 if (f.LocalPath().startswith('third_party')
3874 and not f.LocalPath().startswith('third_party/blink')
3875 and not f.LocalPath().startswith('third_party\\blink')):
3876 continue
Daniel Bratell65b033262019-04-23 08:17:063877
Sam Maiera6e76d72022-02-11 21:43:503878 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3879 continue
Daniel Bratell65b033262019-04-23 08:17:063880
Sam Maiera6e76d72022-02-11 21:43:503881 for _, line in f.ChangedContents():
3882 if line.startswith('#include "'):
3883 included_file = line.split('"')[1]
3884 if _IsCPlusPlusFile(input_api, included_file):
3885 # The most common naming for external files with C++ code,
3886 # apart from standard headers, is to call them foo.inc, but
3887 # Chromium sometimes uses foo-inc.cc so allow that as well.
3888 if not included_file.endswith(('.h', '-inc.cc')):
3889 results.append(
3890 output_api.PresubmitError(
3891 'Only header files or .inc files should be included in other\n'
3892 'C++ files. Compiling the contents of a cc file more than once\n'
3893 'will cause duplicate information in the build which may later\n'
3894 'result in strange link_errors.\n' +
3895 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:063896
Sam Maiera6e76d72022-02-11 21:43:503897 return results
Daniel Bratell65b033262019-04-23 08:17:063898
3899
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203900def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:503901 if not isinstance(key, ast.Str):
3902 return 'Key at line %d must be a string literal' % key.lineno
3903 if not isinstance(value, ast.Dict):
3904 return 'Value at line %d must be a dict' % value.lineno
3905 if len(value.keys) != 1:
3906 return 'Dict at line %d must have single entry' % value.lineno
3907 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3908 return (
3909 'Entry at line %d must have a string literal \'filepath\' as key' %
3910 value.lineno)
3911 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133912
Takeshi Yoshinoe387aa32017-08-02 13:16:133913
Sergey Ulanov4af16052018-11-08 02:41:463914def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:503915 if not isinstance(key, ast.Str):
3916 return 'Key at line %d must be a string literal' % key.lineno
3917 if not isinstance(value, ast.List):
3918 return 'Value at line %d must be a list' % value.lineno
3919 for element in value.elts:
3920 if not isinstance(element, ast.Str):
3921 return 'Watchlist elements on line %d is not a string' % key.lineno
3922 if not email_regex.match(element.s):
3923 return ('Watchlist element on line %d doesn\'t look like a valid '
3924 + 'email: %s') % (key.lineno, element.s)
3925 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133926
Takeshi Yoshinoe387aa32017-08-02 13:16:133927
Sergey Ulanov4af16052018-11-08 02:41:463928def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:503929 mismatch_template = (
3930 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3931 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133932
Sam Maiera6e76d72022-02-11 21:43:503933 email_regex = input_api.re.compile(
3934 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:463935
Sam Maiera6e76d72022-02-11 21:43:503936 ast = input_api.ast
3937 i = 0
3938 last_key = ''
3939 while True:
3940 if i >= len(wd_dict.keys):
3941 if i >= len(w_dict.keys):
3942 return None
3943 return mismatch_template % ('missing',
3944 'line %d' % w_dict.keys[i].lineno)
3945 elif i >= len(w_dict.keys):
3946 return (mismatch_template %
3947 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133948
Sam Maiera6e76d72022-02-11 21:43:503949 wd_key = wd_dict.keys[i]
3950 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133951
Sam Maiera6e76d72022-02-11 21:43:503952 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
3953 wd_dict.values[i], ast)
3954 if result is not None:
3955 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133956
Sam Maiera6e76d72022-02-11 21:43:503957 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
3958 email_regex)
3959 if result is not None:
3960 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203961
Sam Maiera6e76d72022-02-11 21:43:503962 if wd_key.s != w_key.s:
3963 return mismatch_template % ('%s at line %d' %
3964 (wd_key.s, wd_key.lineno),
3965 '%s at line %d' %
3966 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203967
Sam Maiera6e76d72022-02-11 21:43:503968 if wd_key.s < last_key:
3969 return (
3970 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
3971 % (wd_key.lineno, w_key.lineno))
3972 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203973
Sam Maiera6e76d72022-02-11 21:43:503974 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203975
3976
Sergey Ulanov4af16052018-11-08 02:41:463977def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:503978 ast = input_api.ast
3979 if not isinstance(expression, ast.Expression):
3980 return 'WATCHLISTS file must contain a valid expression'
3981 dictionary = expression.body
3982 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3983 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203984
Sam Maiera6e76d72022-02-11 21:43:503985 first_key = dictionary.keys[0]
3986 first_value = dictionary.values[0]
3987 second_key = dictionary.keys[1]
3988 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203989
Sam Maiera6e76d72022-02-11 21:43:503990 if (not isinstance(first_key, ast.Str)
3991 or first_key.s != 'WATCHLIST_DEFINITIONS'
3992 or not isinstance(first_value, ast.Dict)):
3993 return ('The first entry of the dict in WATCHLISTS file must be '
3994 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203995
Sam Maiera6e76d72022-02-11 21:43:503996 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
3997 or not isinstance(second_value, ast.Dict)):
3998 return ('The second entry of the dict in WATCHLISTS file must be '
3999 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204000
Sam Maiera6e76d72022-02-11 21:43:504001 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134002
4003
Saagar Sanghavifceeaae2020-08-12 16:40:364004def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504005 for f in input_api.AffectedFiles(include_deletes=False):
4006 if f.LocalPath() == 'WATCHLISTS':
4007 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134008
Sam Maiera6e76d72022-02-11 21:43:504009 try:
4010 # First, make sure that it can be evaluated.
4011 input_api.ast.literal_eval(contents)
4012 # Get an AST tree for it and scan the tree for detailed style checking.
4013 expression = input_api.ast.parse(contents,
4014 filename='WATCHLISTS',
4015 mode='eval')
4016 except ValueError as e:
4017 return [
4018 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4019 long_text=repr(e))
4020 ]
4021 except SyntaxError as e:
4022 return [
4023 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4024 long_text=repr(e))
4025 ]
4026 except TypeError as e:
4027 return [
4028 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4029 long_text=repr(e))
4030 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134031
Sam Maiera6e76d72022-02-11 21:43:504032 result = _CheckWATCHLISTSSyntax(expression, input_api)
4033 if result is not None:
4034 return [output_api.PresubmitError(result)]
4035 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134036
Sam Maiera6e76d72022-02-11 21:43:504037 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134038
4039
Andrew Grieve1b290e4a22020-11-24 20:07:014040def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504041 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014042
Sam Maiera6e76d72022-02-11 21:43:504043 As documented at //build/docs/writing_gn_templates.md
4044 """
Andrew Grieve1b290e4a22020-11-24 20:07:014045
Sam Maiera6e76d72022-02-11 21:43:504046 def gn_files(f):
4047 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014048
Sam Maiera6e76d72022-02-11 21:43:504049 problems = []
4050 for f in input_api.AffectedSourceFiles(gn_files):
4051 for line_num, line in f.ChangedContents():
4052 if 'forward_variables_from(invoker, "*")' in line:
4053 problems.append(
4054 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4055 (f.LocalPath(), line_num))
4056
4057 if problems:
4058 return [
4059 output_api.PresubmitPromptWarning(
4060 'forward_variables_from("*") without exclusions',
4061 items=sorted(problems),
4062 long_text=(
4063 'The variables "visibilty" and "test_only" should be '
4064 'explicitly listed in forward_variables_from(). For more '
4065 'details, see:\n'
4066 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4067 'build/docs/writing_gn_templates.md'
4068 '#Using-forward_variables_from'))
4069 ]
4070 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014071
4072
Saagar Sanghavifceeaae2020-08-12 16:40:364073def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504074 """Checks that newly added header files have corresponding GN changes.
4075 Note that this is only a heuristic. To be precise, run script:
4076 build/check_gn_headers.py.
4077 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194078
Sam Maiera6e76d72022-02-11 21:43:504079 def headers(f):
4080 return input_api.FilterSourceFile(
4081 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194082
Sam Maiera6e76d72022-02-11 21:43:504083 new_headers = []
4084 for f in input_api.AffectedSourceFiles(headers):
4085 if f.Action() != 'A':
4086 continue
4087 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194088
Sam Maiera6e76d72022-02-11 21:43:504089 def gn_files(f):
4090 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194091
Sam Maiera6e76d72022-02-11 21:43:504092 all_gn_changed_contents = ''
4093 for f in input_api.AffectedSourceFiles(gn_files):
4094 for _, line in f.ChangedContents():
4095 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194096
Sam Maiera6e76d72022-02-11 21:43:504097 problems = []
4098 for header in new_headers:
4099 basename = input_api.os_path.basename(header)
4100 if basename not in all_gn_changed_contents:
4101 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194102
Sam Maiera6e76d72022-02-11 21:43:504103 if problems:
4104 return [
4105 output_api.PresubmitPromptWarning(
4106 'Missing GN changes for new header files',
4107 items=sorted(problems),
4108 long_text=
4109 'Please double check whether newly added header files need '
4110 'corresponding changes in gn or gni files.\nThis checking is only a '
4111 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4112 'Read https://crbug.com/661774 for more info.')
4113 ]
4114 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194115
4116
Saagar Sanghavifceeaae2020-08-12 16:40:364117def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504118 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024119
Sam Maiera6e76d72022-02-11 21:43:504120 This assumes we won't intentionally reference one product from the other
4121 product.
4122 """
4123 all_problems = []
4124 test_cases = [{
4125 "filename_postfix": "google_chrome_strings.grd",
4126 "correct_name": "Chrome",
4127 "incorrect_name": "Chromium",
4128 }, {
4129 "filename_postfix": "chromium_strings.grd",
4130 "correct_name": "Chromium",
4131 "incorrect_name": "Chrome",
4132 }]
Michael Giuffridad3bc8672018-10-25 22:48:024133
Sam Maiera6e76d72022-02-11 21:43:504134 for test_case in test_cases:
4135 problems = []
4136 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4137 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024138
Sam Maiera6e76d72022-02-11 21:43:504139 # Check each new line. Can yield false positives in multiline comments, but
4140 # easier than trying to parse the XML because messages can have nested
4141 # children, and associating message elements with affected lines is hard.
4142 for f in input_api.AffectedSourceFiles(filename_filter):
4143 for line_num, line in f.ChangedContents():
4144 if "<message" in line or "<!--" in line or "-->" in line:
4145 continue
4146 if test_case["incorrect_name"] in line:
4147 problems.append("Incorrect product name in %s:%d" %
4148 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024149
Sam Maiera6e76d72022-02-11 21:43:504150 if problems:
4151 message = (
4152 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4153 % (test_case["correct_name"], test_case["correct_name"],
4154 test_case["incorrect_name"]))
4155 all_problems.append(
4156 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024157
Sam Maiera6e76d72022-02-11 21:43:504158 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024159
4160
Saagar Sanghavifceeaae2020-08-12 16:40:364161def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504162 """Avoid large files, especially binary files, in the repository since
4163 git doesn't scale well for those. They will be in everyone's repo
4164 clones forever, forever making Chromium slower to clone and work
4165 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364166
Sam Maiera6e76d72022-02-11 21:43:504167 # Uploading files to cloud storage is not trivial so we don't want
4168 # to set the limit too low, but the upper limit for "normal" large
4169 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4170 # anything over 20 MB is exceptional.
4171 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364172
Sam Maiera6e76d72022-02-11 21:43:504173 too_large_files = []
4174 for f in input_api.AffectedFiles():
4175 # Check both added and modified files (but not deleted files).
4176 if f.Action() in ('A', 'M'):
4177 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4178 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4179 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364180
Sam Maiera6e76d72022-02-11 21:43:504181 if too_large_files:
4182 message = (
4183 'Do not commit large files to git since git scales badly for those.\n'
4184 +
4185 'Instead put the large files in cloud storage and use DEPS to\n' +
4186 'fetch them.\n' + '\n'.join(too_large_files))
4187 return [
4188 output_api.PresubmitError('Too large files found in commit',
4189 long_text=message + '\n')
4190 ]
4191 else:
4192 return []
Daniel Bratell93eb6c62019-04-29 20:13:364193
Max Morozb47503b2019-08-08 21:03:274194
Saagar Sanghavifceeaae2020-08-12 16:40:364195def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504196 """Checks specific for fuzz target sources."""
4197 EXPORTED_SYMBOLS = [
4198 'LLVMFuzzerInitialize',
4199 'LLVMFuzzerCustomMutator',
4200 'LLVMFuzzerCustomCrossOver',
4201 'LLVMFuzzerMutate',
4202 ]
Max Morozb47503b2019-08-08 21:03:274203
Sam Maiera6e76d72022-02-11 21:43:504204 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274205
Sam Maiera6e76d72022-02-11 21:43:504206 def FilterFile(affected_file):
4207 """Ignore libFuzzer source code."""
4208 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4209 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274210
Sam Maiera6e76d72022-02-11 21:43:504211 return input_api.FilterSourceFile(affected_file,
4212 files_to_check=[files_to_check],
4213 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274214
Sam Maiera6e76d72022-02-11 21:43:504215 files_with_missing_header = []
4216 for f in input_api.AffectedSourceFiles(FilterFile):
4217 contents = input_api.ReadFile(f, 'r')
4218 if REQUIRED_HEADER in contents:
4219 continue
Max Morozb47503b2019-08-08 21:03:274220
Sam Maiera6e76d72022-02-11 21:43:504221 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4222 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274223
Sam Maiera6e76d72022-02-11 21:43:504224 if not files_with_missing_header:
4225 return []
Max Morozb47503b2019-08-08 21:03:274226
Sam Maiera6e76d72022-02-11 21:43:504227 long_text = (
4228 'If you define any of the libFuzzer optional functions (%s), it is '
4229 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4230 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4231 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4232 'to access command line arguments passed to the fuzzer. Instead, prefer '
4233 'static initialization and shared resources as documented in '
4234 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4235 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4236 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274237
Sam Maiera6e76d72022-02-11 21:43:504238 return [
4239 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4240 REQUIRED_HEADER,
4241 items=files_with_missing_header,
4242 long_text=long_text)
4243 ]
Max Morozb47503b2019-08-08 21:03:274244
4245
Mohamed Heikald048240a2019-11-12 16:57:374246def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504247 """
4248 Warns authors who add images into the repo to make sure their images are
4249 optimized before committing.
4250 """
4251 images_added = False
4252 image_paths = []
4253 errors = []
4254 filter_lambda = lambda x: input_api.FilterSourceFile(
4255 x,
4256 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4257 DEFAULT_FILES_TO_SKIP),
4258 files_to_check=[r'.*\/(drawable|mipmap)'])
4259 for f in input_api.AffectedFiles(include_deletes=False,
4260 file_filter=filter_lambda):
4261 local_path = f.LocalPath().lower()
4262 if any(
4263 local_path.endswith(extension)
4264 for extension in _IMAGE_EXTENSIONS):
4265 images_added = True
4266 image_paths.append(f)
4267 if images_added:
4268 errors.append(
4269 output_api.PresubmitPromptWarning(
4270 'It looks like you are trying to commit some images. If these are '
4271 'non-test-only images, please make sure to read and apply the tips in '
4272 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4273 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4274 'FYI only and will not block your CL on the CQ.', image_paths))
4275 return errors
Mohamed Heikald048240a2019-11-12 16:57:374276
4277
Saagar Sanghavifceeaae2020-08-12 16:40:364278def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504279 """Groups upload checks that target android code."""
4280 results = []
4281 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4282 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4283 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4284 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4285 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4286 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4287 input_api, output_api))
4288 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4289 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4290 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4291 results.extend(_CheckNewImagesWarning(input_api, output_api))
4292 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4293 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4294 return results
4295
Becky Zhou7c69b50992018-12-10 19:37:574296
Saagar Sanghavifceeaae2020-08-12 16:40:364297def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504298 """Groups commit checks that target android code."""
4299 results = []
4300 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4301 return results
dgnaa68d5e2015-06-10 10:08:224302
Chris Hall59f8d0c72020-05-01 07:31:194303# TODO(chrishall): could we additionally match on any path owned by
4304# ui/accessibility/OWNERS ?
4305_ACCESSIBILITY_PATHS = (
4306 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4307 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4308 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4309 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4310 r"^content[\\/]browser[\\/]accessibility[\\/]",
4311 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4312 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4313 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4314 r"^ui[\\/]accessibility[\\/]",
4315 r"^ui[\\/]views[\\/]accessibility[\\/]",
4316)
4317
Saagar Sanghavifceeaae2020-08-12 16:40:364318def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504319 """Checks that commits to accessibility code contain an AX-Relnotes field in
4320 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194321
Sam Maiera6e76d72022-02-11 21:43:504322 def FileFilter(affected_file):
4323 paths = _ACCESSIBILITY_PATHS
4324 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194325
Sam Maiera6e76d72022-02-11 21:43:504326 # Only consider changes affecting accessibility paths.
4327 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4328 return []
Akihiro Ota08108e542020-05-20 15:30:534329
Sam Maiera6e76d72022-02-11 21:43:504330 # AX-Relnotes can appear in either the description or the footer.
4331 # When searching the description, require 'AX-Relnotes:' to appear at the
4332 # beginning of a line.
4333 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4334 description_has_relnotes = any(
4335 ax_regex.match(line)
4336 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194337
Sam Maiera6e76d72022-02-11 21:43:504338 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4339 'AX-Relnotes', [])
4340 if description_has_relnotes or footer_relnotes:
4341 return []
Chris Hall59f8d0c72020-05-01 07:31:194342
Sam Maiera6e76d72022-02-11 21:43:504343 # TODO(chrishall): link to Relnotes documentation in message.
4344 message = (
4345 "Missing 'AX-Relnotes:' field required for accessibility changes"
4346 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4347 "user-facing changes"
4348 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4349 "user-facing effects"
4350 "\n if this is confusing or annoying then please contact members "
4351 "of ui/accessibility/OWNERS.")
4352
4353 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224354
Mark Schillacie5a0be22022-01-19 00:38:394355
4356_ACCESSIBILITY_EVENTS_TEST_PATH = (
4357 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]event[\\/].*\.html",
4358)
4359
4360_ACCESSIBILITY_TREE_TEST_PATH = (
4361 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]accname[\\/].*\.html",
4362 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]aria[\\/].*\.html",
4363 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]css[\\/].*\.html",
4364 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]html[\\/].*\.html",
4365)
4366
4367_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
4368 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4369)
4370
4371_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Mark Schillaci6f568a52022-02-17 18:41:444372 r"^.*[\\/]WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394373)
4374
4375def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504376 """Checks that commits that include a newly added, renamed/moved, or deleted
4377 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4378 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394379
Sam Maiera6e76d72022-02-11 21:43:504380 def FilePathFilter(affected_file):
4381 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4382 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394383
Sam Maiera6e76d72022-02-11 21:43:504384 def AndroidFilePathFilter(affected_file):
4385 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4386 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394387
Sam Maiera6e76d72022-02-11 21:43:504388 # Only consider changes in the events test data path with html type.
4389 if not any(
4390 input_api.AffectedFiles(include_deletes=True,
4391 file_filter=FilePathFilter)):
4392 return []
Mark Schillacie5a0be22022-01-19 00:38:394393
Sam Maiera6e76d72022-02-11 21:43:504394 # If the commit contains any change to the Android test file, ignore.
4395 if any(
4396 input_api.AffectedFiles(include_deletes=True,
4397 file_filter=AndroidFilePathFilter)):
4398 return []
Mark Schillacie5a0be22022-01-19 00:38:394399
Sam Maiera6e76d72022-02-11 21:43:504400 # Only consider changes that are adding/renaming or deleting a file
4401 message = []
4402 for f in input_api.AffectedFiles(include_deletes=True,
4403 file_filter=FilePathFilter):
4404 if f.Action() == 'A' or f.Action() == 'D':
4405 message = (
4406 "It appears that you are adding, renaming or deleting"
4407 "\na dump_accessibility_events* test, but have not included"
4408 "\na corresponding change for Android."
4409 "\nPlease include (or remove) the test from:"
4410 "\n content/public/android/javatests/src/org/chromium/"
4411 "content/browser/accessibility/"
4412 "WebContentsAccessibilityEventsTest.java"
4413 "\nIf this message is confusing or annoying, please contact"
4414 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394415
Sam Maiera6e76d72022-02-11 21:43:504416 # If no message was set, return empty.
4417 if not len(message):
4418 return []
4419
4420 return [output_api.PresubmitPromptWarning(message)]
4421
Mark Schillacie5a0be22022-01-19 00:38:394422
4423def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504424 """Checks that commits that include a newly added, renamed/moved, or deleted
4425 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4426 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394427
Sam Maiera6e76d72022-02-11 21:43:504428 def FilePathFilter(affected_file):
4429 paths = _ACCESSIBILITY_TREE_TEST_PATH
4430 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394431
Sam Maiera6e76d72022-02-11 21:43:504432 def AndroidFilePathFilter(affected_file):
4433 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4434 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394435
Sam Maiera6e76d72022-02-11 21:43:504436 # Only consider changes in the various tree test data paths with html type.
4437 if not any(
4438 input_api.AffectedFiles(include_deletes=True,
4439 file_filter=FilePathFilter)):
4440 return []
Mark Schillacie5a0be22022-01-19 00:38:394441
Sam Maiera6e76d72022-02-11 21:43:504442 # If the commit contains any change to the Android test file, ignore.
4443 if any(
4444 input_api.AffectedFiles(include_deletes=True,
4445 file_filter=AndroidFilePathFilter)):
4446 return []
Mark Schillacie5a0be22022-01-19 00:38:394447
Sam Maiera6e76d72022-02-11 21:43:504448 # Only consider changes that are adding/renaming or deleting a file
4449 message = []
4450 for f in input_api.AffectedFiles(include_deletes=True,
4451 file_filter=FilePathFilter):
4452 if f.Action() == 'A' or f.Action() == 'D':
4453 message = (
4454 "It appears that you are adding, renaming or deleting"
4455 "\na dump_accessibility_tree* test, but have not included"
4456 "\na corresponding change for Android."
4457 "\nPlease include (or remove) the test from:"
4458 "\n content/public/android/javatests/src/org/chromium/"
4459 "content/browser/accessibility/"
4460 "WebContentsAccessibilityTreeTest.java"
4461 "\nIf this message is confusing or annoying, please contact"
4462 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394463
Sam Maiera6e76d72022-02-11 21:43:504464 # If no message was set, return empty.
4465 if not len(message):
4466 return []
4467
4468 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394469
4470
seanmccullough4a9356252021-04-08 19:54:094471# string pattern, sequence of strings to show when pattern matches,
4472# error flag. True if match is a presubmit error, otherwise it's a warning.
4473_NON_INCLUSIVE_TERMS = (
4474 (
4475 # Note that \b pattern in python re is pretty particular. In this
4476 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4477 # ...' will not. This may require some tweaking to catch these cases
4478 # without triggering a lot of false positives. Leaving it naive and
4479 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324480 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094481 (
4482 'Please don\'t use blacklist, whitelist, ' # nocheck
4483 'or slave in your', # nocheck
4484 'code and make every effort to use other terms. Using "// nocheck"',
4485 '"# nocheck" or "<!-- nocheck -->"',
4486 'at the end of the offending line will bypass this PRESUBMIT error',
4487 'but avoid using this whenever possible. Reach out to',
4488 '[email protected] if you have questions'),
4489 True),)
4490
Saagar Sanghavifceeaae2020-08-12 16:40:364491def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504492 """Checks common to both upload and commit."""
4493 results = []
Eric Boren6fd2b932018-01-25 15:05:084494 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504495 input_api.canned_checks.PanProjectChecks(
4496 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084497
Sam Maiera6e76d72022-02-11 21:43:504498 author = input_api.change.author_email
4499 if author and author not in _KNOWN_ROBOTS:
4500 results.extend(
4501 input_api.canned_checks.CheckAuthorizedAuthor(
4502 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244503
Sam Maiera6e76d72022-02-11 21:43:504504 results.extend(
4505 input_api.canned_checks.CheckChangeHasNoTabs(
4506 input_api,
4507 output_api,
4508 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
4509 results.extend(
4510 input_api.RunTests(
4511 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:174512
Bruce Dawsonc8054482022-03-28 15:33:374513 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:504514 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:374515 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:504516 results.extend(
4517 input_api.RunTests(
4518 input_api.canned_checks.CheckDirMetadataFormat(
4519 input_api, output_api, dirmd_bin)))
4520 results.extend(
4521 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4522 input_api, output_api))
4523 results.extend(
4524 input_api.canned_checks.CheckNoNewMetadataInOwners(
4525 input_api, output_api))
4526 results.extend(
4527 input_api.canned_checks.CheckInclusiveLanguage(
4528 input_api,
4529 output_api,
4530 excluded_directories_relative_path=[
4531 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
4532 ],
4533 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:594534
Sam Maiera6e76d72022-02-11 21:43:504535 for f in input_api.AffectedFiles():
4536 path, name = input_api.os_path.split(f.LocalPath())
4537 if name == 'PRESUBMIT.py':
4538 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
4539 path)
4540 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4541 if f.Action() != 'D' and input_api.os_path.exists(test_file):
4542 # The PRESUBMIT.py file (and the directory containing it) might
4543 # have been affected by being moved or removed, so only try to
4544 # run the tests if they still exist.
4545 use_python3 = False
4546 with open(f.LocalPath()) as fp:
4547 use_python3 = any(
4548 line.startswith('USE_PYTHON3 = True')
4549 for line in fp.readlines())
4550
4551 results.extend(
4552 input_api.canned_checks.RunUnitTestsInDirectory(
4553 input_api,
4554 output_api,
4555 full_path,
4556 files_to_check=[r'^PRESUBMIT_test\.py$'],
4557 run_on_python2=not use_python3,
4558 run_on_python3=use_python3,
4559 skip_shebang_check=True))
4560 return results
[email protected]1f7b4172010-01-28 01:17:344561
[email protected]b337cb5b2011-01-23 21:24:054562
Saagar Sanghavifceeaae2020-08-12 16:40:364563def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504564 problems = [
4565 f.LocalPath() for f in input_api.AffectedFiles()
4566 if f.LocalPath().endswith(('.orig', '.rej'))
4567 ]
4568 # Cargo.toml.orig files are part of third-party crates downloaded from
4569 # crates.io and should be included.
4570 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
4571 if problems:
4572 return [
4573 output_api.PresubmitError("Don't commit .rej and .orig files.",
4574 problems)
4575 ]
4576 else:
4577 return []
[email protected]b8079ae4a2012-12-05 19:56:494578
4579
Saagar Sanghavifceeaae2020-08-12 16:40:364580def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504581 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4582 macro_re = input_api.re.compile(
4583 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
4584 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
4585 input_api.re.MULTILINE)
4586 extension_re = input_api.re.compile(r'\.[a-z]+$')
4587 errors = []
4588 for f in input_api.AffectedFiles(include_deletes=False):
4589 if not f.LocalPath().endswith(
4590 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4591 continue
4592 found_line_number = None
4593 found_macro = None
4594 all_lines = input_api.ReadFile(f, 'r').splitlines()
4595 for line_num, line in enumerate(all_lines):
4596 match = macro_re.search(line)
4597 if match:
4598 found_line_number = line_num
4599 found_macro = match.group(2)
4600 break
4601 if not found_line_number:
4602 continue
Kent Tamura5a8755d2017-06-29 23:37:074603
Sam Maiera6e76d72022-02-11 21:43:504604 found_include_line = -1
4605 for line_num, line in enumerate(all_lines):
4606 if include_re.search(line):
4607 found_include_line = line_num
4608 break
4609 if found_include_line >= 0 and found_include_line < found_line_number:
4610 continue
Kent Tamura5a8755d2017-06-29 23:37:074611
Sam Maiera6e76d72022-02-11 21:43:504612 if not f.LocalPath().endswith('.h'):
4613 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4614 try:
4615 content = input_api.ReadFile(primary_header_path, 'r')
4616 if include_re.search(content):
4617 continue
4618 except IOError:
4619 pass
4620 errors.append('%s:%d %s macro is used without first including build/'
4621 'build_config.h.' %
4622 (f.LocalPath(), found_line_number, found_macro))
4623 if errors:
4624 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4625 return []
Kent Tamura5a8755d2017-06-29 23:37:074626
4627
Lei Zhang1c12a22f2021-05-12 11:28:454628def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504629 stl_include_re = input_api.re.compile(r'^#include\s+<('
4630 r'algorithm|'
4631 r'array|'
4632 r'limits|'
4633 r'list|'
4634 r'map|'
4635 r'memory|'
4636 r'queue|'
4637 r'set|'
4638 r'string|'
4639 r'unordered_map|'
4640 r'unordered_set|'
4641 r'utility|'
4642 r'vector)>')
4643 std_namespace_re = input_api.re.compile(r'std::')
4644 errors = []
4645 for f in input_api.AffectedFiles():
4646 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4647 continue
Lei Zhang1c12a22f2021-05-12 11:28:454648
Sam Maiera6e76d72022-02-11 21:43:504649 uses_std_namespace = False
4650 has_stl_include = False
4651 for line in f.NewContents():
4652 if has_stl_include and uses_std_namespace:
4653 break
Lei Zhang1c12a22f2021-05-12 11:28:454654
Sam Maiera6e76d72022-02-11 21:43:504655 if not has_stl_include and stl_include_re.search(line):
4656 has_stl_include = True
4657 continue
Lei Zhang1c12a22f2021-05-12 11:28:454658
Bruce Dawson4a5579a2022-04-08 17:11:364659 if not uses_std_namespace and (std_namespace_re.search(line)
4660 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504661 uses_std_namespace = True
4662 continue
Lei Zhang1c12a22f2021-05-12 11:28:454663
Sam Maiera6e76d72022-02-11 21:43:504664 if has_stl_include and not uses_std_namespace:
4665 errors.append(
4666 '%s: Includes STL header(s) but does not reference std::' %
4667 f.LocalPath())
4668 if errors:
4669 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4670 return []
Lei Zhang1c12a22f2021-05-12 11:28:454671
4672
Xiaohan Wang42d96c22022-01-20 17:23:114673def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504674 """Check for sensible looking, totally invalid OS macros."""
4675 preprocessor_statement = input_api.re.compile(r'^\s*#')
4676 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
4677 results = []
4678 for lnum, line in f.ChangedContents():
4679 if preprocessor_statement.search(line):
4680 for match in os_macro.finditer(line):
4681 results.append(
4682 ' %s:%d: %s' %
4683 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
4684 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
4685 return results
[email protected]b00342e7f2013-03-26 16:21:544686
4687
Xiaohan Wang42d96c22022-01-20 17:23:114688def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504689 """Check all affected files for invalid OS macros."""
4690 bad_macros = []
4691 for f in input_api.AffectedSourceFiles(None):
4692 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
4693 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:544694
Sam Maiera6e76d72022-02-11 21:43:504695 if not bad_macros:
4696 return []
[email protected]b00342e7f2013-03-26 16:21:544697
Sam Maiera6e76d72022-02-11 21:43:504698 return [
4699 output_api.PresubmitError(
4700 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
4701 'defined in build_config.h):', bad_macros)
4702 ]
[email protected]b00342e7f2013-03-26 16:21:544703
lliabraa35bab3932014-10-01 12:16:444704
4705def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504706 """Check all affected files for invalid "if defined" macros."""
4707 ALWAYS_DEFINED_MACROS = (
4708 "TARGET_CPU_PPC",
4709 "TARGET_CPU_PPC64",
4710 "TARGET_CPU_68K",
4711 "TARGET_CPU_X86",
4712 "TARGET_CPU_ARM",
4713 "TARGET_CPU_MIPS",
4714 "TARGET_CPU_SPARC",
4715 "TARGET_CPU_ALPHA",
4716 "TARGET_IPHONE_SIMULATOR",
4717 "TARGET_OS_EMBEDDED",
4718 "TARGET_OS_IPHONE",
4719 "TARGET_OS_MAC",
4720 "TARGET_OS_UNIX",
4721 "TARGET_OS_WIN32",
4722 )
4723 ifdef_macro = input_api.re.compile(
4724 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4725 results = []
4726 for lnum, line in f.ChangedContents():
4727 for match in ifdef_macro.finditer(line):
4728 if match.group(1) in ALWAYS_DEFINED_MACROS:
4729 always_defined = ' %s is always defined. ' % match.group(1)
4730 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4731 results.append(
4732 ' %s:%d %s\n\t%s' %
4733 (f.LocalPath(), lnum, always_defined, did_you_mean))
4734 return results
lliabraa35bab3932014-10-01 12:16:444735
4736
Saagar Sanghavifceeaae2020-08-12 16:40:364737def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504738 """Check all affected files for invalid "if defined" macros."""
4739 bad_macros = []
4740 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
4741 for f in input_api.AffectedFiles():
4742 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
4743 continue
4744 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4745 bad_macros.extend(
4746 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:444747
Sam Maiera6e76d72022-02-11 21:43:504748 if not bad_macros:
4749 return []
lliabraa35bab3932014-10-01 12:16:444750
Sam Maiera6e76d72022-02-11 21:43:504751 return [
4752 output_api.PresubmitError(
4753 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4754 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4755 bad_macros)
4756 ]
lliabraa35bab3932014-10-01 12:16:444757
4758
Saagar Sanghavifceeaae2020-08-12 16:40:364759def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504760 """Check for same IPC rules described in
4761 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4762 """
4763 base_pattern = r'IPC_ENUM_TRAITS\('
4764 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4765 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:044766
Sam Maiera6e76d72022-02-11 21:43:504767 problems = []
4768 for f in input_api.AffectedSourceFiles(None):
4769 local_path = f.LocalPath()
4770 if not local_path.endswith('.h'):
4771 continue
4772 for line_number, line in f.ChangedContents():
4773 if inclusion_pattern.search(
4774 line) and not comment_pattern.search(line):
4775 problems.append('%s:%d\n %s' %
4776 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:044777
Sam Maiera6e76d72022-02-11 21:43:504778 if problems:
4779 return [
4780 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
4781 problems)
4782 ]
4783 else:
4784 return []
mlamouria82272622014-09-16 18:45:044785
[email protected]b00342e7f2013-03-26 16:21:544786
Saagar Sanghavifceeaae2020-08-12 16:40:364787def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504788 """Check to make sure no files being submitted have long paths.
4789 This causes issues on Windows.
4790 """
4791 problems = []
4792 for f in input_api.AffectedTestableFiles():
4793 local_path = f.LocalPath()
4794 # Windows has a path limit of 260 characters. Limit path length to 200 so
4795 # that we have some extra for the prefix on dev machines and the bots.
4796 if len(local_path) > 200:
4797 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:054798
Sam Maiera6e76d72022-02-11 21:43:504799 if problems:
4800 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4801 else:
4802 return []
Stephen Martinis97a394142018-06-07 23:06:054803
4804
Saagar Sanghavifceeaae2020-08-12 16:40:364805def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504806 """Check that header files have proper guards against multiple inclusion.
4807 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:364808 should include the string "no-include-guard-because-multiply-included" or
4809 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:504810 """
Daniel Bratell8ba52722018-03-02 16:06:144811
Sam Maiera6e76d72022-02-11 21:43:504812 def is_chromium_header_file(f):
4813 # We only check header files under the control of the Chromium
4814 # project. That is, those outside third_party apart from
4815 # third_party/blink.
4816 # We also exclude *_message_generator.h headers as they use
4817 # include guards in a special, non-typical way.
4818 file_with_path = input_api.os_path.normpath(f.LocalPath())
4819 return (file_with_path.endswith('.h')
4820 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:334821 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:504822 and (not file_with_path.startswith('third_party')
4823 or file_with_path.startswith(
4824 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144825
Sam Maiera6e76d72022-02-11 21:43:504826 def replace_special_with_underscore(string):
4827 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144828
Sam Maiera6e76d72022-02-11 21:43:504829 errors = []
Daniel Bratell8ba52722018-03-02 16:06:144830
Sam Maiera6e76d72022-02-11 21:43:504831 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
4832 guard_name = None
4833 guard_line_number = None
4834 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:144835
Sam Maiera6e76d72022-02-11 21:43:504836 file_with_path = input_api.os_path.normpath(f.LocalPath())
4837 base_file_name = input_api.os_path.splitext(
4838 input_api.os_path.basename(file_with_path))[0]
4839 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:144840
Sam Maiera6e76d72022-02-11 21:43:504841 expected_guard = replace_special_with_underscore(
4842 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144843
Sam Maiera6e76d72022-02-11 21:43:504844 # For "path/elem/file_name.h" we should really only accept
4845 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4846 # are too many (1000+) files with slight deviations from the
4847 # coding style. The most important part is that the include guard
4848 # is there, and that it's unique, not the name so this check is
4849 # forgiving for existing files.
4850 #
4851 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:144852
Sam Maiera6e76d72022-02-11 21:43:504853 guard_name_pattern_list = [
4854 # Anything with the right suffix (maybe with an extra _).
4855 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:144856
Sam Maiera6e76d72022-02-11 21:43:504857 # To cover include guards with old Blink style.
4858 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:144859
Sam Maiera6e76d72022-02-11 21:43:504860 # Anything including the uppercase name of the file.
4861 r'\w*' + input_api.re.escape(
4862 replace_special_with_underscore(upper_base_file_name)) +
4863 r'\w*',
4864 ]
4865 guard_name_pattern = '|'.join(guard_name_pattern_list)
4866 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
4867 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:144868
Sam Maiera6e76d72022-02-11 21:43:504869 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:364870 if ('no-include-guard-because-multiply-included' in line
4871 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504872 guard_name = 'DUMMY' # To not trigger check outside the loop.
4873 break
Daniel Bratell8ba52722018-03-02 16:06:144874
Sam Maiera6e76d72022-02-11 21:43:504875 if guard_name is None:
4876 match = guard_pattern.match(line)
4877 if match:
4878 guard_name = match.group(1)
4879 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:144880
Sam Maiera6e76d72022-02-11 21:43:504881 # We allow existing files to use include guards whose names
4882 # don't match the chromium style guide, but new files should
4883 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:494884 if guard_name != expected_guard:
4885 if not f.OldContents():
Sam Maiera6e76d72022-02-11 21:43:504886 errors.append(
4887 output_api.PresubmitPromptWarning(
4888 'Header using the wrong include guard name %s'
4889 % guard_name, [
4890 '%s:%d' %
4891 (f.LocalPath(), line_number + 1)
4892 ], 'Expected: %r\nFound: %r' %
4893 (expected_guard, guard_name)))
4894 else:
4895 # The line after #ifndef should have a #define of the same name.
4896 if line_number == guard_line_number + 1:
4897 expected_line = '#define %s' % guard_name
4898 if line != expected_line:
4899 errors.append(
4900 output_api.PresubmitPromptWarning(
4901 'Missing "%s" for include guard' %
4902 expected_line,
4903 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4904 'Expected: %r\nGot: %r' %
4905 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:144906
Sam Maiera6e76d72022-02-11 21:43:504907 if not seen_guard_end and line == '#endif // %s' % guard_name:
4908 seen_guard_end = True
4909 elif seen_guard_end:
4910 if line.strip() != '':
4911 errors.append(
4912 output_api.PresubmitPromptWarning(
4913 'Include guard %s not covering the whole file'
4914 % (guard_name), [f.LocalPath()]))
4915 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:144916
Sam Maiera6e76d72022-02-11 21:43:504917 if guard_name is None:
4918 errors.append(
4919 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:494920 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:504921 'Recommended name: %s\n'
4922 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:364923 '"no-include-guard-because-multiply-included" or\n'
4924 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:504925 % (f.LocalPath(), expected_guard)))
4926
4927 return errors
Daniel Bratell8ba52722018-03-02 16:06:144928
4929
Saagar Sanghavifceeaae2020-08-12 16:40:364930def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504931 """Check source code and known ascii text files for Windows style line
4932 endings.
4933 """
Bruce Dawson5efbdc652022-04-11 19:29:514934 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234935
Sam Maiera6e76d72022-02-11 21:43:504936 file_inclusion_pattern = (known_text_files,
4937 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4938 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:234939
Sam Maiera6e76d72022-02-11 21:43:504940 problems = []
4941 source_file_filter = lambda f: input_api.FilterSourceFile(
4942 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
4943 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:514944 # Ignore test files that contain crlf intentionally.
4945 if f.LocalPath().endswith('crlf.txt'):
4946 continue
Sam Maiera6e76d72022-02-11 21:43:504947 include_file = False
4948 for line in input_api.ReadFile(f, 'r').splitlines(True):
4949 if line.endswith('\r\n'):
4950 include_file = True
4951 if include_file:
4952 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234953
Sam Maiera6e76d72022-02-11 21:43:504954 if problems:
4955 return [
4956 output_api.PresubmitPromptWarning(
4957 'Are you sure that you want '
4958 'these files to contain Windows style line endings?\n' +
4959 '\n'.join(problems))
4960 ]
mostynbb639aca52015-01-07 20:31:234961
Sam Maiera6e76d72022-02-11 21:43:504962 return []
4963
mostynbb639aca52015-01-07 20:31:234964
Evan Stade6cfc964c12021-05-18 20:21:164965def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504966 """Check that .icon files (which are fragments of C++) have license headers.
4967 """
Evan Stade6cfc964c12021-05-18 20:21:164968
Sam Maiera6e76d72022-02-11 21:43:504969 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:164970
Sam Maiera6e76d72022-02-11 21:43:504971 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4972 return input_api.canned_checks.CheckLicense(input_api,
4973 output_api,
4974 source_file_filter=icons)
4975
Evan Stade6cfc964c12021-05-18 20:21:164976
Jose Magana2b456f22021-03-09 23:26:404977def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504978 """Check source code for use of Chrome App technologies being
4979 deprecated.
4980 """
Jose Magana2b456f22021-03-09 23:26:404981
Sam Maiera6e76d72022-02-11 21:43:504982 def _CheckForDeprecatedTech(input_api,
4983 output_api,
4984 detection_list,
4985 files_to_check=None,
4986 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:404987
Sam Maiera6e76d72022-02-11 21:43:504988 if (files_to_check or files_to_skip):
4989 source_file_filter = lambda f: input_api.FilterSourceFile(
4990 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
4991 else:
4992 source_file_filter = None
4993
4994 problems = []
4995
4996 for f in input_api.AffectedSourceFiles(source_file_filter):
4997 if f.Action() == 'D':
4998 continue
4999 for _, line in f.ChangedContents():
5000 if any(detect in line for detect in detection_list):
5001 problems.append(f.LocalPath())
5002
5003 return problems
5004
5005 # to avoid this presubmit script triggering warnings
5006 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405007
5008 problems = []
5009
Sam Maiera6e76d72022-02-11 21:43:505010 # NMF: any files with extensions .nmf or NMF
5011 _NMF_FILES = r'\.(nmf|NMF)$'
5012 problems += _CheckForDeprecatedTech(
5013 input_api,
5014 output_api,
5015 detection_list=[''], # any change to the file will trigger warning
5016 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405017
Sam Maiera6e76d72022-02-11 21:43:505018 # MANIFEST: any manifest.json that in its diff includes "app":
5019 _MANIFEST_FILES = r'(manifest\.json)$'
5020 problems += _CheckForDeprecatedTech(
5021 input_api,
5022 output_api,
5023 detection_list=['"app":'],
5024 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405025
Sam Maiera6e76d72022-02-11 21:43:505026 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5027 problems += _CheckForDeprecatedTech(
5028 input_api,
5029 output_api,
5030 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
5031 files_to_skip=files_to_skip + [r"^native_client_sdk[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405032
Sam Maiera6e76d72022-02-11 21:43:505033 # PPAPI: any C/C++ file that in its diff includes a ppappi library
5034 problems += _CheckForDeprecatedTech(
5035 input_api,
5036 output_api,
5037 detection_list=['#include "ppapi', '#include <ppapi'],
5038 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5039 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
5040 files_to_skip=[r"^ppapi[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405041
Sam Maiera6e76d72022-02-11 21:43:505042 if problems:
5043 return [
5044 output_api.PresubmitPromptWarning(
5045 'You are adding/modifying code'
5046 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5047 ' PNaCl, PPAPI). See this blog post for more details:\n'
5048 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5049 'and this documentation for options to replace these technologies:\n'
5050 'https://developer.chrome.com/docs/apps/migration/\n' +
5051 '\n'.join(problems))
5052 ]
Jose Magana2b456f22021-03-09 23:26:405053
Sam Maiera6e76d72022-02-11 21:43:505054 return []
Jose Magana2b456f22021-03-09 23:26:405055
mostynbb639aca52015-01-07 20:31:235056
Saagar Sanghavifceeaae2020-08-12 16:40:365057def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505058 """Checks that all source files use SYSLOG properly."""
5059 syslog_files = []
5060 for f in input_api.AffectedSourceFiles(src_file_filter):
5061 for line_number, line in f.ChangedContents():
5062 if 'SYSLOG' in line:
5063 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565064
Sam Maiera6e76d72022-02-11 21:43:505065 if syslog_files:
5066 return [
5067 output_api.PresubmitPromptWarning(
5068 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5069 ' calls.\nFiles to check:\n',
5070 items=syslog_files)
5071 ]
5072 return []
pastarmovj89f7ee12016-09-20 14:58:135073
5074
[email protected]1f7b4172010-01-28 01:17:345075def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505076 if input_api.version < [2, 0, 0]:
5077 return [
5078 output_api.PresubmitError(
5079 "Your depot_tools is out of date. "
5080 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5081 "but your version is %d.%d.%d" % tuple(input_api.version))
5082 ]
5083 results = []
5084 results.extend(
5085 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5086 return results
[email protected]ca8d1982009-02-19 16:33:125087
5088
5089def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505090 if input_api.version < [2, 0, 0]:
5091 return [
5092 output_api.PresubmitError(
5093 "Your depot_tools is out of date. "
5094 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5095 "but your version is %d.%d.%d" % tuple(input_api.version))
5096 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365097
Sam Maiera6e76d72022-02-11 21:43:505098 results = []
5099 # Make sure the tree is 'open'.
5100 results.extend(
5101 input_api.canned_checks.CheckTreeIsOpen(
5102 input_api,
5103 output_api,
5104 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275105
Sam Maiera6e76d72022-02-11 21:43:505106 results.extend(
5107 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5108 results.extend(
5109 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5110 results.extend(
5111 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5112 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505113 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145114
5115
Saagar Sanghavifceeaae2020-08-12 16:40:365116def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505117 """Check string ICU syntax validity and if translation screenshots exist."""
5118 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5119 # footer is set to true.
5120 git_footers = input_api.change.GitFootersFromDescription()
5121 skip_screenshot_check_footer = [
5122 footer.lower() for footer in git_footers.get(
5123 u'Skip-Translation-Screenshots-Check', [])
5124 ]
5125 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025126
Sam Maiera6e76d72022-02-11 21:43:505127 import os
5128 import re
5129 import sys
5130 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145131
Sam Maiera6e76d72022-02-11 21:43:505132 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5133 if (f.Action() == 'A' or f.Action() == 'M'))
5134 removed_paths = set(f.LocalPath()
5135 for f in input_api.AffectedFiles(include_deletes=True)
5136 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145137
Sam Maiera6e76d72022-02-11 21:43:505138 affected_grds = [
5139 f for f in input_api.AffectedFiles()
5140 if f.LocalPath().endswith(('.grd', '.grdp'))
5141 ]
5142 affected_grds = [
5143 f for f in affected_grds if not 'testdata' in f.LocalPath()
5144 ]
5145 if not affected_grds:
5146 return []
meacer8c0d3832019-12-26 21:46:165147
Sam Maiera6e76d72022-02-11 21:43:505148 affected_png_paths = [
5149 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5150 if (f.LocalPath().endswith('.png'))
5151 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145152
Sam Maiera6e76d72022-02-11 21:43:505153 # Check for screenshots. Developers can upload screenshots using
5154 # tools/translation/upload_screenshots.py which finds and uploads
5155 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5156 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5157 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5158 #
5159 # The logic here is as follows:
5160 #
5161 # - If the CL has a .png file under the screenshots directory for a grd
5162 # file, warn the developer. Actual images should never be checked into the
5163 # Chrome repo.
5164 #
5165 # - If the CL contains modified or new messages in grd files and doesn't
5166 # contain the corresponding .sha1 files, warn the developer to add images
5167 # and upload them via tools/translation/upload_screenshots.py.
5168 #
5169 # - If the CL contains modified or new messages in grd files and the
5170 # corresponding .sha1 files, everything looks good.
5171 #
5172 # - If the CL contains removed messages in grd files but the corresponding
5173 # .sha1 files aren't removed, warn the developer to remove them.
5174 unnecessary_screenshots = []
5175 missing_sha1 = []
5176 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145177
Sam Maiera6e76d72022-02-11 21:43:505178 # This checks verifies that the ICU syntax of messages this CL touched is
5179 # valid, and reports any found syntax errors.
5180 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5181 # without developers being aware of them. Later on, such ICU syntax errors
5182 # break message extraction for translation, hence would block Chromium
5183 # translations until they are fixed.
5184 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145185
Sam Maiera6e76d72022-02-11 21:43:505186 def _CheckScreenshotAdded(screenshots_dir, message_id):
5187 sha1_path = input_api.os_path.join(screenshots_dir,
5188 message_id + '.png.sha1')
5189 if sha1_path not in new_or_added_paths:
5190 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145191
Sam Maiera6e76d72022-02-11 21:43:505192 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5193 sha1_path = input_api.os_path.join(screenshots_dir,
5194 message_id + '.png.sha1')
5195 if input_api.os_path.exists(
5196 sha1_path) and sha1_path not in removed_paths:
5197 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145198
Sam Maiera6e76d72022-02-11 21:43:505199 def _ValidateIcuSyntax(text, level, signatures):
5200 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145201
Sam Maiera6e76d72022-02-11 21:43:505202 Check if text looks similar to ICU and checks for ICU syntax correctness
5203 in this case. Reports various issues with ICU syntax and values of
5204 variants. Supports checking of nested messages. Accumulate information of
5205 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265206
Sam Maiera6e76d72022-02-11 21:43:505207 Args:
5208 text: a string to check.
5209 level: a number of current nesting level.
5210 signatures: an accumulator, a list of tuple of (level, variable,
5211 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265212
Sam Maiera6e76d72022-02-11 21:43:505213 Returns:
5214 None if a string is not ICU or no issue detected.
5215 A tuple of (message, start index, end index) if an issue detected.
5216 """
5217 valid_types = {
5218 'plural': (frozenset(
5219 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5220 'other']), frozenset(['=1', 'other'])),
5221 'selectordinal': (frozenset(
5222 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5223 'other']), frozenset(['one', 'other'])),
5224 'select': (frozenset(), frozenset(['other'])),
5225 }
Rainhard Findlingfc31844c52020-05-15 09:58:265226
Sam Maiera6e76d72022-02-11 21:43:505227 # Check if the message looks like an attempt to use ICU
5228 # plural. If yes - check if its syntax strictly matches ICU format.
5229 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5230 text)
5231 if not like:
5232 signatures.append((level, None, None, None))
5233 return
Rainhard Findlingfc31844c52020-05-15 09:58:265234
Sam Maiera6e76d72022-02-11 21:43:505235 # Check for valid prefix and suffix
5236 m = re.match(
5237 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5238 r'(plural|selectordinal|select),\s*'
5239 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5240 if not m:
5241 return (('This message looks like an ICU plural, '
5242 'but does not follow ICU syntax.'), like.start(),
5243 like.end())
5244 starting, variable, kind, variant_pairs = m.groups()
5245 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5246 m.start(4))
5247 if depth:
5248 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5249 len(text))
5250 first = text[0]
5251 ending = text[last_pos:]
5252 if not starting:
5253 return ('Invalid ICU format. No initial opening bracket',
5254 last_pos - 1, last_pos)
5255 if not ending or '}' not in ending:
5256 return ('Invalid ICU format. No final closing bracket',
5257 last_pos - 1, last_pos)
5258 elif first != '{':
5259 return ((
5260 'Invalid ICU format. Extra characters at the start of a complex '
5261 'message (go/icu-message-migration): "%s"') % starting, 0,
5262 len(starting))
5263 elif ending != '}':
5264 return ((
5265 'Invalid ICU format. Extra characters at the end of a complex '
5266 'message (go/icu-message-migration): "%s"') % ending,
5267 last_pos - 1, len(text) - 1)
5268 if kind not in valid_types:
5269 return (('Unknown ICU message type %s. '
5270 'Valid types are: plural, select, selectordinal') % kind,
5271 0, 0)
5272 known, required = valid_types[kind]
5273 defined_variants = set()
5274 for variant, variant_range, value, value_range in variants:
5275 start, end = variant_range
5276 if variant in defined_variants:
5277 return ('Variant "%s" is defined more than once' % variant,
5278 start, end)
5279 elif known and variant not in known:
5280 return ('Variant "%s" is not valid for %s message' %
5281 (variant, kind), start, end)
5282 defined_variants.add(variant)
5283 # Check for nested structure
5284 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5285 if res:
5286 return (res[0], res[1] + value_range[0] + 1,
5287 res[2] + value_range[0] + 1)
5288 missing = required - defined_variants
5289 if missing:
5290 return ('Required variants missing: %s' % ', '.join(missing), 0,
5291 len(text))
5292 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265293
Sam Maiera6e76d72022-02-11 21:43:505294 def _ParseIcuVariants(text, offset=0):
5295 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265296
Sam Maiera6e76d72022-02-11 21:43:505297 Builds a tuple of variant names and values, as well as
5298 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265299
Sam Maiera6e76d72022-02-11 21:43:505300 Args:
5301 text: a string to parse
5302 offset: additional offset to add to positions in the text to get correct
5303 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265304
Sam Maiera6e76d72022-02-11 21:43:505305 Returns:
5306 List of tuples, each tuple consist of four fields: variant name,
5307 variant name span (tuple of two integers), variant value, value
5308 span (tuple of two integers).
5309 """
5310 depth, start, end = 0, -1, -1
5311 variants = []
5312 key = None
5313 for idx, char in enumerate(text):
5314 if char == '{':
5315 if not depth:
5316 start = idx
5317 chunk = text[end + 1:start]
5318 key = chunk.strip()
5319 pos = offset + end + 1 + chunk.find(key)
5320 span = (pos, pos + len(key))
5321 depth += 1
5322 elif char == '}':
5323 if not depth:
5324 return variants, depth, offset + idx
5325 depth -= 1
5326 if not depth:
5327 end = idx
5328 variants.append((key, span, text[start:end + 1],
5329 (offset + start, offset + end + 1)))
5330 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265331
Sam Maiera6e76d72022-02-11 21:43:505332 try:
5333 old_sys_path = sys.path
5334 sys.path = sys.path + [
5335 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5336 'translation')
5337 ]
5338 from helper import grd_helper
5339 finally:
5340 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265341
Sam Maiera6e76d72022-02-11 21:43:505342 for f in affected_grds:
5343 file_path = f.LocalPath()
5344 old_id_to_msg_map = {}
5345 new_id_to_msg_map = {}
5346 # Note that this code doesn't check if the file has been deleted. This is
5347 # OK because it only uses the old and new file contents and doesn't load
5348 # the file via its path.
5349 # It's also possible that a file's content refers to a renamed or deleted
5350 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5351 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5352 # .grdp files.
5353 if file_path.endswith('.grdp'):
5354 if f.OldContents():
5355 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5356 '\n'.join(f.OldContents()))
5357 if f.NewContents():
5358 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5359 '\n'.join(f.NewContents()))
5360 else:
5361 file_dir = input_api.os_path.dirname(file_path) or '.'
5362 if f.OldContents():
5363 old_id_to_msg_map = grd_helper.GetGrdMessages(
5364 StringIO('\n'.join(f.OldContents())), file_dir)
5365 if f.NewContents():
5366 new_id_to_msg_map = grd_helper.GetGrdMessages(
5367 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265368
Sam Maiera6e76d72022-02-11 21:43:505369 grd_name, ext = input_api.os_path.splitext(
5370 input_api.os_path.basename(file_path))
5371 screenshots_dir = input_api.os_path.join(
5372 input_api.os_path.dirname(file_path),
5373 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265374
Sam Maiera6e76d72022-02-11 21:43:505375 # Compute added, removed and modified message IDs.
5376 old_ids = set(old_id_to_msg_map)
5377 new_ids = set(new_id_to_msg_map)
5378 added_ids = new_ids - old_ids
5379 removed_ids = old_ids - new_ids
5380 modified_ids = set([])
5381 for key in old_ids.intersection(new_ids):
5382 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5383 new_id_to_msg_map[key].ContentsAsXml('', True)):
5384 # The message content itself changed. Require an updated screenshot.
5385 modified_ids.add(key)
5386 elif old_id_to_msg_map[key].attrs['meaning'] != \
5387 new_id_to_msg_map[key].attrs['meaning']:
5388 # The message meaning changed. Ensure there is a screenshot for it.
5389 sha1_path = input_api.os_path.join(screenshots_dir,
5390 key + '.png.sha1')
5391 if sha1_path not in new_or_added_paths and not \
5392 input_api.os_path.exists(sha1_path):
5393 # There is neither a previous screenshot nor is a new one added now.
5394 # Require a screenshot.
5395 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145396
Sam Maiera6e76d72022-02-11 21:43:505397 if run_screenshot_check:
5398 # Check the screenshot directory for .png files. Warn if there is any.
5399 for png_path in affected_png_paths:
5400 if png_path.startswith(screenshots_dir):
5401 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145402
Sam Maiera6e76d72022-02-11 21:43:505403 for added_id in added_ids:
5404 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095405
Sam Maiera6e76d72022-02-11 21:43:505406 for modified_id in modified_ids:
5407 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145408
Sam Maiera6e76d72022-02-11 21:43:505409 for removed_id in removed_ids:
5410 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5411
5412 # Check new and changed strings for ICU syntax errors.
5413 for key in added_ids.union(modified_ids):
5414 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5415 err = _ValidateIcuSyntax(msg, 0, [])
5416 if err is not None:
5417 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5418
5419 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265420 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505421 if unnecessary_screenshots:
5422 results.append(
5423 output_api.PresubmitError(
5424 'Do not include actual screenshots in the changelist. Run '
5425 'tools/translate/upload_screenshots.py to upload them instead:',
5426 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145427
Sam Maiera6e76d72022-02-11 21:43:505428 if missing_sha1:
5429 results.append(
5430 output_api.PresubmitError(
5431 'You are adding or modifying UI strings.\n'
5432 'To ensure the best translations, take screenshots of the relevant UI '
5433 '(https://g.co/chrome/translation) and add these files to your '
5434 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145435
Sam Maiera6e76d72022-02-11 21:43:505436 if unnecessary_sha1_files:
5437 results.append(
5438 output_api.PresubmitError(
5439 'You removed strings associated with these files. Remove:',
5440 sorted(unnecessary_sha1_files)))
5441 else:
5442 results.append(
5443 output_api.PresubmitPromptOrNotify('Skipping translation '
5444 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145445
Sam Maiera6e76d72022-02-11 21:43:505446 if icu_syntax_errors:
5447 results.append(
5448 output_api.PresubmitPromptWarning(
5449 'ICU syntax errors were found in the following strings (problems or '
5450 'feedback? Contact [email protected]):',
5451 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265452
Sam Maiera6e76d72022-02-11 21:43:505453 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125454
5455
Saagar Sanghavifceeaae2020-08-12 16:40:365456def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125457 repo_root=None,
5458 translation_expectations_path=None,
5459 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505460 import sys
5461 affected_grds = [
5462 f for f in input_api.AffectedFiles()
5463 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5464 ]
5465 if not affected_grds:
5466 return []
5467
5468 try:
5469 old_sys_path = sys.path
5470 sys.path = sys.path + [
5471 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5472 'translation')
5473 ]
5474 from helper import git_helper
5475 from helper import translation_helper
5476 finally:
5477 sys.path = old_sys_path
5478
5479 # Check that translation expectations can be parsed and we can get a list of
5480 # translatable grd files. |repo_root| and |translation_expectations_path| are
5481 # only passed by tests.
5482 if not repo_root:
5483 repo_root = input_api.PresubmitLocalPath()
5484 if not translation_expectations_path:
5485 translation_expectations_path = input_api.os_path.join(
5486 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5487 if not grd_files:
5488 grd_files = git_helper.list_grds_in_repository(repo_root)
5489
5490 # Ignore bogus grd files used only for testing
5491 # ui/webui/resoucres/tools/generate_grd.py.
5492 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
5493 'tests')
5494 grd_files = [p for p in grd_files if ignore_path not in p]
5495
5496 try:
5497 translation_helper.get_translatable_grds(
5498 repo_root, grd_files, translation_expectations_path)
5499 except Exception as e:
5500 return [
5501 output_api.PresubmitNotifyResult(
5502 'Failed to get a list of translatable grd files. This happens when:\n'
5503 ' - One of the modified grd or grdp files cannot be parsed or\n'
5504 ' - %s is not updated.\n'
5505 'Stack:\n%s' % (translation_expectations_path, str(e)))
5506 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:125507 return []
5508
Ken Rockotc31f4832020-05-29 18:58:515509
Saagar Sanghavifceeaae2020-08-12 16:40:365510def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505511 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5512 changed_mojoms = input_api.AffectedFiles(
5513 include_deletes=True,
5514 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525515
Sam Maiera6e76d72022-02-11 21:43:505516 if not changed_mojoms:
5517 return []
5518
5519 delta = []
5520 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:505521 delta.append({
5522 'filename': mojom.LocalPath(),
5523 'old': '\n'.join(mojom.OldContents()) or None,
5524 'new': '\n'.join(mojom.NewContents()) or None,
5525 })
5526
5527 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:215528 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:505529 input_api.os_path.join(
5530 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
5531 'check_stable_mojom_compatibility.py'), '--src-root',
5532 input_api.PresubmitLocalPath()
5533 ],
5534 stdin=input_api.subprocess.PIPE,
5535 stdout=input_api.subprocess.PIPE,
5536 stderr=input_api.subprocess.PIPE,
5537 universal_newlines=True)
5538 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5539 if process.returncode:
5540 return [
5541 output_api.PresubmitError(
5542 'One or more [Stable] mojom definitions appears to have been changed '
5543 'in a way that is not backward-compatible.',
5544 long_text=error)
5545 ]
Erik Staabc734cd7a2021-11-23 03:11:525546 return []
5547
Dominic Battre645d42342020-12-04 16:14:105548def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505549 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:105550
Sam Maiera6e76d72022-02-11 21:43:505551 def FilterFile(affected_file):
5552 """Accept only .cc files and the like."""
5553 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5554 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5555 input_api.DEFAULT_FILES_TO_SKIP)
5556 return input_api.FilterSourceFile(
5557 affected_file,
5558 files_to_check=file_inclusion_pattern,
5559 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:105560
Sam Maiera6e76d72022-02-11 21:43:505561 def ModifiedLines(affected_file):
5562 """Returns a list of tuples (line number, line text) of added and removed
5563 lines.
Dominic Battre645d42342020-12-04 16:14:105564
Sam Maiera6e76d72022-02-11 21:43:505565 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:105566
Sam Maiera6e76d72022-02-11 21:43:505567 This relies on the scm diff output describing each changed code section
5568 with a line of the form
Dominic Battre645d42342020-12-04 16:14:105569
Sam Maiera6e76d72022-02-11 21:43:505570 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5571 """
5572 line_num = 0
5573 modified_lines = []
5574 for line in affected_file.GenerateScmDiff().splitlines():
5575 # Extract <new line num> of the patch fragment (see format above).
5576 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
5577 line)
5578 if m:
5579 line_num = int(m.groups(1)[0])
5580 continue
5581 if ((line.startswith('+') and not line.startswith('++'))
5582 or (line.startswith('-') and not line.startswith('--'))):
5583 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:105584
Sam Maiera6e76d72022-02-11 21:43:505585 if not line.startswith('-'):
5586 line_num += 1
5587 return modified_lines
Dominic Battre645d42342020-12-04 16:14:105588
Sam Maiera6e76d72022-02-11 21:43:505589 def FindLineWith(lines, needle):
5590 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:105591
Sam Maiera6e76d72022-02-11 21:43:505592 If 0 or >1 lines contain `needle`, -1 is returned.
5593 """
5594 matching_line_numbers = [
5595 # + 1 for 1-based counting of line numbers.
5596 i + 1 for i, line in enumerate(lines) if needle in line
5597 ]
5598 return matching_line_numbers[0] if len(
5599 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:105600
Sam Maiera6e76d72022-02-11 21:43:505601 def ModifiedPrefMigration(affected_file):
5602 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5603 # Determine first and last lines of MigrateObsolete.*Pref functions.
5604 new_contents = affected_file.NewContents()
5605 range_1 = (FindLineWith(new_contents,
5606 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5607 FindLineWith(new_contents,
5608 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5609 range_2 = (FindLineWith(new_contents,
5610 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5611 FindLineWith(new_contents,
5612 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5613 if (-1 in range_1 + range_2):
5614 raise Exception(
5615 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
5616 )
Dominic Battre645d42342020-12-04 16:14:105617
Sam Maiera6e76d72022-02-11 21:43:505618 # Check whether any of the modified lines are part of the
5619 # MigrateObsolete.*Pref functions.
5620 for line_nr, line in ModifiedLines(affected_file):
5621 if (range_1[0] <= line_nr <= range_1[1]
5622 or range_2[0] <= line_nr <= range_2[1]):
5623 return True
5624 return False
Dominic Battre645d42342020-12-04 16:14:105625
Sam Maiera6e76d72022-02-11 21:43:505626 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5627 browser_prefs_file_pattern = input_api.re.compile(
5628 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:105629
Sam Maiera6e76d72022-02-11 21:43:505630 changes = input_api.AffectedFiles(include_deletes=True,
5631 file_filter=FilterFile)
5632 potential_problems = []
5633 for f in changes:
5634 for line in f.GenerateScmDiff().splitlines():
5635 # Check deleted lines for pref registrations.
5636 if (line.startswith('-') and not line.startswith('--')
5637 and register_pref_pattern.search(line)):
5638 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:105639
Sam Maiera6e76d72022-02-11 21:43:505640 if browser_prefs_file_pattern.search(f.LocalPath()):
5641 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5642 # assume that they knew that they have to deprecate preferences and don't
5643 # warn.
5644 try:
5645 if ModifiedPrefMigration(f):
5646 return []
5647 except Exception as e:
5648 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:105649
Sam Maiera6e76d72022-02-11 21:43:505650 if potential_problems:
5651 return [
5652 output_api.PresubmitPromptWarning(
5653 'Discovered possible removal of preference registrations.\n\n'
5654 'Please make sure to properly deprecate preferences by clearing their\n'
5655 'value for a couple of milestones before finally removing the code.\n'
5656 'Otherwise data may stay in the preferences files forever. See\n'
5657 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5658 'chrome/browser/prefs/README.md for examples.\n'
5659 'This may be a false positive warning (e.g. if you move preference\n'
5660 'registrations to a different place).\n', potential_problems)
5661 ]
5662 return []
5663
Matt Stark6ef08872021-07-29 01:21:465664
5665def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505666 """Changes to GRD files must be consistent for tools to read them."""
5667 changed_grds = input_api.AffectedFiles(
5668 include_deletes=False,
5669 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5670 errors = []
5671 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5672 for matcher, msg in _INVALID_GRD_FILE_LINE]
5673 for grd in changed_grds:
5674 for i, line in enumerate(grd.NewContents()):
5675 for matcher, msg in invalid_file_regexes:
5676 if matcher.search(line):
5677 errors.append(
5678 output_api.PresubmitError(
5679 'Problem on {grd}:{i} - {msg}'.format(
5680 grd=grd.LocalPath(), i=i + 1, msg=msg)))
5681 return errors
5682
Kevin McNee967dd2d22021-11-15 16:09:295683
5684def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505685 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5686 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5687 """
Kevin McNee967dd2d22021-11-15 16:09:295688
Ian Vollickdba956c2022-04-20 23:53:455689 # Only consider top-level directories that (1) can use content APIs or
5690 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
5691 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:505692 files_to_check = (
Ian Vollickdba956c2022-04-20 23:53:455693 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Kevin McNee967dd2d22021-11-15 16:09:295694 _IMPLEMENTATION_EXTENSIONS,
Ian Vollickdba956c2022-04-20 23:53:455695 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Sam Maiera6e76d72022-02-11 21:43:505696 _HEADER_EXTENSIONS,
5697 )
5698 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5699 input_api.DEFAULT_FILES_TO_SKIP)
5700 source_file_filter = lambda f: input_api.FilterSourceFile(
5701 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:295702
Sam Maiera6e76d72022-02-11 21:43:505703 # Note that since these are are just regular expressions and we don't have
5704 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5705 # could have a method named IsInMainFrame).
5706 concerning_class_pattern = input_api.re.compile(
5707 r'WebContentsObserver|WebContentsUserData')
5708 # A subset of WebContentsObserver overrides where there's particular risk for
5709 # confusing tab and page level operations and data (e.g. incorrectly
5710 # resetting page state in DidFinishNavigation).
5711 concerning_wco_methods = [
5712 'DidStartNavigation',
5713 'ReadyToCommitNavigation',
5714 'DidFinishNavigation',
5715 'RenderViewReady',
5716 'RenderViewDeleted',
5717 'RenderViewHostChanged',
5718 'PrimaryMainDocumentElementAvailable',
5719 'DocumentOnLoadCompletedInPrimaryMainFrame',
5720 'DOMContentLoaded',
5721 'DidFinishLoad',
5722 ]
5723 concerning_nav_handle_methods = [
5724 'IsInMainFrame',
5725 ]
5726 concerning_web_contents_methods = [
5727 'ForEachFrame',
5728 'GetAllFrames',
5729 'FromRenderFrameHost',
5730 'FromRenderViewHost',
5731 'GetMainFrame',
5732 'GetRenderViewHost',
5733 ]
5734 concerning_rfh_methods = [
5735 'GetParent',
5736 'GetMainFrame',
5737 'GetFrameTreeNodeId',
5738 ]
Ian Vollickc825b1f2022-04-19 14:30:155739 concerning_rfhi_methods = [
5740 'is_main_frame',
5741 ]
Ian Vollicka77a73ea2022-04-06 18:08:015742 concerning_ftn_methods = [
5743 'IsMainFrame',
5744 ]
Ian Vollickdba956c2022-04-20 23:53:455745 concerning_blink_frame_methods = [
5746 'IsCrossOriginToMainFrame',
5747 ]
Sam Maiera6e76d72022-02-11 21:43:505748 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5749 item for sublist in [
5750 concerning_wco_methods, concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:015751 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:155752 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:455753 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:505754 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:295755
Kevin McNee4eeec792022-02-14 20:02:045756 used_apis = set()
Sam Maiera6e76d72022-02-11 21:43:505757 for f in input_api.AffectedFiles(include_deletes=False,
5758 file_filter=source_file_filter):
5759 for line_num, line in f.ChangedContents():
Kevin McNee4eeec792022-02-14 20:02:045760 class_match = concerning_class_pattern.search(line)
5761 if class_match:
5762 used_apis.add(class_match[0])
5763 method_match = concerning_method_pattern.search(line)
5764 if method_match:
5765 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:505766
Kevin McNee4eeec792022-02-14 20:02:045767 if not used_apis:
5768 return []
Kevin McNee967dd2d22021-11-15 16:09:295769
Kevin McNee4eeec792022-02-14 20:02:045770 output_api.AppendCC('[email protected]')
5771 message = ('This change uses API(s) that are ambiguous in the presence of '
5772 'MPArch features such as bfcache, prerendering, and fenced '
5773 'frames.')
5774 explaination = (
5775 'Please double check whether new code assumes that a WebContents only '
5776 'contains a single page at a time. For example, it is discouraged to '
5777 'reset per-document state in response to the observation of a '
5778 'navigation. See this doc [1] and the comments on the individual APIs '
5779 'for guidance and this doc [2] for context. The MPArch review '
5780 'watchlist has been CC\'d on this change to help identify any issues.\n'
5781 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
5782 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
5783 )
5784 return [
5785 output_api.PresubmitNotifyResult(message,
5786 items=list(used_apis),
5787 long_text=explaination)
5788 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:365789
5790
5791def CheckAssertAshOnlyCode(input_api, output_api):
5792 """Errors if a BUILD.gn file in an ash/ directory doesn't include
5793 assert(is_chromeos_ash).
5794 """
5795
5796 def FileFilter(affected_file):
5797 """Includes directories known to be Ash only."""
5798 return input_api.FilterSourceFile(
5799 affected_file,
5800 files_to_check=(
5801 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
5802 r'.*/ash/.*BUILD\.gn'), # Any path component.
5803 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
5804
5805 errors = []
5806 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:565807 for f in input_api.AffectedFiles(include_deletes=False,
5808 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:365809 if (not pattern.search(input_api.ReadFile(f))):
5810 errors.append(
5811 output_api.PresubmitError(
5812 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
5813 'possible, please create and issue and add a comment such '
5814 'as:\n # TODO(https://crbug.com/XXX): add '
5815 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
5816 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:275817
5818
5819def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:505820 path = affected_file.LocalPath()
5821 if not _IsCPlusPlusFile(input_api, path):
5822 return False
5823
5824 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
5825 if "/renderer/" in path:
5826 return True
5827
5828 # Blink's public/web API is only used/included by Renderer-only code. Note
5829 # that public/platform API may be used in non-Renderer processes (e.g. there
5830 # are some includes in code used by Utility, PDF, or Plugin processes).
5831 if "/blink/public/web/" in path:
5832 return True
5833
5834 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:275835 return False
5836
Lukasz Anforowicz7016d05e2021-11-30 03:56:275837# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
5838# by the Chromium Clang Plugin (which will be preferable because it will
5839# 1) report errors earlier - at compile-time and 2) cover more rules).
5840def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505841 """Rough checks that raw_ptr<T> usage guidelines are followed."""
5842 errors = []
5843 # The regex below matches "raw_ptr<" following a word boundary, but not in a
5844 # C++ comment.
5845 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
5846 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
5847 for f, line_num, line in input_api.RightHandSideLines(file_filter):
5848 if raw_ptr_matcher.search(line):
5849 errors.append(
5850 output_api.PresubmitError(
5851 'Problem on {path}:{line} - '\
5852 'raw_ptr<T> should not be used in Renderer-only code '\
5853 '(as documented in the "Pointers to unprotected memory" '\
5854 'section in //base/memory/raw_ptr.md)'.format(
5855 path=f.LocalPath(), line=line_num)))
5856 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:565857
5858
5859def CheckPythonShebang(input_api, output_api):
5860 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
5861 system-wide python.
5862 """
5863 errors = []
5864 sources = lambda affected_file: input_api.FilterSourceFile(
5865 affected_file,
5866 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
5867 r'third_party/blink/web_tests/external/') + input_api.
5868 DEFAULT_FILES_TO_SKIP),
5869 files_to_check=[r'.*\.py$'])
5870 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:275871 for line_num, line in f.ChangedContents():
5872 if line_num == 1 and line.startswith('#!/usr/bin/python'):
5873 errors.append(f.LocalPath())
5874 break
Henrique Ferreirof9819f2e32021-11-30 13:31:565875
5876 result = []
5877 for file in errors:
5878 result.append(
5879 output_api.PresubmitError(
5880 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
5881 file))
5882 return result