blob: db89961a81c5029595edfa33e8389565807cbb75 [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
14from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1217
Dirk Prankee3c9c62d2021-05-18 18:35:5918# This line is 'magic' in that git-cl looks for it to decide whether to
19# use Python3 instead of Python2 when running the code in this file.
20USE_PYTHON3 = True
21
[email protected]379e7dd2010-01-28 17:39:2122_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1823 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3124 (r"chrome/android/webapk/shell_apk/src/org/chromium"
25 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0826 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3127 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4728 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3129 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2630 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5231 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3132 r"^media/test/data/.*.ts",
33 r"^native_client_sdksrc/build_tools/make_rules.py",
34 r"^native_client_sdk/src/build_tools/make_simple.py",
35 r"^native_client_sdk/src/tools/.*.mk",
36 r"^net/tools/spdyshark/.*",
37 r"^skia/.*",
38 r"^third_party/blink/.*",
39 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4640 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3141 r"^third_party/sqlite/.*",
42 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5443 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5344 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2045 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3146 r".+/pnacl_shim\.c$",
47 r"^gpu/config/.*_list_json\.cc$",
48 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1449 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3150 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5451 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3152 r"tools/perf/page_sets/webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4053)
[email protected]ca8d1982009-02-19 16:33:1254
John Abd-El-Malek759fea62021-03-13 03:41:1455_EXCLUDED_SET_NO_PARENT_PATHS = (
56 # It's for historical reasons that blink isn't a top level directory, where
57 # it would be allowed to have "set noparent" to avoid top level owners
58 # accidentally +1ing changes.
59 'third_party/blink/OWNERS',
60)
61
wnwenbdc444e2016-05-25 13:44:1562
[email protected]06e6d0ff2012-12-11 01:36:4463# Fragment of a regular expression that matches C++ and Objective-C++
64# implementation files.
65_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
66
wnwenbdc444e2016-05-25 13:44:1567
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1968# Fragment of a regular expression that matches C++ and Objective-C++
69# header files.
70_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
71
72
Aleksey Khoroshilov9b28c032022-06-03 16:35:3273# Paths with sources that don't use //base.
74_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3175 r"^chrome/browser/browser_switcher/bho/",
76 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3277)
78
79
[email protected]06e6d0ff2012-12-11 01:36:4480# Regular expression that matches code only used for test binaries
81# (best effort).
82_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3183 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4484 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1385 # Test suite files, like:
86 # foo_browsertest.cc
87 # bar_unittest_mac.cc (suffix)
88 # baz_unittests.cc (plural)
89 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1290 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1891 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2192 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3193 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:4394 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:3195 r'content/shell/.*',
danakj89f47082020-09-02 17:53:4396 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:3197 r'content/web_test/.*',
[email protected]7b054982013-11-27 00:44:4798 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:3199 r'mojo/examples/.*',
[email protected]8176de12014-06-20 19:07:08100 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:31101 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41102 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31103 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17104 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31105 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41106 # Chromium Codelab
Bruce Dawson40fece62022-09-16 19:58:31107 r'codelabs/*'
[email protected]06e6d0ff2012-12-11 01:36:44108)
[email protected]ca8d1982009-02-19 16:33:12109
Daniel Bratell609102be2019-03-27 20:53:21110_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15111
[email protected]eea609a2011-11-18 13:10:12112_TEST_ONLY_WARNING = (
113 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55114 'production code. If you are doing this from inside another method\n'
115 'named as *ForTesting(), then consider exposing things to have tests\n'
116 'make that same call directly.\n'
117 'If that is not possible, you may put a comment on the same line with\n'
118 ' // IN-TEST \n'
119 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
120 'method and can be ignored. Do not do this inside production code.\n'
121 'The android-binary-size trybot will block if the method exists in the\n'
122 'release apk.')
[email protected]eea609a2011-11-18 13:10:12123
124
Daniel Chenga44a1bcd2022-03-15 20:00:15125@dataclass
126class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34127 # String pattern. If the pattern begins with a slash, the pattern will be
128 # treated as a regular expression instead.
129 pattern: str
130 # Explanation as a sequence of strings. Each string in the sequence will be
131 # printed on its own line.
132 explanation: Sequence[str]
133 # Whether or not to treat this ban as a fatal error. If unspecified,
134 # defaults to true.
135 treat_as_error: Optional[bool] = None
136 # Paths that should be excluded from the ban check. Each string is a regular
137 # expression that will be matched against the path of the file being checked
138 # relative to the root of the source tree.
139 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28140
Daniel Chenga44a1bcd2022-03-15 20:00:15141
Daniel Cheng917ce542022-03-15 20:46:57142_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15143 BanRule(
144 'import java.net.URI;',
145 (
146 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
147 ),
148 excluded_paths=(
149 (r'net/android/javatests/src/org/chromium/net/'
150 'AndroidProxySelectorTest\.java'),
151 r'components/cronet/',
152 r'third_party/robolectric/local/',
153 ),
Michael Thiessen44457642020-02-06 00:24:15154 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15155 BanRule(
156 'import android.annotation.TargetApi;',
157 (
158 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
159 'RequiresApi ensures that any calls are guarded by the appropriate '
160 'SDK_INT check. See https://crbug.com/1116486.',
161 ),
162 ),
163 BanRule(
164 'import android.support.test.rule.UiThreadTestRule;',
165 (
166 'Do not use UiThreadTestRule, just use '
167 '@org.chromium.base.test.UiThreadTest on test methods that should run '
168 'on the UI thread. See https://crbug.com/1111893.',
169 ),
170 ),
171 BanRule(
172 'import android.support.test.annotation.UiThreadTest;',
173 ('Do not use android.support.test.annotation.UiThreadTest, use '
174 'org.chromium.base.test.UiThreadTest instead. See '
175 'https://crbug.com/1111893.',
176 ),
177 ),
178 BanRule(
179 'import android.support.test.rule.ActivityTestRule;',
180 (
181 'Do not use ActivityTestRule, use '
182 'org.chromium.base.test.BaseActivityTestRule instead.',
183 ),
184 excluded_paths=(
185 'components/cronet/',
186 ),
187 ),
188)
wnwenbdc444e2016-05-25 13:44:15189
Daniel Cheng917ce542022-03-15 20:46:57190_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15191 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41192 'StrictMode.allowThreadDiskReads()',
193 (
194 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
195 'directly.',
196 ),
197 False,
198 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15199 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41200 'StrictMode.allowThreadDiskWrites()',
201 (
202 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
203 'directly.',
204 ),
205 False,
206 ),
Daniel Cheng917ce542022-03-15 20:46:57207 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36208 '.waitForIdleSync()',
209 (
210 'Do not use waitForIdleSync as it masks underlying issues. There is '
211 'almost always something else you should wait on instead.',
212 ),
213 False,
214 ),
Eric Stevensona9a980972017-09-23 00:04:41215)
216
Daniel Cheng917ce542022-03-15 20:46:57217_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15218 BanRule(
[email protected]127f18ec2012-06-16 05:05:59219 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20220 (
221 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59222 'prohibited. Please use CrTrackingArea instead.',
223 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
224 ),
225 False,
226 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15227 BanRule(
[email protected]eaae1972014-04-16 04:17:26228 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20229 (
230 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59231 'instead.',
232 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
233 ),
234 False,
235 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15236 BanRule(
[email protected]127f18ec2012-06-16 05:05:59237 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20238 (
239 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59240 'Please use |convertPoint:(point) fromView:nil| instead.',
241 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
242 ),
243 True,
244 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15245 BanRule(
[email protected]127f18ec2012-06-16 05:05:59246 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20247 (
248 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59249 'Please use |convertPoint:(point) toView:nil| instead.',
250 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
251 ),
252 True,
253 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15254 BanRule(
[email protected]127f18ec2012-06-16 05:05:59255 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20256 (
257 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59258 'Please use |convertRect:(point) fromView:nil| instead.',
259 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
260 ),
261 True,
262 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15263 BanRule(
[email protected]127f18ec2012-06-16 05:05:59264 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20265 (
266 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59267 'Please use |convertRect:(point) toView:nil| instead.',
268 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
269 ),
270 True,
271 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15272 BanRule(
[email protected]127f18ec2012-06-16 05:05:59273 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20274 (
275 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59276 'Please use |convertSize:(point) fromView:nil| instead.',
277 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
278 ),
279 True,
280 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15281 BanRule(
[email protected]127f18ec2012-06-16 05:05:59282 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20283 (
284 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59285 'Please use |convertSize:(point) toView:nil| instead.',
286 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
287 ),
288 True,
289 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15290 BanRule(
jif65398702016-10-27 10:19:48291 r"/\s+UTF8String\s*]",
292 (
293 'The use of -[NSString UTF8String] is dangerous as it can return null',
294 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
295 'Please use |SysNSStringToUTF8| instead.',
296 ),
297 True,
298 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15299 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34300 r'__unsafe_unretained',
301 (
302 'The use of __unsafe_unretained is almost certainly wrong, unless',
303 'when interacting with NSFastEnumeration or NSInvocation.',
304 'Please use __weak in files build with ARC, nothing otherwise.',
305 ),
306 False,
307 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15308 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13309 'freeWhenDone:NO',
310 (
311 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
312 'Foundation types is prohibited.',
313 ),
314 True,
315 ),
[email protected]127f18ec2012-06-16 05:05:59316)
317
Sylvain Defresnea8b73d252018-02-28 15:45:54318_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15319 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54320 r'/\bTEST[(]',
321 (
322 'TEST() macro should not be used in Objective-C++ code as it does not ',
323 'drain the autorelease pool at the end of the test. Use TEST_F() ',
324 'macro instead with a fixture inheriting from PlatformTest (or a ',
325 'typedef).'
326 ),
327 True,
328 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15329 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54330 r'/\btesting::Test\b',
331 (
332 'testing::Test should not be used in Objective-C++ code as it does ',
333 'not drain the autorelease pool at the end of the test. Use ',
334 'PlatformTest instead.'
335 ),
336 True,
337 ),
Ewann2ecc8d72022-07-18 07:41:23338 BanRule(
339 ' systemImageNamed:',
340 (
341 '+[UIImage systemImageNamed:] should not be used to create symbols.',
342 'Instead use a wrapper defined in:',
343 'ios/chrome/browser/ui/icons/chrome_symbol.h'
344 ),
345 True,
Ewann450a2ef2022-07-19 14:38:23346 excluded_paths=(
347 'ios/chrome/browser/ui/icons/chrome_symbol.mm',
348 ),
Ewann2ecc8d72022-07-18 07:41:23349 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54350)
351
Daniel Cheng917ce542022-03-15 20:46:57352_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15353 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05354 r'/\bEXPECT_OCMOCK_VERIFY\b',
355 (
356 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
357 'it is meant for GTests. Use [mock verify] instead.'
358 ),
359 True,
360 ),
361)
362
Daniel Cheng917ce542022-03-15 20:46:57363_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15364 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04365 r'/\busing namespace ',
366 (
367 'Using directives ("using namespace x") are banned by the Google Style',
368 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
369 'Explicitly qualify symbols or use using declarations ("using x::foo").',
370 ),
371 True,
372 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
373 ),
Antonio Gomes07300d02019-03-13 20:59:57374 # Make sure that gtest's FRIEND_TEST() macro is not used; the
375 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
376 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15377 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20378 'FRIEND_TEST(',
379 (
[email protected]e3c945502012-06-26 20:01:49380 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20381 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
382 ),
383 False,
[email protected]7345da02012-11-27 14:31:49384 (),
[email protected]23e6cbc2012-06-16 18:51:20385 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15386 BanRule(
tomhudsone2c14d552016-05-26 17:07:46387 'setMatrixClip',
388 (
389 'Overriding setMatrixClip() is prohibited; ',
390 'the base function is deprecated. ',
391 ),
392 True,
393 (),
394 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15395 BanRule(
[email protected]52657f62013-05-20 05:30:31396 'SkRefPtr',
397 (
398 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22399 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31400 ),
401 True,
402 (),
403 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15404 BanRule(
[email protected]52657f62013-05-20 05:30:31405 'SkAutoRef',
406 (
407 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22408 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31409 ),
410 True,
411 (),
412 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15413 BanRule(
[email protected]52657f62013-05-20 05:30:31414 'SkAutoTUnref',
415 (
416 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22417 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31418 ),
419 True,
420 (),
421 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15422 BanRule(
[email protected]52657f62013-05-20 05:30:31423 'SkAutoUnref',
424 (
425 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
426 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22427 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31428 ),
429 True,
430 (),
431 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15432 BanRule(
[email protected]d89eec82013-12-03 14:10:59433 r'/HANDLE_EINTR\(.*close',
434 (
435 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
436 'descriptor will be closed, and it is incorrect to retry the close.',
437 'Either call close directly and ignore its return value, or wrap close',
438 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
439 ),
440 True,
441 (),
442 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15443 BanRule(
[email protected]d89eec82013-12-03 14:10:59444 r'/IGNORE_EINTR\((?!.*close)',
445 (
446 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
447 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
448 ),
449 True,
450 (
451 # Files that #define IGNORE_EINTR.
Bruce Dawson40fece62022-09-16 19:58:31452 r'^base/posix/eintr_wrapper\.h$',
453 r'^ppapi/tests/test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59454 ),
455 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15456 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43457 r'/v8::Extension\(',
458 (
459 'Do not introduce new v8::Extensions into the code base, use',
460 'gin::Wrappable instead. See http://crbug.com/334679',
461 ),
462 True,
[email protected]f55c90ee62014-04-12 00:50:03463 (
Bruce Dawson40fece62022-09-16 19:58:31464 r'extensions/renderer/safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03465 ),
[email protected]ec5b3f02014-04-04 18:43:43466 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15467 BanRule(
jame2d1a952016-04-02 00:27:10468 '#pragma comment(lib,',
469 (
470 'Specify libraries to link with in build files and not in the source.',
471 ),
472 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41473 (
Bruce Dawson40fece62022-09-16 19:58:31474 r'^base/third_party/symbolize/.*',
475 r'^third_party/abseil-cpp/.*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41476 ),
jame2d1a952016-04-02 00:27:10477 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15478 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02479 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59480 (
481 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
482 ),
483 False,
484 (),
485 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15486 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02487 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59488 (
489 'Consider using THREAD_CHECKER macros instead of the class directly.',
490 ),
491 False,
492 (),
493 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15494 BanRule(
Sean Maher03efef12022-09-23 22:43:13495 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
496 (
497 'It is not allowed to call these methods from the subclasses ',
498 'of Sequenced or SingleThread task runners.',
499 ),
500 True,
501 (),
502 ),
503 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06504 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
505 (
506 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
507 'deprecated (http://crbug.com/634507). Please avoid converting away',
508 'from the Time types in Chromium code, especially if any math is',
509 'being done on time values. For interfacing with platform/library',
510 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
511 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48512 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06513 'other use cases, please contact base/time/OWNERS.',
514 ),
515 False,
516 (),
517 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15518 BanRule(
dbeamb6f4fde2017-06-15 04:03:06519 'CallJavascriptFunctionUnsafe',
520 (
521 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
522 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
523 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
524 ),
525 False,
526 (
Bruce Dawson40fece62022-09-16 19:58:31527 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
528 r'^content/public/browser/web_ui\.h$',
529 r'^content/public/test/test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06530 ),
531 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15532 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24533 'leveldb::DB::Open',
534 (
535 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
536 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
537 "Chrome's tracing, making their memory usage visible.",
538 ),
539 True,
540 (
541 r'^third_party/leveldatabase/.*\.(cc|h)$',
542 ),
Gabriel Charette0592c3a2017-07-26 12:02:04543 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15544 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08545 'leveldb::NewMemEnv',
546 (
547 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58548 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
549 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08550 ),
551 True,
552 (
553 r'^third_party/leveldatabase/.*\.(cc|h)$',
554 ),
555 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15556 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47557 'RunLoop::QuitCurrent',
558 (
Robert Liao64b7ab22017-08-04 23:03:43559 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
560 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47561 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41562 False,
Gabriel Charetted9839bc2017-07-29 14:17:47563 (),
Gabriel Charettea44975052017-08-21 23:14:04564 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15565 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04566 'base::ScopedMockTimeMessageLoopTaskRunner',
567 (
Gabriel Charette87cc1af2018-04-25 20:52:51568 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11569 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51570 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
571 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
572 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04573 ),
Gabriel Charette87cc1af2018-04-25 20:52:51574 False,
Gabriel Charettea44975052017-08-21 23:14:04575 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57576 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15577 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44578 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57579 (
580 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02581 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57582 ),
583 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16584 # Abseil's benchmarks never linked into chrome.
585 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38586 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15587 BanRule(
Peter Kasting991618a62019-06-17 22:00:09588 r'/\bstd::stoi\b',
589 (
590 'std::stoi uses exceptions to communicate results. ',
591 'Use base::StringToInt() instead.',
592 ),
593 True,
594 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
595 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15596 BanRule(
Peter Kasting991618a62019-06-17 22:00:09597 r'/\bstd::stol\b',
598 (
599 'std::stol uses exceptions to communicate results. ',
600 'Use base::StringToInt() instead.',
601 ),
602 True,
603 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
604 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15605 BanRule(
Peter Kasting991618a62019-06-17 22:00:09606 r'/\bstd::stoul\b',
607 (
608 'std::stoul uses exceptions to communicate results. ',
609 'Use base::StringToUint() instead.',
610 ),
611 True,
612 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
613 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15614 BanRule(
Peter Kasting991618a62019-06-17 22:00:09615 r'/\bstd::stoll\b',
616 (
617 'std::stoll uses exceptions to communicate results. ',
618 'Use base::StringToInt64() instead.',
619 ),
620 True,
621 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
622 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15623 BanRule(
Peter Kasting991618a62019-06-17 22:00:09624 r'/\bstd::stoull\b',
625 (
626 'std::stoull uses exceptions to communicate results. ',
627 'Use base::StringToUint64() instead.',
628 ),
629 True,
630 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
631 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15632 BanRule(
Peter Kasting991618a62019-06-17 22:00:09633 r'/\bstd::stof\b',
634 (
635 'std::stof uses exceptions to communicate results. ',
636 'For locale-independent values, e.g. reading numbers from disk',
637 'profiles, use base::StringToDouble().',
638 'For user-visible values, parse using ICU.',
639 ),
640 True,
641 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
642 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15643 BanRule(
Peter Kasting991618a62019-06-17 22:00:09644 r'/\bstd::stod\b',
645 (
646 'std::stod uses exceptions to communicate results. ',
647 'For locale-independent values, e.g. reading numbers from disk',
648 'profiles, use base::StringToDouble().',
649 'For user-visible values, parse using ICU.',
650 ),
651 True,
652 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
653 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15654 BanRule(
Peter Kasting991618a62019-06-17 22:00:09655 r'/\bstd::stold\b',
656 (
657 'std::stold uses exceptions to communicate results. ',
658 'For locale-independent values, e.g. reading numbers from disk',
659 'profiles, use base::StringToDouble().',
660 'For user-visible values, parse using ICU.',
661 ),
662 True,
663 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
664 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15665 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45666 r'/\bstd::to_string\b',
667 (
668 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09669 'For locale-independent strings, e.g. writing numbers to disk',
670 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45671 'For user-visible strings, use base::FormatNumber() and',
672 'the related functions in base/i18n/number_formatting.h.',
673 ),
Peter Kasting991618a62019-06-17 22:00:09674 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21675 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45676 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15677 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45678 r'/\bstd::shared_ptr\b',
679 (
680 'std::shared_ptr should not be used. Use scoped_refptr instead.',
681 ),
682 True,
Ulan Degenbaev947043882021-02-10 14:02:31683 [
684 # Needed for interop with third-party library.
685 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57686 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58687 '^third_party/blink/renderer/bindings/core/v8/' +
688 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58689 '^gin/array_buffer\.(cc|h)',
690 '^chrome/services/sharing/nearby/',
Stephen Nuskoe09c8ef22022-09-29 00:47:28691 # Needed for interop with third-party library libunwindstack.
Stephen Nuskoe51c1382022-09-26 15:49:03692 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
Meilin Wang00efc7c2021-05-13 01:12:42693 # gRPC provides some C++ libraries that use std::shared_ptr<>.
Yeunjoo Choi1b644402022-08-25 02:36:10694 '^chromeos/ash/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59695 '^chromecast/cast_core/grpc',
696 '^chromecast/cast_core/runtime/browser',
Yue Shef83d95202022-09-26 20:23:45697 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Wez5f56be52021-05-04 09:30:58698 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Fabrice de Gans3b875422022-04-19 19:40:26699 '^base/fuchsia/filtered_service_directory\.(cc|h)',
700 '^base/fuchsia/service_directory_test_base\.h',
Wez5f56be52021-05-04 09:30:58701 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57702 # Needed for clang plugin tests
703 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57704 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21705 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15706 BanRule(
Peter Kasting991618a62019-06-17 22:00:09707 r'/\bstd::weak_ptr\b',
708 (
709 'std::weak_ptr should not be used. Use base::WeakPtr 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'/\blong long\b',
716 (
717 'long long is banned. Use stdint.h if you need a 64 bit number.',
718 ),
719 False, # Only a warning since it is already used.
720 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
721 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15722 BanRule(
Daniel Chengc05fcc62022-01-12 16:54:29723 r'\b(absl|std)::any\b',
724 (
Daniel Chenga44a1bcd2022-03-15 20:00:15725 'absl::any / std::any are not safe to use in a component build.',
Daniel Chengc05fcc62022-01-12 16:54:29726 ),
727 True,
728 # Not an error in third party folders, though it probably should be :)
729 [_THIRD_PARTY_EXCEPT_BLINK],
730 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15731 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21732 r'/\bstd::bind\b',
733 (
734 'std::bind is banned because of lifetime risks.',
735 'Use base::BindOnce or base::BindRepeating instead.',
736 ),
737 True,
738 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
739 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15740 BanRule(
Peter Kasting4f35bfc2022-10-18 18:39:12741 r'/\babsl::bind_front\b',
742 (
743 'absl::bind_front is banned. Use base::Bind instead.',
744 ),
745 True,
746 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
747 ),
748 BanRule(
749 r'/\bABSL_FLAG\b',
750 (
751 'ABSL_FLAG is banned. Use base::CommandLine instead.',
752 ),
753 True,
754 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
755 ),
756 BanRule(
757 r'/\babsl::c_',
758 (
759 'Abseil container utilities are banned. Use base/ranges/algorithm.h',
760 'instead.',
761 ),
762 True,
763 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
764 ),
765 BanRule(
766 r'/\babsl::FunctionRef\b',
767 (
768 'absl::FunctionRef is banned. Use base::FunctionRef instead.',
769 ),
770 True,
771 [
772 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
773 # interoperability.
774 r'^base/functional/bind_internal\.h',
775 # base::FunctionRef is implemented on top of absl::FunctionRef.
776 r'^base/functional/function_ref.*\..+',
777 # Not an error in third_party folders.
778 _THIRD_PARTY_EXCEPT_BLINK,
779 ],
780 ),
781 BanRule(
782 r'/\babsl::(Insecure)?BitGen\b',
783 (
784 'Abseil random number generators are banned. Use base/rand_util.h',
785 'instead.',
786 ),
787 True,
788 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
789 ),
790 BanRule(
791 r'/\babsl::Span\b',
792 (
793 'absl::Span is banned. Use base::span instead.',
794 ),
795 True,
796 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
797 ),
798 BanRule(
799 r'/\babsl::StatusOr\b',
800 (
801 'absl::StatusOr is banned. Use base::expected instead.',
802 ),
803 True,
804 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
805 ),
806 BanRule(
807 r'/\babsl::StrFormat\b',
808 (
809 'absl::StrFormat is banned for now. Use base::StringPrintf instead.',
810 ),
811 True,
812 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
813 ),
814 BanRule(
815 r'/\babsl::string_view\b',
816 (
817 'absl::string_view is banned. Use base::StringPiece instead.',
818 ),
819 True,
820 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
821 ),
822 BanRule(
823 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
824 (
825 'Abseil string utilities are banned. Use base/strings instead.',
826 ),
827 True,
828 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
829 ),
830 BanRule(
831 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
832 (
833 'Abseil synchronization primitives are banned. Use',
834 'base/synchronization instead.',
835 ),
836 True,
837 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
838 ),
839 BanRule(
840 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
841 (
842 'Abseil\'s time library is banned. Use base/time instead.',
843 ),
844 True,
845 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
846 ),
847 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:03848 r'/\bstd::optional\b',
849 (
850 'std::optional is banned. Use absl::optional instead.',
851 ),
852 True,
853 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
854 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15855 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21856 r'/\b#include <chrono>\b',
857 (
858 '<chrono> overlaps with Time APIs in base. Keep using',
859 'base classes.',
860 ),
861 True,
862 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
863 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15864 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21865 r'/\b#include <exception>\b',
866 (
867 'Exceptions are banned and disabled in Chromium.',
868 ),
869 True,
870 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
871 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15872 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21873 r'/\bstd::function\b',
874 (
Colin Blundellea615d422021-05-12 09:35:41875 'std::function is banned. Instead use base::OnceCallback or ',
876 'base::RepeatingCallback, which directly support Chromium\'s weak ',
877 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21878 ),
Daniel Chenge5583e3c2022-09-22 00:19:41879 True,
Daniel Chengcd23b8b2022-09-16 17:16:24880 [
881 # Has tests that template trait helpers don't unintentionally match
882 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:41883 r'base/functional/callback_helpers_unittest\.cc',
884 # Required to implement interfaces from the third-party perfetto
885 # library.
886 r'base/tracing/perfetto_task_runner\.cc',
887 r'base/tracing/perfetto_task_runner\.h',
888 # Needed for interop with the third-party nearby library type
889 # location::nearby::connections::ResultCallback.
890 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
891 # Needed for interop with the internal libassistant library.
892 'chromeos/ash/services/libassistant/callback_utils\.h',
893 # Needed for interop with Fuchsia fidl APIs.
894 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
895 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
896 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
897 # Required to interop with interfaces from the third-party perfetto
898 # library.
899 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
900 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
901 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
902 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
903 'services/tracing/public/cpp/perfetto/producer_client\.cc',
904 'services/tracing/public/cpp/perfetto/producer_client\.h',
905 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
906 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
907 # Required for interop with the third-party webrtc library.
908 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
909 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
910
911 # TODO(https://crbug.com/1364577): Various uses that should be
912 # migrated to something else.
913 # Should use base::OnceCallback or base::RepeatingCallback.
914 'base/allocator/dispatcher/initializer_unittest\.cc',
915 'chrome/browser/ash/accessibility/speech_monitor\.cc',
916 'chrome/browser/ash/accessibility/speech_monitor\.h',
917 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
918 'chromecast/base/observer_unittest\.cc',
919 'chromecast/browser/cast_web_view\.h',
920 'chromecast/public/cast_media_shlib\.h',
921 'device/bluetooth/floss/exported_callback_manager\.h',
922 'device/bluetooth/floss/floss_dbus_client\.h',
923 'device/fido/cable/v2_handshake_unittest\.cc',
924 'device/fido/pin\.cc',
925 'services/tracing/perfetto/test_utils\.h',
926 # Should use base::FunctionRef.
927 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
928 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
929 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
930 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
931 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
932 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
933 # Does not need std::function at all.
934 'components/omnibox/browser/autocomplete_result\.cc',
935 'device/fido/win/webauthn_api\.cc',
936 'media/audio/alsa/alsa_util\.cc',
937 'media/remoting/stream_provider\.h',
938 'sql/vfs_wrapper\.cc',
939 # TODO(https://crbug.com/1364585): Remove usage and exception list
940 # entries.
941 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
942 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
943 # TODO(https://crbug.com/1364579): Remove usage and exception list
944 # entry.
945 'ui/views/controls/focus_ring\.h',
946
947 # Various pre-existing uses in //tools that is low-priority to fix.
948 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
949 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
950 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
951 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
952 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
953
Daniel Chengcd23b8b2022-09-16 17:16:24954 # Not an error in third_party folders.
955 _THIRD_PARTY_EXCEPT_BLINK
956 ],
Daniel Bratell609102be2019-03-27 20:53:21957 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15958 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21959 r'/\b#include <random>\b',
960 (
961 'Do not use any random number engines from <random>. Instead',
962 'use base::RandomBitGenerator.',
963 ),
964 True,
965 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
966 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15967 BanRule(
Tom Andersona95e12042020-09-09 23:08:00968 r'/\b#include <X11/',
969 (
970 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
971 ),
972 True,
973 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
974 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15975 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21976 r'/\bstd::ratio\b',
977 (
978 'std::ratio is banned by the Google Style Guide.',
979 ),
980 True,
981 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45982 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15983 BanRule(
Gabriel Charetted90bcc92021-09-21 00:23:10984 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:38985 (
Gabriel Charetted90bcc92021-09-21 00:23:10986 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:38987 ),
Gabriel Charette04b138f2018-08-06 00:03:22988 False,
Francois Doray43670e32017-09-27 12:40:38989 (),
990 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15991 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:58992 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19993 (
994 'RunMessageLoop is deprecated, use RunLoop instead.',
995 ),
996 False,
997 (),
998 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15999 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441000 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191001 (
1002 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
1003 ),
1004 False,
1005 (),
1006 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151007 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441008 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191009 (
1010 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1011 "if you're convinced you need this.",
1012 ),
1013 False,
1014 (),
1015 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151016 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441017 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191018 (
1019 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041020 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191021 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1022 'async events instead of flushing threads.',
1023 ),
1024 False,
1025 (),
1026 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151027 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191028 r'MessageLoopRunner',
1029 (
1030 'MessageLoopRunner is deprecated, use RunLoop instead.',
1031 ),
1032 False,
1033 (),
1034 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151035 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441036 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191037 (
1038 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1039 "gab@ if you found a use case where this is the only solution.",
1040 ),
1041 False,
1042 (),
1043 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151044 BanRule(
Victor Costane48a2e82019-03-15 22:02:341045 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161046 (
Victor Costane48a2e82019-03-15 22:02:341047 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161048 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1049 ),
1050 True,
1051 (
1052 r'^sql/initialization\.(cc|h)$',
1053 r'^third_party/sqlite/.*\.(c|cc|h)$',
1054 ),
1055 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151056 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441057 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471058 (
1059 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1060 'base::RandomShuffle instead.'
1061 ),
1062 True,
1063 (),
1064 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151065 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241066 'ios/web/public/test/http_server',
1067 (
1068 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1069 ),
1070 False,
1071 (),
1072 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151073 BanRule(
Robert Liao764c9492019-01-24 18:46:281074 'GetAddressOf',
1075 (
1076 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531077 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111078 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531079 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281080 ),
1081 True,
1082 (),
1083 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151084 BanRule(
Ben Lewisa9514602019-04-29 17:53:051085 'SHFileOperation',
1086 (
1087 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1088 'complex functions to achieve the same goals. Use IFileOperation for ',
1089 'any esoteric actions instead.'
1090 ),
1091 True,
1092 (),
1093 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151094 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511095 'StringFromGUID2',
1096 (
1097 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241098 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511099 ),
1100 True,
1101 (
Daniel Chenga44a1bcd2022-03-15 20:00:151102 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511103 ),
1104 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151105 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511106 'StringFromCLSID',
1107 (
1108 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241109 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511110 ),
1111 True,
1112 (
Daniel Chenga44a1bcd2022-03-15 20:00:151113 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511114 ),
1115 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151116 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131117 'kCFAllocatorNull',
1118 (
1119 'The use of kCFAllocatorNull with the NoCopy creation of ',
1120 'CoreFoundation types is prohibited.',
1121 ),
1122 True,
1123 (),
1124 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151125 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291126 'mojo::ConvertTo',
1127 (
1128 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1129 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1130 'StringTraits if you would like to convert between custom types and',
1131 'the wire format of mojom types.'
1132 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221133 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291134 (
David Dorwin13dc48b2022-06-03 21:18:421135 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1136 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291137 r'^third_party/blink/.*\.(cc|h)$',
1138 r'^content/renderer/.*\.(cc|h)$',
1139 ),
1140 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151141 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161142 'GetInterfaceProvider',
1143 (
1144 'InterfaceProvider is deprecated.',
1145 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1146 'or Platform::GetBrowserInterfaceBroker.'
1147 ),
1148 False,
1149 (),
1150 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151151 BanRule(
Robert Liao1d78df52019-11-11 20:02:011152 'CComPtr',
1153 (
1154 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1155 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1156 'details.'
1157 ),
1158 False,
1159 (),
1160 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151161 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201162 r'/\b(IFACE|STD)METHOD_?\(',
1163 (
1164 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1165 'Instead, always use IFACEMETHODIMP in the declaration.'
1166 ),
1167 False,
1168 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1169 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151170 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471171 'set_owned_by_client',
1172 (
1173 'set_owned_by_client is deprecated.',
1174 'views::View already owns the child views by default. This introduces ',
1175 'a competing ownership model which makes the code difficult to reason ',
1176 'about. See http://crbug.com/1044687 for more details.'
1177 ),
1178 False,
1179 (),
1180 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151181 BanRule(
Peter Boström7ff41522021-07-29 03:43:271182 'RemoveAllChildViewsWithoutDeleting',
1183 (
1184 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1185 'This method is deemed dangerous as, unless raw pointers are re-added,',
1186 'calls to this method introduce memory leaks.'
1187 ),
1188 False,
1189 (),
1190 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151191 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121192 r'/\bTRACE_EVENT_ASYNC_',
1193 (
1194 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1195 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1196 ),
1197 False,
1198 (
1199 r'^base/trace_event/.*',
1200 r'^base/tracing/.*',
1201 ),
1202 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151203 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431204 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1205 (
1206 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1207 'dumps and may spam crash reports. Consider if the throttled',
1208 'variants suffice instead.',
1209 ),
1210 False,
1211 (),
1212 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151213 BanRule(
Robert Liao22f66a52021-04-10 00:57:521214 'RoInitialize',
1215 (
Robert Liao48018922021-04-16 23:03:021216 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521217 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1218 'instead. See http://crbug.com/1197722 for more information.'
1219 ),
1220 True,
Robert Liao48018922021-04-16 23:03:021221 (
Bruce Dawson40fece62022-09-16 19:58:311222 r'^base/win/scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021223 ),
Robert Liao22f66a52021-04-10 00:57:521224 ),
Patrick Monettec343bb982022-06-01 17:18:451225 BanRule(
1226 r'base::Watchdog',
1227 (
1228 'base::Watchdog is deprecated because it creates its own thread.',
1229 'Instead, manually start a timer on a SequencedTaskRunner.',
1230 ),
1231 False,
1232 (),
1233 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091234 BanRule(
1235 'base::Passed',
1236 (
1237 'Do not use base::Passed. It is a legacy helper for capturing ',
1238 'move-only types with base::BindRepeating, but invoking the ',
1239 'resulting RepeatingCallback moves the captured value out of ',
1240 'the callback storage, and subsequent invocations may pass the ',
1241 'value in a valid but undefined state. Prefer base::BindOnce().',
1242 'See http://crbug.com/1326449 for context.'
1243 ),
1244 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481245 (
1246 # False positive, but it is also fine to let bind internals reference
1247 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241248 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481249 r'^base[\\/]functional[\\/]bind_internal\.h',
1250 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091251 ),
Daniel Cheng2248b332022-07-27 06:16:591252 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431253 r'base::Feature k',
1254 (
1255 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1256 'directly declaring/defining features.'
1257 ),
1258 True,
1259 [
1260 _THIRD_PARTY_EXCEPT_BLINK,
1261 ],
1262 ),
Robert Ogden92101dcb2022-10-19 23:49:361263 BanRule(
1264 r'\bchartorune\b',
1265 (
1266 'chartorune is not memory-safe, unless you can guarantee the input ',
1267 'string is always null-terminated. Otherwise, please use charntorune ',
1268 'from libphonenumber instead.'
1269 ),
1270 True,
1271 [
1272 _THIRD_PARTY_EXCEPT_BLINK,
1273 # Exceptions to this rule should have a fuzzer.
1274 ],
1275 ),
[email protected]127f18ec2012-06-16 05:05:591276)
1277
Daniel Cheng92c15e32022-03-16 17:48:221278_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1279 BanRule(
1280 'handle<shared_buffer>',
1281 (
1282 'Please use one of the more specific shared memory types instead:',
1283 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1284 ' mojo_base.mojom.WritableSharedMemoryRegion',
1285 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1286 ),
1287 True,
1288 ),
1289)
1290
mlamouria82272622014-09-16 18:45:041291_IPC_ENUM_TRAITS_DEPRECATED = (
1292 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501293 'See http://www.chromium.org/Home/chromium-security/education/'
1294 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041295
Stephen Martinis97a394142018-06-07 23:06:051296_LONG_PATH_ERROR = (
1297 'Some files included in this CL have file names that are too long (> 200'
1298 ' characters). If committed, these files will cause issues on Windows. See'
1299 ' https://crbug.com/612667 for more details.'
1300)
1301
Shenghua Zhangbfaa38b82017-11-16 21:58:021302_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:311303 r".*/AppHooksImpl\.java",
1304 r".*/BuildHooksAndroidImpl\.java",
1305 r".*/LicenseContentProvider\.java",
1306 r".*/PlatformServiceBridgeImpl.java",
1307 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021308]
[email protected]127f18ec2012-06-16 05:05:591309
Mohamed Heikald048240a2019-11-12 16:57:371310# List of image extensions that are used as resources in chromium.
1311_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1312
Sean Kau46e29bc2017-08-28 16:31:161313# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401314_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:311315 r'test/data/',
1316 r'testing/buildbot/',
1317 r'^components/policy/resources/policy_templates\.json$',
1318 r'^third_party/protobuf/',
1319 r'^third_party/blink/perf_tests/speedometer/resources/todomvc/learn.json',
1320 r'^third_party/blink/renderer/devtools/protocol\.json$',
1321 r'^third_party/blink/web_tests/external/wpt/',
1322 r'^tools/perf/',
1323 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311324 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:311325 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:161326]
1327
Andrew Grieveb773bad2020-06-05 18:00:381328# These are not checked on the public chromium-presubmit trybot.
1329# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041330# checkouts.
agrievef32bcc72016-04-04 14:57:401331_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381332 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381333]
1334
1335
1336_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101337 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041338 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361339 'base/android/jni_generator/jni_generator.pydeps',
1340 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361341 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041342 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361343 'build/android/gyp/aar.pydeps',
1344 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271345 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361346 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381347 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361348 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021349 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221350 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111351 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361352 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361354 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111355 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041356 'build/android/gyp/create_app_bundle_apks.pydeps',
1357 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361358 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121359 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091360 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221361 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401362 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001363 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361364 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421365 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041366 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361367 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361368 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211369 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361370 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361371 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361372 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581373 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361374 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141375 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261376 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471377 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041378 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361379 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361380 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101381 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361382 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221383 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361384 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221385 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101386 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461387 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301388 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241389 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361390 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461391 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561392 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361393 'build/android/incremental_install/generate_android_manifest.pydeps',
1394 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321395 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041396 'build/android/resource_sizes.pydeps',
1397 'build/android/test_runner.pydeps',
1398 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361399 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361400 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321401 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271402 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1403 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041404 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001405 'components/cronet/tools/generate_javadoc.pydeps',
1406 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381407 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001408 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381409 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181410 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411411 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1412 'testing/merge_scripts/standard_gtest_merge.pydeps',
1413 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1414 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041415 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421416 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251417 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421418 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131419 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501420 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411421 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1422 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061423 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221424 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451425 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401426]
1427
wnwenbdc444e2016-05-25 13:44:151428
agrievef32bcc72016-04-04 14:57:401429_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1430
1431
Eric Boren6fd2b932018-01-25 15:05:081432# Bypass the AUTHORS check for these accounts.
1433_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591434 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451435 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591436 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521437 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231438 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471439 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461440 'infra-try-recipes-tester', 'lacros-tracking-roller',
1441 'lacros-sdk-version-roller')
Eric Boren835d71f2018-09-07 21:09:041442 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271443 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041444 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161445 for s in ('chromium-internal-autoroll',)
1446 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:551447 for s in ('swarming-tasks',)
1448 ) | set('%[email protected]' % s
1449 for s in ('global-integration-try-builder',
1450 'global-integration-ci-builder'))
Eric Boren6fd2b932018-01-25 15:05:081451
Matt Stark6ef08872021-07-29 01:21:461452_INVALID_GRD_FILE_LINE = [
1453 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1454]
Eric Boren6fd2b932018-01-25 15:05:081455
Daniel Bratell65b033262019-04-23 08:17:061456def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501457 """Returns True if this file contains C++-like code (and not Python,
1458 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061459
Sam Maiera6e76d72022-02-11 21:43:501460 ext = input_api.os_path.splitext(file_path)[1]
1461 # This list is compatible with CppChecker.IsCppFile but we should
1462 # consider adding ".c" to it. If we do that we can use this function
1463 # at more places in the code.
1464 return ext in (
1465 '.h',
1466 '.cc',
1467 '.cpp',
1468 '.m',
1469 '.mm',
1470 )
1471
Daniel Bratell65b033262019-04-23 08:17:061472
1473def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501474 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061475
1476
1477def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501478 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061479
1480
1481def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501482 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061483
Mohamed Heikal5e5b7922020-10-29 18:57:591484
Erik Staabc734cd7a2021-11-23 03:11:521485def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501486 ext = input_api.os_path.splitext(file_path)[1]
1487 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521488
1489
Mohamed Heikal5e5b7922020-10-29 18:57:591490def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501491 """Prevent additions of dependencies from the upstream repo on //clank."""
1492 # clank can depend on clank
1493 if input_api.change.RepositoryRoot().endswith('clank'):
1494 return []
1495 build_file_patterns = [
1496 r'(.+/)?BUILD\.gn',
1497 r'.+\.gni',
1498 ]
1499 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1500 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591501
Sam Maiera6e76d72022-02-11 21:43:501502 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591503
Sam Maiera6e76d72022-02-11 21:43:501504 def FilterFile(affected_file):
1505 return input_api.FilterSourceFile(affected_file,
1506 files_to_check=build_file_patterns,
1507 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591508
Sam Maiera6e76d72022-02-11 21:43:501509 problems = []
1510 for f in input_api.AffectedSourceFiles(FilterFile):
1511 local_path = f.LocalPath()
1512 for line_number, line in f.ChangedContents():
1513 if (bad_pattern.search(line)):
1514 problems.append('%s:%d\n %s' %
1515 (local_path, line_number, line.strip()))
1516 if problems:
1517 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1518 else:
1519 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591520
1521
Saagar Sanghavifceeaae2020-08-12 16:40:361522def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501523 """Attempts to prevent use of functions intended only for testing in
1524 non-testing code. For now this is just a best-effort implementation
1525 that ignores header files and may have some false positives. A
1526 better implementation would probably need a proper C++ parser.
1527 """
1528 # We only scan .cc files and the like, as the declaration of
1529 # for-testing functions in header files are hard to distinguish from
1530 # calls to such functions without a proper C++ parser.
1531 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191532
Sam Maiera6e76d72022-02-11 21:43:501533 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1534 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1535 base_function_pattern)
1536 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1537 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1538 exclusion_pattern = input_api.re.compile(
1539 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1540 (base_function_pattern, base_function_pattern))
1541 # Avoid a false positive in this case, where the method name, the ::, and
1542 # the closing { are all on different lines due to line wrapping.
1543 # HelperClassForTesting::
1544 # HelperClassForTesting(
1545 # args)
1546 # : member(0) {}
1547 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191548
Sam Maiera6e76d72022-02-11 21:43:501549 def FilterFile(affected_file):
1550 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1551 input_api.DEFAULT_FILES_TO_SKIP)
1552 return input_api.FilterSourceFile(
1553 affected_file,
1554 files_to_check=file_inclusion_pattern,
1555 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191556
Sam Maiera6e76d72022-02-11 21:43:501557 problems = []
1558 for f in input_api.AffectedSourceFiles(FilterFile):
1559 local_path = f.LocalPath()
1560 in_method_defn = False
1561 for line_number, line in f.ChangedContents():
1562 if (inclusion_pattern.search(line)
1563 and not comment_pattern.search(line)
1564 and not exclusion_pattern.search(line)
1565 and not allowlist_pattern.search(line)
1566 and not in_method_defn):
1567 problems.append('%s:%d\n %s' %
1568 (local_path, line_number, line.strip()))
1569 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191570
Sam Maiera6e76d72022-02-11 21:43:501571 if problems:
1572 return [
1573 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1574 ]
1575 else:
1576 return []
[email protected]55459852011-08-10 15:17:191577
1578
Saagar Sanghavifceeaae2020-08-12 16:40:361579def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501580 """This is a simplified version of
1581 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1582 """
1583 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1584 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1585 name_pattern = r'ForTest(s|ing)?'
1586 # Describes an occurrence of "ForTest*" inside a // comment.
1587 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1588 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1589 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1590 # Catch calls.
1591 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1592 # Ignore definitions. (Comments are ignored separately.)
1593 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231594
Sam Maiera6e76d72022-02-11 21:43:501595 problems = []
1596 sources = lambda x: input_api.FilterSourceFile(
1597 x,
1598 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1599 DEFAULT_FILES_TO_SKIP),
1600 files_to_check=[r'.*\.java$'])
1601 for f in input_api.AffectedFiles(include_deletes=False,
1602 file_filter=sources):
1603 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231604 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501605 for line_number, line in f.ChangedContents():
1606 if is_inside_javadoc and javadoc_end_re.search(line):
1607 is_inside_javadoc = False
1608 if not is_inside_javadoc and javadoc_start_re.search(line):
1609 is_inside_javadoc = True
1610 if is_inside_javadoc:
1611 continue
1612 if (inclusion_re.search(line) and not comment_re.search(line)
1613 and not annotation_re.search(line)
1614 and not exclusion_re.search(line)):
1615 problems.append('%s:%d\n %s' %
1616 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231617
Sam Maiera6e76d72022-02-11 21:43:501618 if problems:
1619 return [
1620 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1621 ]
1622 else:
1623 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231624
1625
Saagar Sanghavifceeaae2020-08-12 16:40:361626def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501627 """Checks to make sure no .h files include <iostream>."""
1628 files = []
1629 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1630 input_api.re.MULTILINE)
1631 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1632 if not f.LocalPath().endswith('.h'):
1633 continue
1634 contents = input_api.ReadFile(f)
1635 if pattern.search(contents):
1636 files.append(f)
[email protected]10689ca2011-09-02 02:31:541637
Sam Maiera6e76d72022-02-11 21:43:501638 if len(files):
1639 return [
1640 output_api.PresubmitError(
1641 'Do not #include <iostream> in header files, since it inserts static '
1642 'initialization into every file including the header. Instead, '
1643 '#include <ostream>. See http://crbug.com/94794', files)
1644 ]
1645 return []
1646
[email protected]10689ca2011-09-02 02:31:541647
Aleksey Khoroshilov9b28c032022-06-03 16:35:321648def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501649 """Checks no windows headers with StrCat redefined are included directly."""
1650 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:321651 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
1652 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
1653 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
1654 _NON_BASE_DEPENDENT_PATHS)
1655 sources_filter = lambda f: input_api.FilterSourceFile(
1656 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
1657
Sam Maiera6e76d72022-02-11 21:43:501658 pattern_deny = input_api.re.compile(
1659 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1660 input_api.re.MULTILINE)
1661 pattern_allow = input_api.re.compile(
1662 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:321663 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:501664 contents = input_api.ReadFile(f)
1665 if pattern_deny.search(
1666 contents) and not pattern_allow.search(contents):
1667 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431668
Sam Maiera6e76d72022-02-11 21:43:501669 if len(files):
1670 return [
1671 output_api.PresubmitError(
1672 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1673 'directly since they pollute code with StrCat macro. Instead, '
1674 'include matching header from base/win. See http://crbug.com/856536',
1675 files)
1676 ]
1677 return []
Danil Chapovalov3518f362018-08-11 16:13:431678
[email protected]10689ca2011-09-02 02:31:541679
Saagar Sanghavifceeaae2020-08-12 16:40:361680def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501681 """Checks to make sure no source files use UNIT_TEST."""
1682 problems = []
1683 for f in input_api.AffectedFiles():
1684 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1685 continue
[email protected]72df4e782012-06-21 16:28:181686
Sam Maiera6e76d72022-02-11 21:43:501687 for line_num, line in f.ChangedContents():
1688 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1689 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181690
Sam Maiera6e76d72022-02-11 21:43:501691 if not problems:
1692 return []
1693 return [
1694 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1695 '\n'.join(problems))
1696 ]
1697
[email protected]72df4e782012-06-21 16:28:181698
Saagar Sanghavifceeaae2020-08-12 16:40:361699def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501700 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341701
Sam Maiera6e76d72022-02-11 21:43:501702 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1703 instead of DISABLED_. To filter false positives, reports are only generated
1704 if a corresponding MAYBE_ line exists.
1705 """
1706 problems = []
Dominic Battre033531052018-09-24 15:45:341707
Sam Maiera6e76d72022-02-11 21:43:501708 # The following two patterns are looked for in tandem - is a test labeled
1709 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1710 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1711 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341712
Sam Maiera6e76d72022-02-11 21:43:501713 # This is for the case that a test is disabled on all platforms.
1714 full_disable_pattern = input_api.re.compile(
1715 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1716 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341717
Sam Maiera6e76d72022-02-11 21:43:501718 for f in input_api.AffectedFiles(False):
1719 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1720 continue
Dominic Battre033531052018-09-24 15:45:341721
Sam Maiera6e76d72022-02-11 21:43:501722 # Search for MABYE_, DISABLE_ pairs.
1723 disable_lines = {} # Maps of test name to line number.
1724 maybe_lines = {}
1725 for line_num, line in f.ChangedContents():
1726 disable_match = disable_pattern.search(line)
1727 if disable_match:
1728 disable_lines[disable_match.group(1)] = line_num
1729 maybe_match = maybe_pattern.search(line)
1730 if maybe_match:
1731 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341732
Sam Maiera6e76d72022-02-11 21:43:501733 # Search for DISABLE_ occurrences within a TEST() macro.
1734 disable_tests = set(disable_lines.keys())
1735 maybe_tests = set(maybe_lines.keys())
1736 for test in disable_tests.intersection(maybe_tests):
1737 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341738
Sam Maiera6e76d72022-02-11 21:43:501739 contents = input_api.ReadFile(f)
1740 full_disable_match = full_disable_pattern.search(contents)
1741 if full_disable_match:
1742 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341743
Sam Maiera6e76d72022-02-11 21:43:501744 if not problems:
1745 return []
1746 return [
1747 output_api.PresubmitPromptWarning(
1748 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1749 '\n'.join(problems))
1750 ]
1751
Dominic Battre033531052018-09-24 15:45:341752
Nina Satragnof7660532021-09-20 18:03:351753def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501754 """Checks to make sure tests disabled conditionally are not missing a
1755 corresponding MAYBE_ prefix.
1756 """
1757 # Expect at least a lowercase character in the test name. This helps rule out
1758 # false positives with macros wrapping the actual tests name.
1759 define_maybe_pattern = input_api.re.compile(
1760 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191761 # The test_maybe_pattern needs to handle all of these forms. The standard:
1762 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1763 # With a wrapper macro around the test name:
1764 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1765 # And the odd-ball NACL_BROWSER_TEST_f format:
1766 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1767 # The optional E2E_ENABLED-style is handled with (\w*\()?
1768 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1769 # trailing ')'.
1770 test_maybe_pattern = (
1771 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501772 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1773 warnings = []
Nina Satragnof7660532021-09-20 18:03:351774
Sam Maiera6e76d72022-02-11 21:43:501775 # Read the entire files. We can't just read the affected lines, forgetting to
1776 # add MAYBE_ on a change would not show up otherwise.
1777 for f in input_api.AffectedFiles(False):
1778 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1779 continue
1780 contents = input_api.ReadFile(f)
1781 lines = contents.splitlines(True)
1782 current_position = 0
1783 warning_test_names = set()
1784 for line_num, line in enumerate(lines, start=1):
1785 current_position += len(line)
1786 maybe_match = define_maybe_pattern.search(line)
1787 if maybe_match:
1788 test_name = maybe_match.group('test_name')
1789 # Do not warn twice for the same test.
1790 if (test_name in warning_test_names):
1791 continue
1792 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351793
Sam Maiera6e76d72022-02-11 21:43:501794 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1795 # the current position.
1796 test_match = input_api.re.compile(
1797 test_maybe_pattern.format(test_name=test_name),
1798 input_api.re.MULTILINE).search(contents, current_position)
1799 suite_match = input_api.re.compile(
1800 suite_maybe_pattern.format(test_name=test_name),
1801 input_api.re.MULTILINE).search(contents, current_position)
1802 if not test_match and not suite_match:
1803 warnings.append(
1804 output_api.PresubmitPromptWarning(
1805 '%s:%d found MAYBE_ defined without corresponding test %s'
1806 % (f.LocalPath(), line_num, test_name)))
1807 return warnings
1808
[email protected]72df4e782012-06-21 16:28:181809
Saagar Sanghavifceeaae2020-08-12 16:40:361810def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501811 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1812 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:161813 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:501814 input_api.re.MULTILINE)
1815 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1816 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1817 continue
1818 for lnum, line in f.ChangedContents():
1819 if input_api.re.search(pattern, line):
1820 errors.append(
1821 output_api.PresubmitError((
1822 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1823 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1824 (f.LocalPath(), lnum)))
1825 return errors
danakj61c1aa22015-10-26 19:55:521826
1827
Weilun Shia487fad2020-10-28 00:10:341828# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1829# more reliable way. See
1830# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191831
wnwenbdc444e2016-05-25 13:44:151832
Saagar Sanghavifceeaae2020-08-12 16:40:361833def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501834 """Check that FlakyTest annotation is our own instead of the android one"""
1835 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1836 files = []
1837 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1838 if f.LocalPath().endswith('Test.java'):
1839 if pattern.search(input_api.ReadFile(f)):
1840 files.append(f)
1841 if len(files):
1842 return [
1843 output_api.PresubmitError(
1844 'Use org.chromium.base.test.util.FlakyTest instead of '
1845 'android.test.FlakyTest', files)
1846 ]
1847 return []
mcasasb7440c282015-02-04 14:52:191848
wnwenbdc444e2016-05-25 13:44:151849
Saagar Sanghavifceeaae2020-08-12 16:40:361850def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501851 """Make sure .DEPS.git is never modified manually."""
1852 if any(f.LocalPath().endswith('.DEPS.git')
1853 for f in input_api.AffectedFiles()):
1854 return [
1855 output_api.PresubmitError(
1856 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1857 'automated system based on what\'s in DEPS and your changes will be\n'
1858 'overwritten.\n'
1859 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1860 'get-the-code#Rolling_DEPS\n'
1861 'for more information')
1862 ]
1863 return []
[email protected]2a8ac9c2011-10-19 17:20:441864
1865
Saagar Sanghavifceeaae2020-08-12 16:40:361866def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501867 """Checks that DEPS file deps are from allowed_hosts."""
1868 # Run only if DEPS file has been modified to annoy fewer bystanders.
1869 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1870 return []
1871 # Outsource work to gclient verify
1872 try:
1873 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
1874 'third_party', 'depot_tools',
1875 'gclient.py')
1876 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:321877 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:501878 stderr=input_api.subprocess.STDOUT)
1879 return []
1880 except input_api.subprocess.CalledProcessError as error:
1881 return [
1882 output_api.PresubmitError(
1883 'DEPS file must have only git dependencies.',
1884 long_text=error.output)
1885 ]
tandriief664692014-09-23 14:51:471886
1887
Mario Sanchez Prada2472cab2019-09-18 10:58:311888def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151889 ban_rule):
Allen Bauer84778682022-09-22 16:28:561890 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:311891
Sam Maiera6e76d72022-02-11 21:43:501892 Returns an string composed of the name of the file, the line number where the
1893 match has been found and the additional text passed as |message| in case the
1894 target type name matches the text inside the line passed as parameter.
1895 """
1896 result = []
Peng Huang9c5949a02020-06-11 19:20:541897
Daniel Chenga44a1bcd2022-03-15 20:00:151898 # Ignore comments about banned types.
1899 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:501900 return result
Daniel Chenga44a1bcd2022-03-15 20:00:151901 # A // nocheck comment will bypass this error.
1902 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:501903 return result
1904
1905 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:151906 if ban_rule.pattern[0:1] == '/':
1907 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:501908 if input_api.re.search(regex, line):
1909 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:151910 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:501911 matched = True
1912
1913 if matched:
1914 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:151915 for line in ban_rule.explanation:
1916 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:501917
danakjd18e8892020-12-17 17:42:011918 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:311919
1920
Saagar Sanghavifceeaae2020-08-12 16:40:361921def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501922 """Make sure that banned functions are not used."""
1923 warnings = []
1924 errors = []
[email protected]127f18ec2012-06-16 05:05:591925
Sam Maiera6e76d72022-02-11 21:43:501926 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:151927 if not excluded_paths:
1928 return False
1929
Sam Maiera6e76d72022-02-11 21:43:501930 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:311931 # Consistently use / as path separator to simplify the writing of regex
1932 # expressions.
1933 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:501934 for item in excluded_paths:
1935 if input_api.re.match(item, local_path):
1936 return True
1937 return False
wnwenbdc444e2016-05-25 13:44:151938
Sam Maiera6e76d72022-02-11 21:43:501939 def IsIosObjcFile(affected_file):
1940 local_path = affected_file.LocalPath()
1941 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
1942 '.h'):
1943 return False
1944 basename = input_api.os_path.basename(local_path)
1945 if 'ios' in basename.split('_'):
1946 return True
1947 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1948 if sep and 'ios' in local_path.split(sep):
1949 return True
1950 return False
Sylvain Defresnea8b73d252018-02-28 15:45:541951
Daniel Chenga44a1bcd2022-03-15 20:00:151952 def CheckForMatch(affected_file, line_num: int, line: str,
1953 ban_rule: BanRule):
1954 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
1955 return
1956
Sam Maiera6e76d72022-02-11 21:43:501957 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151958 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501959 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:151960 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:501961 errors.extend(problems)
1962 else:
1963 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151964
Sam Maiera6e76d72022-02-11 21:43:501965 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1966 for f in input_api.AffectedFiles(file_filter=file_filter):
1967 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151968 for ban_rule in _BANNED_JAVA_FUNCTIONS:
1969 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:411970
Sam Maiera6e76d72022-02-11 21:43:501971 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1972 for f in input_api.AffectedFiles(file_filter=file_filter):
1973 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151974 for ban_rule in _BANNED_OBJC_FUNCTIONS:
1975 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591976
Sam Maiera6e76d72022-02-11 21:43:501977 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
1978 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151979 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
1980 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:541981
Sam Maiera6e76d72022-02-11 21:43:501982 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1983 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1984 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151985 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
1986 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:051987
Sam Maiera6e76d72022-02-11 21:43:501988 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1989 for f in input_api.AffectedFiles(file_filter=file_filter):
1990 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151991 for ban_rule in _BANNED_CPP_FUNCTIONS:
1992 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591993
Daniel Cheng92c15e32022-03-16 17:48:221994 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
1995 for f in input_api.AffectedFiles(file_filter=file_filter):
1996 for line_num, line in f.ChangedContents():
1997 for ban_rule in _BANNED_MOJOM_PATTERNS:
1998 CheckForMatch(f, line_num, line, ban_rule)
1999
2000
Sam Maiera6e76d72022-02-11 21:43:502001 result = []
2002 if (warnings):
2003 result.append(
2004 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2005 '\n'.join(warnings)))
2006 if (errors):
2007 result.append(
2008 output_api.PresubmitError('Banned functions were used.\n' +
2009 '\n'.join(errors)))
2010 return result
[email protected]127f18ec2012-06-16 05:05:592011
Allen Bauer84778682022-09-22 16:28:562012def CheckNoLayoutCallsInTests(input_api, output_api):
2013 """Make sure there are no explicit calls to View::Layout() in tests"""
2014 warnings = []
2015 ban_rule = BanRule(
2016 r'/(\.|->)Layout\(\);',
2017 (
2018 'Direct calls to View::Layout() are not allowed in tests. '
2019 'If the view must be laid out here, use RunScheduledLayout(view). It '
2020 'is found in //ui/views/test/views_test_utils.h. '
2021 'See http://crbug.com/1350521 for more details.',
2022 ),
2023 False,
2024 )
2025 file_filter = lambda f: input_api.re.search(
2026 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2027 for f in input_api.AffectedFiles(file_filter = file_filter):
2028 for line_num, line in f.ChangedContents():
2029 problems = _GetMessageForMatchingType(input_api, f,
2030 line_num, line,
2031 ban_rule)
2032 if problems:
2033 warnings.extend(problems)
2034 result = []
2035 if (warnings):
2036 result.append(
2037 output_api.PresubmitPromptWarning(
2038 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2039 return result
[email protected]127f18ec2012-06-16 05:05:592040
Michael Thiessen44457642020-02-06 00:24:152041def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502042 """Make sure that banned java imports are not used."""
2043 errors = []
Michael Thiessen44457642020-02-06 00:24:152044
Sam Maiera6e76d72022-02-11 21:43:502045 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2046 for f in input_api.AffectedFiles(file_filter=file_filter):
2047 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152048 for ban_rule in _BANNED_JAVA_IMPORTS:
2049 # Consider merging this into the above function. There is no
2050 # real difference anymore other than helping with a little
2051 # bit of boilerplate text. Doing so means things like
2052 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502053 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152054 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502055 if problems:
2056 errors.extend(problems)
2057 result = []
2058 if (errors):
2059 result.append(
2060 output_api.PresubmitError('Banned imports were used.\n' +
2061 '\n'.join(errors)))
2062 return result
Michael Thiessen44457642020-02-06 00:24:152063
2064
Saagar Sanghavifceeaae2020-08-12 16:40:362065def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502066 """Make sure that banned functions are not used."""
2067 files = []
2068 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2069 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2070 if not f.LocalPath().endswith('.h'):
2071 continue
Bruce Dawson4c4c2922022-05-02 18:07:332072 if f.LocalPath().endswith('com_imported_mstscax.h'):
2073 continue
Sam Maiera6e76d72022-02-11 21:43:502074 contents = input_api.ReadFile(f)
2075 if pattern.search(contents):
2076 files.append(f)
[email protected]6c063c62012-07-11 19:11:062077
Sam Maiera6e76d72022-02-11 21:43:502078 if files:
2079 return [
2080 output_api.PresubmitError(
2081 'Do not use #pragma once in header files.\n'
2082 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2083 files)
2084 ]
2085 return []
[email protected]6c063c62012-07-11 19:11:062086
[email protected]127f18ec2012-06-16 05:05:592087
Saagar Sanghavifceeaae2020-08-12 16:40:362088def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502089 """Checks to make sure we don't introduce use of foo ? true : false."""
2090 problems = []
2091 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2092 for f in input_api.AffectedFiles():
2093 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2094 continue
[email protected]e7479052012-09-19 00:26:122095
Sam Maiera6e76d72022-02-11 21:43:502096 for line_num, line in f.ChangedContents():
2097 if pattern.match(line):
2098 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:122099
Sam Maiera6e76d72022-02-11 21:43:502100 if not problems:
2101 return []
2102 return [
2103 output_api.PresubmitPromptWarning(
2104 'Please consider avoiding the "? true : false" pattern if possible.\n'
2105 + '\n'.join(problems))
2106 ]
[email protected]e7479052012-09-19 00:26:122107
2108
Saagar Sanghavifceeaae2020-08-12 16:40:362109def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502110 """Runs checkdeps on #include and import statements added in this
2111 change. Breaking - rules is an error, breaking ! rules is a
2112 warning.
2113 """
2114 # Return early if no relevant file types were modified.
2115 for f in input_api.AffectedFiles():
2116 path = f.LocalPath()
2117 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2118 or _IsJavaFile(input_api, path)):
2119 break
[email protected]55f9f382012-07-31 11:02:182120 else:
Sam Maiera6e76d72022-02-11 21:43:502121 return []
rhalavati08acd232017-04-03 07:23:282122
Sam Maiera6e76d72022-02-11 21:43:502123 import sys
2124 # We need to wait until we have an input_api object and use this
2125 # roundabout construct to import checkdeps because this file is
2126 # eval-ed and thus doesn't have __file__.
2127 original_sys_path = sys.path
2128 try:
2129 sys.path = sys.path + [
2130 input_api.os_path.join(input_api.PresubmitLocalPath(),
2131 'buildtools', 'checkdeps')
2132 ]
2133 import checkdeps
2134 from rules import Rule
2135 finally:
2136 # Restore sys.path to what it was before.
2137 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:182138
Sam Maiera6e76d72022-02-11 21:43:502139 added_includes = []
2140 added_imports = []
2141 added_java_imports = []
2142 for f in input_api.AffectedFiles():
2143 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2144 changed_lines = [line for _, line in f.ChangedContents()]
2145 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2146 elif _IsProtoFile(input_api, f.LocalPath()):
2147 changed_lines = [line for _, line in f.ChangedContents()]
2148 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2149 elif _IsJavaFile(input_api, f.LocalPath()):
2150 changed_lines = [line for _, line in f.ChangedContents()]
2151 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242152
Sam Maiera6e76d72022-02-11 21:43:502153 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2154
2155 error_descriptions = []
2156 warning_descriptions = []
2157 error_subjects = set()
2158 warning_subjects = set()
2159
2160 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2161 added_includes):
2162 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2163 description_with_path = '%s\n %s' % (path, rule_description)
2164 if rule_type == Rule.DISALLOW:
2165 error_descriptions.append(description_with_path)
2166 error_subjects.add("#includes")
2167 else:
2168 warning_descriptions.append(description_with_path)
2169 warning_subjects.add("#includes")
2170
2171 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2172 added_imports):
2173 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2174 description_with_path = '%s\n %s' % (path, rule_description)
2175 if rule_type == Rule.DISALLOW:
2176 error_descriptions.append(description_with_path)
2177 error_subjects.add("imports")
2178 else:
2179 warning_descriptions.append(description_with_path)
2180 warning_subjects.add("imports")
2181
2182 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2183 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2184 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2185 description_with_path = '%s\n %s' % (path, rule_description)
2186 if rule_type == Rule.DISALLOW:
2187 error_descriptions.append(description_with_path)
2188 error_subjects.add("imports")
2189 else:
2190 warning_descriptions.append(description_with_path)
2191 warning_subjects.add("imports")
2192
2193 results = []
2194 if error_descriptions:
2195 results.append(
2196 output_api.PresubmitError(
2197 'You added one or more %s that violate checkdeps rules.' %
2198 " and ".join(error_subjects), error_descriptions))
2199 if warning_descriptions:
2200 results.append(
2201 output_api.PresubmitPromptOrNotify(
2202 'You added one or more %s of files that are temporarily\n'
2203 'allowed but being removed. Can you avoid introducing the\n'
2204 '%s? See relevant DEPS file(s) for details and contacts.' %
2205 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2206 warning_descriptions))
2207 return results
[email protected]55f9f382012-07-31 11:02:182208
2209
Saagar Sanghavifceeaae2020-08-12 16:40:362210def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502211 """Check that all files have their permissions properly set."""
2212 if input_api.platform == 'win32':
2213 return []
2214 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2215 'tools', 'checkperms',
2216 'checkperms.py')
2217 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322218 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502219 input_api.change.RepositoryRoot()
2220 ]
2221 with input_api.CreateTemporaryFile() as file_list:
2222 for f in input_api.AffectedFiles():
2223 # checkperms.py file/directory arguments must be relative to the
2224 # repository.
2225 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2226 file_list.close()
2227 args += ['--file-list', file_list.name]
2228 try:
2229 input_api.subprocess.check_output(args)
2230 return []
2231 except input_api.subprocess.CalledProcessError as error:
2232 return [
2233 output_api.PresubmitError('checkperms.py failed:',
2234 long_text=error.output.decode(
2235 'utf-8', 'ignore'))
2236 ]
[email protected]fbcafe5a2012-08-08 15:31:222237
2238
Saagar Sanghavifceeaae2020-08-12 16:40:362239def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502240 """Makes sure we don't include ui/aura/window_property.h
2241 in header files.
2242 """
2243 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2244 errors = []
2245 for f in input_api.AffectedFiles():
2246 if not f.LocalPath().endswith('.h'):
2247 continue
2248 for line_num, line in f.ChangedContents():
2249 if pattern.match(line):
2250 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:492251
Sam Maiera6e76d72022-02-11 21:43:502252 results = []
2253 if errors:
2254 results.append(
2255 output_api.PresubmitError(
2256 'Header files should not include ui/aura/window_property.h',
2257 errors))
2258 return results
[email protected]c8278b32012-10-30 20:35:492259
2260
Omer Katzcc77ea92021-04-26 10:23:282261def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502262 """Makes sure we don't include any headers from
2263 third_party/blink/renderer/platform/heap/impl or
2264 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2265 third_party/blink/renderer/platform/heap
2266 """
2267 impl_pattern = input_api.re.compile(
2268 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2269 v8_wrapper_pattern = input_api.re.compile(
2270 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2271 )
Bruce Dawson40fece62022-09-16 19:58:312272 # Consistently use / as path separator to simplify the writing of regex
2273 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502274 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312275 r"^third_party/blink/renderer/platform/heap/.*",
2276 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502277 errors = []
Omer Katzcc77ea92021-04-26 10:23:282278
Sam Maiera6e76d72022-02-11 21:43:502279 for f in input_api.AffectedFiles(file_filter=file_filter):
2280 for line_num, line in f.ChangedContents():
2281 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2282 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282283
Sam Maiera6e76d72022-02-11 21:43:502284 results = []
2285 if errors:
2286 results.append(
2287 output_api.PresubmitError(
2288 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2289 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2290 'relevant counterparts from third_party/blink/renderer/platform/heap',
2291 errors))
2292 return results
Omer Katzcc77ea92021-04-26 10:23:282293
2294
[email protected]70ca77752012-11-20 03:45:032295def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502296 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2297 errors = []
2298 for line_num, line in f.ChangedContents():
2299 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2300 # First-level headers in markdown look a lot like version control
2301 # conflict markers. http://daringfireball.net/projects/markdown/basics
2302 continue
2303 if pattern.match(line):
2304 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2305 return errors
[email protected]70ca77752012-11-20 03:45:032306
2307
Saagar Sanghavifceeaae2020-08-12 16:40:362308def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502309 """Usually this is not intentional and will cause a compile failure."""
2310 errors = []
2311 for f in input_api.AffectedFiles():
2312 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032313
Sam Maiera6e76d72022-02-11 21:43:502314 results = []
2315 if errors:
2316 results.append(
2317 output_api.PresubmitError(
2318 'Version control conflict markers found, please resolve.',
2319 errors))
2320 return results
[email protected]70ca77752012-11-20 03:45:032321
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202322
Saagar Sanghavifceeaae2020-08-12 16:40:362323def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502324 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2325 errors = []
2326 for f in input_api.AffectedFiles():
2327 for line_num, line in f.ChangedContents():
2328 if pattern.search(line):
2329 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162330
Sam Maiera6e76d72022-02-11 21:43:502331 results = []
2332 if errors:
2333 results.append(
2334 output_api.PresubmitPromptWarning(
2335 'Found Google support URL addressed by answer number. Please replace '
2336 'with a p= identifier instead. See crbug.com/679462\n',
2337 errors))
2338 return results
estadee17314a02017-01-12 16:22:162339
[email protected]70ca77752012-11-20 03:45:032340
Saagar Sanghavifceeaae2020-08-12 16:40:362341def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502342 def FilterFile(affected_file):
2343 """Filter function for use with input_api.AffectedSourceFiles,
2344 below. This filters out everything except non-test files from
2345 top-level directories that generally speaking should not hard-code
2346 service URLs (e.g. src/android_webview/, src/content/ and others).
2347 """
2348 return input_api.FilterSourceFile(
2349 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312350 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502351 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2352 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442353
Sam Maiera6e76d72022-02-11 21:43:502354 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2355 '\.(com|net)[^"]*"')
2356 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2357 pattern = input_api.re.compile(base_pattern)
2358 problems = [] # items are (filename, line_number, line)
2359 for f in input_api.AffectedSourceFiles(FilterFile):
2360 for line_num, line in f.ChangedContents():
2361 if not comment_pattern.search(line) and pattern.search(line):
2362 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442363
Sam Maiera6e76d72022-02-11 21:43:502364 if problems:
2365 return [
2366 output_api.PresubmitPromptOrNotify(
2367 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2368 'Are you sure this is correct?', [
2369 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2370 for problem in problems
2371 ])
2372 ]
2373 else:
2374 return []
[email protected]06e6d0ff2012-12-11 01:36:442375
2376
Saagar Sanghavifceeaae2020-08-12 16:40:362377def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502378 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292379
Sam Maiera6e76d72022-02-11 21:43:502380 def FileFilter(affected_file):
2381 """Includes directories known to be Chrome OS only."""
2382 return input_api.FilterSourceFile(
2383 affected_file,
2384 files_to_check=(
2385 '^ash/',
2386 '^chromeos/', # Top-level src/chromeos.
2387 '.*/chromeos/', # Any path component.
2388 '^components/arc',
2389 '^components/exo'),
2390 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292391
Sam Maiera6e76d72022-02-11 21:43:502392 prefs = []
2393 priority_prefs = []
2394 for f in input_api.AffectedFiles(file_filter=FileFilter):
2395 for line_num, line in f.ChangedContents():
2396 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2397 line):
2398 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2399 prefs.append(' %s' % line)
2400 if input_api.re.search(
2401 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2402 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2403 priority_prefs.append(' %s' % line)
2404
2405 results = []
2406 if (prefs):
2407 results.append(
2408 output_api.PresubmitPromptWarning(
2409 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2410 'by browser sync settings. If these prefs should be controlled by OS '
2411 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2412 '\n'.join(prefs)))
2413 if (priority_prefs):
2414 results.append(
2415 output_api.PresubmitPromptWarning(
2416 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2417 'controlled by browser sync settings. If these prefs should be '
2418 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2419 'instead.\n' + '\n'.join(prefs)))
2420 return results
James Cook6b6597c2019-11-06 22:05:292421
2422
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492423# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362424def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502425 """Makes sure there are no abbreviations in the name of PNG files.
2426 The native_client_sdk directory is excluded because it has auto-generated PNG
2427 files for documentation.
2428 """
2429 errors = []
2430 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Bruce Dawson40fece62022-09-16 19:58:312431 files_to_skip = [r'^native_client_sdk/',
2432 r'^services/test/',
2433 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182434 ]
Sam Maiera6e76d72022-02-11 21:43:502435 file_filter = lambda f: input_api.FilterSourceFile(
2436 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2437 for f in input_api.AffectedFiles(include_deletes=False,
2438 file_filter=file_filter):
2439 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272440
Sam Maiera6e76d72022-02-11 21:43:502441 results = []
2442 if errors:
2443 results.append(
2444 output_api.PresubmitError(
2445 'The name of PNG files should not have abbreviations. \n'
2446 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2447 'Contact [email protected] if you have questions.', errors))
2448 return results
[email protected]d2530012013-01-25 16:39:272449
Evan Stade7cd4a2c2022-08-04 23:37:252450def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2451 """Heuristically identifies product icons based on their file name and reminds
2452 contributors not to add them to the Chromium repository.
2453 """
2454 errors = []
2455 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2456 file_filter = lambda f: input_api.FilterSourceFile(
2457 f, files_to_check=files_to_check)
2458 for f in input_api.AffectedFiles(include_deletes=False,
2459 file_filter=file_filter):
2460 errors.append(' %s' % f.LocalPath())
2461
2462 results = []
2463 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082464 # Give warnings instead of errors on presubmit --all and presubmit
2465 # --files.
2466 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2467 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252468 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082469 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252470 'Trademarked images should not be added to the public repo. '
2471 'See crbug.com/944754', errors))
2472 return results
2473
[email protected]d2530012013-01-25 16:39:272474
Daniel Cheng4dcdb6b2017-04-13 08:30:172475def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502476 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172477
Sam Maiera6e76d72022-02-11 21:43:502478 Args:
2479 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2480 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172481 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502482 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172483 if rule.startswith('+') or rule.startswith('!')
2484 ])
Sam Maiera6e76d72022-02-11 21:43:502485 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2486 add_rules.update([
2487 rule[1:] for rule in rules
2488 if rule.startswith('+') or rule.startswith('!')
2489 ])
2490 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172491
2492
2493def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502494 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172495
Sam Maiera6e76d72022-02-11 21:43:502496 # Stubs for handling special syntax in the root DEPS file.
2497 class _VarImpl:
2498 def __init__(self, local_scope):
2499 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172500
Sam Maiera6e76d72022-02-11 21:43:502501 def Lookup(self, var_name):
2502 """Implements the Var syntax."""
2503 try:
2504 return self._local_scope['vars'][var_name]
2505 except KeyError:
2506 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172507
Sam Maiera6e76d72022-02-11 21:43:502508 local_scope = {}
2509 global_scope = {
2510 'Var': _VarImpl(local_scope).Lookup,
2511 'Str': str,
2512 }
Dirk Pranke1b9e06382021-05-14 01:16:222513
Sam Maiera6e76d72022-02-11 21:43:502514 exec(contents, global_scope, local_scope)
2515 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172516
2517
2518def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502519 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2520 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412521
Sam Maiera6e76d72022-02-11 21:43:502522 For a directory (rather than a specific filename) we fake a path to
2523 a specific filename by adding /DEPS. This is chosen as a file that
2524 will seldom or never be subject to per-file include_rules.
2525 """
2526 # We ignore deps entries on auto-generated directories.
2527 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082528
Sam Maiera6e76d72022-02-11 21:43:502529 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2530 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172531
Sam Maiera6e76d72022-02-11 21:43:502532 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172533
Sam Maiera6e76d72022-02-11 21:43:502534 results = set()
2535 for added_dep in added_deps:
2536 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2537 continue
2538 # Assume that a rule that ends in .h is a rule for a specific file.
2539 if added_dep.endswith('.h'):
2540 results.add(added_dep)
2541 else:
2542 results.add(os_path.join(added_dep, 'DEPS'))
2543 return results
[email protected]f32e2d1e2013-07-26 21:39:082544
2545
Saagar Sanghavifceeaae2020-08-12 16:40:362546def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502547 """When a dependency prefixed with + is added to a DEPS file, we
2548 want to make sure that the change is reviewed by an OWNER of the
2549 target file or directory, to avoid layering violations from being
2550 introduced. This check verifies that this happens.
2551 """
2552 # We rely on Gerrit's code-owners to check approvals.
2553 # input_api.gerrit is always set for Chromium, but other projects
2554 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102555 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502556 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302557 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502558 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302559 try:
2560 if (input_api.change.issue and
2561 input_api.gerrit.IsOwnersOverrideApproved(
2562 input_api.change.issue)):
2563 # Skip OWNERS check when Owners-Override label is approved. This is
2564 # intended for global owners, trusted bots, and on-call sheriffs.
2565 # Review is still required for these changes.
2566 return []
2567 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:242568 return [output_api.PresubmitPromptWarning(
2569 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232570
Sam Maiera6e76d72022-02-11 21:43:502571 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242572
Bruce Dawson40fece62022-09-16 19:58:312573 # Consistently use / as path separator to simplify the writing of regex
2574 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502575 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312576 r"^third_party/blink/.*",
2577 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502578 for f in input_api.AffectedFiles(include_deletes=False,
2579 file_filter=file_filter):
2580 filename = input_api.os_path.basename(f.LocalPath())
2581 if filename == 'DEPS':
2582 virtual_depended_on_files.update(
2583 _CalculateAddedDeps(input_api.os_path,
2584 '\n'.join(f.OldContents()),
2585 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552586
Sam Maiera6e76d72022-02-11 21:43:502587 if not virtual_depended_on_files:
2588 return []
[email protected]e871964c2013-05-13 14:14:552589
Sam Maiera6e76d72022-02-11 21:43:502590 if input_api.is_committing:
2591 if input_api.tbr:
2592 return [
2593 output_api.PresubmitNotifyResult(
2594 '--tbr was specified, skipping OWNERS check for DEPS additions'
2595 )
2596 ]
Daniel Cheng3008dc12022-05-13 04:02:112597 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2598 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502599 if input_api.dry_run:
2600 return [
2601 output_api.PresubmitNotifyResult(
2602 'This is a dry run, skipping OWNERS check for DEPS additions'
2603 )
2604 ]
2605 if not input_api.change.issue:
2606 return [
2607 output_api.PresubmitError(
2608 "DEPS approval by OWNERS check failed: this change has "
2609 "no change number, so we can't check it for approvals.")
2610 ]
2611 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412612 else:
Sam Maiera6e76d72022-02-11 21:43:502613 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552614
Sam Maiera6e76d72022-02-11 21:43:502615 owner_email, reviewers = (
2616 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2617 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552618
Sam Maiera6e76d72022-02-11 21:43:502619 owner_email = owner_email or input_api.change.author_email
2620
2621 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2622 virtual_depended_on_files, reviewers.union([owner_email]), [])
2623 missing_files = [
2624 f for f in virtual_depended_on_files
2625 if approval_status[f] != input_api.owners_client.APPROVED
2626 ]
2627
2628 # We strip the /DEPS part that was added by
2629 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2630 # directory.
2631 def StripDeps(path):
2632 start_deps = path.rfind('/DEPS')
2633 if start_deps != -1:
2634 return path[:start_deps]
2635 else:
2636 return path
2637
2638 unapproved_dependencies = [
2639 "'+%s'," % StripDeps(path) for path in missing_files
2640 ]
2641
2642 if unapproved_dependencies:
2643 output_list = [
2644 output(
2645 'You need LGTM from owners of depends-on paths in DEPS that were '
2646 'modified in this CL:\n %s' %
2647 '\n '.join(sorted(unapproved_dependencies)))
2648 ]
2649 suggested_owners = input_api.owners_client.SuggestOwners(
2650 missing_files, exclude=[owner_email])
2651 output_list.append(
2652 output('Suggested missing target path OWNERS:\n %s' %
2653 '\n '.join(suggested_owners or [])))
2654 return output_list
2655
2656 return []
[email protected]e871964c2013-05-13 14:14:552657
2658
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492659# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362660def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502661 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2662 files_to_skip = (
2663 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2664 input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:312665 r"^base/logging\.h$",
2666 r"^base/logging\.cc$",
2667 r"^base/task/thread_pool/task_tracker\.cc$",
2668 r"^chrome/app/chrome_main_delegate\.cc$",
2669 r"^chrome/browser/chrome_browser_main\.cc$",
2670 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
2671 r"^chrome/browser/browser_switcher/bho/.*",
2672 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
2673 r"^chrome/chrome_cleaner/.*",
2674 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
2675 r"^chrome/installer/setup/.*",
2676 r"^chromecast/",
2677 r"^components/browser_watcher/dump_stability_report_main_win\.cc$",
2678 r"^components/media_control/renderer/media_playback_options\.cc$",
2679 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:502680 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312681 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:502682 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:312683 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:502684 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312685 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
2686 r"^courgette/courgette_minimal_tool\.cc$",
2687 r"^courgette/courgette_tool\.cc$",
2688 r"^extensions/renderer/logging_native_handler\.cc$",
2689 r"^fuchsia_web/common/init_logging\.cc$",
2690 r"^fuchsia_web/runners/common/web_component\.cc$",
2691 r"^fuchsia_web/shell/.*_shell\.cc$",
2692 r"^headless/app/headless_shell\.cc$",
2693 r"^ipc/ipc_logging\.cc$",
2694 r"^native_client_sdk/",
2695 r"^remoting/base/logging\.h$",
2696 r"^remoting/host/.*",
2697 r"^sandbox/linux/.*",
2698 r"^storage/browser/file_system/dump_file_system\.cc$",
2699 r"^tools/",
2700 r"^ui/base/resource/data_pack\.cc$",
2701 r"^ui/aura/bench/bench_main\.cc$",
2702 r"^ui/ozone/platform/cast/",
2703 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:502704 r"xwmstartupcheck\.cc$"))
2705 source_file_filter = lambda x: input_api.FilterSourceFile(
2706 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402707
Sam Maiera6e76d72022-02-11 21:43:502708 log_info = set([])
2709 printf = set([])
[email protected]85218562013-11-22 07:41:402710
Sam Maiera6e76d72022-02-11 21:43:502711 for f in input_api.AffectedSourceFiles(source_file_filter):
2712 for _, line in f.ChangedContents():
2713 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2714 log_info.add(f.LocalPath())
2715 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2716 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372717
Sam Maiera6e76d72022-02-11 21:43:502718 if input_api.re.search(r"\bprintf\(", line):
2719 printf.add(f.LocalPath())
2720 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2721 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402722
Sam Maiera6e76d72022-02-11 21:43:502723 if log_info:
2724 return [
2725 output_api.PresubmitError(
2726 'These files spam the console log with LOG(INFO):',
2727 items=log_info)
2728 ]
2729 if printf:
2730 return [
2731 output_api.PresubmitError(
2732 'These files spam the console log with printf/fprintf:',
2733 items=printf)
2734 ]
2735 return []
[email protected]85218562013-11-22 07:41:402736
2737
Saagar Sanghavifceeaae2020-08-12 16:40:362738def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502739 """These types are all expected to hold locks while in scope and
2740 so should never be anonymous (which causes them to be immediately
2741 destroyed)."""
2742 they_who_must_be_named = [
2743 'base::AutoLock',
2744 'base::AutoReset',
2745 'base::AutoUnlock',
2746 'SkAutoAlphaRestore',
2747 'SkAutoBitmapShaderInstall',
2748 'SkAutoBlitterChoose',
2749 'SkAutoBounderCommit',
2750 'SkAutoCallProc',
2751 'SkAutoCanvasRestore',
2752 'SkAutoCommentBlock',
2753 'SkAutoDescriptor',
2754 'SkAutoDisableDirectionCheck',
2755 'SkAutoDisableOvalCheck',
2756 'SkAutoFree',
2757 'SkAutoGlyphCache',
2758 'SkAutoHDC',
2759 'SkAutoLockColors',
2760 'SkAutoLockPixels',
2761 'SkAutoMalloc',
2762 'SkAutoMaskFreeImage',
2763 'SkAutoMutexAcquire',
2764 'SkAutoPathBoundsUpdate',
2765 'SkAutoPDFRelease',
2766 'SkAutoRasterClipValidate',
2767 'SkAutoRef',
2768 'SkAutoTime',
2769 'SkAutoTrace',
2770 'SkAutoUnref',
2771 ]
2772 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2773 # bad: base::AutoLock(lock.get());
2774 # not bad: base::AutoLock lock(lock.get());
2775 bad_pattern = input_api.re.compile(anonymous)
2776 # good: new base::AutoLock(lock.get())
2777 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2778 errors = []
[email protected]49aa76a2013-12-04 06:59:162779
Sam Maiera6e76d72022-02-11 21:43:502780 for f in input_api.AffectedFiles():
2781 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2782 continue
2783 for linenum, line in f.ChangedContents():
2784 if bad_pattern.search(line) and not good_pattern.search(line):
2785 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162786
Sam Maiera6e76d72022-02-11 21:43:502787 if errors:
2788 return [
2789 output_api.PresubmitError(
2790 'These lines create anonymous variables that need to be named:',
2791 items=errors)
2792 ]
2793 return []
[email protected]49aa76a2013-12-04 06:59:162794
2795
Saagar Sanghavifceeaae2020-08-12 16:40:362796def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502797 # Returns whether |template_str| is of the form <T, U...> for some types T
2798 # and U. Assumes that |template_str| is already in the form <...>.
2799 def HasMoreThanOneArg(template_str):
2800 # Level of <...> nesting.
2801 nesting = 0
2802 for c in template_str:
2803 if c == '<':
2804 nesting += 1
2805 elif c == '>':
2806 nesting -= 1
2807 elif c == ',' and nesting == 1:
2808 return True
2809 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532810
Sam Maiera6e76d72022-02-11 21:43:502811 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2812 sources = lambda affected_file: input_api.FilterSourceFile(
2813 affected_file,
2814 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2815 DEFAULT_FILES_TO_SKIP),
2816 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552817
Sam Maiera6e76d72022-02-11 21:43:502818 # Pattern to capture a single "<...>" block of template arguments. It can
2819 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2820 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2821 # latter would likely require counting that < and > match, which is not
2822 # expressible in regular languages. Should the need arise, one can introduce
2823 # limited counting (matching up to a total number of nesting depth), which
2824 # should cover all practical cases for already a low nesting limit.
2825 template_arg_pattern = (
2826 r'<[^>]*' # Opening block of <.
2827 r'>([^<]*>)?') # Closing block of >.
2828 # Prefix expressing that whatever follows is not already inside a <...>
2829 # block.
2830 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2831 null_construct_pattern = input_api.re.compile(
2832 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2833 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552834
Sam Maiera6e76d72022-02-11 21:43:502835 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2836 template_arg_no_array_pattern = (
2837 r'<[^>]*[^]]' # Opening block of <.
2838 r'>([^(<]*[^]]>)?') # Closing block of >.
2839 # Prefix saying that what follows is the start of an expression.
2840 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2841 # Suffix saying that what follows are call parentheses with a non-empty list
2842 # of arguments.
2843 nonempty_arg_list_pattern = r'\(([^)]|$)'
2844 # Put the template argument into a capture group for deeper examination later.
2845 return_construct_pattern = input_api.re.compile(
2846 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2847 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552848
Sam Maiera6e76d72022-02-11 21:43:502849 problems_constructor = []
2850 problems_nullptr = []
2851 for f in input_api.AffectedSourceFiles(sources):
2852 for line_number, line in f.ChangedContents():
2853 # Disallow:
2854 # return std::unique_ptr<T>(foo);
2855 # bar = std::unique_ptr<T>(foo);
2856 # But allow:
2857 # return std::unique_ptr<T[]>(foo);
2858 # bar = std::unique_ptr<T[]>(foo);
2859 # And also allow cases when the second template argument is present. Those
2860 # cases cannot be handled by std::make_unique:
2861 # return std::unique_ptr<T, U>(foo);
2862 # bar = std::unique_ptr<T, U>(foo);
2863 local_path = f.LocalPath()
2864 return_construct_result = return_construct_pattern.search(line)
2865 if return_construct_result and not HasMoreThanOneArg(
2866 return_construct_result.group('template_arg')):
2867 problems_constructor.append(
2868 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2869 # Disallow:
2870 # std::unique_ptr<T>()
2871 if null_construct_pattern.search(line):
2872 problems_nullptr.append(
2873 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052874
Sam Maiera6e76d72022-02-11 21:43:502875 errors = []
2876 if problems_nullptr:
2877 errors.append(
2878 output_api.PresubmitPromptWarning(
2879 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2880 problems_nullptr))
2881 if problems_constructor:
2882 errors.append(
2883 output_api.PresubmitError(
2884 'The following files use explicit std::unique_ptr constructor. '
2885 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2886 'std::make_unique is not an option.', problems_constructor))
2887 return errors
Peter Kasting4844e46e2018-02-23 07:27:102888
2889
Saagar Sanghavifceeaae2020-08-12 16:40:362890def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502891 """Checks if any new user action has been added."""
2892 if any('actions.xml' == input_api.os_path.basename(f)
2893 for f in input_api.LocalPaths()):
2894 # If actions.xml is already included in the changelist, the PRESUBMIT
2895 # for actions.xml will do a more complete presubmit check.
2896 return []
2897
2898 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2899 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2900 input_api.DEFAULT_FILES_TO_SKIP)
2901 file_filter = lambda f: input_api.FilterSourceFile(
2902 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2903
2904 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2905 current_actions = None
2906 for f in input_api.AffectedFiles(file_filter=file_filter):
2907 for line_num, line in f.ChangedContents():
2908 match = input_api.re.search(action_re, line)
2909 if match:
2910 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2911 # loaded only once.
2912 if not current_actions:
2913 with open(
2914 'tools/metrics/actions/actions.xml') as actions_f:
2915 current_actions = actions_f.read()
2916 # Search for the matched user action name in |current_actions|.
2917 for action_name in match.groups():
2918 action = 'name="{0}"'.format(action_name)
2919 if action not in current_actions:
2920 return [
2921 output_api.PresubmitPromptWarning(
2922 'File %s line %d: %s is missing in '
2923 'tools/metrics/actions/actions.xml. Please run '
2924 'tools/metrics/actions/extract_actions.py to update.'
2925 % (f.LocalPath(), line_num, action_name))
2926 ]
[email protected]999261d2014-03-03 20:08:082927 return []
2928
[email protected]999261d2014-03-03 20:08:082929
Daniel Cheng13ca61a882017-08-25 15:11:252930def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502931 import sys
2932 sys.path = sys.path + [
2933 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2934 'json_comment_eater')
2935 ]
2936 import json_comment_eater
2937 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252938
2939
[email protected]99171a92014-06-03 08:44:472940def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172941 try:
Sam Maiera6e76d72022-02-11 21:43:502942 contents = input_api.ReadFile(filename)
2943 if eat_comments:
2944 json_comment_eater = _ImportJSONCommentEater(input_api)
2945 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172946
Sam Maiera6e76d72022-02-11 21:43:502947 input_api.json.loads(contents)
2948 except ValueError as e:
2949 return e
Andrew Grieve4deedb12022-02-03 21:34:502950 return None
2951
2952
Sam Maiera6e76d72022-02-11 21:43:502953def _GetIDLParseError(input_api, filename):
2954 try:
2955 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:282956 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:342957 if not char.isascii():
2958 return (
2959 'Non-ascii character "%s" (ord %d) found at offset %d.' %
2960 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:502961 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2962 'tools', 'json_schema_compiler',
2963 'idl_schema.py')
2964 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282965 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502966 stdin=input_api.subprocess.PIPE,
2967 stdout=input_api.subprocess.PIPE,
2968 stderr=input_api.subprocess.PIPE,
2969 universal_newlines=True)
2970 (_, error) = process.communicate(input=contents)
2971 return error or None
2972 except ValueError as e:
2973 return e
agrievef32bcc72016-04-04 14:57:402974
agrievef32bcc72016-04-04 14:57:402975
Sam Maiera6e76d72022-02-11 21:43:502976def CheckParseErrors(input_api, output_api):
2977 """Check that IDL and JSON files do not contain syntax errors."""
2978 actions = {
2979 '.idl': _GetIDLParseError,
2980 '.json': _GetJSONParseError,
2981 }
2982 # Most JSON files are preprocessed and support comments, but these do not.
2983 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:312984 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:502985 ]
2986 # Only run IDL checker on files in these directories.
2987 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:312988 r'^chrome/common/extensions/api/',
2989 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:502990 ]
agrievef32bcc72016-04-04 14:57:402991
Sam Maiera6e76d72022-02-11 21:43:502992 def get_action(affected_file):
2993 filename = affected_file.LocalPath()
2994 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:402995
Sam Maiera6e76d72022-02-11 21:43:502996 def FilterFile(affected_file):
2997 action = get_action(affected_file)
2998 if not action:
2999 return False
3000 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403001
Sam Maiera6e76d72022-02-11 21:43:503002 if _MatchesFile(input_api,
3003 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3004 return False
3005
3006 if (action == _GetIDLParseError
3007 and not _MatchesFile(input_api, idl_included_patterns, path)):
3008 return False
3009 return True
3010
3011 results = []
3012 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3013 include_deletes=False):
3014 action = get_action(affected_file)
3015 kwargs = {}
3016 if (action == _GetJSONParseError
3017 and _MatchesFile(input_api, json_no_comments_patterns,
3018 affected_file.LocalPath())):
3019 kwargs['eat_comments'] = False
3020 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3021 **kwargs)
3022 if parse_error:
3023 results.append(
3024 output_api.PresubmitError(
3025 '%s could not be parsed: %s' %
3026 (affected_file.LocalPath(), parse_error)))
3027 return results
3028
3029
3030def CheckJavaStyle(input_api, output_api):
3031 """Runs checkstyle on changed java files and returns errors if any exist."""
3032
3033 # Return early if no java files were modified.
3034 if not any(
3035 _IsJavaFile(input_api, f.LocalPath())
3036 for f in input_api.AffectedFiles()):
3037 return []
3038
3039 import sys
3040 original_sys_path = sys.path
3041 try:
3042 sys.path = sys.path + [
3043 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3044 'android', 'checkstyle')
3045 ]
3046 import checkstyle
3047 finally:
3048 # Restore sys.path to what it was before.
3049 sys.path = original_sys_path
3050
3051 return checkstyle.RunCheckstyle(
3052 input_api,
3053 output_api,
3054 'tools/android/checkstyle/chromium-style-5.0.xml',
3055 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3056
3057
3058def CheckPythonDevilInit(input_api, output_api):
3059 """Checks to make sure devil is initialized correctly in python scripts."""
3060 script_common_initialize_pattern = input_api.re.compile(
3061 r'script_common\.InitializeEnvironment\(')
3062 devil_env_config_initialize = input_api.re.compile(
3063 r'devil_env\.config\.Initialize\(')
3064
3065 errors = []
3066
3067 sources = lambda affected_file: input_api.FilterSourceFile(
3068 affected_file,
3069 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313070 r'^build/android/devil_chromium\.py',
3071 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503072 )),
3073 files_to_check=[r'.*\.py$'])
3074
3075 for f in input_api.AffectedSourceFiles(sources):
3076 for line_num, line in f.ChangedContents():
3077 if (script_common_initialize_pattern.search(line)
3078 or devil_env_config_initialize.search(line)):
3079 errors.append("%s:%d" % (f.LocalPath(), line_num))
3080
3081 results = []
3082
3083 if errors:
3084 results.append(
3085 output_api.PresubmitError(
3086 'Devil initialization should always be done using '
3087 'devil_chromium.Initialize() in the chromium project, to use better '
3088 'defaults for dependencies (ex. up-to-date version of adb).',
3089 errors))
3090
3091 return results
3092
3093
3094def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313095 # Consistently use / as path separator to simplify the writing of regex
3096 # expressions.
3097 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503098 for pattern in patterns:
3099 if input_api.re.search(pattern, path):
3100 return True
3101 return False
3102
3103
Daniel Chenga37c03db2022-05-12 17:20:343104def _ChangeHasSecurityReviewer(input_api, owners_file):
3105 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503106
Daniel Chenga37c03db2022-05-12 17:20:343107 Args:
3108 input_api: The presubmit input API.
3109 owners_file: OWNERS file with required reviewers. Typically, this is
3110 something like ipc/SECURITY_OWNERS.
3111
3112 Note: if the presubmit is running for commit rather than for upload, this
3113 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503114 """
Daniel Chengd88244472022-05-16 09:08:473115 # Owners-Override should bypass all additional OWNERS enforcement checks.
3116 # A CR+1 vote will still be required to land this change.
3117 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3118 input_api.change.issue)):
3119 return True
3120
Daniel Chenga37c03db2022-05-12 17:20:343121 owner_email, reviewers = (
3122 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113123 input_api,
3124 None,
3125 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503126
Daniel Chenga37c03db2022-05-12 17:20:343127 security_owners = input_api.owners_client.ListOwners(owners_file)
3128 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503129
Daniel Chenga37c03db2022-05-12 17:20:343130
3131@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253132class _SecurityProblemWithItems:
3133 problem: str
3134 items: Sequence[str]
3135
3136
3137@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343138class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253139 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343140 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253141 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343142
3143
3144def _FindMissingSecurityOwners(input_api,
3145 output_api,
3146 file_patterns: Sequence[str],
3147 excluded_patterns: Sequence[str],
3148 required_owners_file: str,
3149 custom_rule_function: Optional[Callable] = None
3150 ) -> _MissingSecurityOwnersResult:
3151 """Find OWNERS files missing per-file rules for security-sensitive files.
3152
3153 Args:
3154 input_api: the PRESUBMIT input API object.
3155 output_api: the PRESUBMIT output API object.
3156 file_patterns: basename patterns that require a corresponding per-file
3157 security restriction.
3158 excluded_patterns: path patterns that should be exempted from
3159 requiring a security restriction.
3160 required_owners_file: path to the required OWNERS file, e.g.
3161 ipc/SECURITY_OWNERS
3162 cc_alias: If not None, email that will be CCed automatically if the
3163 change contains security-sensitive files, as determined by
3164 `file_patterns` and `excluded_patterns`.
3165 custom_rule_function: If not None, will be called with `input_api` and
3166 the current file under consideration. Returning True will add an
3167 exact match per-file rule check for the current file.
3168 """
3169
3170 # `to_check` is a mapping of an OWNERS file path to Patterns.
3171 #
3172 # Patterns is a dictionary mapping glob patterns (suitable for use in
3173 # per-file rules) to a PatternEntry.
3174 #
Sam Maiera6e76d72022-02-11 21:43:503175 # PatternEntry is a dictionary with two keys:
3176 # - 'files': the files that are matched by this pattern
3177 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343178 #
Sam Maiera6e76d72022-02-11 21:43:503179 # For example, if we expect OWNERS file to contain rules for *.mojom and
3180 # *_struct_traits*.*, Patterns might look like this:
3181 # {
3182 # '*.mojom': {
3183 # 'files': ...,
3184 # 'rules': [
3185 # 'per-file *.mojom=set noparent',
3186 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3187 # ],
3188 # },
3189 # '*_struct_traits*.*': {
3190 # 'files': ...,
3191 # 'rules': [
3192 # 'per-file *_struct_traits*.*=set noparent',
3193 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3194 # ],
3195 # },
3196 # }
3197 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343198 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503199
Daniel Chenga37c03db2022-05-12 17:20:343200 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503201 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473202 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503203 if owners_file not in to_check:
3204 to_check[owners_file] = {}
3205 if pattern not in to_check[owners_file]:
3206 to_check[owners_file][pattern] = {
3207 'files': [],
3208 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343209 f'per-file {pattern}=set noparent',
3210 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503211 ]
3212 }
Daniel Chenged57a162022-05-25 02:56:343213 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343214 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503215
Daniel Chenga37c03db2022-05-12 17:20:343216 # Only enforce security OWNERS rules for a directory if that directory has a
3217 # file that matches `file_patterns`. For example, if a directory only
3218 # contains *.mojom files and no *_messages*.h files, the check should only
3219 # ensure that rules for *.mojom files are present.
3220 for file in input_api.AffectedFiles(include_deletes=False):
3221 file_basename = input_api.os_path.basename(file.LocalPath())
3222 if custom_rule_function is not None and custom_rule_function(
3223 input_api, file):
3224 AddPatternToCheck(file, file_basename)
3225 continue
Sam Maiera6e76d72022-02-11 21:43:503226
Daniel Chenga37c03db2022-05-12 17:20:343227 if any(
3228 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3229 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503230 continue
3231
3232 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343233 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3234 # file's basename.
3235 if input_api.fnmatch.fnmatch(file_basename, pattern):
3236 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503237 break
3238
Daniel Chenga37c03db2022-05-12 17:20:343239 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253240
3241 # Check if any newly added lines in OWNERS files intersect with required
3242 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3243 # This is a hack, but is needed because the OWNERS check (by design) ignores
3244 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3245 # OWNER and have that newly-added OWNER self-approve their own addition.
3246 newly_covered_files = []
3247 for file in input_api.AffectedFiles(include_deletes=False):
3248 if not file.LocalPath() in to_check:
3249 continue
3250 for _, line in file.ChangedContents():
3251 for _, entry in to_check[file.LocalPath()].items():
3252 if line in entry['rules']:
3253 newly_covered_files.extend(entry['files'])
3254
3255 missing_reviewer_problems = None
3256 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343257 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253258 missing_reviewer_problems = _SecurityProblemWithItems(
3259 f'Review from an owner in {required_owners_file} is required for '
3260 'the following newly-added files:',
3261 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503262
3263 # Go through the OWNERS files to check, filtering out rules that are already
3264 # present in that OWNERS file.
3265 for owners_file, patterns in to_check.items():
3266 try:
Daniel Cheng171dad8d2022-05-21 00:40:253267 lines = set(
3268 input_api.ReadFile(
3269 input_api.os_path.join(input_api.change.RepositoryRoot(),
3270 owners_file)).splitlines())
3271 for entry in patterns.values():
3272 entry['rules'] = [
3273 rule for rule in entry['rules'] if rule not in lines
3274 ]
Sam Maiera6e76d72022-02-11 21:43:503275 except IOError:
3276 # No OWNERS file, so all the rules are definitely missing.
3277 continue
3278
3279 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253280 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343281
Sam Maiera6e76d72022-02-11 21:43:503282 for owners_file, patterns in to_check.items():
3283 missing_lines = []
3284 files = []
3285 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343286 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503287 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503288 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253289 joined_missing_lines = '\n'.join(line for line in missing_lines)
3290 owners_file_problems.append(
3291 _SecurityProblemWithItems(
3292 'Found missing OWNERS lines for security-sensitive files. '
3293 f'Please add the following lines to {owners_file}:\n'
3294 f'{joined_missing_lines}\n\nTo ensure security review for:',
3295 files))
Daniel Chenga37c03db2022-05-12 17:20:343296
Daniel Cheng171dad8d2022-05-21 00:40:253297 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343298 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253299 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343300
3301
3302def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3303 # Whether or not a file affects IPC is (mostly) determined by a simple list
3304 # of filename patterns.
3305 file_patterns = [
3306 # Legacy IPC:
3307 '*_messages.cc',
3308 '*_messages*.h',
3309 '*_param_traits*.*',
3310 # Mojo IPC:
3311 '*.mojom',
3312 '*_mojom_traits*.*',
3313 '*_type_converter*.*',
3314 # Android native IPC:
3315 '*.aidl',
3316 ]
3317
Daniel Chenga37c03db2022-05-12 17:20:343318 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463319 # These third_party directories do not contain IPCs, but contain files
3320 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343321 'third_party/crashpad/*',
3322 'third_party/blink/renderer/platform/bindings/*',
3323 'third_party/protobuf/benchmarks/python/*',
3324 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473325 # Enum-only mojoms used for web metrics, so no security review needed.
3326 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343327 # These files are just used to communicate between class loaders running
3328 # in the same process.
3329 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3330 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3331 ]
3332
3333 def IsMojoServiceManifestFile(input_api, file):
3334 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3335 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3336 if not manifest_pattern.search(file.LocalPath()):
3337 return False
3338
3339 if test_manifest_pattern.search(file.LocalPath()):
3340 return False
3341
3342 # All actual service manifest files should contain at least one
3343 # qualified reference to service_manager::Manifest.
3344 return any('service_manager::Manifest' in line
3345 for line in file.NewContents())
3346
3347 return _FindMissingSecurityOwners(
3348 input_api,
3349 output_api,
3350 file_patterns,
3351 excluded_patterns,
3352 'ipc/SECURITY_OWNERS',
3353 custom_rule_function=IsMojoServiceManifestFile)
3354
3355
3356def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3357 file_patterns = [
3358 # Component specifications.
3359 '*.cml', # Component Framework v2.
3360 '*.cmx', # Component Framework v1.
3361
3362 # Fuchsia IDL protocol specifications.
3363 '*.fidl',
3364 ]
3365
3366 # Don't check for owners files for changes in these directories.
3367 excluded_patterns = [
3368 'third_party/crashpad/*',
3369 ]
3370
3371 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3372 excluded_patterns,
3373 'build/fuchsia/SECURITY_OWNERS')
3374
3375
3376def CheckSecurityOwners(input_api, output_api):
3377 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3378 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3379 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3380 input_api, output_api)
3381
3382 if ipc_results.has_security_sensitive_files:
3383 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503384
3385 results = []
Daniel Chenga37c03db2022-05-12 17:20:343386
Daniel Cheng171dad8d2022-05-21 00:40:253387 missing_reviewer_problems = []
3388 if ipc_results.missing_reviewer_problem:
3389 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3390 if fuchsia_results.missing_reviewer_problem:
3391 missing_reviewer_problems.append(
3392 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343393
Daniel Cheng171dad8d2022-05-21 00:40:253394 # Missing reviewers are an error unless there's no issue number
3395 # associated with this branch; in that case, the presubmit is being run
3396 # with --all or --files.
3397 #
3398 # Note that upload should never be an error; otherwise, it would be
3399 # impossible to upload changes at all.
3400 if input_api.is_committing and input_api.change.issue:
3401 make_presubmit_message = output_api.PresubmitError
3402 else:
3403 make_presubmit_message = output_api.PresubmitNotifyResult
3404 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503405 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253406 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343407
Daniel Cheng171dad8d2022-05-21 00:40:253408 owners_file_problems = []
3409 owners_file_problems.extend(ipc_results.owners_file_problems)
3410 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343411
Daniel Cheng171dad8d2022-05-21 00:40:253412 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113413 # Missing per-file rules are always an error. While swarming and caching
3414 # means that uploading a patchset with updated OWNERS files and sending
3415 # it to the CQ again should not have a large incremental cost, it is
3416 # still frustrating to discover the error only after the change has
3417 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343418 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253419 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503420
3421 return results
3422
3423
3424def _GetFilesUsingSecurityCriticalFunctions(input_api):
3425 """Checks affected files for changes to security-critical calls. This
3426 function checks the full change diff, to catch both additions/changes
3427 and removals.
3428
3429 Returns a dict keyed by file name, and the value is a set of detected
3430 functions.
3431 """
3432 # Map of function pretty name (displayed in an error) to the pattern to
3433 # match it with.
3434 _PATTERNS_TO_CHECK = {
3435 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3436 }
3437 _PATTERNS_TO_CHECK = {
3438 k: input_api.re.compile(v)
3439 for k, v in _PATTERNS_TO_CHECK.items()
3440 }
3441
Sam Maiera6e76d72022-02-11 21:43:503442 # We don't want to trigger on strings within this file.
3443 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343444 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503445
3446 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3447 files_to_functions = {}
3448 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3449 diff = f.GenerateScmDiff()
3450 for line in diff.split('\n'):
3451 # Not using just RightHandSideLines() because removing a
3452 # call to a security-critical function can be just as important
3453 # as adding or changing the arguments.
3454 if line.startswith('-') or (line.startswith('+')
3455 and not line.startswith('++')):
3456 for name, pattern in _PATTERNS_TO_CHECK.items():
3457 if pattern.search(line):
3458 path = f.LocalPath()
3459 if not path in files_to_functions:
3460 files_to_functions[path] = set()
3461 files_to_functions[path].add(name)
3462 return files_to_functions
3463
3464
3465def CheckSecurityChanges(input_api, output_api):
3466 """Checks that changes involving security-critical functions are reviewed
3467 by the security team.
3468 """
3469 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3470 if not len(files_to_functions):
3471 return []
3472
Sam Maiera6e76d72022-02-11 21:43:503473 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343474 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503475 return []
3476
Daniel Chenga37c03db2022-05-12 17:20:343477 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503478 'that need to be reviewed by {}.\n'.format(owners_file)
3479 for path, names in files_to_functions.items():
3480 msg += ' {}\n'.format(path)
3481 for name in names:
3482 msg += ' {}\n'.format(name)
3483 msg += '\n'
3484
3485 if input_api.is_committing:
3486 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033487 else:
Sam Maiera6e76d72022-02-11 21:43:503488 output = output_api.PresubmitNotifyResult
3489 return [output(msg)]
3490
3491
3492def CheckSetNoParent(input_api, output_api):
3493 """Checks that set noparent is only used together with an OWNERS file in
3494 //build/OWNERS.setnoparent (see also
3495 //docs/code_reviews.md#owners-files-details)
3496 """
3497 # Return early if no OWNERS files were modified.
3498 if not any(f.LocalPath().endswith('OWNERS')
3499 for f in input_api.AffectedFiles(include_deletes=False)):
3500 return []
3501
3502 errors = []
3503
3504 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3505 allowed_owners_files = set()
3506 with open(allowed_owners_files_file, 'r') as f:
3507 for line in f:
3508 line = line.strip()
3509 if not line or line.startswith('#'):
3510 continue
3511 allowed_owners_files.add(line)
3512
3513 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3514
3515 for f in input_api.AffectedFiles(include_deletes=False):
3516 if not f.LocalPath().endswith('OWNERS'):
3517 continue
3518
3519 found_owners_files = set()
3520 found_set_noparent_lines = dict()
3521
3522 # Parse the OWNERS file.
3523 for lineno, line in enumerate(f.NewContents(), 1):
3524 line = line.strip()
3525 if line.startswith('set noparent'):
3526 found_set_noparent_lines[''] = lineno
3527 if line.startswith('file://'):
3528 if line in allowed_owners_files:
3529 found_owners_files.add('')
3530 if line.startswith('per-file'):
3531 match = per_file_pattern.match(line)
3532 if match:
3533 glob = match.group(1).strip()
3534 directive = match.group(2).strip()
3535 if directive == 'set noparent':
3536 found_set_noparent_lines[glob] = lineno
3537 if directive.startswith('file://'):
3538 if directive in allowed_owners_files:
3539 found_owners_files.add(glob)
3540
3541 # Check that every set noparent line has a corresponding file:// line
3542 # listed in build/OWNERS.setnoparent. An exception is made for top level
3543 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493544 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3545 if (linux_path.count('/') != 1
3546 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503547 for set_noparent_line in found_set_noparent_lines:
3548 if set_noparent_line in found_owners_files:
3549 continue
3550 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493551 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503552 found_set_noparent_lines[set_noparent_line]))
3553
3554 results = []
3555 if errors:
3556 if input_api.is_committing:
3557 output = output_api.PresubmitError
3558 else:
3559 output = output_api.PresubmitPromptWarning
3560 results.append(
3561 output(
3562 'Found the following "set noparent" restrictions in OWNERS files that '
3563 'do not include owners from build/OWNERS.setnoparent:',
3564 long_text='\n\n'.join(errors)))
3565 return results
3566
3567
3568def CheckUselessForwardDeclarations(input_api, output_api):
3569 """Checks that added or removed lines in non third party affected
3570 header files do not lead to new useless class or struct forward
3571 declaration.
3572 """
3573 results = []
3574 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3575 input_api.re.MULTILINE)
3576 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3577 input_api.re.MULTILINE)
3578 for f in input_api.AffectedFiles(include_deletes=False):
3579 if (f.LocalPath().startswith('third_party')
3580 and not f.LocalPath().startswith('third_party/blink')
3581 and not f.LocalPath().startswith('third_party\\blink')):
3582 continue
3583
3584 if not f.LocalPath().endswith('.h'):
3585 continue
3586
3587 contents = input_api.ReadFile(f)
3588 fwd_decls = input_api.re.findall(class_pattern, contents)
3589 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3590
3591 useless_fwd_decls = []
3592 for decl in fwd_decls:
3593 count = sum(1 for _ in input_api.re.finditer(
3594 r'\b%s\b' % input_api.re.escape(decl), contents))
3595 if count == 1:
3596 useless_fwd_decls.append(decl)
3597
3598 if not useless_fwd_decls:
3599 continue
3600
3601 for line in f.GenerateScmDiff().splitlines():
3602 if (line.startswith('-') and not line.startswith('--')
3603 or line.startswith('+') and not line.startswith('++')):
3604 for decl in useless_fwd_decls:
3605 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3606 results.append(
3607 output_api.PresubmitPromptWarning(
3608 '%s: %s forward declaration is no longer needed'
3609 % (f.LocalPath(), decl)))
3610 useless_fwd_decls.remove(decl)
3611
3612 return results
3613
3614
3615def _CheckAndroidDebuggableBuild(input_api, output_api):
3616 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3617 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3618 this is a debuggable build of Android.
3619 """
3620 build_type_check_pattern = input_api.re.compile(
3621 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3622
3623 errors = []
3624
3625 sources = lambda affected_file: input_api.FilterSourceFile(
3626 affected_file,
3627 files_to_skip=(
3628 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3629 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313630 r"^android_webview/support_library/boundary_interfaces/",
3631 r"^chrome/android/webapk/.*",
3632 r'^third_party/.*',
3633 r"tools/android/customtabs_benchmark/.*",
3634 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:503635 )),
3636 files_to_check=[r'.*\.java$'])
3637
3638 for f in input_api.AffectedSourceFiles(sources):
3639 for line_num, line in f.ChangedContents():
3640 if build_type_check_pattern.search(line):
3641 errors.append("%s:%d" % (f.LocalPath(), line_num))
3642
3643 results = []
3644
3645 if errors:
3646 results.append(
3647 output_api.PresubmitPromptWarning(
3648 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3649 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3650
3651 return results
3652
3653# TODO: add unit tests
3654def _CheckAndroidToastUsage(input_api, output_api):
3655 """Checks that code uses org.chromium.ui.widget.Toast instead of
3656 android.widget.Toast (Chromium Toast doesn't force hardware
3657 acceleration on low-end devices, saving memory).
3658 """
3659 toast_import_pattern = input_api.re.compile(
3660 r'^import android\.widget\.Toast;$')
3661
3662 errors = []
3663
3664 sources = lambda affected_file: input_api.FilterSourceFile(
3665 affected_file,
3666 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:313667 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
3668 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:503669 files_to_check=[r'.*\.java$'])
3670
3671 for f in input_api.AffectedSourceFiles(sources):
3672 for line_num, line in f.ChangedContents():
3673 if toast_import_pattern.search(line):
3674 errors.append("%s:%d" % (f.LocalPath(), line_num))
3675
3676 results = []
3677
3678 if errors:
3679 results.append(
3680 output_api.PresubmitError(
3681 'android.widget.Toast usage is detected. Android toasts use hardware'
3682 ' acceleration, and can be\ncostly on low-end devices. Please use'
3683 ' org.chromium.ui.widget.Toast instead.\n'
3684 'Contact [email protected] if you have any questions.',
3685 errors))
3686
3687 return results
3688
3689
3690def _CheckAndroidCrLogUsage(input_api, output_api):
3691 """Checks that new logs using org.chromium.base.Log:
3692 - Are using 'TAG' as variable name for the tags (warn)
3693 - Are using a tag that is shorter than 20 characters (error)
3694 """
3695
3696 # Do not check format of logs in the given files
3697 cr_log_check_excluded_paths = [
3698 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:313699 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:503700 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:313701 r"^android_webview/glue/java/src/com/android/"
3702 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:503703 # The customtabs_benchmark is a small app that does not depend on Chromium
3704 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:313705 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:503706 ]
3707
3708 cr_log_import_pattern = input_api.re.compile(
3709 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3710 class_in_base_pattern = input_api.re.compile(
3711 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3712 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3713 input_api.re.MULTILINE)
3714 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3715 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3716 log_decl_pattern = input_api.re.compile(
3717 r'static final String TAG = "(?P<name>(.*))"')
3718 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3719
3720 REF_MSG = ('See docs/android_logging.md for more info.')
3721 sources = lambda x: input_api.FilterSourceFile(
3722 x,
3723 files_to_check=[r'.*\.java$'],
3724 files_to_skip=cr_log_check_excluded_paths)
3725
3726 tag_decl_errors = []
3727 tag_length_errors = []
3728 tag_errors = []
3729 tag_with_dot_errors = []
3730 util_log_errors = []
3731
3732 for f in input_api.AffectedSourceFiles(sources):
3733 file_content = input_api.ReadFile(f)
3734 has_modified_logs = False
3735 # Per line checks
3736 if (cr_log_import_pattern.search(file_content)
3737 or (class_in_base_pattern.search(file_content)
3738 and not has_some_log_import_pattern.search(file_content))):
3739 # Checks to run for files using cr log
3740 for line_num, line in f.ChangedContents():
3741 if rough_log_decl_pattern.search(line):
3742 has_modified_logs = True
3743
3744 # Check if the new line is doing some logging
3745 match = log_call_pattern.search(line)
3746 if match:
3747 has_modified_logs = True
3748
3749 # Make sure it uses "TAG"
3750 if not match.group('tag') == 'TAG':
3751 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3752 else:
3753 # Report non cr Log function calls in changed lines
3754 for line_num, line in f.ChangedContents():
3755 if log_call_pattern.search(line):
3756 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3757
3758 # Per file checks
3759 if has_modified_logs:
3760 # Make sure the tag is using the "cr" prefix and is not too long
3761 match = log_decl_pattern.search(file_content)
3762 tag_name = match.group('name') if match else None
3763 if not tag_name:
3764 tag_decl_errors.append(f.LocalPath())
3765 elif len(tag_name) > 20:
3766 tag_length_errors.append(f.LocalPath())
3767 elif '.' in tag_name:
3768 tag_with_dot_errors.append(f.LocalPath())
3769
3770 results = []
3771 if tag_decl_errors:
3772 results.append(
3773 output_api.PresubmitPromptWarning(
3774 'Please define your tags using the suggested format: .\n'
3775 '"private static final String TAG = "<package tag>".\n'
3776 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3777 tag_decl_errors))
3778
3779 if tag_length_errors:
3780 results.append(
3781 output_api.PresubmitError(
3782 'The tag length is restricted by the system to be at most '
3783 '20 characters.\n' + REF_MSG, tag_length_errors))
3784
3785 if tag_errors:
3786 results.append(
3787 output_api.PresubmitPromptWarning(
3788 'Please use a variable named "TAG" for your log tags.\n' +
3789 REF_MSG, tag_errors))
3790
3791 if util_log_errors:
3792 results.append(
3793 output_api.PresubmitPromptWarning(
3794 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3795 util_log_errors))
3796
3797 if tag_with_dot_errors:
3798 results.append(
3799 output_api.PresubmitPromptWarning(
3800 'Dot in log tags cause them to be elided in crash reports.\n' +
3801 REF_MSG, tag_with_dot_errors))
3802
3803 return results
3804
3805
3806def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3807 """Checks that junit.framework.* is no longer used."""
3808 deprecated_junit_framework_pattern = input_api.re.compile(
3809 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3810 sources = lambda x: input_api.FilterSourceFile(
3811 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3812 errors = []
3813 for f in input_api.AffectedFiles(file_filter=sources):
3814 for line_num, line in f.ChangedContents():
3815 if deprecated_junit_framework_pattern.search(line):
3816 errors.append("%s:%d" % (f.LocalPath(), line_num))
3817
3818 results = []
3819 if errors:
3820 results.append(
3821 output_api.PresubmitError(
3822 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3823 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3824 ' if you have any question.', errors))
3825 return results
3826
3827
3828def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3829 """Checks that if new Java test classes have inheritance.
3830 Either the new test class is JUnit3 test or it is a JUnit4 test class
3831 with a base class, either case is undesirable.
3832 """
3833 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3834
3835 sources = lambda x: input_api.FilterSourceFile(
3836 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3837 errors = []
3838 for f in input_api.AffectedFiles(file_filter=sources):
3839 if not f.OldContents():
3840 class_declaration_start_flag = False
3841 for line_num, line in f.ChangedContents():
3842 if class_declaration_pattern.search(line):
3843 class_declaration_start_flag = True
3844 if class_declaration_start_flag and ' extends ' in line:
3845 errors.append('%s:%d' % (f.LocalPath(), line_num))
3846 if '{' in line:
3847 class_declaration_start_flag = False
3848
3849 results = []
3850 if errors:
3851 results.append(
3852 output_api.PresubmitPromptWarning(
3853 'The newly created files include Test classes that inherits from base'
3854 ' class. Please do not use inheritance in JUnit4 tests or add new'
3855 ' JUnit3 tests. Contact [email protected] if you have any'
3856 ' questions.', errors))
3857 return results
3858
3859
3860def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3861 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3862 deprecated_annotation_import_pattern = input_api.re.compile(
3863 r'^import android\.test\.suitebuilder\.annotation\..*;',
3864 input_api.re.MULTILINE)
3865 sources = lambda x: input_api.FilterSourceFile(
3866 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3867 errors = []
3868 for f in input_api.AffectedFiles(file_filter=sources):
3869 for line_num, line in f.ChangedContents():
3870 if deprecated_annotation_import_pattern.search(line):
3871 errors.append("%s:%d" % (f.LocalPath(), line_num))
3872
3873 results = []
3874 if errors:
3875 results.append(
3876 output_api.PresubmitError(
3877 'Annotations in android.test.suitebuilder.annotation have been'
3878 ' deprecated since API level 24. Please use android.support.test.filters'
3879 ' from //third_party/android_support_test_runner:runner_java instead.'
3880 ' Contact [email protected] if you have any questions.',
3881 errors))
3882 return results
3883
3884
3885def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3886 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:513887 file_filter = lambda f: (f.LocalPath().endswith(
3888 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
3889 LocalPath() or '/res/drawable-ldrtl/'.replace(
3890 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:503891 errors = []
3892 for f in input_api.AffectedFiles(include_deletes=False,
3893 file_filter=file_filter):
3894 errors.append(' %s' % f.LocalPath())
3895
3896 results = []
3897 if errors:
3898 results.append(
3899 output_api.PresubmitError(
3900 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3901 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3902 '/res/drawable-ldrtl/.\n'
3903 'Contact [email protected] if you have questions.', errors))
3904 return results
3905
3906
3907def _CheckAndroidWebkitImports(input_api, output_api):
3908 """Checks that code uses org.chromium.base.Callback instead of
3909 android.webview.ValueCallback except in the WebView glue layer
3910 and WebLayer.
3911 """
3912 valuecallback_import_pattern = input_api.re.compile(
3913 r'^import android\.webkit\.ValueCallback;$')
3914
3915 errors = []
3916
3917 sources = lambda affected_file: input_api.FilterSourceFile(
3918 affected_file,
3919 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3920 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313921 r'^android_webview/glue/.*',
3922 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:503923 )),
3924 files_to_check=[r'.*\.java$'])
3925
3926 for f in input_api.AffectedSourceFiles(sources):
3927 for line_num, line in f.ChangedContents():
3928 if valuecallback_import_pattern.search(line):
3929 errors.append("%s:%d" % (f.LocalPath(), line_num))
3930
3931 results = []
3932
3933 if errors:
3934 results.append(
3935 output_api.PresubmitError(
3936 'android.webkit.ValueCallback usage is detected outside of the glue'
3937 ' layer. To stay compatible with the support library, android.webkit.*'
3938 ' classes should only be used inside the glue layer and'
3939 ' org.chromium.base.Callback should be used instead.', errors))
3940
3941 return results
3942
3943
3944def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3945 """Checks Android XML styles """
3946
3947 # Return early if no relevant files were modified.
3948 if not any(
3949 _IsXmlOrGrdFile(input_api, f.LocalPath())
3950 for f in input_api.AffectedFiles(include_deletes=False)):
3951 return []
3952
3953 import sys
3954 original_sys_path = sys.path
3955 try:
3956 sys.path = sys.path + [
3957 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3958 'android', 'checkxmlstyle')
3959 ]
3960 import checkxmlstyle
3961 finally:
3962 # Restore sys.path to what it was before.
3963 sys.path = original_sys_path
3964
3965 if is_check_on_upload:
3966 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3967 else:
3968 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3969
3970
3971def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3972 """Checks Android Infobar Deprecation """
3973
3974 import sys
3975 original_sys_path = sys.path
3976 try:
3977 sys.path = sys.path + [
3978 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3979 'android', 'infobar_deprecation')
3980 ]
3981 import infobar_deprecation
3982 finally:
3983 # Restore sys.path to what it was before.
3984 sys.path = original_sys_path
3985
3986 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3987
3988
3989class _PydepsCheckerResult:
3990 def __init__(self, cmd, pydeps_path, process, old_contents):
3991 self._cmd = cmd
3992 self._pydeps_path = pydeps_path
3993 self._process = process
3994 self._old_contents = old_contents
3995
3996 def GetError(self):
3997 """Returns an error message, or None."""
3998 import difflib
3999 if self._process.wait() != 0:
4000 # STDERR should already be printed.
4001 return 'Command failed: ' + self._cmd
4002 new_contents = self._process.stdout.read().splitlines()[2:]
4003 if self._old_contents != new_contents:
4004 diff = '\n'.join(
4005 difflib.context_diff(self._old_contents, new_contents))
4006 return ('File is stale: {}\n'
4007 'Diff (apply to fix):\n'
4008 '{}\n'
4009 'To regenerate, run:\n\n'
4010 ' {}').format(self._pydeps_path, diff, self._cmd)
4011 return None
4012
4013
4014class PydepsChecker:
4015 def __init__(self, input_api, pydeps_files):
4016 self._file_cache = {}
4017 self._input_api = input_api
4018 self._pydeps_files = pydeps_files
4019
4020 def _LoadFile(self, path):
4021 """Returns the list of paths within a .pydeps file relative to //."""
4022 if path not in self._file_cache:
4023 with open(path, encoding='utf-8') as f:
4024 self._file_cache[path] = f.read()
4025 return self._file_cache[path]
4026
4027 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594028 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504029 pydeps_data = self._LoadFile(pydeps_path)
4030 uses_gn_paths = '--gn-paths' in pydeps_data
4031 entries = (l for l in pydeps_data.splitlines()
4032 if not l.startswith('#'))
4033 if uses_gn_paths:
4034 # Paths look like: //foo/bar/baz
4035 return (e[2:] for e in entries)
4036 else:
4037 # Paths look like: path/relative/to/file.pydeps
4038 os_path = self._input_api.os_path
4039 pydeps_dir = os_path.dirname(pydeps_path)
4040 return (os_path.normpath(os_path.join(pydeps_dir, e))
4041 for e in entries)
4042
4043 def _CreateFilesToPydepsMap(self):
4044 """Returns a map of local_path -> list_of_pydeps."""
4045 ret = {}
4046 for pydep_local_path in self._pydeps_files:
4047 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4048 ret.setdefault(path, []).append(pydep_local_path)
4049 return ret
4050
4051 def ComputeAffectedPydeps(self):
4052 """Returns an iterable of .pydeps files that might need regenerating."""
4053 affected_pydeps = set()
4054 file_to_pydeps_map = None
4055 for f in self._input_api.AffectedFiles(include_deletes=True):
4056 local_path = f.LocalPath()
4057 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4058 # subrepositories. We can't figure out which files change, so re-check
4059 # all files.
4060 # Changes to print_python_deps.py affect all .pydeps.
4061 if local_path in ('DEPS', 'PRESUBMIT.py'
4062 ) or local_path.endswith('print_python_deps.py'):
4063 return self._pydeps_files
4064 elif local_path.endswith('.pydeps'):
4065 if local_path in self._pydeps_files:
4066 affected_pydeps.add(local_path)
4067 elif local_path.endswith('.py'):
4068 if file_to_pydeps_map is None:
4069 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4070 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4071 return affected_pydeps
4072
4073 def DetermineIfStaleAsync(self, pydeps_path):
4074 """Runs print_python_deps.py to see if the files is stale."""
4075 import os
4076
4077 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4078 if old_pydeps_data:
4079 cmd = old_pydeps_data[1][1:].strip()
4080 if '--output' not in cmd:
4081 cmd += ' --output ' + pydeps_path
4082 old_contents = old_pydeps_data[2:]
4083 else:
4084 # A default cmd that should work in most cases (as long as pydeps filename
4085 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4086 # file is empty/new.
4087 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4088 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4089 old_contents = []
4090 env = dict(os.environ)
4091 env['PYTHONDONTWRITEBYTECODE'] = '1'
4092 process = self._input_api.subprocess.Popen(
4093 cmd + ' --output ""',
4094 shell=True,
4095 env=env,
4096 stdout=self._input_api.subprocess.PIPE,
4097 encoding='utf-8')
4098 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404099
4100
Tibor Goldschwendt360793f72019-06-25 18:23:494101def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504102 args = {}
4103 with open('build/config/gclient_args.gni', 'r') as f:
4104 for line in f:
4105 line = line.strip()
4106 if not line or line.startswith('#'):
4107 continue
4108 attribute, value = line.split('=')
4109 args[attribute.strip()] = value.strip()
4110 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494111
4112
Saagar Sanghavifceeaae2020-08-12 16:40:364113def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504114 """Checks if a .pydeps file needs to be regenerated."""
4115 # This check is for Python dependency lists (.pydeps files), and involves
4116 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4117 # doesn't work on Windows and Mac, so skip it on other platforms.
4118 if not input_api.platform.startswith('linux'):
4119 return []
Erik Staabc734cd7a2021-11-23 03:11:524120
Sam Maiera6e76d72022-02-11 21:43:504121 results = []
4122 # First, check for new / deleted .pydeps.
4123 for f in input_api.AffectedFiles(include_deletes=True):
4124 # Check whether we are running the presubmit check for a file in src.
4125 # f.LocalPath is relative to repo (src, or internal repo).
4126 # os_path.exists is relative to src repo.
4127 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4128 # to src and we can conclude that the pydeps is in src.
4129 if f.LocalPath().endswith('.pydeps'):
4130 if input_api.os_path.exists(f.LocalPath()):
4131 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4132 results.append(
4133 output_api.PresubmitError(
4134 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4135 'remove %s' % f.LocalPath()))
4136 elif f.Action() != 'D' and f.LocalPath(
4137 ) not in _ALL_PYDEPS_FILES:
4138 results.append(
4139 output_api.PresubmitError(
4140 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4141 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404142
Sam Maiera6e76d72022-02-11 21:43:504143 if results:
4144 return results
4145
4146 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4147 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4148 affected_pydeps = set(checker.ComputeAffectedPydeps())
4149 affected_android_pydeps = affected_pydeps.intersection(
4150 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4151 if affected_android_pydeps and not is_android:
4152 results.append(
4153 output_api.PresubmitPromptOrNotify(
4154 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594155 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504156 'run because you are not using an Android checkout. To validate that\n'
4157 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4158 'use the android-internal-presubmit optional trybot.\n'
4159 'Possibly stale pydeps files:\n{}'.format(
4160 '\n'.join(affected_android_pydeps))))
4161
4162 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4163 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4164 # Process these concurrently, as each one takes 1-2 seconds.
4165 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4166 for result in pydep_results:
4167 error_msg = result.GetError()
4168 if error_msg:
4169 results.append(output_api.PresubmitError(error_msg))
4170
agrievef32bcc72016-04-04 14:57:404171 return results
4172
agrievef32bcc72016-04-04 14:57:404173
Saagar Sanghavifceeaae2020-08-12 16:40:364174def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504175 """Checks to make sure no header files have |Singleton<|."""
4176
4177 def FileFilter(affected_file):
4178 # It's ok for base/memory/singleton.h to have |Singleton<|.
4179 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314180 (r"^base/memory/singleton\.h$",
4181 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504182 return input_api.FilterSourceFile(affected_file,
4183 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434184
Sam Maiera6e76d72022-02-11 21:43:504185 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4186 files = []
4187 for f in input_api.AffectedSourceFiles(FileFilter):
4188 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4189 or f.LocalPath().endswith('.hpp')
4190 or f.LocalPath().endswith('.inl')):
4191 contents = input_api.ReadFile(f)
4192 for line in contents.splitlines(False):
4193 if (not line.lstrip().startswith('//')
4194 and # Strip C++ comment.
4195 pattern.search(line)):
4196 files.append(f)
4197 break
glidere61efad2015-02-18 17:39:434198
Sam Maiera6e76d72022-02-11 21:43:504199 if files:
4200 return [
4201 output_api.PresubmitError(
4202 'Found base::Singleton<T> in the following header files.\n' +
4203 'Please move them to an appropriate source file so that the ' +
4204 'template gets instantiated in a single compilation unit.',
4205 files)
4206 ]
4207 return []
glidere61efad2015-02-18 17:39:434208
4209
[email protected]fd20b902014-05-09 02:14:534210_DEPRECATED_CSS = [
4211 # Values
4212 ( "-webkit-box", "flex" ),
4213 ( "-webkit-inline-box", "inline-flex" ),
4214 ( "-webkit-flex", "flex" ),
4215 ( "-webkit-inline-flex", "inline-flex" ),
4216 ( "-webkit-min-content", "min-content" ),
4217 ( "-webkit-max-content", "max-content" ),
4218
4219 # Properties
4220 ( "-webkit-background-clip", "background-clip" ),
4221 ( "-webkit-background-origin", "background-origin" ),
4222 ( "-webkit-background-size", "background-size" ),
4223 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444224 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:534225
4226 # Functions
4227 ( "-webkit-gradient", "gradient" ),
4228 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4229 ( "-webkit-linear-gradient", "linear-gradient" ),
4230 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4231 ( "-webkit-radial-gradient", "radial-gradient" ),
4232 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4233]
4234
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204235
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494236# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364237def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504238 """ Make sure that we don't use deprecated CSS
4239 properties, functions or values. Our external
4240 documentation and iOS CSS for dom distiller
4241 (reader mode) are ignored by the hooks as it
4242 needs to be consumed by WebKit. """
4243 results = []
4244 file_inclusion_pattern = [r".+\.css$"]
4245 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4246 input_api.DEFAULT_FILES_TO_SKIP +
4247 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4248 r"^native_client_sdk"))
4249 file_filter = lambda f: input_api.FilterSourceFile(
4250 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4251 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4252 for line_num, line in fpath.ChangedContents():
4253 for (deprecated_value, value) in _DEPRECATED_CSS:
4254 if deprecated_value in line:
4255 results.append(
4256 output_api.PresubmitError(
4257 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4258 (fpath.LocalPath(), line_num, deprecated_value,
4259 value)))
4260 return results
[email protected]fd20b902014-05-09 02:14:534261
mohan.reddyf21db962014-10-16 12:26:474262
Saagar Sanghavifceeaae2020-08-12 16:40:364263def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504264 bad_files = {}
4265 for f in input_api.AffectedFiles(include_deletes=False):
4266 if (f.LocalPath().startswith('third_party')
4267 and not f.LocalPath().startswith('third_party/blink')
4268 and not f.LocalPath().startswith('third_party\\blink')):
4269 continue
rlanday6802cf632017-05-30 17:48:364270
Sam Maiera6e76d72022-02-11 21:43:504271 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4272 continue
rlanday6802cf632017-05-30 17:48:364273
Sam Maiera6e76d72022-02-11 21:43:504274 relative_includes = [
4275 line for _, line in f.ChangedContents()
4276 if "#include" in line and "../" in line
4277 ]
4278 if not relative_includes:
4279 continue
4280 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364281
Sam Maiera6e76d72022-02-11 21:43:504282 if not bad_files:
4283 return []
rlanday6802cf632017-05-30 17:48:364284
Sam Maiera6e76d72022-02-11 21:43:504285 error_descriptions = []
4286 for file_path, bad_lines in bad_files.items():
4287 error_description = file_path
4288 for line in bad_lines:
4289 error_description += '\n ' + line
4290 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364291
Sam Maiera6e76d72022-02-11 21:43:504292 results = []
4293 results.append(
4294 output_api.PresubmitError(
4295 'You added one or more relative #include paths (including "../").\n'
4296 'These shouldn\'t be used because they can be used to include headers\n'
4297 'from code that\'s not correctly specified as a dependency in the\n'
4298 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364299
Sam Maiera6e76d72022-02-11 21:43:504300 return results
rlanday6802cf632017-05-30 17:48:364301
Takeshi Yoshinoe387aa32017-08-02 13:16:134302
Saagar Sanghavifceeaae2020-08-12 16:40:364303def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504304 """Check that nobody tries to include a cc file. It's a relatively
4305 common error which results in duplicate symbols in object
4306 files. This may not always break the build until someone later gets
4307 very confusing linking errors."""
4308 results = []
4309 for f in input_api.AffectedFiles(include_deletes=False):
4310 # We let third_party code do whatever it wants
4311 if (f.LocalPath().startswith('third_party')
4312 and not f.LocalPath().startswith('third_party/blink')
4313 and not f.LocalPath().startswith('third_party\\blink')):
4314 continue
Daniel Bratell65b033262019-04-23 08:17:064315
Sam Maiera6e76d72022-02-11 21:43:504316 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4317 continue
Daniel Bratell65b033262019-04-23 08:17:064318
Sam Maiera6e76d72022-02-11 21:43:504319 for _, line in f.ChangedContents():
4320 if line.startswith('#include "'):
4321 included_file = line.split('"')[1]
4322 if _IsCPlusPlusFile(input_api, included_file):
4323 # The most common naming for external files with C++ code,
4324 # apart from standard headers, is to call them foo.inc, but
4325 # Chromium sometimes uses foo-inc.cc so allow that as well.
4326 if not included_file.endswith(('.h', '-inc.cc')):
4327 results.append(
4328 output_api.PresubmitError(
4329 'Only header files or .inc files should be included in other\n'
4330 'C++ files. Compiling the contents of a cc file more than once\n'
4331 'will cause duplicate information in the build which may later\n'
4332 'result in strange link_errors.\n' +
4333 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064334
Sam Maiera6e76d72022-02-11 21:43:504335 return results
Daniel Bratell65b033262019-04-23 08:17:064336
4337
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204338def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504339 if not isinstance(key, ast.Str):
4340 return 'Key at line %d must be a string literal' % key.lineno
4341 if not isinstance(value, ast.Dict):
4342 return 'Value at line %d must be a dict' % value.lineno
4343 if len(value.keys) != 1:
4344 return 'Dict at line %d must have single entry' % value.lineno
4345 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4346 return (
4347 'Entry at line %d must have a string literal \'filepath\' as key' %
4348 value.lineno)
4349 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134350
Takeshi Yoshinoe387aa32017-08-02 13:16:134351
Sergey Ulanov4af16052018-11-08 02:41:464352def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504353 if not isinstance(key, ast.Str):
4354 return 'Key at line %d must be a string literal' % key.lineno
4355 if not isinstance(value, ast.List):
4356 return 'Value at line %d must be a list' % value.lineno
4357 for element in value.elts:
4358 if not isinstance(element, ast.Str):
4359 return 'Watchlist elements on line %d is not a string' % key.lineno
4360 if not email_regex.match(element.s):
4361 return ('Watchlist element on line %d doesn\'t look like a valid '
4362 + 'email: %s') % (key.lineno, element.s)
4363 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134364
Takeshi Yoshinoe387aa32017-08-02 13:16:134365
Sergey Ulanov4af16052018-11-08 02:41:464366def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504367 mismatch_template = (
4368 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4369 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134370
Sam Maiera6e76d72022-02-11 21:43:504371 email_regex = input_api.re.compile(
4372 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464373
Sam Maiera6e76d72022-02-11 21:43:504374 ast = input_api.ast
4375 i = 0
4376 last_key = ''
4377 while True:
4378 if i >= len(wd_dict.keys):
4379 if i >= len(w_dict.keys):
4380 return None
4381 return mismatch_template % ('missing',
4382 'line %d' % w_dict.keys[i].lineno)
4383 elif i >= len(w_dict.keys):
4384 return (mismatch_template %
4385 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134386
Sam Maiera6e76d72022-02-11 21:43:504387 wd_key = wd_dict.keys[i]
4388 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134389
Sam Maiera6e76d72022-02-11 21:43:504390 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4391 wd_dict.values[i], ast)
4392 if result is not None:
4393 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134394
Sam Maiera6e76d72022-02-11 21:43:504395 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4396 email_regex)
4397 if result is not None:
4398 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204399
Sam Maiera6e76d72022-02-11 21:43:504400 if wd_key.s != w_key.s:
4401 return mismatch_template % ('%s at line %d' %
4402 (wd_key.s, wd_key.lineno),
4403 '%s at line %d' %
4404 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204405
Sam Maiera6e76d72022-02-11 21:43:504406 if wd_key.s < last_key:
4407 return (
4408 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4409 % (wd_key.lineno, w_key.lineno))
4410 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204411
Sam Maiera6e76d72022-02-11 21:43:504412 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204413
4414
Sergey Ulanov4af16052018-11-08 02:41:464415def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504416 ast = input_api.ast
4417 if not isinstance(expression, ast.Expression):
4418 return 'WATCHLISTS file must contain a valid expression'
4419 dictionary = expression.body
4420 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4421 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204422
Sam Maiera6e76d72022-02-11 21:43:504423 first_key = dictionary.keys[0]
4424 first_value = dictionary.values[0]
4425 second_key = dictionary.keys[1]
4426 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204427
Sam Maiera6e76d72022-02-11 21:43:504428 if (not isinstance(first_key, ast.Str)
4429 or first_key.s != 'WATCHLIST_DEFINITIONS'
4430 or not isinstance(first_value, ast.Dict)):
4431 return ('The first entry of the dict in WATCHLISTS file must be '
4432 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204433
Sam Maiera6e76d72022-02-11 21:43:504434 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4435 or not isinstance(second_value, ast.Dict)):
4436 return ('The second entry of the dict in WATCHLISTS file must be '
4437 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204438
Sam Maiera6e76d72022-02-11 21:43:504439 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134440
4441
Saagar Sanghavifceeaae2020-08-12 16:40:364442def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504443 for f in input_api.AffectedFiles(include_deletes=False):
4444 if f.LocalPath() == 'WATCHLISTS':
4445 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134446
Sam Maiera6e76d72022-02-11 21:43:504447 try:
4448 # First, make sure that it can be evaluated.
4449 input_api.ast.literal_eval(contents)
4450 # Get an AST tree for it and scan the tree for detailed style checking.
4451 expression = input_api.ast.parse(contents,
4452 filename='WATCHLISTS',
4453 mode='eval')
4454 except ValueError as e:
4455 return [
4456 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4457 long_text=repr(e))
4458 ]
4459 except SyntaxError as e:
4460 return [
4461 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4462 long_text=repr(e))
4463 ]
4464 except TypeError as e:
4465 return [
4466 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4467 long_text=repr(e))
4468 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134469
Sam Maiera6e76d72022-02-11 21:43:504470 result = _CheckWATCHLISTSSyntax(expression, input_api)
4471 if result is not None:
4472 return [output_api.PresubmitError(result)]
4473 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134474
Sam Maiera6e76d72022-02-11 21:43:504475 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134476
4477
Andrew Grieve1b290e4a22020-11-24 20:07:014478def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504479 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014480
Sam Maiera6e76d72022-02-11 21:43:504481 As documented at //build/docs/writing_gn_templates.md
4482 """
Andrew Grieve1b290e4a22020-11-24 20:07:014483
Sam Maiera6e76d72022-02-11 21:43:504484 def gn_files(f):
4485 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014486
Sam Maiera6e76d72022-02-11 21:43:504487 problems = []
4488 for f in input_api.AffectedSourceFiles(gn_files):
4489 for line_num, line in f.ChangedContents():
4490 if 'forward_variables_from(invoker, "*")' in line:
4491 problems.append(
4492 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4493 (f.LocalPath(), line_num))
4494
4495 if problems:
4496 return [
4497 output_api.PresubmitPromptWarning(
4498 'forward_variables_from("*") without exclusions',
4499 items=sorted(problems),
4500 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594501 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504502 'explicitly listed in forward_variables_from(). For more '
4503 'details, see:\n'
4504 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4505 'build/docs/writing_gn_templates.md'
4506 '#Using-forward_variables_from'))
4507 ]
4508 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014509
4510
Saagar Sanghavifceeaae2020-08-12 16:40:364511def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504512 """Checks that newly added header files have corresponding GN changes.
4513 Note that this is only a heuristic. To be precise, run script:
4514 build/check_gn_headers.py.
4515 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194516
Sam Maiera6e76d72022-02-11 21:43:504517 def headers(f):
4518 return input_api.FilterSourceFile(
4519 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194520
Sam Maiera6e76d72022-02-11 21:43:504521 new_headers = []
4522 for f in input_api.AffectedSourceFiles(headers):
4523 if f.Action() != 'A':
4524 continue
4525 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194526
Sam Maiera6e76d72022-02-11 21:43:504527 def gn_files(f):
4528 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194529
Sam Maiera6e76d72022-02-11 21:43:504530 all_gn_changed_contents = ''
4531 for f in input_api.AffectedSourceFiles(gn_files):
4532 for _, line in f.ChangedContents():
4533 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194534
Sam Maiera6e76d72022-02-11 21:43:504535 problems = []
4536 for header in new_headers:
4537 basename = input_api.os_path.basename(header)
4538 if basename not in all_gn_changed_contents:
4539 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194540
Sam Maiera6e76d72022-02-11 21:43:504541 if problems:
4542 return [
4543 output_api.PresubmitPromptWarning(
4544 'Missing GN changes for new header files',
4545 items=sorted(problems),
4546 long_text=
4547 'Please double check whether newly added header files need '
4548 'corresponding changes in gn or gni files.\nThis checking is only a '
4549 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4550 'Read https://crbug.com/661774 for more info.')
4551 ]
4552 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194553
4554
Saagar Sanghavifceeaae2020-08-12 16:40:364555def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504556 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024557
Sam Maiera6e76d72022-02-11 21:43:504558 This assumes we won't intentionally reference one product from the other
4559 product.
4560 """
4561 all_problems = []
4562 test_cases = [{
4563 "filename_postfix": "google_chrome_strings.grd",
4564 "correct_name": "Chrome",
4565 "incorrect_name": "Chromium",
4566 }, {
4567 "filename_postfix": "chromium_strings.grd",
4568 "correct_name": "Chromium",
4569 "incorrect_name": "Chrome",
4570 }]
Michael Giuffridad3bc8672018-10-25 22:48:024571
Sam Maiera6e76d72022-02-11 21:43:504572 for test_case in test_cases:
4573 problems = []
4574 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4575 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024576
Sam Maiera6e76d72022-02-11 21:43:504577 # Check each new line. Can yield false positives in multiline comments, but
4578 # easier than trying to parse the XML because messages can have nested
4579 # children, and associating message elements with affected lines is hard.
4580 for f in input_api.AffectedSourceFiles(filename_filter):
4581 for line_num, line in f.ChangedContents():
4582 if "<message" in line or "<!--" in line or "-->" in line:
4583 continue
4584 if test_case["incorrect_name"] in line:
4585 problems.append("Incorrect product name in %s:%d" %
4586 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024587
Sam Maiera6e76d72022-02-11 21:43:504588 if problems:
4589 message = (
4590 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4591 % (test_case["correct_name"], test_case["correct_name"],
4592 test_case["incorrect_name"]))
4593 all_problems.append(
4594 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024595
Sam Maiera6e76d72022-02-11 21:43:504596 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024597
4598
Saagar Sanghavifceeaae2020-08-12 16:40:364599def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504600 """Avoid large files, especially binary files, in the repository since
4601 git doesn't scale well for those. They will be in everyone's repo
4602 clones forever, forever making Chromium slower to clone and work
4603 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364604
Sam Maiera6e76d72022-02-11 21:43:504605 # Uploading files to cloud storage is not trivial so we don't want
4606 # to set the limit too low, but the upper limit for "normal" large
4607 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4608 # anything over 20 MB is exceptional.
4609 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364610
Sam Maiera6e76d72022-02-11 21:43:504611 too_large_files = []
4612 for f in input_api.AffectedFiles():
4613 # Check both added and modified files (but not deleted files).
4614 if f.Action() in ('A', 'M'):
4615 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4616 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4617 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364618
Sam Maiera6e76d72022-02-11 21:43:504619 if too_large_files:
4620 message = (
4621 'Do not commit large files to git since git scales badly for those.\n'
4622 +
4623 'Instead put the large files in cloud storage and use DEPS to\n' +
4624 'fetch them.\n' + '\n'.join(too_large_files))
4625 return [
4626 output_api.PresubmitError('Too large files found in commit',
4627 long_text=message + '\n')
4628 ]
4629 else:
4630 return []
Daniel Bratell93eb6c62019-04-29 20:13:364631
Max Morozb47503b2019-08-08 21:03:274632
Saagar Sanghavifceeaae2020-08-12 16:40:364633def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504634 """Checks specific for fuzz target sources."""
4635 EXPORTED_SYMBOLS = [
4636 'LLVMFuzzerInitialize',
4637 'LLVMFuzzerCustomMutator',
4638 'LLVMFuzzerCustomCrossOver',
4639 'LLVMFuzzerMutate',
4640 ]
Max Morozb47503b2019-08-08 21:03:274641
Sam Maiera6e76d72022-02-11 21:43:504642 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274643
Sam Maiera6e76d72022-02-11 21:43:504644 def FilterFile(affected_file):
4645 """Ignore libFuzzer source code."""
4646 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:314647 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:274648
Sam Maiera6e76d72022-02-11 21:43:504649 return input_api.FilterSourceFile(affected_file,
4650 files_to_check=[files_to_check],
4651 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274652
Sam Maiera6e76d72022-02-11 21:43:504653 files_with_missing_header = []
4654 for f in input_api.AffectedSourceFiles(FilterFile):
4655 contents = input_api.ReadFile(f, 'r')
4656 if REQUIRED_HEADER in contents:
4657 continue
Max Morozb47503b2019-08-08 21:03:274658
Sam Maiera6e76d72022-02-11 21:43:504659 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4660 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274661
Sam Maiera6e76d72022-02-11 21:43:504662 if not files_with_missing_header:
4663 return []
Max Morozb47503b2019-08-08 21:03:274664
Sam Maiera6e76d72022-02-11 21:43:504665 long_text = (
4666 'If you define any of the libFuzzer optional functions (%s), it is '
4667 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4668 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4669 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4670 'to access command line arguments passed to the fuzzer. Instead, prefer '
4671 'static initialization and shared resources as documented in '
4672 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4673 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4674 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274675
Sam Maiera6e76d72022-02-11 21:43:504676 return [
4677 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4678 REQUIRED_HEADER,
4679 items=files_with_missing_header,
4680 long_text=long_text)
4681 ]
Max Morozb47503b2019-08-08 21:03:274682
4683
Mohamed Heikald048240a2019-11-12 16:57:374684def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504685 """
4686 Warns authors who add images into the repo to make sure their images are
4687 optimized before committing.
4688 """
4689 images_added = False
4690 image_paths = []
4691 errors = []
4692 filter_lambda = lambda x: input_api.FilterSourceFile(
4693 x,
4694 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4695 DEFAULT_FILES_TO_SKIP),
4696 files_to_check=[r'.*\/(drawable|mipmap)'])
4697 for f in input_api.AffectedFiles(include_deletes=False,
4698 file_filter=filter_lambda):
4699 local_path = f.LocalPath().lower()
4700 if any(
4701 local_path.endswith(extension)
4702 for extension in _IMAGE_EXTENSIONS):
4703 images_added = True
4704 image_paths.append(f)
4705 if images_added:
4706 errors.append(
4707 output_api.PresubmitPromptWarning(
4708 'It looks like you are trying to commit some images. If these are '
4709 'non-test-only images, please make sure to read and apply the tips in '
4710 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4711 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4712 'FYI only and will not block your CL on the CQ.', image_paths))
4713 return errors
Mohamed Heikald048240a2019-11-12 16:57:374714
4715
Saagar Sanghavifceeaae2020-08-12 16:40:364716def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504717 """Groups upload checks that target android code."""
4718 results = []
4719 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4720 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4721 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4722 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4723 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4724 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4725 input_api, output_api))
4726 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4727 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4728 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4729 results.extend(_CheckNewImagesWarning(input_api, output_api))
4730 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4731 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4732 return results
4733
Becky Zhou7c69b50992018-12-10 19:37:574734
Saagar Sanghavifceeaae2020-08-12 16:40:364735def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504736 """Groups commit checks that target android code."""
4737 results = []
4738 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4739 return results
dgnaa68d5e2015-06-10 10:08:224740
Chris Hall59f8d0c72020-05-01 07:31:194741# TODO(chrishall): could we additionally match on any path owned by
4742# ui/accessibility/OWNERS ?
4743_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:314744 r"^chrome/browser.*/accessibility/",
4745 r"^chrome/browser/extensions/api/automation.*/",
4746 r"^chrome/renderer/extensions/accessibility_.*",
4747 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:174748 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:314749 r"^content/browser/accessibility/",
4750 r"^content/renderer/accessibility/",
4751 r"^content/tests/data/accessibility/",
4752 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:174753 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:314754 r"^ui/accessibility/",
4755 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:194756)
4757
Saagar Sanghavifceeaae2020-08-12 16:40:364758def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504759 """Checks that commits to accessibility code contain an AX-Relnotes field in
4760 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194761
Sam Maiera6e76d72022-02-11 21:43:504762 def FileFilter(affected_file):
4763 paths = _ACCESSIBILITY_PATHS
4764 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194765
Sam Maiera6e76d72022-02-11 21:43:504766 # Only consider changes affecting accessibility paths.
4767 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4768 return []
Akihiro Ota08108e542020-05-20 15:30:534769
Sam Maiera6e76d72022-02-11 21:43:504770 # AX-Relnotes can appear in either the description or the footer.
4771 # When searching the description, require 'AX-Relnotes:' to appear at the
4772 # beginning of a line.
4773 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4774 description_has_relnotes = any(
4775 ax_regex.match(line)
4776 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194777
Sam Maiera6e76d72022-02-11 21:43:504778 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4779 'AX-Relnotes', [])
4780 if description_has_relnotes or footer_relnotes:
4781 return []
Chris Hall59f8d0c72020-05-01 07:31:194782
Sam Maiera6e76d72022-02-11 21:43:504783 # TODO(chrishall): link to Relnotes documentation in message.
4784 message = (
4785 "Missing 'AX-Relnotes:' field required for accessibility changes"
4786 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4787 "user-facing changes"
4788 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4789 "user-facing effects"
4790 "\n if this is confusing or annoying then please contact members "
4791 "of ui/accessibility/OWNERS.")
4792
4793 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224794
Mark Schillacie5a0be22022-01-19 00:38:394795
4796_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:314797 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:394798)
4799
4800_ACCESSIBILITY_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:314801 r"^content/test/data/accessibility/accname/.*\.html",
4802 r"^content/test/data/accessibility/aria/.*\.html",
4803 r"^content/test/data/accessibility/css/.*\.html",
4804 r"^content/test/data/accessibility/html/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:394805)
4806
4807_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:314808 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394809)
4810
4811_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:314812 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394813)
4814
4815def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504816 """Checks that commits that include a newly added, renamed/moved, or deleted
4817 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4818 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394819
Sam Maiera6e76d72022-02-11 21:43:504820 def FilePathFilter(affected_file):
4821 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4822 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394823
Sam Maiera6e76d72022-02-11 21:43:504824 def AndroidFilePathFilter(affected_file):
4825 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4826 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394827
Sam Maiera6e76d72022-02-11 21:43:504828 # Only consider changes in the events test data path with html type.
4829 if not any(
4830 input_api.AffectedFiles(include_deletes=True,
4831 file_filter=FilePathFilter)):
4832 return []
Mark Schillacie5a0be22022-01-19 00:38:394833
Sam Maiera6e76d72022-02-11 21:43:504834 # If the commit contains any change to the Android test file, ignore.
4835 if any(
4836 input_api.AffectedFiles(include_deletes=True,
4837 file_filter=AndroidFilePathFilter)):
4838 return []
Mark Schillacie5a0be22022-01-19 00:38:394839
Sam Maiera6e76d72022-02-11 21:43:504840 # Only consider changes that are adding/renaming or deleting a file
4841 message = []
4842 for f in input_api.AffectedFiles(include_deletes=True,
4843 file_filter=FilePathFilter):
4844 if f.Action() == 'A' or f.Action() == 'D':
4845 message = (
4846 "It appears that you are adding, renaming or deleting"
4847 "\na dump_accessibility_events* test, but have not included"
4848 "\na corresponding change for Android."
4849 "\nPlease include (or remove) the test from:"
4850 "\n content/public/android/javatests/src/org/chromium/"
4851 "content/browser/accessibility/"
4852 "WebContentsAccessibilityEventsTest.java"
4853 "\nIf this message is confusing or annoying, please contact"
4854 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394855
Sam Maiera6e76d72022-02-11 21:43:504856 # If no message was set, return empty.
4857 if not len(message):
4858 return []
4859
4860 return [output_api.PresubmitPromptWarning(message)]
4861
Mark Schillacie5a0be22022-01-19 00:38:394862
4863def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504864 """Checks that commits that include a newly added, renamed/moved, or deleted
4865 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4866 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394867
Sam Maiera6e76d72022-02-11 21:43:504868 def FilePathFilter(affected_file):
4869 paths = _ACCESSIBILITY_TREE_TEST_PATH
4870 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394871
Sam Maiera6e76d72022-02-11 21:43:504872 def AndroidFilePathFilter(affected_file):
4873 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4874 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394875
Sam Maiera6e76d72022-02-11 21:43:504876 # Only consider changes in the various tree test data paths with html type.
4877 if not any(
4878 input_api.AffectedFiles(include_deletes=True,
4879 file_filter=FilePathFilter)):
4880 return []
Mark Schillacie5a0be22022-01-19 00:38:394881
Sam Maiera6e76d72022-02-11 21:43:504882 # If the commit contains any change to the Android test file, ignore.
4883 if any(
4884 input_api.AffectedFiles(include_deletes=True,
4885 file_filter=AndroidFilePathFilter)):
4886 return []
Mark Schillacie5a0be22022-01-19 00:38:394887
Sam Maiera6e76d72022-02-11 21:43:504888 # Only consider changes that are adding/renaming or deleting a file
4889 message = []
4890 for f in input_api.AffectedFiles(include_deletes=True,
4891 file_filter=FilePathFilter):
4892 if f.Action() == 'A' or f.Action() == 'D':
4893 message = (
4894 "It appears that you are adding, renaming or deleting"
4895 "\na dump_accessibility_tree* test, but have not included"
4896 "\na corresponding change for Android."
4897 "\nPlease include (or remove) the test from:"
4898 "\n content/public/android/javatests/src/org/chromium/"
4899 "content/browser/accessibility/"
4900 "WebContentsAccessibilityTreeTest.java"
4901 "\nIf this message is confusing or annoying, please contact"
4902 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394903
Sam Maiera6e76d72022-02-11 21:43:504904 # If no message was set, return empty.
4905 if not len(message):
4906 return []
4907
4908 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394909
4910
seanmccullough4a9356252021-04-08 19:54:094911# string pattern, sequence of strings to show when pattern matches,
4912# error flag. True if match is a presubmit error, otherwise it's a warning.
4913_NON_INCLUSIVE_TERMS = (
4914 (
4915 # Note that \b pattern in python re is pretty particular. In this
4916 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4917 # ...' will not. This may require some tweaking to catch these cases
4918 # without triggering a lot of false positives. Leaving it naive and
4919 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324920 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094921 (
4922 'Please don\'t use blacklist, whitelist, ' # nocheck
4923 'or slave in your', # nocheck
4924 'code and make every effort to use other terms. Using "// nocheck"',
4925 '"# nocheck" or "<!-- nocheck -->"',
4926 'at the end of the offending line will bypass this PRESUBMIT error',
4927 'but avoid using this whenever possible. Reach out to',
4928 '[email protected] if you have questions'),
4929 True),)
4930
Saagar Sanghavifceeaae2020-08-12 16:40:364931def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504932 """Checks common to both upload and commit."""
4933 results = []
Eric Boren6fd2b932018-01-25 15:05:084934 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504935 input_api.canned_checks.PanProjectChecks(
4936 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084937
Sam Maiera6e76d72022-02-11 21:43:504938 author = input_api.change.author_email
4939 if author and author not in _KNOWN_ROBOTS:
4940 results.extend(
4941 input_api.canned_checks.CheckAuthorizedAuthor(
4942 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244943
Sam Maiera6e76d72022-02-11 21:43:504944 results.extend(
4945 input_api.canned_checks.CheckChangeHasNoTabs(
4946 input_api,
4947 output_api,
4948 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
4949 results.extend(
4950 input_api.RunTests(
4951 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:174952
Bruce Dawsonc8054482022-03-28 15:33:374953 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:504954 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:374955 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:504956 results.extend(
4957 input_api.RunTests(
4958 input_api.canned_checks.CheckDirMetadataFormat(
4959 input_api, output_api, dirmd_bin)))
4960 results.extend(
4961 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4962 input_api, output_api))
4963 results.extend(
4964 input_api.canned_checks.CheckNoNewMetadataInOwners(
4965 input_api, output_api))
4966 results.extend(
4967 input_api.canned_checks.CheckInclusiveLanguage(
4968 input_api,
4969 output_api,
4970 excluded_directories_relative_path=[
4971 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
4972 ],
4973 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:594974
Aleksey Khoroshilov2978c942022-06-13 16:14:124975 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:474976 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:124977 for f in input_api.AffectedFiles(include_deletes=False,
4978 file_filter=presubmit_py_filter):
4979 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
4980 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
4981 # The PRESUBMIT.py file (and the directory containing it) might have
4982 # been affected by being moved or removed, so only try to run the tests
4983 # if they still exist.
4984 if not input_api.os_path.exists(test_file):
4985 continue
Sam Maiera6e76d72022-02-11 21:43:504986
Aleksey Khoroshilov2978c942022-06-13 16:14:124987 use_python3 = False
4988 with open(f.LocalPath()) as fp:
4989 use_python3 = any(
4990 line.startswith('USE_PYTHON3 = True')
4991 for line in fp.readlines())
4992
4993 results.extend(
4994 input_api.canned_checks.RunUnitTestsInDirectory(
4995 input_api,
4996 output_api,
4997 full_path,
4998 files_to_check=[r'^PRESUBMIT_test\.py$'],
4999 run_on_python2=not use_python3,
5000 run_on_python3=use_python3,
5001 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:505002 return results
[email protected]1f7b4172010-01-28 01:17:345003
[email protected]b337cb5b2011-01-23 21:24:055004
Saagar Sanghavifceeaae2020-08-12 16:40:365005def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505006 problems = [
5007 f.LocalPath() for f in input_api.AffectedFiles()
5008 if f.LocalPath().endswith(('.orig', '.rej'))
5009 ]
5010 # Cargo.toml.orig files are part of third-party crates downloaded from
5011 # crates.io and should be included.
5012 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5013 if problems:
5014 return [
5015 output_api.PresubmitError("Don't commit .rej and .orig files.",
5016 problems)
5017 ]
5018 else:
5019 return []
[email protected]b8079ae4a2012-12-05 19:56:495020
5021
Saagar Sanghavifceeaae2020-08-12 16:40:365022def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505023 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5024 macro_re = input_api.re.compile(
5025 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5026 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5027 input_api.re.MULTILINE)
5028 extension_re = input_api.re.compile(r'\.[a-z]+$')
5029 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005030 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505031 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005032 # The build-config macros are allowed to be used in build_config.h
5033 # without including itself.
5034 if f.LocalPath() == config_h_file:
5035 continue
Sam Maiera6e76d72022-02-11 21:43:505036 if not f.LocalPath().endswith(
5037 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5038 continue
5039 found_line_number = None
5040 found_macro = None
5041 all_lines = input_api.ReadFile(f, 'r').splitlines()
5042 for line_num, line in enumerate(all_lines):
5043 match = macro_re.search(line)
5044 if match:
5045 found_line_number = line_num
5046 found_macro = match.group(2)
5047 break
5048 if not found_line_number:
5049 continue
Kent Tamura5a8755d2017-06-29 23:37:075050
Sam Maiera6e76d72022-02-11 21:43:505051 found_include_line = -1
5052 for line_num, line in enumerate(all_lines):
5053 if include_re.search(line):
5054 found_include_line = line_num
5055 break
5056 if found_include_line >= 0 and found_include_line < found_line_number:
5057 continue
Kent Tamura5a8755d2017-06-29 23:37:075058
Sam Maiera6e76d72022-02-11 21:43:505059 if not f.LocalPath().endswith('.h'):
5060 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5061 try:
5062 content = input_api.ReadFile(primary_header_path, 'r')
5063 if include_re.search(content):
5064 continue
5065 except IOError:
5066 pass
5067 errors.append('%s:%d %s macro is used without first including build/'
5068 'build_config.h.' %
5069 (f.LocalPath(), found_line_number, found_macro))
5070 if errors:
5071 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5072 return []
Kent Tamura5a8755d2017-06-29 23:37:075073
5074
Lei Zhang1c12a22f2021-05-12 11:28:455075def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505076 stl_include_re = input_api.re.compile(r'^#include\s+<('
5077 r'algorithm|'
5078 r'array|'
5079 r'limits|'
5080 r'list|'
5081 r'map|'
5082 r'memory|'
5083 r'queue|'
5084 r'set|'
5085 r'string|'
5086 r'unordered_map|'
5087 r'unordered_set|'
5088 r'utility|'
5089 r'vector)>')
5090 std_namespace_re = input_api.re.compile(r'std::')
5091 errors = []
5092 for f in input_api.AffectedFiles():
5093 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5094 continue
Lei Zhang1c12a22f2021-05-12 11:28:455095
Sam Maiera6e76d72022-02-11 21:43:505096 uses_std_namespace = False
5097 has_stl_include = False
5098 for line in f.NewContents():
5099 if has_stl_include and uses_std_namespace:
5100 break
Lei Zhang1c12a22f2021-05-12 11:28:455101
Sam Maiera6e76d72022-02-11 21:43:505102 if not has_stl_include and stl_include_re.search(line):
5103 has_stl_include = True
5104 continue
Lei Zhang1c12a22f2021-05-12 11:28:455105
Bruce Dawson4a5579a2022-04-08 17:11:365106 if not uses_std_namespace and (std_namespace_re.search(line)
5107 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505108 uses_std_namespace = True
5109 continue
Lei Zhang1c12a22f2021-05-12 11:28:455110
Sam Maiera6e76d72022-02-11 21:43:505111 if has_stl_include and not uses_std_namespace:
5112 errors.append(
5113 '%s: Includes STL header(s) but does not reference std::' %
5114 f.LocalPath())
5115 if errors:
5116 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5117 return []
Lei Zhang1c12a22f2021-05-12 11:28:455118
5119
Xiaohan Wang42d96c22022-01-20 17:23:115120def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505121 """Check for sensible looking, totally invalid OS macros."""
5122 preprocessor_statement = input_api.re.compile(r'^\s*#')
5123 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5124 results = []
5125 for lnum, line in f.ChangedContents():
5126 if preprocessor_statement.search(line):
5127 for match in os_macro.finditer(line):
5128 results.append(
5129 ' %s:%d: %s' %
5130 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5131 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5132 return results
[email protected]b00342e7f2013-03-26 16:21:545133
5134
Xiaohan Wang42d96c22022-01-20 17:23:115135def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505136 """Check all affected files for invalid OS macros."""
5137 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005138 # The OS_ macros are allowed to be used in build/build_config.h.
5139 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505140 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005141 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5142 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505143 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:545144
Sam Maiera6e76d72022-02-11 21:43:505145 if not bad_macros:
5146 return []
[email protected]b00342e7f2013-03-26 16:21:545147
Sam Maiera6e76d72022-02-11 21:43:505148 return [
5149 output_api.PresubmitError(
5150 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5151 'defined in build_config.h):', bad_macros)
5152 ]
[email protected]b00342e7f2013-03-26 16:21:545153
lliabraa35bab3932014-10-01 12:16:445154
5155def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505156 """Check all affected files for invalid "if defined" macros."""
5157 ALWAYS_DEFINED_MACROS = (
5158 "TARGET_CPU_PPC",
5159 "TARGET_CPU_PPC64",
5160 "TARGET_CPU_68K",
5161 "TARGET_CPU_X86",
5162 "TARGET_CPU_ARM",
5163 "TARGET_CPU_MIPS",
5164 "TARGET_CPU_SPARC",
5165 "TARGET_CPU_ALPHA",
5166 "TARGET_IPHONE_SIMULATOR",
5167 "TARGET_OS_EMBEDDED",
5168 "TARGET_OS_IPHONE",
5169 "TARGET_OS_MAC",
5170 "TARGET_OS_UNIX",
5171 "TARGET_OS_WIN32",
5172 )
5173 ifdef_macro = input_api.re.compile(
5174 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5175 results = []
5176 for lnum, line in f.ChangedContents():
5177 for match in ifdef_macro.finditer(line):
5178 if match.group(1) in ALWAYS_DEFINED_MACROS:
5179 always_defined = ' %s is always defined. ' % match.group(1)
5180 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5181 results.append(
5182 ' %s:%d %s\n\t%s' %
5183 (f.LocalPath(), lnum, always_defined, did_you_mean))
5184 return results
lliabraa35bab3932014-10-01 12:16:445185
5186
Saagar Sanghavifceeaae2020-08-12 16:40:365187def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505188 """Check all affected files for invalid "if defined" macros."""
5189 bad_macros = []
5190 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5191 for f in input_api.AffectedFiles():
5192 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5193 continue
5194 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5195 bad_macros.extend(
5196 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445197
Sam Maiera6e76d72022-02-11 21:43:505198 if not bad_macros:
5199 return []
lliabraa35bab3932014-10-01 12:16:445200
Sam Maiera6e76d72022-02-11 21:43:505201 return [
5202 output_api.PresubmitError(
5203 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5204 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5205 bad_macros)
5206 ]
lliabraa35bab3932014-10-01 12:16:445207
5208
Saagar Sanghavifceeaae2020-08-12 16:40:365209def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505210 """Check for same IPC rules described in
5211 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5212 """
5213 base_pattern = r'IPC_ENUM_TRAITS\('
5214 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5215 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045216
Sam Maiera6e76d72022-02-11 21:43:505217 problems = []
5218 for f in input_api.AffectedSourceFiles(None):
5219 local_path = f.LocalPath()
5220 if not local_path.endswith('.h'):
5221 continue
5222 for line_number, line in f.ChangedContents():
5223 if inclusion_pattern.search(
5224 line) and not comment_pattern.search(line):
5225 problems.append('%s:%d\n %s' %
5226 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045227
Sam Maiera6e76d72022-02-11 21:43:505228 if problems:
5229 return [
5230 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5231 problems)
5232 ]
5233 else:
5234 return []
mlamouria82272622014-09-16 18:45:045235
[email protected]b00342e7f2013-03-26 16:21:545236
Saagar Sanghavifceeaae2020-08-12 16:40:365237def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505238 """Check to make sure no files being submitted have long paths.
5239 This causes issues on Windows.
5240 """
5241 problems = []
5242 for f in input_api.AffectedTestableFiles():
5243 local_path = f.LocalPath()
5244 # Windows has a path limit of 260 characters. Limit path length to 200 so
5245 # that we have some extra for the prefix on dev machines and the bots.
5246 if len(local_path) > 200:
5247 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055248
Sam Maiera6e76d72022-02-11 21:43:505249 if problems:
5250 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5251 else:
5252 return []
Stephen Martinis97a394142018-06-07 23:06:055253
5254
Saagar Sanghavifceeaae2020-08-12 16:40:365255def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505256 """Check that header files have proper guards against multiple inclusion.
5257 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365258 should include the string "no-include-guard-because-multiply-included" or
5259 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505260 """
Daniel Bratell8ba52722018-03-02 16:06:145261
Sam Maiera6e76d72022-02-11 21:43:505262 def is_chromium_header_file(f):
5263 # We only check header files under the control of the Chromium
5264 # project. That is, those outside third_party apart from
5265 # third_party/blink.
5266 # We also exclude *_message_generator.h headers as they use
5267 # include guards in a special, non-typical way.
5268 file_with_path = input_api.os_path.normpath(f.LocalPath())
5269 return (file_with_path.endswith('.h')
5270 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335271 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505272 and (not file_with_path.startswith('third_party')
5273 or file_with_path.startswith(
5274 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145275
Sam Maiera6e76d72022-02-11 21:43:505276 def replace_special_with_underscore(string):
5277 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145278
Sam Maiera6e76d72022-02-11 21:43:505279 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145280
Sam Maiera6e76d72022-02-11 21:43:505281 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5282 guard_name = None
5283 guard_line_number = None
5284 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145285
Sam Maiera6e76d72022-02-11 21:43:505286 file_with_path = input_api.os_path.normpath(f.LocalPath())
5287 base_file_name = input_api.os_path.splitext(
5288 input_api.os_path.basename(file_with_path))[0]
5289 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145290
Sam Maiera6e76d72022-02-11 21:43:505291 expected_guard = replace_special_with_underscore(
5292 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145293
Sam Maiera6e76d72022-02-11 21:43:505294 # For "path/elem/file_name.h" we should really only accept
5295 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5296 # are too many (1000+) files with slight deviations from the
5297 # coding style. The most important part is that the include guard
5298 # is there, and that it's unique, not the name so this check is
5299 # forgiving for existing files.
5300 #
5301 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145302
Sam Maiera6e76d72022-02-11 21:43:505303 guard_name_pattern_list = [
5304 # Anything with the right suffix (maybe with an extra _).
5305 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145306
Sam Maiera6e76d72022-02-11 21:43:505307 # To cover include guards with old Blink style.
5308 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145309
Sam Maiera6e76d72022-02-11 21:43:505310 # Anything including the uppercase name of the file.
5311 r'\w*' + input_api.re.escape(
5312 replace_special_with_underscore(upper_base_file_name)) +
5313 r'\w*',
5314 ]
5315 guard_name_pattern = '|'.join(guard_name_pattern_list)
5316 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5317 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145318
Sam Maiera6e76d72022-02-11 21:43:505319 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365320 if ('no-include-guard-because-multiply-included' in line
5321 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505322 guard_name = 'DUMMY' # To not trigger check outside the loop.
5323 break
Daniel Bratell8ba52722018-03-02 16:06:145324
Sam Maiera6e76d72022-02-11 21:43:505325 if guard_name is None:
5326 match = guard_pattern.match(line)
5327 if match:
5328 guard_name = match.group(1)
5329 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145330
Sam Maiera6e76d72022-02-11 21:43:505331 # We allow existing files to use include guards whose names
5332 # don't match the chromium style guide, but new files should
5333 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495334 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165335 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505336 errors.append(
5337 output_api.PresubmitPromptWarning(
5338 'Header using the wrong include guard name %s'
5339 % guard_name, [
5340 '%s:%d' %
5341 (f.LocalPath(), line_number + 1)
5342 ], 'Expected: %r\nFound: %r' %
5343 (expected_guard, guard_name)))
5344 else:
5345 # The line after #ifndef should have a #define of the same name.
5346 if line_number == guard_line_number + 1:
5347 expected_line = '#define %s' % guard_name
5348 if line != expected_line:
5349 errors.append(
5350 output_api.PresubmitPromptWarning(
5351 'Missing "%s" for include guard' %
5352 expected_line,
5353 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5354 'Expected: %r\nGot: %r' %
5355 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145356
Sam Maiera6e76d72022-02-11 21:43:505357 if not seen_guard_end and line == '#endif // %s' % guard_name:
5358 seen_guard_end = True
5359 elif seen_guard_end:
5360 if line.strip() != '':
5361 errors.append(
5362 output_api.PresubmitPromptWarning(
5363 'Include guard %s not covering the whole file'
5364 % (guard_name), [f.LocalPath()]))
5365 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145366
Sam Maiera6e76d72022-02-11 21:43:505367 if guard_name is None:
5368 errors.append(
5369 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495370 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505371 'Recommended name: %s\n'
5372 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365373 '"no-include-guard-because-multiply-included" or\n'
5374 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505375 % (f.LocalPath(), expected_guard)))
5376
5377 return errors
Daniel Bratell8ba52722018-03-02 16:06:145378
5379
Saagar Sanghavifceeaae2020-08-12 16:40:365380def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505381 """Check source code and known ascii text files for Windows style line
5382 endings.
5383 """
Bruce Dawson5efbdc652022-04-11 19:29:515384 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235385
Sam Maiera6e76d72022-02-11 21:43:505386 file_inclusion_pattern = (known_text_files,
5387 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5388 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235389
Sam Maiera6e76d72022-02-11 21:43:505390 problems = []
5391 source_file_filter = lambda f: input_api.FilterSourceFile(
5392 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5393 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515394 # Ignore test files that contain crlf intentionally.
5395 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345396 continue
Sam Maiera6e76d72022-02-11 21:43:505397 include_file = False
5398 for line in input_api.ReadFile(f, 'r').splitlines(True):
5399 if line.endswith('\r\n'):
5400 include_file = True
5401 if include_file:
5402 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235403
Sam Maiera6e76d72022-02-11 21:43:505404 if problems:
5405 return [
5406 output_api.PresubmitPromptWarning(
5407 'Are you sure that you want '
5408 'these files to contain Windows style line endings?\n' +
5409 '\n'.join(problems))
5410 ]
mostynbb639aca52015-01-07 20:31:235411
Sam Maiera6e76d72022-02-11 21:43:505412 return []
5413
mostynbb639aca52015-01-07 20:31:235414
Evan Stade6cfc964c12021-05-18 20:21:165415def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505416 """Check that .icon files (which are fragments of C++) have license headers.
5417 """
Evan Stade6cfc964c12021-05-18 20:21:165418
Sam Maiera6e76d72022-02-11 21:43:505419 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165420
Sam Maiera6e76d72022-02-11 21:43:505421 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5422 return input_api.canned_checks.CheckLicense(input_api,
5423 output_api,
5424 source_file_filter=icons)
5425
Evan Stade6cfc964c12021-05-18 20:21:165426
Jose Magana2b456f22021-03-09 23:26:405427def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505428 """Check source code for use of Chrome App technologies being
5429 deprecated.
5430 """
Jose Magana2b456f22021-03-09 23:26:405431
Sam Maiera6e76d72022-02-11 21:43:505432 def _CheckForDeprecatedTech(input_api,
5433 output_api,
5434 detection_list,
5435 files_to_check=None,
5436 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405437
Sam Maiera6e76d72022-02-11 21:43:505438 if (files_to_check or files_to_skip):
5439 source_file_filter = lambda f: input_api.FilterSourceFile(
5440 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5441 else:
5442 source_file_filter = None
5443
5444 problems = []
5445
5446 for f in input_api.AffectedSourceFiles(source_file_filter):
5447 if f.Action() == 'D':
5448 continue
5449 for _, line in f.ChangedContents():
5450 if any(detect in line for detect in detection_list):
5451 problems.append(f.LocalPath())
5452
5453 return problems
5454
5455 # to avoid this presubmit script triggering warnings
5456 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405457
5458 problems = []
5459
Sam Maiera6e76d72022-02-11 21:43:505460 # NMF: any files with extensions .nmf or NMF
5461 _NMF_FILES = r'\.(nmf|NMF)$'
5462 problems += _CheckForDeprecatedTech(
5463 input_api,
5464 output_api,
5465 detection_list=[''], # any change to the file will trigger warning
5466 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405467
Sam Maiera6e76d72022-02-11 21:43:505468 # MANIFEST: any manifest.json that in its diff includes "app":
5469 _MANIFEST_FILES = r'(manifest\.json)$'
5470 problems += _CheckForDeprecatedTech(
5471 input_api,
5472 output_api,
5473 detection_list=['"app":'],
5474 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405475
Sam Maiera6e76d72022-02-11 21:43:505476 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5477 problems += _CheckForDeprecatedTech(
5478 input_api,
5479 output_api,
5480 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:315481 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:405482
Gao Shenga79ebd42022-08-08 17:25:595483 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505484 problems += _CheckForDeprecatedTech(
5485 input_api,
5486 output_api,
5487 detection_list=['#include "ppapi', '#include <ppapi'],
5488 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5489 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:315490 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:405491
Sam Maiera6e76d72022-02-11 21:43:505492 if problems:
5493 return [
5494 output_api.PresubmitPromptWarning(
5495 'You are adding/modifying code'
5496 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5497 ' PNaCl, PPAPI). See this blog post for more details:\n'
5498 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5499 'and this documentation for options to replace these technologies:\n'
5500 'https://developer.chrome.com/docs/apps/migration/\n' +
5501 '\n'.join(problems))
5502 ]
Jose Magana2b456f22021-03-09 23:26:405503
Sam Maiera6e76d72022-02-11 21:43:505504 return []
Jose Magana2b456f22021-03-09 23:26:405505
mostynbb639aca52015-01-07 20:31:235506
Saagar Sanghavifceeaae2020-08-12 16:40:365507def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505508 """Checks that all source files use SYSLOG properly."""
5509 syslog_files = []
5510 for f in input_api.AffectedSourceFiles(src_file_filter):
5511 for line_number, line in f.ChangedContents():
5512 if 'SYSLOG' in line:
5513 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565514
Sam Maiera6e76d72022-02-11 21:43:505515 if syslog_files:
5516 return [
5517 output_api.PresubmitPromptWarning(
5518 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5519 ' calls.\nFiles to check:\n',
5520 items=syslog_files)
5521 ]
5522 return []
pastarmovj89f7ee12016-09-20 14:58:135523
5524
[email protected]1f7b4172010-01-28 01:17:345525def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505526 if input_api.version < [2, 0, 0]:
5527 return [
5528 output_api.PresubmitError(
5529 "Your depot_tools is out of date. "
5530 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5531 "but your version is %d.%d.%d" % tuple(input_api.version))
5532 ]
5533 results = []
5534 results.extend(
5535 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5536 return results
[email protected]ca8d1982009-02-19 16:33:125537
5538
5539def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505540 if input_api.version < [2, 0, 0]:
5541 return [
5542 output_api.PresubmitError(
5543 "Your depot_tools is out of date. "
5544 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5545 "but your version is %d.%d.%d" % tuple(input_api.version))
5546 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365547
Sam Maiera6e76d72022-02-11 21:43:505548 results = []
5549 # Make sure the tree is 'open'.
5550 results.extend(
5551 input_api.canned_checks.CheckTreeIsOpen(
5552 input_api,
5553 output_api,
5554 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275555
Sam Maiera6e76d72022-02-11 21:43:505556 results.extend(
5557 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5558 results.extend(
5559 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5560 results.extend(
5561 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5562 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505563 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145564
5565
Saagar Sanghavifceeaae2020-08-12 16:40:365566def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505567 """Check string ICU syntax validity and if translation screenshots exist."""
5568 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5569 # footer is set to true.
5570 git_footers = input_api.change.GitFootersFromDescription()
5571 skip_screenshot_check_footer = [
5572 footer.lower() for footer in git_footers.get(
5573 u'Skip-Translation-Screenshots-Check', [])
5574 ]
5575 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025576
Sam Maiera6e76d72022-02-11 21:43:505577 import os
5578 import re
5579 import sys
5580 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145581
Sam Maiera6e76d72022-02-11 21:43:505582 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5583 if (f.Action() == 'A' or f.Action() == 'M'))
5584 removed_paths = set(f.LocalPath()
5585 for f in input_api.AffectedFiles(include_deletes=True)
5586 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145587
Sam Maiera6e76d72022-02-11 21:43:505588 affected_grds = [
5589 f for f in input_api.AffectedFiles()
5590 if f.LocalPath().endswith(('.grd', '.grdp'))
5591 ]
5592 affected_grds = [
5593 f for f in affected_grds if not 'testdata' in f.LocalPath()
5594 ]
5595 if not affected_grds:
5596 return []
meacer8c0d3832019-12-26 21:46:165597
Sam Maiera6e76d72022-02-11 21:43:505598 affected_png_paths = [
5599 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5600 if (f.LocalPath().endswith('.png'))
5601 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145602
Sam Maiera6e76d72022-02-11 21:43:505603 # Check for screenshots. Developers can upload screenshots using
5604 # tools/translation/upload_screenshots.py which finds and uploads
5605 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5606 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5607 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5608 #
5609 # The logic here is as follows:
5610 #
5611 # - If the CL has a .png file under the screenshots directory for a grd
5612 # file, warn the developer. Actual images should never be checked into the
5613 # Chrome repo.
5614 #
5615 # - If the CL contains modified or new messages in grd files and doesn't
5616 # contain the corresponding .sha1 files, warn the developer to add images
5617 # and upload them via tools/translation/upload_screenshots.py.
5618 #
5619 # - If the CL contains modified or new messages in grd files and the
5620 # corresponding .sha1 files, everything looks good.
5621 #
5622 # - If the CL contains removed messages in grd files but the corresponding
5623 # .sha1 files aren't removed, warn the developer to remove them.
5624 unnecessary_screenshots = []
5625 missing_sha1 = []
5626 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145627
Sam Maiera6e76d72022-02-11 21:43:505628 # This checks verifies that the ICU syntax of messages this CL touched is
5629 # valid, and reports any found syntax errors.
5630 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5631 # without developers being aware of them. Later on, such ICU syntax errors
5632 # break message extraction for translation, hence would block Chromium
5633 # translations until they are fixed.
5634 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145635
Sam Maiera6e76d72022-02-11 21:43:505636 def _CheckScreenshotAdded(screenshots_dir, message_id):
5637 sha1_path = input_api.os_path.join(screenshots_dir,
5638 message_id + '.png.sha1')
5639 if sha1_path not in new_or_added_paths:
5640 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145641
Sam Maiera6e76d72022-02-11 21:43:505642 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5643 sha1_path = input_api.os_path.join(screenshots_dir,
5644 message_id + '.png.sha1')
5645 if input_api.os_path.exists(
5646 sha1_path) and sha1_path not in removed_paths:
5647 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145648
Sam Maiera6e76d72022-02-11 21:43:505649 def _ValidateIcuSyntax(text, level, signatures):
5650 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145651
Sam Maiera6e76d72022-02-11 21:43:505652 Check if text looks similar to ICU and checks for ICU syntax correctness
5653 in this case. Reports various issues with ICU syntax and values of
5654 variants. Supports checking of nested messages. Accumulate information of
5655 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265656
Sam Maiera6e76d72022-02-11 21:43:505657 Args:
5658 text: a string to check.
5659 level: a number of current nesting level.
5660 signatures: an accumulator, a list of tuple of (level, variable,
5661 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265662
Sam Maiera6e76d72022-02-11 21:43:505663 Returns:
5664 None if a string is not ICU or no issue detected.
5665 A tuple of (message, start index, end index) if an issue detected.
5666 """
5667 valid_types = {
5668 'plural': (frozenset(
5669 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5670 'other']), frozenset(['=1', 'other'])),
5671 'selectordinal': (frozenset(
5672 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5673 'other']), frozenset(['one', 'other'])),
5674 'select': (frozenset(), frozenset(['other'])),
5675 }
Rainhard Findlingfc31844c52020-05-15 09:58:265676
Sam Maiera6e76d72022-02-11 21:43:505677 # Check if the message looks like an attempt to use ICU
5678 # plural. If yes - check if its syntax strictly matches ICU format.
5679 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5680 text)
5681 if not like:
5682 signatures.append((level, None, None, None))
5683 return
Rainhard Findlingfc31844c52020-05-15 09:58:265684
Sam Maiera6e76d72022-02-11 21:43:505685 # Check for valid prefix and suffix
5686 m = re.match(
5687 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5688 r'(plural|selectordinal|select),\s*'
5689 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5690 if not m:
5691 return (('This message looks like an ICU plural, '
5692 'but does not follow ICU syntax.'), like.start(),
5693 like.end())
5694 starting, variable, kind, variant_pairs = m.groups()
5695 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5696 m.start(4))
5697 if depth:
5698 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5699 len(text))
5700 first = text[0]
5701 ending = text[last_pos:]
5702 if not starting:
5703 return ('Invalid ICU format. No initial opening bracket',
5704 last_pos - 1, last_pos)
5705 if not ending or '}' not in ending:
5706 return ('Invalid ICU format. No final closing bracket',
5707 last_pos - 1, last_pos)
5708 elif first != '{':
5709 return ((
5710 'Invalid ICU format. Extra characters at the start of a complex '
5711 'message (go/icu-message-migration): "%s"') % starting, 0,
5712 len(starting))
5713 elif ending != '}':
5714 return ((
5715 'Invalid ICU format. Extra characters at the end of a complex '
5716 'message (go/icu-message-migration): "%s"') % ending,
5717 last_pos - 1, len(text) - 1)
5718 if kind not in valid_types:
5719 return (('Unknown ICU message type %s. '
5720 'Valid types are: plural, select, selectordinal') % kind,
5721 0, 0)
5722 known, required = valid_types[kind]
5723 defined_variants = set()
5724 for variant, variant_range, value, value_range in variants:
5725 start, end = variant_range
5726 if variant in defined_variants:
5727 return ('Variant "%s" is defined more than once' % variant,
5728 start, end)
5729 elif known and variant not in known:
5730 return ('Variant "%s" is not valid for %s message' %
5731 (variant, kind), start, end)
5732 defined_variants.add(variant)
5733 # Check for nested structure
5734 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5735 if res:
5736 return (res[0], res[1] + value_range[0] + 1,
5737 res[2] + value_range[0] + 1)
5738 missing = required - defined_variants
5739 if missing:
5740 return ('Required variants missing: %s' % ', '.join(missing), 0,
5741 len(text))
5742 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265743
Sam Maiera6e76d72022-02-11 21:43:505744 def _ParseIcuVariants(text, offset=0):
5745 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265746
Sam Maiera6e76d72022-02-11 21:43:505747 Builds a tuple of variant names and values, as well as
5748 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265749
Sam Maiera6e76d72022-02-11 21:43:505750 Args:
5751 text: a string to parse
5752 offset: additional offset to add to positions in the text to get correct
5753 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265754
Sam Maiera6e76d72022-02-11 21:43:505755 Returns:
5756 List of tuples, each tuple consist of four fields: variant name,
5757 variant name span (tuple of two integers), variant value, value
5758 span (tuple of two integers).
5759 """
5760 depth, start, end = 0, -1, -1
5761 variants = []
5762 key = None
5763 for idx, char in enumerate(text):
5764 if char == '{':
5765 if not depth:
5766 start = idx
5767 chunk = text[end + 1:start]
5768 key = chunk.strip()
5769 pos = offset + end + 1 + chunk.find(key)
5770 span = (pos, pos + len(key))
5771 depth += 1
5772 elif char == '}':
5773 if not depth:
5774 return variants, depth, offset + idx
5775 depth -= 1
5776 if not depth:
5777 end = idx
5778 variants.append((key, span, text[start:end + 1],
5779 (offset + start, offset + end + 1)))
5780 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265781
Sam Maiera6e76d72022-02-11 21:43:505782 try:
5783 old_sys_path = sys.path
5784 sys.path = sys.path + [
5785 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5786 'translation')
5787 ]
5788 from helper import grd_helper
5789 finally:
5790 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265791
Sam Maiera6e76d72022-02-11 21:43:505792 for f in affected_grds:
5793 file_path = f.LocalPath()
5794 old_id_to_msg_map = {}
5795 new_id_to_msg_map = {}
5796 # Note that this code doesn't check if the file has been deleted. This is
5797 # OK because it only uses the old and new file contents and doesn't load
5798 # the file via its path.
5799 # It's also possible that a file's content refers to a renamed or deleted
5800 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5801 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5802 # .grdp files.
5803 if file_path.endswith('.grdp'):
5804 if f.OldContents():
5805 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5806 '\n'.join(f.OldContents()))
5807 if f.NewContents():
5808 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5809 '\n'.join(f.NewContents()))
5810 else:
5811 file_dir = input_api.os_path.dirname(file_path) or '.'
5812 if f.OldContents():
5813 old_id_to_msg_map = grd_helper.GetGrdMessages(
5814 StringIO('\n'.join(f.OldContents())), file_dir)
5815 if f.NewContents():
5816 new_id_to_msg_map = grd_helper.GetGrdMessages(
5817 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265818
Sam Maiera6e76d72022-02-11 21:43:505819 grd_name, ext = input_api.os_path.splitext(
5820 input_api.os_path.basename(file_path))
5821 screenshots_dir = input_api.os_path.join(
5822 input_api.os_path.dirname(file_path),
5823 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265824
Sam Maiera6e76d72022-02-11 21:43:505825 # Compute added, removed and modified message IDs.
5826 old_ids = set(old_id_to_msg_map)
5827 new_ids = set(new_id_to_msg_map)
5828 added_ids = new_ids - old_ids
5829 removed_ids = old_ids - new_ids
5830 modified_ids = set([])
5831 for key in old_ids.intersection(new_ids):
5832 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5833 new_id_to_msg_map[key].ContentsAsXml('', True)):
5834 # The message content itself changed. Require an updated screenshot.
5835 modified_ids.add(key)
5836 elif old_id_to_msg_map[key].attrs['meaning'] != \
5837 new_id_to_msg_map[key].attrs['meaning']:
5838 # The message meaning changed. Ensure there is a screenshot for it.
5839 sha1_path = input_api.os_path.join(screenshots_dir,
5840 key + '.png.sha1')
5841 if sha1_path not in new_or_added_paths and not \
5842 input_api.os_path.exists(sha1_path):
5843 # There is neither a previous screenshot nor is a new one added now.
5844 # Require a screenshot.
5845 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145846
Sam Maiera6e76d72022-02-11 21:43:505847 if run_screenshot_check:
5848 # Check the screenshot directory for .png files. Warn if there is any.
5849 for png_path in affected_png_paths:
5850 if png_path.startswith(screenshots_dir):
5851 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145852
Sam Maiera6e76d72022-02-11 21:43:505853 for added_id in added_ids:
5854 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095855
Sam Maiera6e76d72022-02-11 21:43:505856 for modified_id in modified_ids:
5857 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145858
Sam Maiera6e76d72022-02-11 21:43:505859 for removed_id in removed_ids:
5860 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5861
5862 # Check new and changed strings for ICU syntax errors.
5863 for key in added_ids.union(modified_ids):
5864 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5865 err = _ValidateIcuSyntax(msg, 0, [])
5866 if err is not None:
5867 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5868
5869 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265870 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505871 if unnecessary_screenshots:
5872 results.append(
5873 output_api.PresubmitError(
5874 'Do not include actual screenshots in the changelist. Run '
5875 'tools/translate/upload_screenshots.py to upload them instead:',
5876 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145877
Sam Maiera6e76d72022-02-11 21:43:505878 if missing_sha1:
5879 results.append(
5880 output_api.PresubmitError(
5881 'You are adding or modifying UI strings.\n'
5882 'To ensure the best translations, take screenshots of the relevant UI '
5883 '(https://g.co/chrome/translation) and add these files to your '
5884 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145885
Sam Maiera6e76d72022-02-11 21:43:505886 if unnecessary_sha1_files:
5887 results.append(
5888 output_api.PresubmitError(
5889 'You removed strings associated with these files. Remove:',
5890 sorted(unnecessary_sha1_files)))
5891 else:
5892 results.append(
5893 output_api.PresubmitPromptOrNotify('Skipping translation '
5894 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145895
Sam Maiera6e76d72022-02-11 21:43:505896 if icu_syntax_errors:
5897 results.append(
5898 output_api.PresubmitPromptWarning(
5899 'ICU syntax errors were found in the following strings (problems or '
5900 'feedback? Contact [email protected]):',
5901 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265902
Sam Maiera6e76d72022-02-11 21:43:505903 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125904
5905
Saagar Sanghavifceeaae2020-08-12 16:40:365906def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125907 repo_root=None,
5908 translation_expectations_path=None,
5909 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505910 import sys
5911 affected_grds = [
5912 f for f in input_api.AffectedFiles()
5913 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5914 ]
5915 if not affected_grds:
5916 return []
5917
5918 try:
5919 old_sys_path = sys.path
5920 sys.path = sys.path + [
5921 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5922 'translation')
5923 ]
5924 from helper import git_helper
5925 from helper import translation_helper
5926 finally:
5927 sys.path = old_sys_path
5928
5929 # Check that translation expectations can be parsed and we can get a list of
5930 # translatable grd files. |repo_root| and |translation_expectations_path| are
5931 # only passed by tests.
5932 if not repo_root:
5933 repo_root = input_api.PresubmitLocalPath()
5934 if not translation_expectations_path:
5935 translation_expectations_path = input_api.os_path.join(
5936 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5937 if not grd_files:
5938 grd_files = git_helper.list_grds_in_repository(repo_root)
5939
5940 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:595941 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:505942 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
5943 'tests')
5944 grd_files = [p for p in grd_files if ignore_path not in p]
5945
5946 try:
5947 translation_helper.get_translatable_grds(
5948 repo_root, grd_files, translation_expectations_path)
5949 except Exception as e:
5950 return [
5951 output_api.PresubmitNotifyResult(
5952 'Failed to get a list of translatable grd files. This happens when:\n'
5953 ' - One of the modified grd or grdp files cannot be parsed or\n'
5954 ' - %s is not updated.\n'
5955 'Stack:\n%s' % (translation_expectations_path, str(e)))
5956 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:125957 return []
5958
Ken Rockotc31f4832020-05-29 18:58:515959
Saagar Sanghavifceeaae2020-08-12 16:40:365960def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505961 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5962 changed_mojoms = input_api.AffectedFiles(
5963 include_deletes=True,
5964 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525965
Bruce Dawson344ab262022-06-04 11:35:105966 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:505967 return []
5968
5969 delta = []
5970 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:505971 delta.append({
5972 'filename': mojom.LocalPath(),
5973 'old': '\n'.join(mojom.OldContents()) or None,
5974 'new': '\n'.join(mojom.NewContents()) or None,
5975 })
5976
5977 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:215978 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:505979 input_api.os_path.join(
5980 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
5981 'check_stable_mojom_compatibility.py'), '--src-root',
5982 input_api.PresubmitLocalPath()
5983 ],
5984 stdin=input_api.subprocess.PIPE,
5985 stdout=input_api.subprocess.PIPE,
5986 stderr=input_api.subprocess.PIPE,
5987 universal_newlines=True)
5988 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5989 if process.returncode:
5990 return [
5991 output_api.PresubmitError(
5992 'One or more [Stable] mojom definitions appears to have been changed '
5993 'in a way that is not backward-compatible.',
5994 long_text=error)
5995 ]
Erik Staabc734cd7a2021-11-23 03:11:525996 return []
5997
Dominic Battre645d42342020-12-04 16:14:105998def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505999 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106000
Sam Maiera6e76d72022-02-11 21:43:506001 def FilterFile(affected_file):
6002 """Accept only .cc files and the like."""
6003 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6004 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6005 input_api.DEFAULT_FILES_TO_SKIP)
6006 return input_api.FilterSourceFile(
6007 affected_file,
6008 files_to_check=file_inclusion_pattern,
6009 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106010
Sam Maiera6e76d72022-02-11 21:43:506011 def ModifiedLines(affected_file):
6012 """Returns a list of tuples (line number, line text) of added and removed
6013 lines.
Dominic Battre645d42342020-12-04 16:14:106014
Sam Maiera6e76d72022-02-11 21:43:506015 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106016
Sam Maiera6e76d72022-02-11 21:43:506017 This relies on the scm diff output describing each changed code section
6018 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106019
Sam Maiera6e76d72022-02-11 21:43:506020 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6021 """
6022 line_num = 0
6023 modified_lines = []
6024 for line in affected_file.GenerateScmDiff().splitlines():
6025 # Extract <new line num> of the patch fragment (see format above).
6026 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6027 line)
6028 if m:
6029 line_num = int(m.groups(1)[0])
6030 continue
6031 if ((line.startswith('+') and not line.startswith('++'))
6032 or (line.startswith('-') and not line.startswith('--'))):
6033 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106034
Sam Maiera6e76d72022-02-11 21:43:506035 if not line.startswith('-'):
6036 line_num += 1
6037 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106038
Sam Maiera6e76d72022-02-11 21:43:506039 def FindLineWith(lines, needle):
6040 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106041
Sam Maiera6e76d72022-02-11 21:43:506042 If 0 or >1 lines contain `needle`, -1 is returned.
6043 """
6044 matching_line_numbers = [
6045 # + 1 for 1-based counting of line numbers.
6046 i + 1 for i, line in enumerate(lines) if needle in line
6047 ]
6048 return matching_line_numbers[0] if len(
6049 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106050
Sam Maiera6e76d72022-02-11 21:43:506051 def ModifiedPrefMigration(affected_file):
6052 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6053 # Determine first and last lines of MigrateObsolete.*Pref functions.
6054 new_contents = affected_file.NewContents()
6055 range_1 = (FindLineWith(new_contents,
6056 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6057 FindLineWith(new_contents,
6058 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6059 range_2 = (FindLineWith(new_contents,
6060 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6061 FindLineWith(new_contents,
6062 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6063 if (-1 in range_1 + range_2):
6064 raise Exception(
6065 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6066 )
Dominic Battre645d42342020-12-04 16:14:106067
Sam Maiera6e76d72022-02-11 21:43:506068 # Check whether any of the modified lines are part of the
6069 # MigrateObsolete.*Pref functions.
6070 for line_nr, line in ModifiedLines(affected_file):
6071 if (range_1[0] <= line_nr <= range_1[1]
6072 or range_2[0] <= line_nr <= range_2[1]):
6073 return True
6074 return False
Dominic Battre645d42342020-12-04 16:14:106075
Sam Maiera6e76d72022-02-11 21:43:506076 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6077 browser_prefs_file_pattern = input_api.re.compile(
6078 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106079
Sam Maiera6e76d72022-02-11 21:43:506080 changes = input_api.AffectedFiles(include_deletes=True,
6081 file_filter=FilterFile)
6082 potential_problems = []
6083 for f in changes:
6084 for line in f.GenerateScmDiff().splitlines():
6085 # Check deleted lines for pref registrations.
6086 if (line.startswith('-') and not line.startswith('--')
6087 and register_pref_pattern.search(line)):
6088 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106089
Sam Maiera6e76d72022-02-11 21:43:506090 if browser_prefs_file_pattern.search(f.LocalPath()):
6091 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6092 # assume that they knew that they have to deprecate preferences and don't
6093 # warn.
6094 try:
6095 if ModifiedPrefMigration(f):
6096 return []
6097 except Exception as e:
6098 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106099
Sam Maiera6e76d72022-02-11 21:43:506100 if potential_problems:
6101 return [
6102 output_api.PresubmitPromptWarning(
6103 'Discovered possible removal of preference registrations.\n\n'
6104 'Please make sure to properly deprecate preferences by clearing their\n'
6105 'value for a couple of milestones before finally removing the code.\n'
6106 'Otherwise data may stay in the preferences files forever. See\n'
6107 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6108 'chrome/browser/prefs/README.md for examples.\n'
6109 'This may be a false positive warning (e.g. if you move preference\n'
6110 'registrations to a different place).\n', potential_problems)
6111 ]
6112 return []
6113
Matt Stark6ef08872021-07-29 01:21:466114
6115def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506116 """Changes to GRD files must be consistent for tools to read them."""
6117 changed_grds = input_api.AffectedFiles(
6118 include_deletes=False,
6119 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6120 errors = []
6121 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6122 for matcher, msg in _INVALID_GRD_FILE_LINE]
6123 for grd in changed_grds:
6124 for i, line in enumerate(grd.NewContents()):
6125 for matcher, msg in invalid_file_regexes:
6126 if matcher.search(line):
6127 errors.append(
6128 output_api.PresubmitError(
6129 'Problem on {grd}:{i} - {msg}'.format(
6130 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6131 return errors
6132
Kevin McNee967dd2d22021-11-15 16:09:296133
6134def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506135 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
6136 presence of MPArch features such as bfcache, prerendering, and fenced frames.
6137 """
Kevin McNee967dd2d22021-11-15 16:09:296138
Ian Vollickdba956c2022-04-20 23:53:456139 # Only consider top-level directories that (1) can use content APIs or
6140 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
6141 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:506142 files_to_check = (
Bruce Dawson40fece62022-09-16 19:58:316143 r'^(chrome|components|content|extensions|third_party/blink/renderer)/.+%s' %
Kevin McNee967dd2d22021-11-15 16:09:296144 _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:316145 r'^(chrome|components|content|extensions|third_party/blink/renderer)/.+%s' %
Sam Maiera6e76d72022-02-11 21:43:506146 _HEADER_EXTENSIONS,
6147 )
6148 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6149 input_api.DEFAULT_FILES_TO_SKIP)
6150 source_file_filter = lambda f: input_api.FilterSourceFile(
6151 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:296152
Kevin McNee29c0e8232022-08-05 15:36:096153 # Here we list the classes/methods we're monitoring. For the "fyi" cases,
6154 # we add the CL to the watchlist, but we don't omit a warning or have it be
6155 # included in the triage rotation.
Sam Maiera6e76d72022-02-11 21:43:506156 # Note that since these are are just regular expressions and we don't have
6157 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
6158 # could have a method named IsInMainFrame).
Kevin McNee29c0e8232022-08-05 15:36:096159 fyi_concerning_class_pattern = input_api.re.compile(
Sam Maiera6e76d72022-02-11 21:43:506160 r'WebContentsObserver|WebContentsUserData')
6161 # A subset of WebContentsObserver overrides where there's particular risk for
6162 # confusing tab and page level operations and data (e.g. incorrectly
6163 # resetting page state in DidFinishNavigation).
Kevin McNee29c0e8232022-08-05 15:36:096164 fyi_concerning_wco_methods = [
Sam Maiera6e76d72022-02-11 21:43:506165 'DidStartNavigation',
6166 'ReadyToCommitNavigation',
6167 'DidFinishNavigation',
6168 'RenderViewReady',
6169 'RenderViewDeleted',
6170 'RenderViewHostChanged',
Sam Maiera6e76d72022-02-11 21:43:506171 'DOMContentLoaded',
6172 'DidFinishLoad',
6173 ]
6174 concerning_nav_handle_methods = [
6175 'IsInMainFrame',
6176 ]
6177 concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:506178 'FromRenderFrameHost',
6179 'FromRenderViewHost',
Kevin McNee29c0e8232022-08-05 15:36:096180 ]
6181 fyi_concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:506182 'GetRenderViewHost',
6183 ]
6184 concerning_rfh_methods = [
6185 'GetParent',
6186 'GetMainFrame',
Kevin McNee29c0e8232022-08-05 15:36:096187 ]
6188 fyi_concerning_rfh_methods = [
Sam Maiera6e76d72022-02-11 21:43:506189 'GetFrameTreeNodeId',
6190 ]
Ian Vollickc825b1f2022-04-19 14:30:156191 concerning_rfhi_methods = [
6192 'is_main_frame',
6193 ]
Ian Vollicka77a73ea2022-04-06 18:08:016194 concerning_ftn_methods = [
6195 'IsMainFrame',
6196 ]
Ian Vollickdba956c2022-04-20 23:53:456197 concerning_blink_frame_methods = [
Ian Vollick4d785d22022-06-18 00:10:026198 'IsCrossOriginToNearestMainFrame',
Ian Vollickdba956c2022-04-20 23:53:456199 ]
Sam Maiera6e76d72022-02-11 21:43:506200 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
6201 item for sublist in [
Kevin McNee29c0e8232022-08-05 15:36:096202 concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:016203 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:156204 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:456205 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:506206 ] for item in sublist) + r')\(')
Kevin McNee29c0e8232022-08-05 15:36:096207 fyi_concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
6208 item for sublist in [
6209 fyi_concerning_wco_methods, fyi_concerning_web_contents_methods,
6210 fyi_concerning_rfh_methods,
6211 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:296212
Kevin McNee4eeec792022-02-14 20:02:046213 used_apis = set()
Kevin McNee29c0e8232022-08-05 15:36:096214 used_fyi_methods = False
Sam Maiera6e76d72022-02-11 21:43:506215 for f in input_api.AffectedFiles(include_deletes=False,
6216 file_filter=source_file_filter):
6217 for line_num, line in f.ChangedContents():
Kevin McNee29c0e8232022-08-05 15:36:096218 fyi_class_match = fyi_concerning_class_pattern.search(line)
6219 if fyi_class_match:
6220 used_fyi_methods = True
6221 fyi_method_match = fyi_concerning_method_pattern.search(line)
6222 if fyi_method_match:
6223 used_fyi_methods = True
Kevin McNee4eeec792022-02-14 20:02:046224 method_match = concerning_method_pattern.search(line)
6225 if method_match:
6226 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:506227
Kevin McNee4eeec792022-02-14 20:02:046228 if not used_apis:
Kevin McNee29c0e8232022-08-05 15:36:096229 if used_fyi_methods:
6230 output_api.AppendCC('[email protected]')
6231
Kevin McNee4eeec792022-02-14 20:02:046232 return []
Kevin McNee967dd2d22021-11-15 16:09:296233
Kevin McNee4eeec792022-02-14 20:02:046234 output_api.AppendCC('[email protected]')
6235 message = ('This change uses API(s) that are ambiguous in the presence of '
6236 'MPArch features such as bfcache, prerendering, and fenced '
6237 'frames.')
Kevin McNee29c0e8232022-08-05 15:36:096238 explanation = (
Kevin McNee4eeec792022-02-14 20:02:046239 'Please double check whether new code assumes that a WebContents only '
Kevin McNee29c0e8232022-08-05 15:36:096240 'contains a single page at a time. Notably, checking whether a frame '
6241 'is the \"main frame\" is not specific enough to determine whether it '
6242 'corresponds to the document reflected in the omnibox. A WebContents '
6243 'may have additional main frames for prerendered pages, bfcached '
6244 'pages, fenced frames, etc. '
6245 'See this doc [1] and the comments on the individual APIs '
Kevin McNee4eeec792022-02-14 20:02:046246 'for guidance and this doc [2] for context. The MPArch review '
6247 'watchlist has been CC\'d on this change to help identify any issues.\n'
6248 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
6249 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
6250 )
6251 return [
6252 output_api.PresubmitNotifyResult(message,
6253 items=list(used_apis),
Kevin McNee29c0e8232022-08-05 15:36:096254 long_text=explanation)
Kevin McNee4eeec792022-02-14 20:02:046255 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:366256
6257
6258def CheckAssertAshOnlyCode(input_api, output_api):
6259 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6260 assert(is_chromeos_ash).
6261 """
6262
6263 def FileFilter(affected_file):
6264 """Includes directories known to be Ash only."""
6265 return input_api.FilterSourceFile(
6266 affected_file,
6267 files_to_check=(
6268 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6269 r'.*/ash/.*BUILD\.gn'), # Any path component.
6270 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6271
6272 errors = []
6273 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566274 for f in input_api.AffectedFiles(include_deletes=False,
6275 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366276 if (not pattern.search(input_api.ReadFile(f))):
6277 errors.append(
6278 output_api.PresubmitError(
6279 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6280 'possible, please create and issue and add a comment such '
6281 'as:\n # TODO(https://crbug.com/XXX): add '
6282 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6283 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276284
6285
6286def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506287 path = affected_file.LocalPath()
6288 if not _IsCPlusPlusFile(input_api, path):
6289 return False
6290
6291 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6292 if "/renderer/" in path:
6293 return True
6294
6295 # Blink's public/web API is only used/included by Renderer-only code. Note
6296 # that public/platform API may be used in non-Renderer processes (e.g. there
6297 # are some includes in code used by Utility, PDF, or Plugin processes).
6298 if "/blink/public/web/" in path:
6299 return True
6300
6301 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276302 return False
6303
Lukasz Anforowicz7016d05e2021-11-30 03:56:276304# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6305# by the Chromium Clang Plugin (which will be preferable because it will
6306# 1) report errors earlier - at compile-time and 2) cover more rules).
6307def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506308 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6309 errors = []
6310 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6311 # C++ comment.
6312 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6313 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6314 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6315 if raw_ptr_matcher.search(line):
6316 errors.append(
6317 output_api.PresubmitError(
6318 'Problem on {path}:{line} - '\
6319 'raw_ptr<T> should not be used in Renderer-only code '\
6320 '(as documented in the "Pointers to unprotected memory" '\
6321 'section in //base/memory/raw_ptr.md)'.format(
6322 path=f.LocalPath(), line=line_num)))
6323 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566324
6325
6326def CheckPythonShebang(input_api, output_api):
6327 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6328 system-wide python.
6329 """
6330 errors = []
6331 sources = lambda affected_file: input_api.FilterSourceFile(
6332 affected_file,
6333 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6334 r'third_party/blink/web_tests/external/') + input_api.
6335 DEFAULT_FILES_TO_SKIP),
6336 files_to_check=[r'.*\.py$'])
6337 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276338 for line_num, line in f.ChangedContents():
6339 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6340 errors.append(f.LocalPath())
6341 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566342
6343 result = []
6344 for file in errors:
6345 result.append(
6346 output_api.PresubmitError(
6347 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6348 file))
6349 return result
James Shen81cc0e22022-06-15 21:10:456350
6351
6352def CheckBatchAnnotation(input_api, output_api):
6353 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6354 is not an instrumentation test, disregard."""
6355
6356 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6357 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6358 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6359 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6360 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6361
ckitagawae8fd23b2022-06-17 15:29:386362 missing_annotation_errors = []
6363 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456364
6365 def _FilterFile(affected_file):
6366 return input_api.FilterSourceFile(
6367 affected_file,
6368 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6369 files_to_check=[r'.*Test\.java$'])
6370
6371 for f in input_api.AffectedSourceFiles(_FilterFile):
6372 batch_matched = None
6373 do_not_batch_matched = None
6374 is_instrumentation_test = True
6375 for line in f.NewContents():
6376 if robolectric_test.search(line) or uiautomator_test.search(line):
6377 # Skip Robolectric and UiAutomator tests.
6378 is_instrumentation_test = False
6379 break
6380 if not batch_matched:
6381 batch_matched = batch_annotation.search(line)
6382 if not do_not_batch_matched:
6383 do_not_batch_matched = do_not_batch_annotation.search(line)
6384 test_class_declaration_matched = test_class_declaration.search(
6385 line)
6386 if test_class_declaration_matched:
6387 break
6388 if (is_instrumentation_test and
6389 not batch_matched and
6390 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246391 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386392 if (not is_instrumentation_test and
6393 (batch_matched or
6394 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246395 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456396
6397 results = []
6398
ckitagawae8fd23b2022-06-17 15:29:386399 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456400 results.append(
6401 output_api.PresubmitPromptWarning(
6402 """
6403Instrumentation tests should use either @Batch or @DoNotBatch. If tests are not
6404safe to run in batch, please use @DoNotBatch with reasons.
ckitagawae8fd23b2022-06-17 15:29:386405""", missing_annotation_errors))
6406 if extra_annotation_errors:
6407 results.append(
6408 output_api.PresubmitPromptWarning(
6409 """
6410Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6411""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456412
6413 return results
Sam Maier4cef9242022-10-03 14:21:246414
6415
6416def CheckMockAnnotation(input_api, output_api):
6417 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6418 classes with @Mock or @Spy. If this is not an instrumentation test,
6419 disregard."""
6420
6421 # This is just trying to be approximately correct. We are not writing a
6422 # Java parser, so special cases like statically importing mock() then
6423 # calling an unrelated non-mockito spy() function will cause a false
6424 # positive.
6425 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6426 mock_static_import = input_api.re.compile(
6427 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6428 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6429 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6430 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6431 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6432 fully_qualified_mock_function = input_api.re.compile(
6433 r'Mockito\.' + mock_or_spy_function_call)
6434 statically_imported_mock_function = input_api.re.compile(
6435 r'\W' + mock_or_spy_function_call)
6436 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6437 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6438
6439 def _DoClassLookup(class_name, class_name_map, package):
6440 found = class_name_map.get(class_name)
6441 if found is not None:
6442 return found
6443 else:
6444 return package + '.' + class_name
6445
6446 def _FilterFile(affected_file):
6447 return input_api.FilterSourceFile(
6448 affected_file,
6449 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6450 files_to_check=[r'.*Test\.java$'])
6451
6452 mocked_by_function_classes = set()
6453 mocked_by_annotation_classes = set()
6454 class_to_filename = {}
6455 for f in input_api.AffectedSourceFiles(_FilterFile):
6456 mock_function_regex = fully_qualified_mock_function
6457 next_line_is_annotated = False
6458 fully_qualified_class_map = {}
6459 package = None
6460
6461 for line in f.NewContents():
6462 if robolectric_test.search(line) or uiautomator_test.search(line):
6463 # Skip Robolectric and UiAutomator tests.
6464 break
6465
6466 m = package_name.search(line)
6467 if m:
6468 package = m.group(1)
6469 continue
6470
6471 if mock_static_import.search(line):
6472 mock_function_regex = statically_imported_mock_function
6473 continue
6474
6475 m = import_class.search(line)
6476 if m:
6477 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
6478 continue
6479
6480 if next_line_is_annotated:
6481 next_line_is_annotated = False
6482 fully_qualified_class = _DoClassLookup(
6483 field_type.search(line).group(1), fully_qualified_class_map,
6484 package)
6485 mocked_by_annotation_classes.add(fully_qualified_class)
6486 continue
6487
6488 if mock_annotation.search(line):
6489 next_line_is_annotated = True
6490 continue
6491
6492 m = mock_function_regex.search(line)
6493 if m:
6494 fully_qualified_class = _DoClassLookup(m.group(1),
6495 fully_qualified_class_map, package)
6496 # Skipping builtin classes, since they don't get optimized.
6497 if fully_qualified_class.startswith(
6498 'android.') or fully_qualified_class.startswith(
6499 'java.'):
6500 continue
6501 class_to_filename[fully_qualified_class] = str(f.LocalPath())
6502 mocked_by_function_classes.add(fully_qualified_class)
6503
6504 results = []
6505 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
6506 if missed_classes:
6507 error_locations = []
6508 for c in missed_classes:
6509 error_locations.append(c + ' in ' + class_to_filename[c])
6510 results.append(
6511 output_api.PresubmitPromptWarning(
6512 """
6513Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
65141) If the mocked variable can be a class member, annotate the member with
6515 @Mock/@Spy.
65162) If the mocked variable cannot be a class member, create a dummy member
6517 variable of that type, annotated with @Mock/@Spy. This dummy does not need
6518 to be used or initialized in any way.
65193) If the mocked type is definitely not going to be optimized, whether it's a
6520 builtin type which we don't ship, or a class you know R8 will treat
6521 specially, you can ignore this warning.
6522""", error_locations))
6523
6524 return results