blob: f10beeccdf4ce1fa586f7f34fa0ebf65f1db847e [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
14from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1217
Dirk Prankee3c9c62d2021-05-18 18:35:5918# This line is 'magic' in that git-cl looks for it to decide whether to
19# use Python3 instead of Python2 when running the code in this file.
20USE_PYTHON3 = True
21
[email protected]379e7dd2010-01-28 17:39:2122_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1823 # Generated file
Bruce 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]ca8d19842009-02-19 16:33:1254
John Abd-El-Malek759fea62021-03-13 03:41:1455_EXCLUDED_SET_NO_PARENT_PATHS = (
56 # It's for historical reasons that blink isn't a top level directory, where
57 # it would be allowed to have "set noparent" to avoid top level owners
58 # accidentally +1ing changes.
59 'third_party/blink/OWNERS',
60)
61
wnwenbdc444e2016-05-25 13:44:1562
[email protected]06e6d0ff2012-12-11 01:36:4463# Fragment of a regular expression that matches C++ and Objective-C++
64# implementation files.
65_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
66
wnwenbdc444e2016-05-25 13:44:1567
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1968# Fragment of a regular expression that matches C++ and Objective-C++
69# header files.
70_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
71
72
Aleksey Khoroshilov9b28c032022-06-03 16:35:3273# Paths with sources that don't use //base.
74_NON_BASE_DEPENDENT_PATHS = (
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]ca8d19842009-02-19 16:33:12109
Daniel Bratell609102be2019-03-27 20:53:21110_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15111
[email protected]eea609a2011-11-18 13:10:12112_TEST_ONLY_WARNING = (
113 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55114 'production code. If you are doing this from inside another method\n'
115 'named as *ForTesting(), then consider exposing things to have tests\n'
116 'make that same call directly.\n'
117 'If that is not possible, you may put a comment on the same line with\n'
118 ' // IN-TEST \n'
119 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
120 'method and can be ignored. Do not do this inside production code.\n'
121 'The android-binary-size trybot will block if the method exists in the\n'
122 'release apk.')
[email protected]eea609a2011-11-18 13:10:12123
124
Daniel Chenga44a1bcd2022-03-15 20:00:15125@dataclass
126class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34127 # String pattern. If the pattern begins with a slash, the pattern will be
128 # treated as a regular expression instead.
129 pattern: str
130 # Explanation as a sequence of strings. Each string in the sequence will be
131 # printed on its own line.
132 explanation: Sequence[str]
133 # Whether or not to treat this ban as a fatal error. If unspecified,
134 # defaults to true.
135 treat_as_error: Optional[bool] = None
136 # Paths that should be excluded from the ban check. Each string is a regular
137 # expression that will be matched against the path of the file being checked
138 # relative to the root of the source tree.
139 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28140
Daniel Chenga44a1bcd2022-03-15 20:00:15141
Daniel Cheng917ce542022-03-15 20:46:57142_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15143 BanRule(
144 'import java.net.URI;',
145 (
146 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
147 ),
148 excluded_paths=(
149 (r'net/android/javatests/src/org/chromium/net/'
150 'AndroidProxySelectorTest\.java'),
151 r'components/cronet/',
152 r'third_party/robolectric/local/',
153 ),
Michael Thiessen44457642020-02-06 00:24:15154 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15155 BanRule(
156 'import android.annotation.TargetApi;',
157 (
158 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
159 'RequiresApi ensures that any calls are guarded by the appropriate '
160 'SDK_INT check. See https://crbug.com/1116486.',
161 ),
162 ),
163 BanRule(
164 'import android.support.test.rule.UiThreadTestRule;',
165 (
166 'Do not use UiThreadTestRule, just use '
167 '@org.chromium.base.test.UiThreadTest on test methods that should run '
168 'on the UI thread. See https://crbug.com/1111893.',
169 ),
170 ),
171 BanRule(
172 'import android.support.test.annotation.UiThreadTest;',
173 ('Do not use android.support.test.annotation.UiThreadTest, use '
174 'org.chromium.base.test.UiThreadTest instead. See '
175 'https://crbug.com/1111893.',
176 ),
177 ),
178 BanRule(
179 'import android.support.test.rule.ActivityTestRule;',
180 (
181 'Do not use ActivityTestRule, use '
182 'org.chromium.base.test.BaseActivityTestRule instead.',
183 ),
184 excluded_paths=(
185 'components/cronet/',
186 ),
187 ),
188)
wnwenbdc444e2016-05-25 13:44:15189
Daniel Cheng917ce542022-03-15 20:46:57190_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15191 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41192 'StrictMode.allowThreadDiskReads()',
193 (
194 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
195 'directly.',
196 ),
197 False,
198 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15199 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41200 'StrictMode.allowThreadDiskWrites()',
201 (
202 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
203 'directly.',
204 ),
205 False,
206 ),
Daniel Cheng917ce542022-03-15 20:46:57207 BanRule(
Michael 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 ),
Ashley Newson09cbd602022-10-26 11:40:14215 BanRule(
216 r'/(?<!\bsuper\.)(?<!\bIntent )registerReceiver\(',
217 (
218 'Do not call android.content.Context.registerReceiver (or an override) '
219 'directly. Use one of the wrapper methods defined in '
220 'org.chromium.base.ContextUtils, such as '
221 'registerProtectedBroadcastReceiver, '
222 'registerExportedBroadcastReceiver, or '
223 'registerNonExportedBroadcastReceiver. See their documentation for '
224 'which one to use.',
225 ),
226 True,
227 excluded_paths=(
228 r'Test[^a-z]',
229 r'^third_party/',
230 'base/android/java/src/org/chromium/base/ContextUtils.java',
231 ),
232 ),
Eric Stevensona9a980972017-09-23 00:04:41233)
234
Daniel Cheng917ce542022-03-15 20:46:57235_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15236 BanRule(
[email protected]127f18ec2012-06-16 05:05:59237 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20238 (
239 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59240 'prohibited. Please use CrTrackingArea instead.',
241 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
242 ),
243 False,
244 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15245 BanRule(
[email protected]eaae1972014-04-16 04:17:26246 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20247 (
248 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59249 'instead.',
250 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
251 ),
252 False,
253 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15254 BanRule(
[email protected]127f18ec2012-06-16 05:05:59255 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20256 (
257 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59258 'Please use |convertPoint:(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 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20265 (
266 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59267 'Please use |convertPoint:(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 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20274 (
275 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59276 'Please use |convertRect:(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 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20283 (
284 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59285 'Please use |convertRect:(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(
[email protected]127f18ec2012-06-16 05:05:59291 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20292 (
293 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59294 'Please use |convertSize:(point) fromView:nil| instead.',
295 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
296 ),
297 True,
298 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15299 BanRule(
[email protected]127f18ec2012-06-16 05:05:59300 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20301 (
302 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59303 'Please use |convertSize:(point) toView:nil| instead.',
304 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
305 ),
306 True,
307 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15308 BanRule(
jif65398702016-10-27 10:19:48309 r"/\s+UTF8String\s*]",
310 (
311 'The use of -[NSString UTF8String] is dangerous as it can return null',
312 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
313 'Please use |SysNSStringToUTF8| instead.',
314 ),
315 True,
316 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15317 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34318 r'__unsafe_unretained',
319 (
320 'The use of __unsafe_unretained is almost certainly wrong, unless',
321 'when interacting with NSFastEnumeration or NSInvocation.',
322 'Please use __weak in files build with ARC, nothing otherwise.',
323 ),
324 False,
325 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15326 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13327 'freeWhenDone:NO',
328 (
329 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
330 'Foundation types is prohibited.',
331 ),
332 True,
333 ),
[email protected]127f18ec2012-06-16 05:05:59334)
335
Sylvain Defresnea8b73d252018-02-28 15:45:54336_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15337 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54338 r'/\bTEST[(]',
339 (
340 'TEST() macro should not be used in Objective-C++ code as it does not ',
341 'drain the autorelease pool at the end of the test. Use TEST_F() ',
342 'macro instead with a fixture inheriting from PlatformTest (or a ',
343 'typedef).'
344 ),
345 True,
346 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15347 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54348 r'/\btesting::Test\b',
349 (
350 'testing::Test should not be used in Objective-C++ code as it does ',
351 'not drain the autorelease pool at the end of the test. Use ',
352 'PlatformTest instead.'
353 ),
354 True,
355 ),
Ewann2ecc8d72022-07-18 07:41:23356 BanRule(
357 ' systemImageNamed:',
358 (
359 '+[UIImage systemImageNamed:] should not be used to create symbols.',
360 'Instead use a wrapper defined in:',
361 'ios/chrome/browser/ui/icons/chrome_symbol.h'
362 ),
363 True,
Ewann450a2ef2022-07-19 14:38:23364 excluded_paths=(
365 'ios/chrome/browser/ui/icons/chrome_symbol.mm',
366 ),
Ewann2ecc8d72022-07-18 07:41:23367 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54368)
369
Daniel Cheng917ce542022-03-15 20:46:57370_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15371 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05372 r'/\bEXPECT_OCMOCK_VERIFY\b',
373 (
374 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
375 'it is meant for GTests. Use [mock verify] instead.'
376 ),
377 True,
378 ),
379)
380
Daniel Cheng917ce542022-03-15 20:46:57381_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15382 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04383 r'/\busing namespace ',
384 (
385 'Using directives ("using namespace x") are banned by the Google Style',
386 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
387 'Explicitly qualify symbols or use using declarations ("using x::foo").',
388 ),
389 True,
390 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
391 ),
Antonio Gomes07300d02019-03-13 20:59:57392 # Make sure that gtest's FRIEND_TEST() macro is not used; the
393 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
394 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15395 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20396 'FRIEND_TEST(',
397 (
[email protected]e3c945502012-06-26 20:01:49398 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20399 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
400 ),
401 False,
[email protected]7345da02012-11-27 14:31:49402 (),
[email protected]23e6cbc2012-06-16 18:51:20403 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15404 BanRule(
tomhudsone2c14d552016-05-26 17:07:46405 'setMatrixClip',
406 (
407 'Overriding setMatrixClip() is prohibited; ',
408 'the base function is deprecated. ',
409 ),
410 True,
411 (),
412 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15413 BanRule(
[email protected]52657f62013-05-20 05:30:31414 'SkRefPtr',
415 (
416 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22417 '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 'SkAutoRef',
424 (
425 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22426 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31427 ),
428 True,
429 (),
430 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15431 BanRule(
[email protected]52657f62013-05-20 05:30:31432 'SkAutoTUnref',
433 (
434 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22435 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31436 ),
437 True,
438 (),
439 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15440 BanRule(
[email protected]52657f62013-05-20 05:30:31441 'SkAutoUnref',
442 (
443 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
444 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22445 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31446 ),
447 True,
448 (),
449 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15450 BanRule(
[email protected]d89eec82013-12-03 14:10:59451 r'/HANDLE_EINTR\(.*close',
452 (
453 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
454 'descriptor will be closed, and it is incorrect to retry the close.',
455 'Either call close directly and ignore its return value, or wrap close',
456 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
457 ),
458 True,
459 (),
460 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15461 BanRule(
[email protected]d89eec82013-12-03 14:10:59462 r'/IGNORE_EINTR\((?!.*close)',
463 (
464 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
465 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
466 ),
467 True,
468 (
469 # Files that #define IGNORE_EINTR.
Bruce Dawson40fece62022-09-16 19:58:31470 r'^base/posix/eintr_wrapper\.h$',
471 r'^ppapi/tests/test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59472 ),
473 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15474 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43475 r'/v8::Extension\(',
476 (
477 'Do not introduce new v8::Extensions into the code base, use',
478 'gin::Wrappable instead. See http://crbug.com/334679',
479 ),
480 True,
[email protected]f55c90ee62014-04-12 00:50:03481 (
Bruce Dawson40fece62022-09-16 19:58:31482 r'extensions/renderer/safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03483 ),
[email protected]ec5b3f02014-04-04 18:43:43484 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15485 BanRule(
jame2d1a952016-04-02 00:27:10486 '#pragma comment(lib,',
487 (
488 'Specify libraries to link with in build files and not in the source.',
489 ),
490 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41491 (
Bruce Dawson40fece62022-09-16 19:58:31492 r'^base/third_party/symbolize/.*',
493 r'^third_party/abseil-cpp/.*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41494 ),
jame2d1a952016-04-02 00:27:10495 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15496 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02497 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59498 (
499 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
500 ),
501 False,
502 (),
503 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15504 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02505 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59506 (
507 'Consider using THREAD_CHECKER macros instead of the class directly.',
508 ),
509 False,
510 (),
511 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15512 BanRule(
Sean Maher03efef12022-09-23 22:43:13513 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
514 (
515 'It is not allowed to call these methods from the subclasses ',
516 'of Sequenced or SingleThread task runners.',
517 ),
518 True,
519 (),
520 ),
521 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06522 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
523 (
524 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
525 'deprecated (http://crbug.com/634507). Please avoid converting away',
526 'from the Time types in Chromium code, especially if any math is',
527 'being done on time values. For interfacing with platform/library',
528 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
529 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48530 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06531 'other use cases, please contact base/time/OWNERS.',
532 ),
533 False,
534 (),
535 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15536 BanRule(
dbeamb6f4fde2017-06-15 04:03:06537 'CallJavascriptFunctionUnsafe',
538 (
539 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
540 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
541 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
542 ),
543 False,
544 (
Bruce Dawson40fece62022-09-16 19:58:31545 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
546 r'^content/public/browser/web_ui\.h$',
547 r'^content/public/test/test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06548 ),
549 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15550 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24551 'leveldb::DB::Open',
552 (
553 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
554 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
555 "Chrome's tracing, making their memory usage visible.",
556 ),
557 True,
558 (
559 r'^third_party/leveldatabase/.*\.(cc|h)$',
560 ),
Gabriel Charette0592c3a2017-07-26 12:02:04561 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15562 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08563 'leveldb::NewMemEnv',
564 (
565 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58566 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
567 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08568 ),
569 True,
570 (
571 r'^third_party/leveldatabase/.*\.(cc|h)$',
572 ),
573 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15574 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47575 'RunLoop::QuitCurrent',
576 (
Robert Liao64b7ab22017-08-04 23:03:43577 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
578 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47579 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41580 False,
Gabriel Charetted9839bc2017-07-29 14:17:47581 (),
Gabriel Charettea44975052017-08-21 23:14:04582 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15583 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04584 'base::ScopedMockTimeMessageLoopTaskRunner',
585 (
Gabriel Charette87cc1af2018-04-25 20:52:51586 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11587 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51588 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
589 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
590 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04591 ),
Gabriel Charette87cc1af2018-04-25 20:52:51592 False,
Gabriel Charettea44975052017-08-21 23:14:04593 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57594 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15595 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44596 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57597 (
598 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02599 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57600 ),
601 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16602 # Abseil's benchmarks never linked into chrome.
603 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38604 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15605 BanRule(
Peter Kasting991618a62019-06-17 22:00:09606 r'/\bstd::stoi\b',
607 (
608 'std::stoi uses exceptions to communicate results. ',
609 'Use base::StringToInt() 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::stol\b',
616 (
617 'std::stol uses exceptions to communicate results. ',
618 'Use base::StringToInt() 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::stoul\b',
625 (
626 'std::stoul uses exceptions to communicate results. ',
627 'Use base::StringToUint() 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::stoll\b',
634 (
635 'std::stoll uses exceptions to communicate results. ',
636 'Use base::StringToInt64() instead.',
637 ),
638 True,
639 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
640 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15641 BanRule(
Peter Kasting991618a62019-06-17 22:00:09642 r'/\bstd::stoull\b',
643 (
644 'std::stoull uses exceptions to communicate results. ',
645 'Use base::StringToUint64() instead.',
646 ),
647 True,
648 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
649 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15650 BanRule(
Peter Kasting991618a62019-06-17 22:00:09651 r'/\bstd::stof\b',
652 (
653 'std::stof uses exceptions to communicate results. ',
654 'For locale-independent values, e.g. reading numbers from disk',
655 'profiles, use base::StringToDouble().',
656 'For user-visible values, parse using ICU.',
657 ),
658 True,
659 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
660 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15661 BanRule(
Peter Kasting991618a62019-06-17 22:00:09662 r'/\bstd::stod\b',
663 (
664 'std::stod uses exceptions to communicate results. ',
665 'For locale-independent values, e.g. reading numbers from disk',
666 'profiles, use base::StringToDouble().',
667 'For user-visible values, parse using ICU.',
668 ),
669 True,
670 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
671 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15672 BanRule(
Peter Kasting991618a62019-06-17 22:00:09673 r'/\bstd::stold\b',
674 (
675 'std::stold uses exceptions to communicate results. ',
676 'For locale-independent values, e.g. reading numbers from disk',
677 'profiles, use base::StringToDouble().',
678 'For user-visible values, parse using ICU.',
679 ),
680 True,
681 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
682 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15683 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45684 r'/\bstd::to_string\b',
685 (
686 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09687 'For locale-independent strings, e.g. writing numbers to disk',
688 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45689 'For user-visible strings, use base::FormatNumber() and',
690 'the related functions in base/i18n/number_formatting.h.',
691 ),
Peter Kasting991618a62019-06-17 22:00:09692 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21693 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45694 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15695 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45696 r'/\bstd::shared_ptr\b',
697 (
698 'std::shared_ptr should not be used. Use scoped_refptr instead.',
699 ),
700 True,
Ulan Degenbaev947043882021-02-10 14:02:31701 [
702 # Needed for interop with third-party library.
703 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57704 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58705 '^third_party/blink/renderer/bindings/core/v8/' +
706 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58707 '^gin/array_buffer\.(cc|h)',
708 '^chrome/services/sharing/nearby/',
Stephen Nuskoe09c8ef22022-09-29 00:47:28709 # Needed for interop with third-party library libunwindstack.
Stephen Nuskoe51c1382022-09-26 15:49:03710 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
Meilin Wang00efc7c2021-05-13 01:12:42711 # gRPC provides some C++ libraries that use std::shared_ptr<>.
Yeunjoo Choi1b644402022-08-25 02:36:10712 '^chromeos/ash/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59713 '^chromecast/cast_core/grpc',
714 '^chromecast/cast_core/runtime/browser',
Yue Shef83d95202022-09-26 20:23:45715 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Wez5f56be52021-05-04 09:30:58716 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Fabrice de Gans3b875422022-04-19 19:40:26717 '^base/fuchsia/filtered_service_directory\.(cc|h)',
718 '^base/fuchsia/service_directory_test_base\.h',
Wez5f56be52021-05-04 09:30:58719 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57720 # Needed for clang plugin tests
721 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57722 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21723 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15724 BanRule(
Peter Kasting991618a62019-06-17 22:00:09725 r'/\bstd::weak_ptr\b',
726 (
727 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
728 ),
729 True,
730 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
731 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15732 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21733 r'/\blong long\b',
734 (
735 'long long is banned. Use stdint.h if you need a 64 bit number.',
736 ),
737 False, # Only a warning since it is already used.
738 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
739 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15740 BanRule(
Daniel Chengc05fcc62022-01-12 16:54:29741 r'\b(absl|std)::any\b',
742 (
Daniel Chenga44a1bcd2022-03-15 20:00:15743 'absl::any / std::any are not safe to use in a component build.',
Daniel Chengc05fcc62022-01-12 16:54:29744 ),
745 True,
746 # Not an error in third party folders, though it probably should be :)
747 [_THIRD_PARTY_EXCEPT_BLINK],
748 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15749 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21750 r'/\bstd::bind\b',
751 (
752 'std::bind is banned because of lifetime risks.',
753 'Use base::BindOnce or base::BindRepeating instead.',
754 ),
755 True,
756 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
757 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15758 BanRule(
Peter Kasting4f35bfc2022-10-18 18:39:12759 r'/\babsl::bind_front\b',
760 (
761 'absl::bind_front is banned. Use base::Bind instead.',
762 ),
763 True,
764 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
765 ),
766 BanRule(
767 r'/\bABSL_FLAG\b',
768 (
769 'ABSL_FLAG is banned. Use base::CommandLine instead.',
770 ),
771 True,
772 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
773 ),
774 BanRule(
775 r'/\babsl::c_',
776 (
777 'Abseil container utilities are banned. Use base/ranges/algorithm.h',
778 'instead.',
779 ),
780 True,
781 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
782 ),
783 BanRule(
784 r'/\babsl::FunctionRef\b',
785 (
786 'absl::FunctionRef is banned. Use base::FunctionRef instead.',
787 ),
788 True,
789 [
790 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
791 # interoperability.
792 r'^base/functional/bind_internal\.h',
793 # base::FunctionRef is implemented on top of absl::FunctionRef.
794 r'^base/functional/function_ref.*\..+',
795 # Not an error in third_party folders.
796 _THIRD_PARTY_EXCEPT_BLINK,
797 ],
798 ),
799 BanRule(
800 r'/\babsl::(Insecure)?BitGen\b',
801 (
802 'Abseil random number generators are banned. Use base/rand_util.h',
803 'instead.',
804 ),
805 True,
806 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
807 ),
808 BanRule(
809 r'/\babsl::Span\b',
810 (
811 'absl::Span is banned. Use base::span instead.',
812 ),
813 True,
814 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
815 ),
816 BanRule(
817 r'/\babsl::StatusOr\b',
818 (
819 'absl::StatusOr is banned. Use base::expected instead.',
820 ),
821 True,
Adithya Srinivasanb2041882022-10-21 19:34:20822 [
823 # Needed to use liburlpattern API.
824 r'third_party/blink/renderer/core/url_pattern/.*',
825 # Not an error in third_party folders.
826 _THIRD_PARTY_EXCEPT_BLINK
827 ],
Peter Kasting4f35bfc2022-10-18 18:39:12828 ),
829 BanRule(
830 r'/\babsl::StrFormat\b',
831 (
832 'absl::StrFormat is banned for now. Use base::StringPrintf instead.',
833 ),
834 True,
835 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
836 ),
837 BanRule(
838 r'/\babsl::string_view\b',
839 (
840 'absl::string_view is banned. Use base::StringPiece instead.',
841 ),
842 True,
Adithya Srinivasanb2041882022-10-21 19:34:20843 [
844 # Needed to use liburlpattern API.
845 r'third_party/blink/renderer/core/url_pattern/.*',
846 # Not an error in third_party folders.
847 _THIRD_PARTY_EXCEPT_BLINK
848 ],
Peter Kasting4f35bfc2022-10-18 18:39:12849 ),
850 BanRule(
851 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
852 (
853 'Abseil string utilities are banned. Use base/strings instead.',
854 ),
855 True,
856 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
857 ),
858 BanRule(
859 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
860 (
861 'Abseil synchronization primitives are banned. Use',
862 'base/synchronization instead.',
863 ),
864 True,
865 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
866 ),
867 BanRule(
868 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
869 (
870 'Abseil\'s time library is banned. Use base/time instead.',
871 ),
872 True,
873 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
874 ),
875 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:03876 r'/\bstd::optional\b',
877 (
878 'std::optional is banned. Use absl::optional instead.',
879 ),
880 True,
881 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
882 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15883 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21884 r'/\b#include <chrono>\b',
885 (
886 '<chrono> overlaps with Time APIs in base. Keep using',
887 'base classes.',
888 ),
889 True,
890 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
891 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15892 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21893 r'/\b#include <exception>\b',
894 (
895 'Exceptions are banned and disabled in Chromium.',
896 ),
897 True,
898 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
899 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15900 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21901 r'/\bstd::function\b',
902 (
Colin Blundellea615d422021-05-12 09:35:41903 'std::function is banned. Instead use base::OnceCallback or ',
904 'base::RepeatingCallback, which directly support Chromium\'s weak ',
905 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21906 ),
Daniel Chenge5583e3c2022-09-22 00:19:41907 True,
Daniel Chengcd23b8b2022-09-16 17:16:24908 [
909 # Has tests that template trait helpers don't unintentionally match
910 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:41911 r'base/functional/callback_helpers_unittest\.cc',
912 # Required to implement interfaces from the third-party perfetto
913 # library.
914 r'base/tracing/perfetto_task_runner\.cc',
915 r'base/tracing/perfetto_task_runner\.h',
916 # Needed for interop with the third-party nearby library type
917 # location::nearby::connections::ResultCallback.
918 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
919 # Needed for interop with the internal libassistant library.
920 'chromeos/ash/services/libassistant/callback_utils\.h',
921 # Needed for interop with Fuchsia fidl APIs.
922 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
923 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
924 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
925 # Required to interop with interfaces from the third-party perfetto
926 # library.
927 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
928 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
929 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
930 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
931 'services/tracing/public/cpp/perfetto/producer_client\.cc',
932 'services/tracing/public/cpp/perfetto/producer_client\.h',
933 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
934 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
935 # Required for interop with the third-party webrtc library.
936 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
937 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
938
939 # TODO(https://crbug.com/1364577): Various uses that should be
940 # migrated to something else.
941 # Should use base::OnceCallback or base::RepeatingCallback.
942 'base/allocator/dispatcher/initializer_unittest\.cc',
943 'chrome/browser/ash/accessibility/speech_monitor\.cc',
944 'chrome/browser/ash/accessibility/speech_monitor\.h',
945 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
946 'chromecast/base/observer_unittest\.cc',
947 'chromecast/browser/cast_web_view\.h',
948 'chromecast/public/cast_media_shlib\.h',
949 'device/bluetooth/floss/exported_callback_manager\.h',
950 'device/bluetooth/floss/floss_dbus_client\.h',
951 'device/fido/cable/v2_handshake_unittest\.cc',
952 'device/fido/pin\.cc',
953 'services/tracing/perfetto/test_utils\.h',
954 # Should use base::FunctionRef.
955 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
956 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
957 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
958 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
959 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
960 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
961 # Does not need std::function at all.
962 'components/omnibox/browser/autocomplete_result\.cc',
963 'device/fido/win/webauthn_api\.cc',
964 'media/audio/alsa/alsa_util\.cc',
965 'media/remoting/stream_provider\.h',
966 'sql/vfs_wrapper\.cc',
967 # TODO(https://crbug.com/1364585): Remove usage and exception list
968 # entries.
969 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
970 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
971 # TODO(https://crbug.com/1364579): Remove usage and exception list
972 # entry.
973 'ui/views/controls/focus_ring\.h',
974
975 # Various pre-existing uses in //tools that is low-priority to fix.
976 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
977 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
978 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
979 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
980 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
981
Daniel Chengcd23b8b2022-09-16 17:16:24982 # Not an error in third_party folders.
983 _THIRD_PARTY_EXCEPT_BLINK
984 ],
Daniel Bratell609102be2019-03-27 20:53:21985 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15986 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21987 r'/\b#include <random>\b',
988 (
989 'Do not use any random number engines from <random>. Instead',
990 'use base::RandomBitGenerator.',
991 ),
992 True,
993 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
994 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15995 BanRule(
Tom Andersona95e12042020-09-09 23:08:00996 r'/\b#include <X11/',
997 (
998 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
999 ),
1000 True,
1001 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1002 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151003 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211004 r'/\bstd::ratio\b',
1005 (
1006 'std::ratio is banned by the Google Style Guide.',
1007 ),
1008 True,
1009 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451010 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151011 BanRule(
Gabriel Charetted90bcc92021-09-21 00:23:101012 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:381013 (
Gabriel Charetted90bcc92021-09-21 00:23:101014 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:381015 ),
Gabriel Charette04b138f2018-08-06 00:03:221016 False,
Francois Doray43670e32017-09-27 12:40:381017 (),
1018 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151019 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:581020 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:191021 (
1022 'RunMessageLoop is deprecated, use RunLoop instead.',
1023 ),
1024 False,
1025 (),
1026 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151027 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441028 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191029 (
1030 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
1031 ),
1032 False,
1033 (),
1034 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151035 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441036 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191037 (
1038 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1039 "if you're convinced you need this.",
1040 ),
1041 False,
1042 (),
1043 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151044 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441045 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191046 (
1047 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041048 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191049 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1050 'async events instead of flushing threads.',
1051 ),
1052 False,
1053 (),
1054 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151055 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191056 r'MessageLoopRunner',
1057 (
1058 'MessageLoopRunner is deprecated, use RunLoop instead.',
1059 ),
1060 False,
1061 (),
1062 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151063 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441064 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191065 (
1066 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1067 "gab@ if you found a use case where this is the only solution.",
1068 ),
1069 False,
1070 (),
1071 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151072 BanRule(
Victor Costane48a2e82019-03-15 22:02:341073 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161074 (
Victor Costane48a2e82019-03-15 22:02:341075 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161076 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1077 ),
1078 True,
1079 (
1080 r'^sql/initialization\.(cc|h)$',
1081 r'^third_party/sqlite/.*\.(c|cc|h)$',
1082 ),
1083 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151084 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441085 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471086 (
1087 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1088 'base::RandomShuffle instead.'
1089 ),
1090 True,
1091 (),
1092 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151093 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241094 'ios/web/public/test/http_server',
1095 (
1096 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1097 ),
1098 False,
1099 (),
1100 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151101 BanRule(
Robert Liao764c9492019-01-24 18:46:281102 'GetAddressOf',
1103 (
1104 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531105 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111106 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531107 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281108 ),
1109 True,
1110 (),
1111 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151112 BanRule(
Ben Lewisa9514602019-04-29 17:53:051113 'SHFileOperation',
1114 (
1115 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1116 'complex functions to achieve the same goals. Use IFileOperation for ',
1117 'any esoteric actions instead.'
1118 ),
1119 True,
1120 (),
1121 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151122 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511123 'StringFromGUID2',
1124 (
1125 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241126 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511127 ),
1128 True,
1129 (
Daniel Chenga44a1bcd2022-03-15 20:00:151130 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511131 ),
1132 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151133 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511134 'StringFromCLSID',
1135 (
1136 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241137 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511138 ),
1139 True,
1140 (
Daniel Chenga44a1bcd2022-03-15 20:00:151141 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511142 ),
1143 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151144 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131145 'kCFAllocatorNull',
1146 (
1147 'The use of kCFAllocatorNull with the NoCopy creation of ',
1148 'CoreFoundation types is prohibited.',
1149 ),
1150 True,
1151 (),
1152 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151153 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291154 'mojo::ConvertTo',
1155 (
1156 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1157 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1158 'StringTraits if you would like to convert between custom types and',
1159 'the wire format of mojom types.'
1160 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221161 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291162 (
David Dorwin13dc48b2022-06-03 21:18:421163 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1164 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291165 r'^third_party/blink/.*\.(cc|h)$',
1166 r'^content/renderer/.*\.(cc|h)$',
1167 ),
1168 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151169 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161170 'GetInterfaceProvider',
1171 (
1172 'InterfaceProvider is deprecated.',
1173 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1174 'or Platform::GetBrowserInterfaceBroker.'
1175 ),
1176 False,
1177 (),
1178 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151179 BanRule(
Robert Liao1d78df52019-11-11 20:02:011180 'CComPtr',
1181 (
1182 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1183 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1184 'details.'
1185 ),
1186 False,
1187 (),
1188 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151189 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201190 r'/\b(IFACE|STD)METHOD_?\(',
1191 (
1192 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1193 'Instead, always use IFACEMETHODIMP in the declaration.'
1194 ),
1195 False,
1196 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1197 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151198 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471199 'set_owned_by_client',
1200 (
1201 'set_owned_by_client is deprecated.',
1202 'views::View already owns the child views by default. This introduces ',
1203 'a competing ownership model which makes the code difficult to reason ',
1204 'about. See http://crbug.com/1044687 for more details.'
1205 ),
1206 False,
1207 (),
1208 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151209 BanRule(
Peter Boström7ff41522021-07-29 03:43:271210 'RemoveAllChildViewsWithoutDeleting',
1211 (
1212 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1213 'This method is deemed dangerous as, unless raw pointers are re-added,',
1214 'calls to this method introduce memory leaks.'
1215 ),
1216 False,
1217 (),
1218 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151219 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121220 r'/\bTRACE_EVENT_ASYNC_',
1221 (
1222 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1223 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1224 ),
1225 False,
1226 (
1227 r'^base/trace_event/.*',
1228 r'^base/tracing/.*',
1229 ),
1230 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151231 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431232 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1233 (
1234 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1235 'dumps and may spam crash reports. Consider if the throttled',
1236 'variants suffice instead.',
1237 ),
1238 False,
1239 (),
1240 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151241 BanRule(
Robert Liao22f66a52021-04-10 00:57:521242 'RoInitialize',
1243 (
Robert Liao48018922021-04-16 23:03:021244 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521245 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1246 'instead. See http://crbug.com/1197722 for more information.'
1247 ),
1248 True,
Robert Liao48018922021-04-16 23:03:021249 (
Bruce Dawson40fece62022-09-16 19:58:311250 r'^base/win/scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021251 ),
Robert Liao22f66a52021-04-10 00:57:521252 ),
Patrick Monettec343bb982022-06-01 17:18:451253 BanRule(
1254 r'base::Watchdog',
1255 (
1256 'base::Watchdog is deprecated because it creates its own thread.',
1257 'Instead, manually start a timer on a SequencedTaskRunner.',
1258 ),
1259 False,
1260 (),
1261 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091262 BanRule(
1263 'base::Passed',
1264 (
1265 'Do not use base::Passed. It is a legacy helper for capturing ',
1266 'move-only types with base::BindRepeating, but invoking the ',
1267 'resulting RepeatingCallback moves the captured value out of ',
1268 'the callback storage, and subsequent invocations may pass the ',
1269 'value in a valid but undefined state. Prefer base::BindOnce().',
1270 'See http://crbug.com/1326449 for context.'
1271 ),
1272 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481273 (
1274 # False positive, but it is also fine to let bind internals reference
1275 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241276 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481277 r'^base[\\/]functional[\\/]bind_internal\.h',
1278 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091279 ),
Daniel Cheng2248b332022-07-27 06:16:591280 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431281 r'base::Feature k',
1282 (
1283 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1284 'directly declaring/defining features.'
1285 ),
1286 True,
1287 [
1288 _THIRD_PARTY_EXCEPT_BLINK,
1289 ],
1290 ),
Robert Ogden92101dcb2022-10-19 23:49:361291 BanRule(
1292 r'\bchartorune\b',
1293 (
1294 'chartorune is not memory-safe, unless you can guarantee the input ',
1295 'string is always null-terminated. Otherwise, please use charntorune ',
1296 'from libphonenumber instead.'
1297 ),
1298 True,
1299 [
1300 _THIRD_PARTY_EXCEPT_BLINK,
1301 # Exceptions to this rule should have a fuzzer.
1302 ],
1303 ),
[email protected]127f18ec2012-06-16 05:05:591304)
1305
Daniel Cheng92c15e32022-03-16 17:48:221306_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1307 BanRule(
1308 'handle<shared_buffer>',
1309 (
1310 'Please use one of the more specific shared memory types instead:',
1311 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1312 ' mojo_base.mojom.WritableSharedMemoryRegion',
1313 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1314 ),
1315 True,
1316 ),
1317)
1318
mlamouria82272622014-09-16 18:45:041319_IPC_ENUM_TRAITS_DEPRECATED = (
1320 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501321 'See http://www.chromium.org/Home/chromium-security/education/'
1322 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041323
Stephen Martinis97a394142018-06-07 23:06:051324_LONG_PATH_ERROR = (
1325 'Some files included in this CL have file names that are too long (> 200'
1326 ' characters). If committed, these files will cause issues on Windows. See'
1327 ' https://crbug.com/612667 for more details.'
1328)
1329
Shenghua Zhangbfaa38b82017-11-16 21:58:021330_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:311331 r".*/AppHooksImpl\.java",
1332 r".*/BuildHooksAndroidImpl\.java",
1333 r".*/LicenseContentProvider\.java",
1334 r".*/PlatformServiceBridgeImpl.java",
1335 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021336]
[email protected]127f18ec2012-06-16 05:05:591337
Mohamed Heikald048240a2019-11-12 16:57:371338# List of image extensions that are used as resources in chromium.
1339_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1340
Sean Kau46e29bc2017-08-28 16:31:161341# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401342_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:311343 r'test/data/',
1344 r'testing/buildbot/',
1345 r'^components/policy/resources/policy_templates\.json$',
1346 r'^third_party/protobuf/',
1347 r'^third_party/blink/perf_tests/speedometer/resources/todomvc/learn.json',
1348 r'^third_party/blink/renderer/devtools/protocol\.json$',
1349 r'^third_party/blink/web_tests/external/wpt/',
1350 r'^tools/perf/',
1351 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311352 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:311353 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:161354]
1355
Andrew Grieveb773bad2020-06-05 18:00:381356# These are not checked on the public chromium-presubmit trybot.
1357# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041358# checkouts.
agrievef32bcc72016-04-04 14:57:401359_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381360 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381361]
1362
1363
1364_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101365 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041366 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361367 'base/android/jni_generator/jni_generator.pydeps',
1368 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361369 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041370 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361371 'build/android/gyp/aar.pydeps',
1372 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271373 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361374 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381375 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361376 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021377 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221378 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111379 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361380 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361381 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361382 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111383 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041384 'build/android/gyp/create_app_bundle_apks.pydeps',
1385 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361386 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121387 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091388 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221389 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401390 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001391 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361392 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421393 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041394 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361395 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361396 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211397 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361398 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361399 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361400 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581401 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361402 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141403 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261404 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471405 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041406 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361407 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361408 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101409 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361410 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221411 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361412 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221413 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101414 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461415 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301416 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241417 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361418 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461419 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561420 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361421 'build/android/incremental_install/generate_android_manifest.pydeps',
1422 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321423 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041424 'build/android/resource_sizes.pydeps',
1425 'build/android/test_runner.pydeps',
1426 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361427 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361428 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321429 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271430 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1431 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041432 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001433 'components/cronet/tools/generate_javadoc.pydeps',
1434 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381435 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001436 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381437 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181438 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411439 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1440 'testing/merge_scripts/standard_gtest_merge.pydeps',
1441 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1442 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041443 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421444 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251445 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421446 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131447 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501448 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411449 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1450 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061451 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221452 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451453 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401454]
1455
wnwenbdc444e2016-05-25 13:44:151456
agrievef32bcc72016-04-04 14:57:401457_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1458
1459
Eric Boren6fd2b932018-01-25 15:05:081460# Bypass the AUTHORS check for these accounts.
1461_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591462 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451463 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591464 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521465 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231466 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471467 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461468 'infra-try-recipes-tester', 'lacros-tracking-roller',
1469 'lacros-sdk-version-roller')
Eric Boren835d71f2018-09-07 21:09:041470 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271471 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041472 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161473 for s in ('chromium-internal-autoroll',)
1474 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:551475 for s in ('swarming-tasks',)
1476 ) | set('%[email protected]' % s
1477 for s in ('global-integration-try-builder',
1478 'global-integration-ci-builder'))
Eric Boren6fd2b932018-01-25 15:05:081479
Matt Stark6ef08872021-07-29 01:21:461480_INVALID_GRD_FILE_LINE = [
1481 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1482]
Eric Boren6fd2b932018-01-25 15:05:081483
Daniel Bratell65b033262019-04-23 08:17:061484def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501485 """Returns True if this file contains C++-like code (and not Python,
1486 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061487
Sam Maiera6e76d72022-02-11 21:43:501488 ext = input_api.os_path.splitext(file_path)[1]
1489 # This list is compatible with CppChecker.IsCppFile but we should
1490 # consider adding ".c" to it. If we do that we can use this function
1491 # at more places in the code.
1492 return ext in (
1493 '.h',
1494 '.cc',
1495 '.cpp',
1496 '.m',
1497 '.mm',
1498 )
1499
Daniel Bratell65b033262019-04-23 08:17:061500
1501def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501502 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061503
1504
1505def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501506 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061507
1508
1509def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501510 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061511
Mohamed Heikal5e5b7922020-10-29 18:57:591512
Erik Staabc734cd7a2021-11-23 03:11:521513def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501514 ext = input_api.os_path.splitext(file_path)[1]
1515 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521516
1517
Mohamed Heikal5e5b7922020-10-29 18:57:591518def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501519 """Prevent additions of dependencies from the upstream repo on //clank."""
1520 # clank can depend on clank
1521 if input_api.change.RepositoryRoot().endswith('clank'):
1522 return []
1523 build_file_patterns = [
1524 r'(.+/)?BUILD\.gn',
1525 r'.+\.gni',
1526 ]
1527 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1528 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591529
Sam Maiera6e76d72022-02-11 21:43:501530 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591531
Sam Maiera6e76d72022-02-11 21:43:501532 def FilterFile(affected_file):
1533 return input_api.FilterSourceFile(affected_file,
1534 files_to_check=build_file_patterns,
1535 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591536
Sam Maiera6e76d72022-02-11 21:43:501537 problems = []
1538 for f in input_api.AffectedSourceFiles(FilterFile):
1539 local_path = f.LocalPath()
1540 for line_number, line in f.ChangedContents():
1541 if (bad_pattern.search(line)):
1542 problems.append('%s:%d\n %s' %
1543 (local_path, line_number, line.strip()))
1544 if problems:
1545 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1546 else:
1547 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591548
1549
Saagar Sanghavifceeaae2020-08-12 16:40:361550def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501551 """Attempts to prevent use of functions intended only for testing in
1552 non-testing code. For now this is just a best-effort implementation
1553 that ignores header files and may have some false positives. A
1554 better implementation would probably need a proper C++ parser.
1555 """
1556 # We only scan .cc files and the like, as the declaration of
1557 # for-testing functions in header files are hard to distinguish from
1558 # calls to such functions without a proper C++ parser.
1559 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191560
Sam Maiera6e76d72022-02-11 21:43:501561 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1562 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1563 base_function_pattern)
1564 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1565 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1566 exclusion_pattern = input_api.re.compile(
1567 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1568 (base_function_pattern, base_function_pattern))
1569 # Avoid a false positive in this case, where the method name, the ::, and
1570 # the closing { are all on different lines due to line wrapping.
1571 # HelperClassForTesting::
1572 # HelperClassForTesting(
1573 # args)
1574 # : member(0) {}
1575 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191576
Sam Maiera6e76d72022-02-11 21:43:501577 def FilterFile(affected_file):
1578 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1579 input_api.DEFAULT_FILES_TO_SKIP)
1580 return input_api.FilterSourceFile(
1581 affected_file,
1582 files_to_check=file_inclusion_pattern,
1583 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191584
Sam Maiera6e76d72022-02-11 21:43:501585 problems = []
1586 for f in input_api.AffectedSourceFiles(FilterFile):
1587 local_path = f.LocalPath()
1588 in_method_defn = False
1589 for line_number, line in f.ChangedContents():
1590 if (inclusion_pattern.search(line)
1591 and not comment_pattern.search(line)
1592 and not exclusion_pattern.search(line)
1593 and not allowlist_pattern.search(line)
1594 and not in_method_defn):
1595 problems.append('%s:%d\n %s' %
1596 (local_path, line_number, line.strip()))
1597 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191598
Sam Maiera6e76d72022-02-11 21:43:501599 if problems:
1600 return [
1601 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1602 ]
1603 else:
1604 return []
[email protected]55459852011-08-10 15:17:191605
1606
Saagar Sanghavifceeaae2020-08-12 16:40:361607def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501608 """This is a simplified version of
1609 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1610 """
1611 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1612 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1613 name_pattern = r'ForTest(s|ing)?'
1614 # Describes an occurrence of "ForTest*" inside a // comment.
1615 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1616 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1617 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1618 # Catch calls.
1619 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1620 # Ignore definitions. (Comments are ignored separately.)
1621 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231622
Sam Maiera6e76d72022-02-11 21:43:501623 problems = []
1624 sources = lambda x: input_api.FilterSourceFile(
1625 x,
1626 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1627 DEFAULT_FILES_TO_SKIP),
1628 files_to_check=[r'.*\.java$'])
1629 for f in input_api.AffectedFiles(include_deletes=False,
1630 file_filter=sources):
1631 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231632 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501633 for line_number, line in f.ChangedContents():
1634 if is_inside_javadoc and javadoc_end_re.search(line):
1635 is_inside_javadoc = False
1636 if not is_inside_javadoc and javadoc_start_re.search(line):
1637 is_inside_javadoc = True
1638 if is_inside_javadoc:
1639 continue
1640 if (inclusion_re.search(line) and not comment_re.search(line)
1641 and not annotation_re.search(line)
1642 and not exclusion_re.search(line)):
1643 problems.append('%s:%d\n %s' %
1644 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231645
Sam Maiera6e76d72022-02-11 21:43:501646 if problems:
1647 return [
1648 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1649 ]
1650 else:
1651 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231652
1653
Saagar Sanghavifceeaae2020-08-12 16:40:361654def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501655 """Checks to make sure no .h files include <iostream>."""
1656 files = []
1657 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1658 input_api.re.MULTILINE)
1659 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1660 if not f.LocalPath().endswith('.h'):
1661 continue
1662 contents = input_api.ReadFile(f)
1663 if pattern.search(contents):
1664 files.append(f)
[email protected]10689ca2011-09-02 02:31:541665
Sam Maiera6e76d72022-02-11 21:43:501666 if len(files):
1667 return [
1668 output_api.PresubmitError(
1669 'Do not #include <iostream> in header files, since it inserts static '
1670 'initialization into every file including the header. Instead, '
1671 '#include <ostream>. See http://crbug.com/94794', files)
1672 ]
1673 return []
1674
[email protected]10689ca2011-09-02 02:31:541675
Aleksey Khoroshilov9b28c032022-06-03 16:35:321676def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501677 """Checks no windows headers with StrCat redefined are included directly."""
1678 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:321679 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
1680 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
1681 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
1682 _NON_BASE_DEPENDENT_PATHS)
1683 sources_filter = lambda f: input_api.FilterSourceFile(
1684 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
1685
Sam Maiera6e76d72022-02-11 21:43:501686 pattern_deny = input_api.re.compile(
1687 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1688 input_api.re.MULTILINE)
1689 pattern_allow = input_api.re.compile(
1690 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:321691 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:501692 contents = input_api.ReadFile(f)
1693 if pattern_deny.search(
1694 contents) and not pattern_allow.search(contents):
1695 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431696
Sam Maiera6e76d72022-02-11 21:43:501697 if len(files):
1698 return [
1699 output_api.PresubmitError(
1700 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1701 'directly since they pollute code with StrCat macro. Instead, '
1702 'include matching header from base/win. See http://crbug.com/856536',
1703 files)
1704 ]
1705 return []
Danil Chapovalov3518f362018-08-11 16:13:431706
[email protected]10689ca2011-09-02 02:31:541707
Saagar Sanghavifceeaae2020-08-12 16:40:361708def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501709 """Checks to make sure no source files use UNIT_TEST."""
1710 problems = []
1711 for f in input_api.AffectedFiles():
1712 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1713 continue
[email protected]72df4e782012-06-21 16:28:181714
Sam Maiera6e76d72022-02-11 21:43:501715 for line_num, line in f.ChangedContents():
1716 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1717 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181718
Sam Maiera6e76d72022-02-11 21:43:501719 if not problems:
1720 return []
1721 return [
1722 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1723 '\n'.join(problems))
1724 ]
1725
[email protected]72df4e782012-06-21 16:28:181726
Saagar Sanghavifceeaae2020-08-12 16:40:361727def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501728 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341729
Sam Maiera6e76d72022-02-11 21:43:501730 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1731 instead of DISABLED_. To filter false positives, reports are only generated
1732 if a corresponding MAYBE_ line exists.
1733 """
1734 problems = []
Dominic Battre033531052018-09-24 15:45:341735
Sam Maiera6e76d72022-02-11 21:43:501736 # The following two patterns are looked for in tandem - is a test labeled
1737 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1738 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1739 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341740
Sam Maiera6e76d72022-02-11 21:43:501741 # This is for the case that a test is disabled on all platforms.
1742 full_disable_pattern = input_api.re.compile(
1743 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1744 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341745
Sam Maiera6e76d72022-02-11 21:43:501746 for f in input_api.AffectedFiles(False):
1747 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1748 continue
Dominic Battre033531052018-09-24 15:45:341749
Sam Maiera6e76d72022-02-11 21:43:501750 # Search for MABYE_, DISABLE_ pairs.
1751 disable_lines = {} # Maps of test name to line number.
1752 maybe_lines = {}
1753 for line_num, line in f.ChangedContents():
1754 disable_match = disable_pattern.search(line)
1755 if disable_match:
1756 disable_lines[disable_match.group(1)] = line_num
1757 maybe_match = maybe_pattern.search(line)
1758 if maybe_match:
1759 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341760
Sam Maiera6e76d72022-02-11 21:43:501761 # Search for DISABLE_ occurrences within a TEST() macro.
1762 disable_tests = set(disable_lines.keys())
1763 maybe_tests = set(maybe_lines.keys())
1764 for test in disable_tests.intersection(maybe_tests):
1765 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341766
Sam Maiera6e76d72022-02-11 21:43:501767 contents = input_api.ReadFile(f)
1768 full_disable_match = full_disable_pattern.search(contents)
1769 if full_disable_match:
1770 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341771
Sam Maiera6e76d72022-02-11 21:43:501772 if not problems:
1773 return []
1774 return [
1775 output_api.PresubmitPromptWarning(
1776 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1777 '\n'.join(problems))
1778 ]
1779
Dominic Battre033531052018-09-24 15:45:341780
Nina Satragnof7660532021-09-20 18:03:351781def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501782 """Checks to make sure tests disabled conditionally are not missing a
1783 corresponding MAYBE_ prefix.
1784 """
1785 # Expect at least a lowercase character in the test name. This helps rule out
1786 # false positives with macros wrapping the actual tests name.
1787 define_maybe_pattern = input_api.re.compile(
1788 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191789 # The test_maybe_pattern needs to handle all of these forms. The standard:
1790 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1791 # With a wrapper macro around the test name:
1792 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1793 # And the odd-ball NACL_BROWSER_TEST_f format:
1794 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1795 # The optional E2E_ENABLED-style is handled with (\w*\()?
1796 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1797 # trailing ')'.
1798 test_maybe_pattern = (
1799 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501800 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1801 warnings = []
Nina Satragnof7660532021-09-20 18:03:351802
Sam Maiera6e76d72022-02-11 21:43:501803 # Read the entire files. We can't just read the affected lines, forgetting to
1804 # add MAYBE_ on a change would not show up otherwise.
1805 for f in input_api.AffectedFiles(False):
1806 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1807 continue
1808 contents = input_api.ReadFile(f)
1809 lines = contents.splitlines(True)
1810 current_position = 0
1811 warning_test_names = set()
1812 for line_num, line in enumerate(lines, start=1):
1813 current_position += len(line)
1814 maybe_match = define_maybe_pattern.search(line)
1815 if maybe_match:
1816 test_name = maybe_match.group('test_name')
1817 # Do not warn twice for the same test.
1818 if (test_name in warning_test_names):
1819 continue
1820 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351821
Sam Maiera6e76d72022-02-11 21:43:501822 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1823 # the current position.
1824 test_match = input_api.re.compile(
1825 test_maybe_pattern.format(test_name=test_name),
1826 input_api.re.MULTILINE).search(contents, current_position)
1827 suite_match = input_api.re.compile(
1828 suite_maybe_pattern.format(test_name=test_name),
1829 input_api.re.MULTILINE).search(contents, current_position)
1830 if not test_match and not suite_match:
1831 warnings.append(
1832 output_api.PresubmitPromptWarning(
1833 '%s:%d found MAYBE_ defined without corresponding test %s'
1834 % (f.LocalPath(), line_num, test_name)))
1835 return warnings
1836
[email protected]72df4e782012-06-21 16:28:181837
Saagar Sanghavifceeaae2020-08-12 16:40:361838def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501839 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1840 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:161841 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:501842 input_api.re.MULTILINE)
1843 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1844 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1845 continue
1846 for lnum, line in f.ChangedContents():
1847 if input_api.re.search(pattern, line):
1848 errors.append(
1849 output_api.PresubmitError((
1850 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1851 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1852 (f.LocalPath(), lnum)))
1853 return errors
danakj61c1aa22015-10-26 19:55:521854
1855
Weilun Shia487fad2020-10-28 00:10:341856# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1857# more reliable way. See
1858# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191859
wnwenbdc444e2016-05-25 13:44:151860
Saagar Sanghavifceeaae2020-08-12 16:40:361861def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501862 """Check that FlakyTest annotation is our own instead of the android one"""
1863 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1864 files = []
1865 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1866 if f.LocalPath().endswith('Test.java'):
1867 if pattern.search(input_api.ReadFile(f)):
1868 files.append(f)
1869 if len(files):
1870 return [
1871 output_api.PresubmitError(
1872 'Use org.chromium.base.test.util.FlakyTest instead of '
1873 'android.test.FlakyTest', files)
1874 ]
1875 return []
mcasasb7440c282015-02-04 14:52:191876
wnwenbdc444e2016-05-25 13:44:151877
Saagar Sanghavifceeaae2020-08-12 16:40:361878def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501879 """Make sure .DEPS.git is never modified manually."""
1880 if any(f.LocalPath().endswith('.DEPS.git')
1881 for f in input_api.AffectedFiles()):
1882 return [
1883 output_api.PresubmitError(
1884 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1885 'automated system based on what\'s in DEPS and your changes will be\n'
1886 'overwritten.\n'
1887 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1888 'get-the-code#Rolling_DEPS\n'
1889 'for more information')
1890 ]
1891 return []
[email protected]2a8ac9c2011-10-19 17:20:441892
1893
Saagar Sanghavifceeaae2020-08-12 16:40:361894def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501895 """Checks that DEPS file deps are from allowed_hosts."""
1896 # Run only if DEPS file has been modified to annoy fewer bystanders.
1897 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1898 return []
1899 # Outsource work to gclient verify
1900 try:
1901 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
1902 'third_party', 'depot_tools',
1903 'gclient.py')
1904 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:321905 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:501906 stderr=input_api.subprocess.STDOUT)
1907 return []
1908 except input_api.subprocess.CalledProcessError as error:
1909 return [
1910 output_api.PresubmitError(
1911 'DEPS file must have only git dependencies.',
1912 long_text=error.output)
1913 ]
tandriief664692014-09-23 14:51:471914
1915
Mario Sanchez Prada2472cab2019-09-18 10:58:311916def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151917 ban_rule):
Allen Bauer84778682022-09-22 16:28:561918 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:311919
Sam Maiera6e76d72022-02-11 21:43:501920 Returns an string composed of the name of the file, the line number where the
1921 match has been found and the additional text passed as |message| in case the
1922 target type name matches the text inside the line passed as parameter.
1923 """
1924 result = []
Peng Huang9c5949a02020-06-11 19:20:541925
Daniel Chenga44a1bcd2022-03-15 20:00:151926 # Ignore comments about banned types.
1927 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:501928 return result
Daniel Chenga44a1bcd2022-03-15 20:00:151929 # A // nocheck comment will bypass this error.
1930 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:501931 return result
1932
1933 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:151934 if ban_rule.pattern[0:1] == '/':
1935 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:501936 if input_api.re.search(regex, line):
1937 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:151938 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:501939 matched = True
1940
1941 if matched:
1942 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:151943 for line in ban_rule.explanation:
1944 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:501945
danakjd18e8892020-12-17 17:42:011946 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:311947
1948
Saagar Sanghavifceeaae2020-08-12 16:40:361949def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501950 """Make sure that banned functions are not used."""
1951 warnings = []
1952 errors = []
[email protected]127f18ec2012-06-16 05:05:591953
Sam Maiera6e76d72022-02-11 21:43:501954 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:151955 if not excluded_paths:
1956 return False
1957
Sam Maiera6e76d72022-02-11 21:43:501958 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:311959 # Consistently use / as path separator to simplify the writing of regex
1960 # expressions.
1961 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:501962 for item in excluded_paths:
1963 if input_api.re.match(item, local_path):
1964 return True
1965 return False
wnwenbdc444e2016-05-25 13:44:151966
Sam Maiera6e76d72022-02-11 21:43:501967 def IsIosObjcFile(affected_file):
1968 local_path = affected_file.LocalPath()
1969 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
1970 '.h'):
1971 return False
1972 basename = input_api.os_path.basename(local_path)
1973 if 'ios' in basename.split('_'):
1974 return True
1975 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1976 if sep and 'ios' in local_path.split(sep):
1977 return True
1978 return False
Sylvain Defresnea8b73d252018-02-28 15:45:541979
Daniel Chenga44a1bcd2022-03-15 20:00:151980 def CheckForMatch(affected_file, line_num: int, line: str,
1981 ban_rule: BanRule):
1982 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
1983 return
1984
Sam Maiera6e76d72022-02-11 21:43:501985 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151986 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501987 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:151988 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:501989 errors.extend(problems)
1990 else:
1991 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151992
Sam Maiera6e76d72022-02-11 21:43:501993 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1994 for f in input_api.AffectedFiles(file_filter=file_filter):
1995 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151996 for ban_rule in _BANNED_JAVA_FUNCTIONS:
1997 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:411998
Sam Maiera6e76d72022-02-11 21:43:501999 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2000 for f in input_api.AffectedFiles(file_filter=file_filter):
2001 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152002 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2003 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592004
Sam Maiera6e76d72022-02-11 21:43:502005 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2006 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152007 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2008 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542009
Sam Maiera6e76d72022-02-11 21:43:502010 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2011 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2012 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152013 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2014 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052015
Sam Maiera6e76d72022-02-11 21:43:502016 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2017 for f in input_api.AffectedFiles(file_filter=file_filter):
2018 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152019 for ban_rule in _BANNED_CPP_FUNCTIONS:
2020 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592021
Daniel Cheng92c15e32022-03-16 17:48:222022 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2023 for f in input_api.AffectedFiles(file_filter=file_filter):
2024 for line_num, line in f.ChangedContents():
2025 for ban_rule in _BANNED_MOJOM_PATTERNS:
2026 CheckForMatch(f, line_num, line, ban_rule)
2027
2028
Sam Maiera6e76d72022-02-11 21:43:502029 result = []
2030 if (warnings):
2031 result.append(
2032 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2033 '\n'.join(warnings)))
2034 if (errors):
2035 result.append(
2036 output_api.PresubmitError('Banned functions were used.\n' +
2037 '\n'.join(errors)))
2038 return result
[email protected]127f18ec2012-06-16 05:05:592039
Allen Bauer84778682022-09-22 16:28:562040def CheckNoLayoutCallsInTests(input_api, output_api):
2041 """Make sure there are no explicit calls to View::Layout() in tests"""
2042 warnings = []
2043 ban_rule = BanRule(
2044 r'/(\.|->)Layout\(\);',
2045 (
2046 'Direct calls to View::Layout() are not allowed in tests. '
2047 'If the view must be laid out here, use RunScheduledLayout(view). It '
2048 'is found in //ui/views/test/views_test_utils.h. '
2049 'See http://crbug.com/1350521 for more details.',
2050 ),
2051 False,
2052 )
2053 file_filter = lambda f: input_api.re.search(
2054 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2055 for f in input_api.AffectedFiles(file_filter = file_filter):
2056 for line_num, line in f.ChangedContents():
2057 problems = _GetMessageForMatchingType(input_api, f,
2058 line_num, line,
2059 ban_rule)
2060 if problems:
2061 warnings.extend(problems)
2062 result = []
2063 if (warnings):
2064 result.append(
2065 output_api.PresubmitPromptWarning(
2066 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2067 return result
[email protected]127f18ec2012-06-16 05:05:592068
Michael Thiessen44457642020-02-06 00:24:152069def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502070 """Make sure that banned java imports are not used."""
2071 errors = []
Michael Thiessen44457642020-02-06 00:24:152072
Sam Maiera6e76d72022-02-11 21:43:502073 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2074 for f in input_api.AffectedFiles(file_filter=file_filter):
2075 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152076 for ban_rule in _BANNED_JAVA_IMPORTS:
2077 # Consider merging this into the above function. There is no
2078 # real difference anymore other than helping with a little
2079 # bit of boilerplate text. Doing so means things like
2080 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502081 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152082 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502083 if problems:
2084 errors.extend(problems)
2085 result = []
2086 if (errors):
2087 result.append(
2088 output_api.PresubmitError('Banned imports were used.\n' +
2089 '\n'.join(errors)))
2090 return result
Michael Thiessen44457642020-02-06 00:24:152091
2092
Saagar Sanghavifceeaae2020-08-12 16:40:362093def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502094 """Make sure that banned functions are not used."""
2095 files = []
2096 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2097 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2098 if not f.LocalPath().endswith('.h'):
2099 continue
Bruce Dawson4c4c2922022-05-02 18:07:332100 if f.LocalPath().endswith('com_imported_mstscax.h'):
2101 continue
Sam Maiera6e76d72022-02-11 21:43:502102 contents = input_api.ReadFile(f)
2103 if pattern.search(contents):
2104 files.append(f)
[email protected]6c063c62012-07-11 19:11:062105
Sam Maiera6e76d72022-02-11 21:43:502106 if files:
2107 return [
2108 output_api.PresubmitError(
2109 'Do not use #pragma once in header files.\n'
2110 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2111 files)
2112 ]
2113 return []
[email protected]6c063c62012-07-11 19:11:062114
[email protected]127f18ec2012-06-16 05:05:592115
Saagar Sanghavifceeaae2020-08-12 16:40:362116def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502117 """Checks to make sure we don't introduce use of foo ? true : false."""
2118 problems = []
2119 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2120 for f in input_api.AffectedFiles():
2121 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2122 continue
[email protected]e7479052012-09-19 00:26:122123
Sam Maiera6e76d72022-02-11 21:43:502124 for line_num, line in f.ChangedContents():
2125 if pattern.match(line):
2126 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:122127
Sam Maiera6e76d72022-02-11 21:43:502128 if not problems:
2129 return []
2130 return [
2131 output_api.PresubmitPromptWarning(
2132 'Please consider avoiding the "? true : false" pattern if possible.\n'
2133 + '\n'.join(problems))
2134 ]
[email protected]e7479052012-09-19 00:26:122135
2136
Saagar Sanghavifceeaae2020-08-12 16:40:362137def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502138 """Runs checkdeps on #include and import statements added in this
2139 change. Breaking - rules is an error, breaking ! rules is a
2140 warning.
2141 """
2142 # Return early if no relevant file types were modified.
2143 for f in input_api.AffectedFiles():
2144 path = f.LocalPath()
2145 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2146 or _IsJavaFile(input_api, path)):
2147 break
[email protected]55f9f382012-07-31 11:02:182148 else:
Sam Maiera6e76d72022-02-11 21:43:502149 return []
rhalavati08acd232017-04-03 07:23:282150
Sam Maiera6e76d72022-02-11 21:43:502151 import sys
2152 # We need to wait until we have an input_api object and use this
2153 # roundabout construct to import checkdeps because this file is
2154 # eval-ed and thus doesn't have __file__.
2155 original_sys_path = sys.path
2156 try:
2157 sys.path = sys.path + [
2158 input_api.os_path.join(input_api.PresubmitLocalPath(),
2159 'buildtools', 'checkdeps')
2160 ]
2161 import checkdeps
2162 from rules import Rule
2163 finally:
2164 # Restore sys.path to what it was before.
2165 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:182166
Sam Maiera6e76d72022-02-11 21:43:502167 added_includes = []
2168 added_imports = []
2169 added_java_imports = []
2170 for f in input_api.AffectedFiles():
2171 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2172 changed_lines = [line for _, line in f.ChangedContents()]
2173 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2174 elif _IsProtoFile(input_api, f.LocalPath()):
2175 changed_lines = [line for _, line in f.ChangedContents()]
2176 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2177 elif _IsJavaFile(input_api, f.LocalPath()):
2178 changed_lines = [line for _, line in f.ChangedContents()]
2179 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242180
Sam Maiera6e76d72022-02-11 21:43:502181 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2182
2183 error_descriptions = []
2184 warning_descriptions = []
2185 error_subjects = set()
2186 warning_subjects = set()
2187
2188 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2189 added_includes):
2190 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2191 description_with_path = '%s\n %s' % (path, rule_description)
2192 if rule_type == Rule.DISALLOW:
2193 error_descriptions.append(description_with_path)
2194 error_subjects.add("#includes")
2195 else:
2196 warning_descriptions.append(description_with_path)
2197 warning_subjects.add("#includes")
2198
2199 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2200 added_imports):
2201 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2202 description_with_path = '%s\n %s' % (path, rule_description)
2203 if rule_type == Rule.DISALLOW:
2204 error_descriptions.append(description_with_path)
2205 error_subjects.add("imports")
2206 else:
2207 warning_descriptions.append(description_with_path)
2208 warning_subjects.add("imports")
2209
2210 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2211 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2212 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2213 description_with_path = '%s\n %s' % (path, rule_description)
2214 if rule_type == Rule.DISALLOW:
2215 error_descriptions.append(description_with_path)
2216 error_subjects.add("imports")
2217 else:
2218 warning_descriptions.append(description_with_path)
2219 warning_subjects.add("imports")
2220
2221 results = []
2222 if error_descriptions:
2223 results.append(
2224 output_api.PresubmitError(
2225 'You added one or more %s that violate checkdeps rules.' %
2226 " and ".join(error_subjects), error_descriptions))
2227 if warning_descriptions:
2228 results.append(
2229 output_api.PresubmitPromptOrNotify(
2230 'You added one or more %s of files that are temporarily\n'
2231 'allowed but being removed. Can you avoid introducing the\n'
2232 '%s? See relevant DEPS file(s) for details and contacts.' %
2233 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2234 warning_descriptions))
2235 return results
[email protected]55f9f382012-07-31 11:02:182236
2237
Saagar Sanghavifceeaae2020-08-12 16:40:362238def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502239 """Check that all files have their permissions properly set."""
2240 if input_api.platform == 'win32':
2241 return []
2242 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2243 'tools', 'checkperms',
2244 'checkperms.py')
2245 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322246 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502247 input_api.change.RepositoryRoot()
2248 ]
2249 with input_api.CreateTemporaryFile() as file_list:
2250 for f in input_api.AffectedFiles():
2251 # checkperms.py file/directory arguments must be relative to the
2252 # repository.
2253 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2254 file_list.close()
2255 args += ['--file-list', file_list.name]
2256 try:
2257 input_api.subprocess.check_output(args)
2258 return []
2259 except input_api.subprocess.CalledProcessError as error:
2260 return [
2261 output_api.PresubmitError('checkperms.py failed:',
2262 long_text=error.output.decode(
2263 'utf-8', 'ignore'))
2264 ]
[email protected]fbcafe5a2012-08-08 15:31:222265
2266
Saagar Sanghavifceeaae2020-08-12 16:40:362267def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502268 """Makes sure we don't include ui/aura/window_property.h
2269 in header files.
2270 """
2271 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2272 errors = []
2273 for f in input_api.AffectedFiles():
2274 if not f.LocalPath().endswith('.h'):
2275 continue
2276 for line_num, line in f.ChangedContents():
2277 if pattern.match(line):
2278 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:492279
Sam Maiera6e76d72022-02-11 21:43:502280 results = []
2281 if errors:
2282 results.append(
2283 output_api.PresubmitError(
2284 'Header files should not include ui/aura/window_property.h',
2285 errors))
2286 return results
[email protected]c8278b32012-10-30 20:35:492287
2288
Omer Katzcc77ea92021-04-26 10:23:282289def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502290 """Makes sure we don't include any headers from
2291 third_party/blink/renderer/platform/heap/impl or
2292 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2293 third_party/blink/renderer/platform/heap
2294 """
2295 impl_pattern = input_api.re.compile(
2296 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2297 v8_wrapper_pattern = input_api.re.compile(
2298 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2299 )
Bruce Dawson40fece62022-09-16 19:58:312300 # Consistently use / as path separator to simplify the writing of regex
2301 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502302 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312303 r"^third_party/blink/renderer/platform/heap/.*",
2304 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502305 errors = []
Omer Katzcc77ea92021-04-26 10:23:282306
Sam Maiera6e76d72022-02-11 21:43:502307 for f in input_api.AffectedFiles(file_filter=file_filter):
2308 for line_num, line in f.ChangedContents():
2309 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2310 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282311
Sam Maiera6e76d72022-02-11 21:43:502312 results = []
2313 if errors:
2314 results.append(
2315 output_api.PresubmitError(
2316 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2317 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2318 'relevant counterparts from third_party/blink/renderer/platform/heap',
2319 errors))
2320 return results
Omer Katzcc77ea92021-04-26 10:23:282321
2322
[email protected]70ca77752012-11-20 03:45:032323def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502324 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2325 errors = []
2326 for line_num, line in f.ChangedContents():
2327 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2328 # First-level headers in markdown look a lot like version control
2329 # conflict markers. http://daringfireball.net/projects/markdown/basics
2330 continue
2331 if pattern.match(line):
2332 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2333 return errors
[email protected]70ca77752012-11-20 03:45:032334
2335
Saagar Sanghavifceeaae2020-08-12 16:40:362336def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502337 """Usually this is not intentional and will cause a compile failure."""
2338 errors = []
2339 for f in input_api.AffectedFiles():
2340 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032341
Sam Maiera6e76d72022-02-11 21:43:502342 results = []
2343 if errors:
2344 results.append(
2345 output_api.PresubmitError(
2346 'Version control conflict markers found, please resolve.',
2347 errors))
2348 return results
[email protected]70ca77752012-11-20 03:45:032349
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202350
Saagar Sanghavifceeaae2020-08-12 16:40:362351def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502352 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2353 errors = []
2354 for f in input_api.AffectedFiles():
2355 for line_num, line in f.ChangedContents():
2356 if pattern.search(line):
2357 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162358
Sam Maiera6e76d72022-02-11 21:43:502359 results = []
2360 if errors:
2361 results.append(
2362 output_api.PresubmitPromptWarning(
2363 'Found Google support URL addressed by answer number. Please replace '
2364 'with a p= identifier instead. See crbug.com/679462\n',
2365 errors))
2366 return results
estadee17314a02017-01-12 16:22:162367
[email protected]70ca77752012-11-20 03:45:032368
Saagar Sanghavifceeaae2020-08-12 16:40:362369def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502370 def FilterFile(affected_file):
2371 """Filter function for use with input_api.AffectedSourceFiles,
2372 below. This filters out everything except non-test files from
2373 top-level directories that generally speaking should not hard-code
2374 service URLs (e.g. src/android_webview/, src/content/ and others).
2375 """
2376 return input_api.FilterSourceFile(
2377 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312378 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502379 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2380 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442381
Sam Maiera6e76d72022-02-11 21:43:502382 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2383 '\.(com|net)[^"]*"')
2384 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2385 pattern = input_api.re.compile(base_pattern)
2386 problems = [] # items are (filename, line_number, line)
2387 for f in input_api.AffectedSourceFiles(FilterFile):
2388 for line_num, line in f.ChangedContents():
2389 if not comment_pattern.search(line) and pattern.search(line):
2390 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442391
Sam Maiera6e76d72022-02-11 21:43:502392 if problems:
2393 return [
2394 output_api.PresubmitPromptOrNotify(
2395 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2396 'Are you sure this is correct?', [
2397 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2398 for problem in problems
2399 ])
2400 ]
2401 else:
2402 return []
[email protected]06e6d0ff2012-12-11 01:36:442403
2404
Saagar Sanghavifceeaae2020-08-12 16:40:362405def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502406 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292407
Sam Maiera6e76d72022-02-11 21:43:502408 def FileFilter(affected_file):
2409 """Includes directories known to be Chrome OS only."""
2410 return input_api.FilterSourceFile(
2411 affected_file,
2412 files_to_check=(
2413 '^ash/',
2414 '^chromeos/', # Top-level src/chromeos.
2415 '.*/chromeos/', # Any path component.
2416 '^components/arc',
2417 '^components/exo'),
2418 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292419
Sam Maiera6e76d72022-02-11 21:43:502420 prefs = []
2421 priority_prefs = []
2422 for f in input_api.AffectedFiles(file_filter=FileFilter):
2423 for line_num, line in f.ChangedContents():
2424 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2425 line):
2426 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2427 prefs.append(' %s' % line)
2428 if input_api.re.search(
2429 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2430 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2431 priority_prefs.append(' %s' % line)
2432
2433 results = []
2434 if (prefs):
2435 results.append(
2436 output_api.PresubmitPromptWarning(
2437 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2438 'by browser sync settings. If these prefs should be controlled by OS '
2439 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2440 '\n'.join(prefs)))
2441 if (priority_prefs):
2442 results.append(
2443 output_api.PresubmitPromptWarning(
2444 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2445 'controlled by browser sync settings. If these prefs should be '
2446 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2447 'instead.\n' + '\n'.join(prefs)))
2448 return results
James Cook6b6597c2019-11-06 22:05:292449
2450
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492451# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362452def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502453 """Makes sure there are no abbreviations in the name of PNG files.
2454 The native_client_sdk directory is excluded because it has auto-generated PNG
2455 files for documentation.
2456 """
2457 errors = []
2458 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Bruce Dawson40fece62022-09-16 19:58:312459 files_to_skip = [r'^native_client_sdk/',
2460 r'^services/test/',
2461 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182462 ]
Sam Maiera6e76d72022-02-11 21:43:502463 file_filter = lambda f: input_api.FilterSourceFile(
2464 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2465 for f in input_api.AffectedFiles(include_deletes=False,
2466 file_filter=file_filter):
2467 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272468
Sam Maiera6e76d72022-02-11 21:43:502469 results = []
2470 if errors:
2471 results.append(
2472 output_api.PresubmitError(
2473 'The name of PNG files should not have abbreviations. \n'
2474 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2475 'Contact [email protected] if you have questions.', errors))
2476 return results
[email protected]d2530012013-01-25 16:39:272477
Evan Stade7cd4a2c2022-08-04 23:37:252478def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2479 """Heuristically identifies product icons based on their file name and reminds
2480 contributors not to add them to the Chromium repository.
2481 """
2482 errors = []
2483 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2484 file_filter = lambda f: input_api.FilterSourceFile(
2485 f, files_to_check=files_to_check)
2486 for f in input_api.AffectedFiles(include_deletes=False,
2487 file_filter=file_filter):
2488 errors.append(' %s' % f.LocalPath())
2489
2490 results = []
2491 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082492 # Give warnings instead of errors on presubmit --all and presubmit
2493 # --files.
2494 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2495 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252496 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082497 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252498 'Trademarked images should not be added to the public repo. '
2499 'See crbug.com/944754', errors))
2500 return results
2501
[email protected]d2530012013-01-25 16:39:272502
Daniel Cheng4dcdb6b2017-04-13 08:30:172503def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502504 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172505
Sam Maiera6e76d72022-02-11 21:43:502506 Args:
2507 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2508 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172509 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502510 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172511 if rule.startswith('+') or rule.startswith('!')
2512 ])
Sam Maiera6e76d72022-02-11 21:43:502513 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2514 add_rules.update([
2515 rule[1:] for rule in rules
2516 if rule.startswith('+') or rule.startswith('!')
2517 ])
2518 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172519
2520
2521def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502522 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172523
Sam Maiera6e76d72022-02-11 21:43:502524 # Stubs for handling special syntax in the root DEPS file.
2525 class _VarImpl:
2526 def __init__(self, local_scope):
2527 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172528
Sam Maiera6e76d72022-02-11 21:43:502529 def Lookup(self, var_name):
2530 """Implements the Var syntax."""
2531 try:
2532 return self._local_scope['vars'][var_name]
2533 except KeyError:
2534 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172535
Sam Maiera6e76d72022-02-11 21:43:502536 local_scope = {}
2537 global_scope = {
2538 'Var': _VarImpl(local_scope).Lookup,
2539 'Str': str,
2540 }
Dirk Pranke1b9e06382021-05-14 01:16:222541
Sam Maiera6e76d72022-02-11 21:43:502542 exec(contents, global_scope, local_scope)
2543 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172544
2545
2546def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502547 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2548 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412549
Sam Maiera6e76d72022-02-11 21:43:502550 For a directory (rather than a specific filename) we fake a path to
2551 a specific filename by adding /DEPS. This is chosen as a file that
2552 will seldom or never be subject to per-file include_rules.
2553 """
2554 # We ignore deps entries on auto-generated directories.
2555 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082556
Sam Maiera6e76d72022-02-11 21:43:502557 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2558 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172559
Sam Maiera6e76d72022-02-11 21:43:502560 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172561
Sam Maiera6e76d72022-02-11 21:43:502562 results = set()
2563 for added_dep in added_deps:
2564 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2565 continue
2566 # Assume that a rule that ends in .h is a rule for a specific file.
2567 if added_dep.endswith('.h'):
2568 results.add(added_dep)
2569 else:
2570 results.add(os_path.join(added_dep, 'DEPS'))
2571 return results
[email protected]f32e2d1e2013-07-26 21:39:082572
2573
Saagar Sanghavifceeaae2020-08-12 16:40:362574def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502575 """When a dependency prefixed with + is added to a DEPS file, we
2576 want to make sure that the change is reviewed by an OWNER of the
2577 target file or directory, to avoid layering violations from being
2578 introduced. This check verifies that this happens.
2579 """
2580 # We rely on Gerrit's code-owners to check approvals.
2581 # input_api.gerrit is always set for Chromium, but other projects
2582 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102583 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502584 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302585 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502586 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302587 try:
2588 if (input_api.change.issue and
2589 input_api.gerrit.IsOwnersOverrideApproved(
2590 input_api.change.issue)):
2591 # Skip OWNERS check when Owners-Override label is approved. This is
2592 # intended for global owners, trusted bots, and on-call sheriffs.
2593 # Review is still required for these changes.
2594 return []
2595 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:242596 return [output_api.PresubmitPromptWarning(
2597 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232598
Sam Maiera6e76d72022-02-11 21:43:502599 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242600
Bruce Dawson40fece62022-09-16 19:58:312601 # Consistently use / as path separator to simplify the writing of regex
2602 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502603 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312604 r"^third_party/blink/.*",
2605 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502606 for f in input_api.AffectedFiles(include_deletes=False,
2607 file_filter=file_filter):
2608 filename = input_api.os_path.basename(f.LocalPath())
2609 if filename == 'DEPS':
2610 virtual_depended_on_files.update(
2611 _CalculateAddedDeps(input_api.os_path,
2612 '\n'.join(f.OldContents()),
2613 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552614
Sam Maiera6e76d72022-02-11 21:43:502615 if not virtual_depended_on_files:
2616 return []
[email protected]e871964c2013-05-13 14:14:552617
Sam Maiera6e76d72022-02-11 21:43:502618 if input_api.is_committing:
2619 if input_api.tbr:
2620 return [
2621 output_api.PresubmitNotifyResult(
2622 '--tbr was specified, skipping OWNERS check for DEPS additions'
2623 )
2624 ]
Daniel Cheng3008dc12022-05-13 04:02:112625 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2626 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502627 if input_api.dry_run:
2628 return [
2629 output_api.PresubmitNotifyResult(
2630 'This is a dry run, skipping OWNERS check for DEPS additions'
2631 )
2632 ]
2633 if not input_api.change.issue:
2634 return [
2635 output_api.PresubmitError(
2636 "DEPS approval by OWNERS check failed: this change has "
2637 "no change number, so we can't check it for approvals.")
2638 ]
2639 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412640 else:
Sam Maiera6e76d72022-02-11 21:43:502641 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552642
Sam Maiera6e76d72022-02-11 21:43:502643 owner_email, reviewers = (
2644 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2645 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552646
Sam Maiera6e76d72022-02-11 21:43:502647 owner_email = owner_email or input_api.change.author_email
2648
2649 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2650 virtual_depended_on_files, reviewers.union([owner_email]), [])
2651 missing_files = [
2652 f for f in virtual_depended_on_files
2653 if approval_status[f] != input_api.owners_client.APPROVED
2654 ]
2655
2656 # We strip the /DEPS part that was added by
2657 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2658 # directory.
2659 def StripDeps(path):
2660 start_deps = path.rfind('/DEPS')
2661 if start_deps != -1:
2662 return path[:start_deps]
2663 else:
2664 return path
2665
2666 unapproved_dependencies = [
2667 "'+%s'," % StripDeps(path) for path in missing_files
2668 ]
2669
2670 if unapproved_dependencies:
2671 output_list = [
2672 output(
2673 'You need LGTM from owners of depends-on paths in DEPS that were '
2674 'modified in this CL:\n %s' %
2675 '\n '.join(sorted(unapproved_dependencies)))
2676 ]
2677 suggested_owners = input_api.owners_client.SuggestOwners(
2678 missing_files, exclude=[owner_email])
2679 output_list.append(
2680 output('Suggested missing target path OWNERS:\n %s' %
2681 '\n '.join(suggested_owners or [])))
2682 return output_list
2683
2684 return []
[email protected]e871964c2013-05-13 14:14:552685
2686
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492687# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362688def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502689 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2690 files_to_skip = (
2691 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2692 input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:312693 r"^base/logging\.h$",
2694 r"^base/logging\.cc$",
2695 r"^base/task/thread_pool/task_tracker\.cc$",
2696 r"^chrome/app/chrome_main_delegate\.cc$",
2697 r"^chrome/browser/chrome_browser_main\.cc$",
2698 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
2699 r"^chrome/browser/browser_switcher/bho/.*",
2700 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
2701 r"^chrome/chrome_cleaner/.*",
2702 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
2703 r"^chrome/installer/setup/.*",
2704 r"^chromecast/",
2705 r"^components/browser_watcher/dump_stability_report_main_win\.cc$",
2706 r"^components/media_control/renderer/media_playback_options\.cc$",
2707 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:502708 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312709 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:502710 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:312711 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:502712 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:312713 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
2714 r"^courgette/courgette_minimal_tool\.cc$",
2715 r"^courgette/courgette_tool\.cc$",
2716 r"^extensions/renderer/logging_native_handler\.cc$",
2717 r"^fuchsia_web/common/init_logging\.cc$",
2718 r"^fuchsia_web/runners/common/web_component\.cc$",
2719 r"^fuchsia_web/shell/.*_shell\.cc$",
2720 r"^headless/app/headless_shell\.cc$",
2721 r"^ipc/ipc_logging\.cc$",
2722 r"^native_client_sdk/",
2723 r"^remoting/base/logging\.h$",
2724 r"^remoting/host/.*",
2725 r"^sandbox/linux/.*",
2726 r"^storage/browser/file_system/dump_file_system\.cc$",
2727 r"^tools/",
2728 r"^ui/base/resource/data_pack\.cc$",
2729 r"^ui/aura/bench/bench_main\.cc$",
2730 r"^ui/ozone/platform/cast/",
2731 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:502732 r"xwmstartupcheck\.cc$"))
2733 source_file_filter = lambda x: input_api.FilterSourceFile(
2734 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402735
Sam Maiera6e76d72022-02-11 21:43:502736 log_info = set([])
2737 printf = set([])
[email protected]85218562013-11-22 07:41:402738
Sam Maiera6e76d72022-02-11 21:43:502739 for f in input_api.AffectedSourceFiles(source_file_filter):
2740 for _, line in f.ChangedContents():
2741 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2742 log_info.add(f.LocalPath())
2743 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2744 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372745
Sam Maiera6e76d72022-02-11 21:43:502746 if input_api.re.search(r"\bprintf\(", line):
2747 printf.add(f.LocalPath())
2748 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2749 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402750
Sam Maiera6e76d72022-02-11 21:43:502751 if log_info:
2752 return [
2753 output_api.PresubmitError(
2754 'These files spam the console log with LOG(INFO):',
2755 items=log_info)
2756 ]
2757 if printf:
2758 return [
2759 output_api.PresubmitError(
2760 'These files spam the console log with printf/fprintf:',
2761 items=printf)
2762 ]
2763 return []
[email protected]85218562013-11-22 07:41:402764
2765
Saagar Sanghavifceeaae2020-08-12 16:40:362766def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502767 """These types are all expected to hold locks while in scope and
2768 so should never be anonymous (which causes them to be immediately
2769 destroyed)."""
2770 they_who_must_be_named = [
2771 'base::AutoLock',
2772 'base::AutoReset',
2773 'base::AutoUnlock',
2774 'SkAutoAlphaRestore',
2775 'SkAutoBitmapShaderInstall',
2776 'SkAutoBlitterChoose',
2777 'SkAutoBounderCommit',
2778 'SkAutoCallProc',
2779 'SkAutoCanvasRestore',
2780 'SkAutoCommentBlock',
2781 'SkAutoDescriptor',
2782 'SkAutoDisableDirectionCheck',
2783 'SkAutoDisableOvalCheck',
2784 'SkAutoFree',
2785 'SkAutoGlyphCache',
2786 'SkAutoHDC',
2787 'SkAutoLockColors',
2788 'SkAutoLockPixels',
2789 'SkAutoMalloc',
2790 'SkAutoMaskFreeImage',
2791 'SkAutoMutexAcquire',
2792 'SkAutoPathBoundsUpdate',
2793 'SkAutoPDFRelease',
2794 'SkAutoRasterClipValidate',
2795 'SkAutoRef',
2796 'SkAutoTime',
2797 'SkAutoTrace',
2798 'SkAutoUnref',
2799 ]
2800 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2801 # bad: base::AutoLock(lock.get());
2802 # not bad: base::AutoLock lock(lock.get());
2803 bad_pattern = input_api.re.compile(anonymous)
2804 # good: new base::AutoLock(lock.get())
2805 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2806 errors = []
[email protected]49aa76a2013-12-04 06:59:162807
Sam Maiera6e76d72022-02-11 21:43:502808 for f in input_api.AffectedFiles():
2809 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2810 continue
2811 for linenum, line in f.ChangedContents():
2812 if bad_pattern.search(line) and not good_pattern.search(line):
2813 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162814
Sam Maiera6e76d72022-02-11 21:43:502815 if errors:
2816 return [
2817 output_api.PresubmitError(
2818 'These lines create anonymous variables that need to be named:',
2819 items=errors)
2820 ]
2821 return []
[email protected]49aa76a2013-12-04 06:59:162822
2823
Saagar Sanghavifceeaae2020-08-12 16:40:362824def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502825 # Returns whether |template_str| is of the form <T, U...> for some types T
2826 # and U. Assumes that |template_str| is already in the form <...>.
2827 def HasMoreThanOneArg(template_str):
2828 # Level of <...> nesting.
2829 nesting = 0
2830 for c in template_str:
2831 if c == '<':
2832 nesting += 1
2833 elif c == '>':
2834 nesting -= 1
2835 elif c == ',' and nesting == 1:
2836 return True
2837 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532838
Sam Maiera6e76d72022-02-11 21:43:502839 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2840 sources = lambda affected_file: input_api.FilterSourceFile(
2841 affected_file,
2842 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2843 DEFAULT_FILES_TO_SKIP),
2844 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552845
Sam Maiera6e76d72022-02-11 21:43:502846 # Pattern to capture a single "<...>" block of template arguments. It can
2847 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2848 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2849 # latter would likely require counting that < and > match, which is not
2850 # expressible in regular languages. Should the need arise, one can introduce
2851 # limited counting (matching up to a total number of nesting depth), which
2852 # should cover all practical cases for already a low nesting limit.
2853 template_arg_pattern = (
2854 r'<[^>]*' # Opening block of <.
2855 r'>([^<]*>)?') # Closing block of >.
2856 # Prefix expressing that whatever follows is not already inside a <...>
2857 # block.
2858 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2859 null_construct_pattern = input_api.re.compile(
2860 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2861 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552862
Sam Maiera6e76d72022-02-11 21:43:502863 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2864 template_arg_no_array_pattern = (
2865 r'<[^>]*[^]]' # Opening block of <.
2866 r'>([^(<]*[^]]>)?') # Closing block of >.
2867 # Prefix saying that what follows is the start of an expression.
2868 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2869 # Suffix saying that what follows are call parentheses with a non-empty list
2870 # of arguments.
2871 nonempty_arg_list_pattern = r'\(([^)]|$)'
2872 # Put the template argument into a capture group for deeper examination later.
2873 return_construct_pattern = input_api.re.compile(
2874 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2875 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552876
Sam Maiera6e76d72022-02-11 21:43:502877 problems_constructor = []
2878 problems_nullptr = []
2879 for f in input_api.AffectedSourceFiles(sources):
2880 for line_number, line in f.ChangedContents():
2881 # Disallow:
2882 # return std::unique_ptr<T>(foo);
2883 # bar = std::unique_ptr<T>(foo);
2884 # But allow:
2885 # return std::unique_ptr<T[]>(foo);
2886 # bar = std::unique_ptr<T[]>(foo);
2887 # And also allow cases when the second template argument is present. Those
2888 # cases cannot be handled by std::make_unique:
2889 # return std::unique_ptr<T, U>(foo);
2890 # bar = std::unique_ptr<T, U>(foo);
2891 local_path = f.LocalPath()
2892 return_construct_result = return_construct_pattern.search(line)
2893 if return_construct_result and not HasMoreThanOneArg(
2894 return_construct_result.group('template_arg')):
2895 problems_constructor.append(
2896 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2897 # Disallow:
2898 # std::unique_ptr<T>()
2899 if null_construct_pattern.search(line):
2900 problems_nullptr.append(
2901 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052902
Sam Maiera6e76d72022-02-11 21:43:502903 errors = []
2904 if problems_nullptr:
2905 errors.append(
2906 output_api.PresubmitPromptWarning(
2907 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2908 problems_nullptr))
2909 if problems_constructor:
2910 errors.append(
2911 output_api.PresubmitError(
2912 'The following files use explicit std::unique_ptr constructor. '
2913 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2914 'std::make_unique is not an option.', problems_constructor))
2915 return errors
Peter Kasting4844e46e2018-02-23 07:27:102916
2917
Saagar Sanghavifceeaae2020-08-12 16:40:362918def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502919 """Checks if any new user action has been added."""
2920 if any('actions.xml' == input_api.os_path.basename(f)
2921 for f in input_api.LocalPaths()):
2922 # If actions.xml is already included in the changelist, the PRESUBMIT
2923 # for actions.xml will do a more complete presubmit check.
2924 return []
2925
2926 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2927 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2928 input_api.DEFAULT_FILES_TO_SKIP)
2929 file_filter = lambda f: input_api.FilterSourceFile(
2930 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2931
2932 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2933 current_actions = None
2934 for f in input_api.AffectedFiles(file_filter=file_filter):
2935 for line_num, line in f.ChangedContents():
2936 match = input_api.re.search(action_re, line)
2937 if match:
2938 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2939 # loaded only once.
2940 if not current_actions:
2941 with open(
2942 'tools/metrics/actions/actions.xml') as actions_f:
2943 current_actions = actions_f.read()
2944 # Search for the matched user action name in |current_actions|.
2945 for action_name in match.groups():
2946 action = 'name="{0}"'.format(action_name)
2947 if action not in current_actions:
2948 return [
2949 output_api.PresubmitPromptWarning(
2950 'File %s line %d: %s is missing in '
2951 'tools/metrics/actions/actions.xml. Please run '
2952 'tools/metrics/actions/extract_actions.py to update.'
2953 % (f.LocalPath(), line_num, action_name))
2954 ]
[email protected]999261d2014-03-03 20:08:082955 return []
2956
[email protected]999261d2014-03-03 20:08:082957
Daniel Cheng13ca61a882017-08-25 15:11:252958def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502959 import sys
2960 sys.path = sys.path + [
2961 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2962 'json_comment_eater')
2963 ]
2964 import json_comment_eater
2965 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252966
2967
[email protected]99171a92014-06-03 08:44:472968def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172969 try:
Sam Maiera6e76d72022-02-11 21:43:502970 contents = input_api.ReadFile(filename)
2971 if eat_comments:
2972 json_comment_eater = _ImportJSONCommentEater(input_api)
2973 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172974
Sam Maiera6e76d72022-02-11 21:43:502975 input_api.json.loads(contents)
2976 except ValueError as e:
2977 return e
Andrew Grieve4deedb12022-02-03 21:34:502978 return None
2979
2980
Sam Maiera6e76d72022-02-11 21:43:502981def _GetIDLParseError(input_api, filename):
2982 try:
2983 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:282984 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:342985 if not char.isascii():
2986 return (
2987 'Non-ascii character "%s" (ord %d) found at offset %d.' %
2988 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:502989 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2990 'tools', 'json_schema_compiler',
2991 'idl_schema.py')
2992 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282993 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502994 stdin=input_api.subprocess.PIPE,
2995 stdout=input_api.subprocess.PIPE,
2996 stderr=input_api.subprocess.PIPE,
2997 universal_newlines=True)
2998 (_, error) = process.communicate(input=contents)
2999 return error or None
3000 except ValueError as e:
3001 return e
agrievef32bcc72016-04-04 14:57:403002
agrievef32bcc72016-04-04 14:57:403003
Sam Maiera6e76d72022-02-11 21:43:503004def CheckParseErrors(input_api, output_api):
3005 """Check that IDL and JSON files do not contain syntax errors."""
3006 actions = {
3007 '.idl': _GetIDLParseError,
3008 '.json': _GetJSONParseError,
3009 }
3010 # Most JSON files are preprocessed and support comments, but these do not.
3011 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313012 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:503013 ]
3014 # Only run IDL checker on files in these directories.
3015 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313016 r'^chrome/common/extensions/api/',
3017 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:503018 ]
agrievef32bcc72016-04-04 14:57:403019
Sam Maiera6e76d72022-02-11 21:43:503020 def get_action(affected_file):
3021 filename = affected_file.LocalPath()
3022 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:403023
Sam Maiera6e76d72022-02-11 21:43:503024 def FilterFile(affected_file):
3025 action = get_action(affected_file)
3026 if not action:
3027 return False
3028 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403029
Sam Maiera6e76d72022-02-11 21:43:503030 if _MatchesFile(input_api,
3031 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3032 return False
3033
3034 if (action == _GetIDLParseError
3035 and not _MatchesFile(input_api, idl_included_patterns, path)):
3036 return False
3037 return True
3038
3039 results = []
3040 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3041 include_deletes=False):
3042 action = get_action(affected_file)
3043 kwargs = {}
3044 if (action == _GetJSONParseError
3045 and _MatchesFile(input_api, json_no_comments_patterns,
3046 affected_file.LocalPath())):
3047 kwargs['eat_comments'] = False
3048 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3049 **kwargs)
3050 if parse_error:
3051 results.append(
3052 output_api.PresubmitError(
3053 '%s could not be parsed: %s' %
3054 (affected_file.LocalPath(), parse_error)))
3055 return results
3056
3057
3058def CheckJavaStyle(input_api, output_api):
3059 """Runs checkstyle on changed java files and returns errors if any exist."""
3060
3061 # Return early if no java files were modified.
3062 if not any(
3063 _IsJavaFile(input_api, f.LocalPath())
3064 for f in input_api.AffectedFiles()):
3065 return []
3066
3067 import sys
3068 original_sys_path = sys.path
3069 try:
3070 sys.path = sys.path + [
3071 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3072 'android', 'checkstyle')
3073 ]
3074 import checkstyle
3075 finally:
3076 # Restore sys.path to what it was before.
3077 sys.path = original_sys_path
3078
3079 return checkstyle.RunCheckstyle(
3080 input_api,
3081 output_api,
3082 'tools/android/checkstyle/chromium-style-5.0.xml',
3083 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3084
3085
3086def CheckPythonDevilInit(input_api, output_api):
3087 """Checks to make sure devil is initialized correctly in python scripts."""
3088 script_common_initialize_pattern = input_api.re.compile(
3089 r'script_common\.InitializeEnvironment\(')
3090 devil_env_config_initialize = input_api.re.compile(
3091 r'devil_env\.config\.Initialize\(')
3092
3093 errors = []
3094
3095 sources = lambda affected_file: input_api.FilterSourceFile(
3096 affected_file,
3097 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313098 r'^build/android/devil_chromium\.py',
3099 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503100 )),
3101 files_to_check=[r'.*\.py$'])
3102
3103 for f in input_api.AffectedSourceFiles(sources):
3104 for line_num, line in f.ChangedContents():
3105 if (script_common_initialize_pattern.search(line)
3106 or devil_env_config_initialize.search(line)):
3107 errors.append("%s:%d" % (f.LocalPath(), line_num))
3108
3109 results = []
3110
3111 if errors:
3112 results.append(
3113 output_api.PresubmitError(
3114 'Devil initialization should always be done using '
3115 'devil_chromium.Initialize() in the chromium project, to use better '
3116 'defaults for dependencies (ex. up-to-date version of adb).',
3117 errors))
3118
3119 return results
3120
3121
3122def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313123 # Consistently use / as path separator to simplify the writing of regex
3124 # expressions.
3125 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503126 for pattern in patterns:
3127 if input_api.re.search(pattern, path):
3128 return True
3129 return False
3130
3131
Daniel Chenga37c03db2022-05-12 17:20:343132def _ChangeHasSecurityReviewer(input_api, owners_file):
3133 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503134
Daniel Chenga37c03db2022-05-12 17:20:343135 Args:
3136 input_api: The presubmit input API.
3137 owners_file: OWNERS file with required reviewers. Typically, this is
3138 something like ipc/SECURITY_OWNERS.
3139
3140 Note: if the presubmit is running for commit rather than for upload, this
3141 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503142 """
Daniel Chengd88244472022-05-16 09:08:473143 # Owners-Override should bypass all additional OWNERS enforcement checks.
3144 # A CR+1 vote will still be required to land this change.
3145 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3146 input_api.change.issue)):
3147 return True
3148
Daniel Chenga37c03db2022-05-12 17:20:343149 owner_email, reviewers = (
3150 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113151 input_api,
3152 None,
3153 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503154
Daniel Chenga37c03db2022-05-12 17:20:343155 security_owners = input_api.owners_client.ListOwners(owners_file)
3156 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503157
Daniel Chenga37c03db2022-05-12 17:20:343158
3159@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253160class _SecurityProblemWithItems:
3161 problem: str
3162 items: Sequence[str]
3163
3164
3165@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343166class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253167 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343168 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253169 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343170
3171
3172def _FindMissingSecurityOwners(input_api,
3173 output_api,
3174 file_patterns: Sequence[str],
3175 excluded_patterns: Sequence[str],
3176 required_owners_file: str,
3177 custom_rule_function: Optional[Callable] = None
3178 ) -> _MissingSecurityOwnersResult:
3179 """Find OWNERS files missing per-file rules for security-sensitive files.
3180
3181 Args:
3182 input_api: the PRESUBMIT input API object.
3183 output_api: the PRESUBMIT output API object.
3184 file_patterns: basename patterns that require a corresponding per-file
3185 security restriction.
3186 excluded_patterns: path patterns that should be exempted from
3187 requiring a security restriction.
3188 required_owners_file: path to the required OWNERS file, e.g.
3189 ipc/SECURITY_OWNERS
3190 cc_alias: If not None, email that will be CCed automatically if the
3191 change contains security-sensitive files, as determined by
3192 `file_patterns` and `excluded_patterns`.
3193 custom_rule_function: If not None, will be called with `input_api` and
3194 the current file under consideration. Returning True will add an
3195 exact match per-file rule check for the current file.
3196 """
3197
3198 # `to_check` is a mapping of an OWNERS file path to Patterns.
3199 #
3200 # Patterns is a dictionary mapping glob patterns (suitable for use in
3201 # per-file rules) to a PatternEntry.
3202 #
Sam Maiera6e76d72022-02-11 21:43:503203 # PatternEntry is a dictionary with two keys:
3204 # - 'files': the files that are matched by this pattern
3205 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343206 #
Sam Maiera6e76d72022-02-11 21:43:503207 # For example, if we expect OWNERS file to contain rules for *.mojom and
3208 # *_struct_traits*.*, Patterns might look like this:
3209 # {
3210 # '*.mojom': {
3211 # 'files': ...,
3212 # 'rules': [
3213 # 'per-file *.mojom=set noparent',
3214 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3215 # ],
3216 # },
3217 # '*_struct_traits*.*': {
3218 # 'files': ...,
3219 # 'rules': [
3220 # 'per-file *_struct_traits*.*=set noparent',
3221 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3222 # ],
3223 # },
3224 # }
3225 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343226 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503227
Daniel Chenga37c03db2022-05-12 17:20:343228 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503229 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473230 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503231 if owners_file not in to_check:
3232 to_check[owners_file] = {}
3233 if pattern not in to_check[owners_file]:
3234 to_check[owners_file][pattern] = {
3235 'files': [],
3236 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343237 f'per-file {pattern}=set noparent',
3238 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503239 ]
3240 }
Daniel Chenged57a162022-05-25 02:56:343241 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343242 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503243
Daniel Chenga37c03db2022-05-12 17:20:343244 # Only enforce security OWNERS rules for a directory if that directory has a
3245 # file that matches `file_patterns`. For example, if a directory only
3246 # contains *.mojom files and no *_messages*.h files, the check should only
3247 # ensure that rules for *.mojom files are present.
3248 for file in input_api.AffectedFiles(include_deletes=False):
3249 file_basename = input_api.os_path.basename(file.LocalPath())
3250 if custom_rule_function is not None and custom_rule_function(
3251 input_api, file):
3252 AddPatternToCheck(file, file_basename)
3253 continue
Sam Maiera6e76d72022-02-11 21:43:503254
Daniel Chenga37c03db2022-05-12 17:20:343255 if any(
3256 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3257 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503258 continue
3259
3260 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343261 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3262 # file's basename.
3263 if input_api.fnmatch.fnmatch(file_basename, pattern):
3264 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503265 break
3266
Daniel Chenga37c03db2022-05-12 17:20:343267 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253268
3269 # Check if any newly added lines in OWNERS files intersect with required
3270 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3271 # This is a hack, but is needed because the OWNERS check (by design) ignores
3272 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3273 # OWNER and have that newly-added OWNER self-approve their own addition.
3274 newly_covered_files = []
3275 for file in input_api.AffectedFiles(include_deletes=False):
3276 if not file.LocalPath() in to_check:
3277 continue
3278 for _, line in file.ChangedContents():
3279 for _, entry in to_check[file.LocalPath()].items():
3280 if line in entry['rules']:
3281 newly_covered_files.extend(entry['files'])
3282
3283 missing_reviewer_problems = None
3284 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343285 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253286 missing_reviewer_problems = _SecurityProblemWithItems(
3287 f'Review from an owner in {required_owners_file} is required for '
3288 'the following newly-added files:',
3289 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503290
3291 # Go through the OWNERS files to check, filtering out rules that are already
3292 # present in that OWNERS file.
3293 for owners_file, patterns in to_check.items():
3294 try:
Daniel Cheng171dad8d2022-05-21 00:40:253295 lines = set(
3296 input_api.ReadFile(
3297 input_api.os_path.join(input_api.change.RepositoryRoot(),
3298 owners_file)).splitlines())
3299 for entry in patterns.values():
3300 entry['rules'] = [
3301 rule for rule in entry['rules'] if rule not in lines
3302 ]
Sam Maiera6e76d72022-02-11 21:43:503303 except IOError:
3304 # No OWNERS file, so all the rules are definitely missing.
3305 continue
3306
3307 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253308 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343309
Sam Maiera6e76d72022-02-11 21:43:503310 for owners_file, patterns in to_check.items():
3311 missing_lines = []
3312 files = []
3313 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343314 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503315 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503316 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253317 joined_missing_lines = '\n'.join(line for line in missing_lines)
3318 owners_file_problems.append(
3319 _SecurityProblemWithItems(
3320 'Found missing OWNERS lines for security-sensitive files. '
3321 f'Please add the following lines to {owners_file}:\n'
3322 f'{joined_missing_lines}\n\nTo ensure security review for:',
3323 files))
Daniel Chenga37c03db2022-05-12 17:20:343324
Daniel Cheng171dad8d2022-05-21 00:40:253325 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343326 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253327 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343328
3329
3330def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3331 # Whether or not a file affects IPC is (mostly) determined by a simple list
3332 # of filename patterns.
3333 file_patterns = [
3334 # Legacy IPC:
3335 '*_messages.cc',
3336 '*_messages*.h',
3337 '*_param_traits*.*',
3338 # Mojo IPC:
3339 '*.mojom',
3340 '*_mojom_traits*.*',
3341 '*_type_converter*.*',
3342 # Android native IPC:
3343 '*.aidl',
3344 ]
3345
Daniel Chenga37c03db2022-05-12 17:20:343346 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463347 # These third_party directories do not contain IPCs, but contain files
3348 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343349 'third_party/crashpad/*',
3350 'third_party/blink/renderer/platform/bindings/*',
3351 'third_party/protobuf/benchmarks/python/*',
3352 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473353 # Enum-only mojoms used for web metrics, so no security review needed.
3354 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343355 # These files are just used to communicate between class loaders running
3356 # in the same process.
3357 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3358 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3359 ]
3360
3361 def IsMojoServiceManifestFile(input_api, file):
3362 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3363 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3364 if not manifest_pattern.search(file.LocalPath()):
3365 return False
3366
3367 if test_manifest_pattern.search(file.LocalPath()):
3368 return False
3369
3370 # All actual service manifest files should contain at least one
3371 # qualified reference to service_manager::Manifest.
3372 return any('service_manager::Manifest' in line
3373 for line in file.NewContents())
3374
3375 return _FindMissingSecurityOwners(
3376 input_api,
3377 output_api,
3378 file_patterns,
3379 excluded_patterns,
3380 'ipc/SECURITY_OWNERS',
3381 custom_rule_function=IsMojoServiceManifestFile)
3382
3383
3384def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3385 file_patterns = [
3386 # Component specifications.
3387 '*.cml', # Component Framework v2.
3388 '*.cmx', # Component Framework v1.
3389
3390 # Fuchsia IDL protocol specifications.
3391 '*.fidl',
3392 ]
3393
3394 # Don't check for owners files for changes in these directories.
3395 excluded_patterns = [
3396 'third_party/crashpad/*',
3397 ]
3398
3399 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3400 excluded_patterns,
3401 'build/fuchsia/SECURITY_OWNERS')
3402
3403
3404def CheckSecurityOwners(input_api, output_api):
3405 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3406 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3407 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3408 input_api, output_api)
3409
3410 if ipc_results.has_security_sensitive_files:
3411 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503412
3413 results = []
Daniel Chenga37c03db2022-05-12 17:20:343414
Daniel Cheng171dad8d2022-05-21 00:40:253415 missing_reviewer_problems = []
3416 if ipc_results.missing_reviewer_problem:
3417 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3418 if fuchsia_results.missing_reviewer_problem:
3419 missing_reviewer_problems.append(
3420 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343421
Daniel Cheng171dad8d2022-05-21 00:40:253422 # Missing reviewers are an error unless there's no issue number
3423 # associated with this branch; in that case, the presubmit is being run
3424 # with --all or --files.
3425 #
3426 # Note that upload should never be an error; otherwise, it would be
3427 # impossible to upload changes at all.
3428 if input_api.is_committing and input_api.change.issue:
3429 make_presubmit_message = output_api.PresubmitError
3430 else:
3431 make_presubmit_message = output_api.PresubmitNotifyResult
3432 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503433 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253434 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343435
Daniel Cheng171dad8d2022-05-21 00:40:253436 owners_file_problems = []
3437 owners_file_problems.extend(ipc_results.owners_file_problems)
3438 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343439
Daniel Cheng171dad8d2022-05-21 00:40:253440 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113441 # Missing per-file rules are always an error. While swarming and caching
3442 # means that uploading a patchset with updated OWNERS files and sending
3443 # it to the CQ again should not have a large incremental cost, it is
3444 # still frustrating to discover the error only after the change has
3445 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343446 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253447 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503448
3449 return results
3450
3451
3452def _GetFilesUsingSecurityCriticalFunctions(input_api):
3453 """Checks affected files for changes to security-critical calls. This
3454 function checks the full change diff, to catch both additions/changes
3455 and removals.
3456
3457 Returns a dict keyed by file name, and the value is a set of detected
3458 functions.
3459 """
3460 # Map of function pretty name (displayed in an error) to the pattern to
3461 # match it with.
3462 _PATTERNS_TO_CHECK = {
3463 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3464 }
3465 _PATTERNS_TO_CHECK = {
3466 k: input_api.re.compile(v)
3467 for k, v in _PATTERNS_TO_CHECK.items()
3468 }
3469
Sam Maiera6e76d72022-02-11 21:43:503470 # We don't want to trigger on strings within this file.
3471 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343472 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503473
3474 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3475 files_to_functions = {}
3476 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3477 diff = f.GenerateScmDiff()
3478 for line in diff.split('\n'):
3479 # Not using just RightHandSideLines() because removing a
3480 # call to a security-critical function can be just as important
3481 # as adding or changing the arguments.
3482 if line.startswith('-') or (line.startswith('+')
3483 and not line.startswith('++')):
3484 for name, pattern in _PATTERNS_TO_CHECK.items():
3485 if pattern.search(line):
3486 path = f.LocalPath()
3487 if not path in files_to_functions:
3488 files_to_functions[path] = set()
3489 files_to_functions[path].add(name)
3490 return files_to_functions
3491
3492
3493def CheckSecurityChanges(input_api, output_api):
3494 """Checks that changes involving security-critical functions are reviewed
3495 by the security team.
3496 """
3497 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3498 if not len(files_to_functions):
3499 return []
3500
Sam Maiera6e76d72022-02-11 21:43:503501 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343502 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503503 return []
3504
Daniel Chenga37c03db2022-05-12 17:20:343505 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503506 'that need to be reviewed by {}.\n'.format(owners_file)
3507 for path, names in files_to_functions.items():
3508 msg += ' {}\n'.format(path)
3509 for name in names:
3510 msg += ' {}\n'.format(name)
3511 msg += '\n'
3512
3513 if input_api.is_committing:
3514 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033515 else:
Sam Maiera6e76d72022-02-11 21:43:503516 output = output_api.PresubmitNotifyResult
3517 return [output(msg)]
3518
3519
3520def CheckSetNoParent(input_api, output_api):
3521 """Checks that set noparent is only used together with an OWNERS file in
3522 //build/OWNERS.setnoparent (see also
3523 //docs/code_reviews.md#owners-files-details)
3524 """
3525 # Return early if no OWNERS files were modified.
3526 if not any(f.LocalPath().endswith('OWNERS')
3527 for f in input_api.AffectedFiles(include_deletes=False)):
3528 return []
3529
3530 errors = []
3531
3532 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3533 allowed_owners_files = set()
3534 with open(allowed_owners_files_file, 'r') as f:
3535 for line in f:
3536 line = line.strip()
3537 if not line or line.startswith('#'):
3538 continue
3539 allowed_owners_files.add(line)
3540
3541 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3542
3543 for f in input_api.AffectedFiles(include_deletes=False):
3544 if not f.LocalPath().endswith('OWNERS'):
3545 continue
3546
3547 found_owners_files = set()
3548 found_set_noparent_lines = dict()
3549
3550 # Parse the OWNERS file.
3551 for lineno, line in enumerate(f.NewContents(), 1):
3552 line = line.strip()
3553 if line.startswith('set noparent'):
3554 found_set_noparent_lines[''] = lineno
3555 if line.startswith('file://'):
3556 if line in allowed_owners_files:
3557 found_owners_files.add('')
3558 if line.startswith('per-file'):
3559 match = per_file_pattern.match(line)
3560 if match:
3561 glob = match.group(1).strip()
3562 directive = match.group(2).strip()
3563 if directive == 'set noparent':
3564 found_set_noparent_lines[glob] = lineno
3565 if directive.startswith('file://'):
3566 if directive in allowed_owners_files:
3567 found_owners_files.add(glob)
3568
3569 # Check that every set noparent line has a corresponding file:// line
3570 # listed in build/OWNERS.setnoparent. An exception is made for top level
3571 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493572 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3573 if (linux_path.count('/') != 1
3574 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503575 for set_noparent_line in found_set_noparent_lines:
3576 if set_noparent_line in found_owners_files:
3577 continue
3578 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493579 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503580 found_set_noparent_lines[set_noparent_line]))
3581
3582 results = []
3583 if errors:
3584 if input_api.is_committing:
3585 output = output_api.PresubmitError
3586 else:
3587 output = output_api.PresubmitPromptWarning
3588 results.append(
3589 output(
3590 'Found the following "set noparent" restrictions in OWNERS files that '
3591 'do not include owners from build/OWNERS.setnoparent:',
3592 long_text='\n\n'.join(errors)))
3593 return results
3594
3595
3596def CheckUselessForwardDeclarations(input_api, output_api):
3597 """Checks that added or removed lines in non third party affected
3598 header files do not lead to new useless class or struct forward
3599 declaration.
3600 """
3601 results = []
3602 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3603 input_api.re.MULTILINE)
3604 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3605 input_api.re.MULTILINE)
3606 for f in input_api.AffectedFiles(include_deletes=False):
3607 if (f.LocalPath().startswith('third_party')
3608 and not f.LocalPath().startswith('third_party/blink')
3609 and not f.LocalPath().startswith('third_party\\blink')):
3610 continue
3611
3612 if not f.LocalPath().endswith('.h'):
3613 continue
3614
3615 contents = input_api.ReadFile(f)
3616 fwd_decls = input_api.re.findall(class_pattern, contents)
3617 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3618
3619 useless_fwd_decls = []
3620 for decl in fwd_decls:
3621 count = sum(1 for _ in input_api.re.finditer(
3622 r'\b%s\b' % input_api.re.escape(decl), contents))
3623 if count == 1:
3624 useless_fwd_decls.append(decl)
3625
3626 if not useless_fwd_decls:
3627 continue
3628
3629 for line in f.GenerateScmDiff().splitlines():
3630 if (line.startswith('-') and not line.startswith('--')
3631 or line.startswith('+') and not line.startswith('++')):
3632 for decl in useless_fwd_decls:
3633 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3634 results.append(
3635 output_api.PresubmitPromptWarning(
3636 '%s: %s forward declaration is no longer needed'
3637 % (f.LocalPath(), decl)))
3638 useless_fwd_decls.remove(decl)
3639
3640 return results
3641
3642
3643def _CheckAndroidDebuggableBuild(input_api, output_api):
3644 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3645 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3646 this is a debuggable build of Android.
3647 """
3648 build_type_check_pattern = input_api.re.compile(
3649 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3650
3651 errors = []
3652
3653 sources = lambda affected_file: input_api.FilterSourceFile(
3654 affected_file,
3655 files_to_skip=(
3656 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3657 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313658 r"^android_webview/support_library/boundary_interfaces/",
3659 r"^chrome/android/webapk/.*",
3660 r'^third_party/.*',
3661 r"tools/android/customtabs_benchmark/.*",
3662 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:503663 )),
3664 files_to_check=[r'.*\.java$'])
3665
3666 for f in input_api.AffectedSourceFiles(sources):
3667 for line_num, line in f.ChangedContents():
3668 if build_type_check_pattern.search(line):
3669 errors.append("%s:%d" % (f.LocalPath(), line_num))
3670
3671 results = []
3672
3673 if errors:
3674 results.append(
3675 output_api.PresubmitPromptWarning(
3676 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3677 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3678
3679 return results
3680
3681# TODO: add unit tests
3682def _CheckAndroidToastUsage(input_api, output_api):
3683 """Checks that code uses org.chromium.ui.widget.Toast instead of
3684 android.widget.Toast (Chromium Toast doesn't force hardware
3685 acceleration on low-end devices, saving memory).
3686 """
3687 toast_import_pattern = input_api.re.compile(
3688 r'^import android\.widget\.Toast;$')
3689
3690 errors = []
3691
3692 sources = lambda affected_file: input_api.FilterSourceFile(
3693 affected_file,
3694 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:313695 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
3696 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:503697 files_to_check=[r'.*\.java$'])
3698
3699 for f in input_api.AffectedSourceFiles(sources):
3700 for line_num, line in f.ChangedContents():
3701 if toast_import_pattern.search(line):
3702 errors.append("%s:%d" % (f.LocalPath(), line_num))
3703
3704 results = []
3705
3706 if errors:
3707 results.append(
3708 output_api.PresubmitError(
3709 'android.widget.Toast usage is detected. Android toasts use hardware'
3710 ' acceleration, and can be\ncostly on low-end devices. Please use'
3711 ' org.chromium.ui.widget.Toast instead.\n'
3712 'Contact [email protected] if you have any questions.',
3713 errors))
3714
3715 return results
3716
3717
3718def _CheckAndroidCrLogUsage(input_api, output_api):
3719 """Checks that new logs using org.chromium.base.Log:
3720 - Are using 'TAG' as variable name for the tags (warn)
3721 - Are using a tag that is shorter than 20 characters (error)
3722 """
3723
3724 # Do not check format of logs in the given files
3725 cr_log_check_excluded_paths = [
3726 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:313727 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:503728 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:313729 r"^android_webview/glue/java/src/com/android/"
3730 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:503731 # The customtabs_benchmark is a small app that does not depend on Chromium
3732 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:313733 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:503734 ]
3735
3736 cr_log_import_pattern = input_api.re.compile(
3737 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3738 class_in_base_pattern = input_api.re.compile(
3739 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3740 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3741 input_api.re.MULTILINE)
3742 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3743 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3744 log_decl_pattern = input_api.re.compile(
3745 r'static final String TAG = "(?P<name>(.*))"')
3746 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3747
3748 REF_MSG = ('See docs/android_logging.md for more info.')
3749 sources = lambda x: input_api.FilterSourceFile(
3750 x,
3751 files_to_check=[r'.*\.java$'],
3752 files_to_skip=cr_log_check_excluded_paths)
3753
3754 tag_decl_errors = []
3755 tag_length_errors = []
3756 tag_errors = []
3757 tag_with_dot_errors = []
3758 util_log_errors = []
3759
3760 for f in input_api.AffectedSourceFiles(sources):
3761 file_content = input_api.ReadFile(f)
3762 has_modified_logs = False
3763 # Per line checks
3764 if (cr_log_import_pattern.search(file_content)
3765 or (class_in_base_pattern.search(file_content)
3766 and not has_some_log_import_pattern.search(file_content))):
3767 # Checks to run for files using cr log
3768 for line_num, line in f.ChangedContents():
3769 if rough_log_decl_pattern.search(line):
3770 has_modified_logs = True
3771
3772 # Check if the new line is doing some logging
3773 match = log_call_pattern.search(line)
3774 if match:
3775 has_modified_logs = True
3776
3777 # Make sure it uses "TAG"
3778 if not match.group('tag') == 'TAG':
3779 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3780 else:
3781 # Report non cr Log function calls in changed lines
3782 for line_num, line in f.ChangedContents():
3783 if log_call_pattern.search(line):
3784 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3785
3786 # Per file checks
3787 if has_modified_logs:
3788 # Make sure the tag is using the "cr" prefix and is not too long
3789 match = log_decl_pattern.search(file_content)
3790 tag_name = match.group('name') if match else None
3791 if not tag_name:
3792 tag_decl_errors.append(f.LocalPath())
3793 elif len(tag_name) > 20:
3794 tag_length_errors.append(f.LocalPath())
3795 elif '.' in tag_name:
3796 tag_with_dot_errors.append(f.LocalPath())
3797
3798 results = []
3799 if tag_decl_errors:
3800 results.append(
3801 output_api.PresubmitPromptWarning(
3802 'Please define your tags using the suggested format: .\n'
3803 '"private static final String TAG = "<package tag>".\n'
3804 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3805 tag_decl_errors))
3806
3807 if tag_length_errors:
3808 results.append(
3809 output_api.PresubmitError(
3810 'The tag length is restricted by the system to be at most '
3811 '20 characters.\n' + REF_MSG, tag_length_errors))
3812
3813 if tag_errors:
3814 results.append(
3815 output_api.PresubmitPromptWarning(
3816 'Please use a variable named "TAG" for your log tags.\n' +
3817 REF_MSG, tag_errors))
3818
3819 if util_log_errors:
3820 results.append(
3821 output_api.PresubmitPromptWarning(
3822 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3823 util_log_errors))
3824
3825 if tag_with_dot_errors:
3826 results.append(
3827 output_api.PresubmitPromptWarning(
3828 'Dot in log tags cause them to be elided in crash reports.\n' +
3829 REF_MSG, tag_with_dot_errors))
3830
3831 return results
3832
3833
3834def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3835 """Checks that junit.framework.* is no longer used."""
3836 deprecated_junit_framework_pattern = input_api.re.compile(
3837 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3838 sources = lambda x: input_api.FilterSourceFile(
3839 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3840 errors = []
3841 for f in input_api.AffectedFiles(file_filter=sources):
3842 for line_num, line in f.ChangedContents():
3843 if deprecated_junit_framework_pattern.search(line):
3844 errors.append("%s:%d" % (f.LocalPath(), line_num))
3845
3846 results = []
3847 if errors:
3848 results.append(
3849 output_api.PresubmitError(
3850 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3851 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3852 ' if you have any question.', errors))
3853 return results
3854
3855
3856def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3857 """Checks that if new Java test classes have inheritance.
3858 Either the new test class is JUnit3 test or it is a JUnit4 test class
3859 with a base class, either case is undesirable.
3860 """
3861 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3862
3863 sources = lambda x: input_api.FilterSourceFile(
3864 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3865 errors = []
3866 for f in input_api.AffectedFiles(file_filter=sources):
3867 if not f.OldContents():
3868 class_declaration_start_flag = False
3869 for line_num, line in f.ChangedContents():
3870 if class_declaration_pattern.search(line):
3871 class_declaration_start_flag = True
3872 if class_declaration_start_flag and ' extends ' in line:
3873 errors.append('%s:%d' % (f.LocalPath(), line_num))
3874 if '{' in line:
3875 class_declaration_start_flag = False
3876
3877 results = []
3878 if errors:
3879 results.append(
3880 output_api.PresubmitPromptWarning(
3881 'The newly created files include Test classes that inherits from base'
3882 ' class. Please do not use inheritance in JUnit4 tests or add new'
3883 ' JUnit3 tests. Contact [email protected] if you have any'
3884 ' questions.', errors))
3885 return results
3886
3887
3888def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3889 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3890 deprecated_annotation_import_pattern = input_api.re.compile(
3891 r'^import android\.test\.suitebuilder\.annotation\..*;',
3892 input_api.re.MULTILINE)
3893 sources = lambda x: input_api.FilterSourceFile(
3894 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3895 errors = []
3896 for f in input_api.AffectedFiles(file_filter=sources):
3897 for line_num, line in f.ChangedContents():
3898 if deprecated_annotation_import_pattern.search(line):
3899 errors.append("%s:%d" % (f.LocalPath(), line_num))
3900
3901 results = []
3902 if errors:
3903 results.append(
3904 output_api.PresubmitError(
3905 'Annotations in android.test.suitebuilder.annotation have been'
3906 ' deprecated since API level 24. Please use android.support.test.filters'
3907 ' from //third_party/android_support_test_runner:runner_java instead.'
3908 ' Contact [email protected] if you have any questions.',
3909 errors))
3910 return results
3911
3912
3913def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3914 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:513915 file_filter = lambda f: (f.LocalPath().endswith(
3916 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
3917 LocalPath() or '/res/drawable-ldrtl/'.replace(
3918 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:503919 errors = []
3920 for f in input_api.AffectedFiles(include_deletes=False,
3921 file_filter=file_filter):
3922 errors.append(' %s' % f.LocalPath())
3923
3924 results = []
3925 if errors:
3926 results.append(
3927 output_api.PresubmitError(
3928 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3929 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3930 '/res/drawable-ldrtl/.\n'
3931 'Contact [email protected] if you have questions.', errors))
3932 return results
3933
3934
3935def _CheckAndroidWebkitImports(input_api, output_api):
3936 """Checks that code uses org.chromium.base.Callback instead of
3937 android.webview.ValueCallback except in the WebView glue layer
3938 and WebLayer.
3939 """
3940 valuecallback_import_pattern = input_api.re.compile(
3941 r'^import android\.webkit\.ValueCallback;$')
3942
3943 errors = []
3944
3945 sources = lambda affected_file: input_api.FilterSourceFile(
3946 affected_file,
3947 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3948 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313949 r'^android_webview/glue/.*',
3950 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:503951 )),
3952 files_to_check=[r'.*\.java$'])
3953
3954 for f in input_api.AffectedSourceFiles(sources):
3955 for line_num, line in f.ChangedContents():
3956 if valuecallback_import_pattern.search(line):
3957 errors.append("%s:%d" % (f.LocalPath(), line_num))
3958
3959 results = []
3960
3961 if errors:
3962 results.append(
3963 output_api.PresubmitError(
3964 'android.webkit.ValueCallback usage is detected outside of the glue'
3965 ' layer. To stay compatible with the support library, android.webkit.*'
3966 ' classes should only be used inside the glue layer and'
3967 ' org.chromium.base.Callback should be used instead.', errors))
3968
3969 return results
3970
3971
3972def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3973 """Checks Android XML styles """
3974
3975 # Return early if no relevant files were modified.
3976 if not any(
3977 _IsXmlOrGrdFile(input_api, f.LocalPath())
3978 for f in input_api.AffectedFiles(include_deletes=False)):
3979 return []
3980
3981 import sys
3982 original_sys_path = sys.path
3983 try:
3984 sys.path = sys.path + [
3985 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3986 'android', 'checkxmlstyle')
3987 ]
3988 import checkxmlstyle
3989 finally:
3990 # Restore sys.path to what it was before.
3991 sys.path = original_sys_path
3992
3993 if is_check_on_upload:
3994 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3995 else:
3996 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3997
3998
3999def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4000 """Checks Android Infobar Deprecation """
4001
4002 import sys
4003 original_sys_path = sys.path
4004 try:
4005 sys.path = sys.path + [
4006 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4007 'android', 'infobar_deprecation')
4008 ]
4009 import infobar_deprecation
4010 finally:
4011 # Restore sys.path to what it was before.
4012 sys.path = original_sys_path
4013
4014 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4015
4016
4017class _PydepsCheckerResult:
4018 def __init__(self, cmd, pydeps_path, process, old_contents):
4019 self._cmd = cmd
4020 self._pydeps_path = pydeps_path
4021 self._process = process
4022 self._old_contents = old_contents
4023
4024 def GetError(self):
4025 """Returns an error message, or None."""
4026 import difflib
4027 if self._process.wait() != 0:
4028 # STDERR should already be printed.
4029 return 'Command failed: ' + self._cmd
4030 new_contents = self._process.stdout.read().splitlines()[2:]
4031 if self._old_contents != new_contents:
4032 diff = '\n'.join(
4033 difflib.context_diff(self._old_contents, new_contents))
4034 return ('File is stale: {}\n'
4035 'Diff (apply to fix):\n'
4036 '{}\n'
4037 'To regenerate, run:\n\n'
4038 ' {}').format(self._pydeps_path, diff, self._cmd)
4039 return None
4040
4041
4042class PydepsChecker:
4043 def __init__(self, input_api, pydeps_files):
4044 self._file_cache = {}
4045 self._input_api = input_api
4046 self._pydeps_files = pydeps_files
4047
4048 def _LoadFile(self, path):
4049 """Returns the list of paths within a .pydeps file relative to //."""
4050 if path not in self._file_cache:
4051 with open(path, encoding='utf-8') as f:
4052 self._file_cache[path] = f.read()
4053 return self._file_cache[path]
4054
4055 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594056 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504057 pydeps_data = self._LoadFile(pydeps_path)
4058 uses_gn_paths = '--gn-paths' in pydeps_data
4059 entries = (l for l in pydeps_data.splitlines()
4060 if not l.startswith('#'))
4061 if uses_gn_paths:
4062 # Paths look like: //foo/bar/baz
4063 return (e[2:] for e in entries)
4064 else:
4065 # Paths look like: path/relative/to/file.pydeps
4066 os_path = self._input_api.os_path
4067 pydeps_dir = os_path.dirname(pydeps_path)
4068 return (os_path.normpath(os_path.join(pydeps_dir, e))
4069 for e in entries)
4070
4071 def _CreateFilesToPydepsMap(self):
4072 """Returns a map of local_path -> list_of_pydeps."""
4073 ret = {}
4074 for pydep_local_path in self._pydeps_files:
4075 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4076 ret.setdefault(path, []).append(pydep_local_path)
4077 return ret
4078
4079 def ComputeAffectedPydeps(self):
4080 """Returns an iterable of .pydeps files that might need regenerating."""
4081 affected_pydeps = set()
4082 file_to_pydeps_map = None
4083 for f in self._input_api.AffectedFiles(include_deletes=True):
4084 local_path = f.LocalPath()
4085 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4086 # subrepositories. We can't figure out which files change, so re-check
4087 # all files.
4088 # Changes to print_python_deps.py affect all .pydeps.
4089 if local_path in ('DEPS', 'PRESUBMIT.py'
4090 ) or local_path.endswith('print_python_deps.py'):
4091 return self._pydeps_files
4092 elif local_path.endswith('.pydeps'):
4093 if local_path in self._pydeps_files:
4094 affected_pydeps.add(local_path)
4095 elif local_path.endswith('.py'):
4096 if file_to_pydeps_map is None:
4097 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4098 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4099 return affected_pydeps
4100
4101 def DetermineIfStaleAsync(self, pydeps_path):
4102 """Runs print_python_deps.py to see if the files is stale."""
4103 import os
4104
4105 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4106 if old_pydeps_data:
4107 cmd = old_pydeps_data[1][1:].strip()
4108 if '--output' not in cmd:
4109 cmd += ' --output ' + pydeps_path
4110 old_contents = old_pydeps_data[2:]
4111 else:
4112 # A default cmd that should work in most cases (as long as pydeps filename
4113 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4114 # file is empty/new.
4115 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4116 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4117 old_contents = []
4118 env = dict(os.environ)
4119 env['PYTHONDONTWRITEBYTECODE'] = '1'
4120 process = self._input_api.subprocess.Popen(
4121 cmd + ' --output ""',
4122 shell=True,
4123 env=env,
4124 stdout=self._input_api.subprocess.PIPE,
4125 encoding='utf-8')
4126 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404127
4128
Tibor Goldschwendt360793f72019-06-25 18:23:494129def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504130 args = {}
4131 with open('build/config/gclient_args.gni', 'r') as f:
4132 for line in f:
4133 line = line.strip()
4134 if not line or line.startswith('#'):
4135 continue
4136 attribute, value = line.split('=')
4137 args[attribute.strip()] = value.strip()
4138 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494139
4140
Saagar Sanghavifceeaae2020-08-12 16:40:364141def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504142 """Checks if a .pydeps file needs to be regenerated."""
4143 # This check is for Python dependency lists (.pydeps files), and involves
4144 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4145 # doesn't work on Windows and Mac, so skip it on other platforms.
4146 if not input_api.platform.startswith('linux'):
4147 return []
Erik Staabc734cd7a2021-11-23 03:11:524148
Sam Maiera6e76d72022-02-11 21:43:504149 results = []
4150 # First, check for new / deleted .pydeps.
4151 for f in input_api.AffectedFiles(include_deletes=True):
4152 # Check whether we are running the presubmit check for a file in src.
4153 # f.LocalPath is relative to repo (src, or internal repo).
4154 # os_path.exists is relative to src repo.
4155 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4156 # to src and we can conclude that the pydeps is in src.
4157 if f.LocalPath().endswith('.pydeps'):
4158 if input_api.os_path.exists(f.LocalPath()):
4159 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4160 results.append(
4161 output_api.PresubmitError(
4162 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4163 'remove %s' % f.LocalPath()))
4164 elif f.Action() != 'D' and f.LocalPath(
4165 ) not in _ALL_PYDEPS_FILES:
4166 results.append(
4167 output_api.PresubmitError(
4168 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4169 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404170
Sam Maiera6e76d72022-02-11 21:43:504171 if results:
4172 return results
4173
4174 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4175 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4176 affected_pydeps = set(checker.ComputeAffectedPydeps())
4177 affected_android_pydeps = affected_pydeps.intersection(
4178 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4179 if affected_android_pydeps and not is_android:
4180 results.append(
4181 output_api.PresubmitPromptOrNotify(
4182 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594183 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504184 'run because you are not using an Android checkout. To validate that\n'
4185 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4186 'use the android-internal-presubmit optional trybot.\n'
4187 'Possibly stale pydeps files:\n{}'.format(
4188 '\n'.join(affected_android_pydeps))))
4189
4190 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4191 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4192 # Process these concurrently, as each one takes 1-2 seconds.
4193 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4194 for result in pydep_results:
4195 error_msg = result.GetError()
4196 if error_msg:
4197 results.append(output_api.PresubmitError(error_msg))
4198
agrievef32bcc72016-04-04 14:57:404199 return results
4200
agrievef32bcc72016-04-04 14:57:404201
Saagar Sanghavifceeaae2020-08-12 16:40:364202def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504203 """Checks to make sure no header files have |Singleton<|."""
4204
4205 def FileFilter(affected_file):
4206 # It's ok for base/memory/singleton.h to have |Singleton<|.
4207 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314208 (r"^base/memory/singleton\.h$",
4209 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504210 return input_api.FilterSourceFile(affected_file,
4211 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434212
Sam Maiera6e76d72022-02-11 21:43:504213 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4214 files = []
4215 for f in input_api.AffectedSourceFiles(FileFilter):
4216 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4217 or f.LocalPath().endswith('.hpp')
4218 or f.LocalPath().endswith('.inl')):
4219 contents = input_api.ReadFile(f)
4220 for line in contents.splitlines(False):
4221 if (not line.lstrip().startswith('//')
4222 and # Strip C++ comment.
4223 pattern.search(line)):
4224 files.append(f)
4225 break
glidere61efad2015-02-18 17:39:434226
Sam Maiera6e76d72022-02-11 21:43:504227 if files:
4228 return [
4229 output_api.PresubmitError(
4230 'Found base::Singleton<T> in the following header files.\n' +
4231 'Please move them to an appropriate source file so that the ' +
4232 'template gets instantiated in a single compilation unit.',
4233 files)
4234 ]
4235 return []
glidere61efad2015-02-18 17:39:434236
4237
[email protected]fd20b902014-05-09 02:14:534238_DEPRECATED_CSS = [
4239 # Values
4240 ( "-webkit-box", "flex" ),
4241 ( "-webkit-inline-box", "inline-flex" ),
4242 ( "-webkit-flex", "flex" ),
4243 ( "-webkit-inline-flex", "inline-flex" ),
4244 ( "-webkit-min-content", "min-content" ),
4245 ( "-webkit-max-content", "max-content" ),
4246
4247 # Properties
4248 ( "-webkit-background-clip", "background-clip" ),
4249 ( "-webkit-background-origin", "background-origin" ),
4250 ( "-webkit-background-size", "background-size" ),
4251 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444252 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:534253
4254 # Functions
4255 ( "-webkit-gradient", "gradient" ),
4256 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4257 ( "-webkit-linear-gradient", "linear-gradient" ),
4258 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4259 ( "-webkit-radial-gradient", "radial-gradient" ),
4260 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4261]
4262
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204263
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494264# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364265def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504266 """ Make sure that we don't use deprecated CSS
4267 properties, functions or values. Our external
4268 documentation and iOS CSS for dom distiller
4269 (reader mode) are ignored by the hooks as it
4270 needs to be consumed by WebKit. """
4271 results = []
4272 file_inclusion_pattern = [r".+\.css$"]
4273 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4274 input_api.DEFAULT_FILES_TO_SKIP +
4275 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4276 r"^native_client_sdk"))
4277 file_filter = lambda f: input_api.FilterSourceFile(
4278 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4279 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4280 for line_num, line in fpath.ChangedContents():
4281 for (deprecated_value, value) in _DEPRECATED_CSS:
4282 if deprecated_value in line:
4283 results.append(
4284 output_api.PresubmitError(
4285 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4286 (fpath.LocalPath(), line_num, deprecated_value,
4287 value)))
4288 return results
[email protected]fd20b902014-05-09 02:14:534289
mohan.reddyf21db962014-10-16 12:26:474290
Saagar Sanghavifceeaae2020-08-12 16:40:364291def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504292 bad_files = {}
4293 for f in input_api.AffectedFiles(include_deletes=False):
4294 if (f.LocalPath().startswith('third_party')
4295 and not f.LocalPath().startswith('third_party/blink')
4296 and not f.LocalPath().startswith('third_party\\blink')):
4297 continue
rlanday6802cf632017-05-30 17:48:364298
Sam Maiera6e76d72022-02-11 21:43:504299 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4300 continue
rlanday6802cf632017-05-30 17:48:364301
Sam Maiera6e76d72022-02-11 21:43:504302 relative_includes = [
4303 line for _, line in f.ChangedContents()
4304 if "#include" in line and "../" in line
4305 ]
4306 if not relative_includes:
4307 continue
4308 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364309
Sam Maiera6e76d72022-02-11 21:43:504310 if not bad_files:
4311 return []
rlanday6802cf632017-05-30 17:48:364312
Sam Maiera6e76d72022-02-11 21:43:504313 error_descriptions = []
4314 for file_path, bad_lines in bad_files.items():
4315 error_description = file_path
4316 for line in bad_lines:
4317 error_description += '\n ' + line
4318 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364319
Sam Maiera6e76d72022-02-11 21:43:504320 results = []
4321 results.append(
4322 output_api.PresubmitError(
4323 'You added one or more relative #include paths (including "../").\n'
4324 'These shouldn\'t be used because they can be used to include headers\n'
4325 'from code that\'s not correctly specified as a dependency in the\n'
4326 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364327
Sam Maiera6e76d72022-02-11 21:43:504328 return results
rlanday6802cf632017-05-30 17:48:364329
Takeshi Yoshinoe387aa32017-08-02 13:16:134330
Saagar Sanghavifceeaae2020-08-12 16:40:364331def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504332 """Check that nobody tries to include a cc file. It's a relatively
4333 common error which results in duplicate symbols in object
4334 files. This may not always break the build until someone later gets
4335 very confusing linking errors."""
4336 results = []
4337 for f in input_api.AffectedFiles(include_deletes=False):
4338 # We let third_party code do whatever it wants
4339 if (f.LocalPath().startswith('third_party')
4340 and not f.LocalPath().startswith('third_party/blink')
4341 and not f.LocalPath().startswith('third_party\\blink')):
4342 continue
Daniel Bratell65b033262019-04-23 08:17:064343
Sam Maiera6e76d72022-02-11 21:43:504344 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4345 continue
Daniel Bratell65b033262019-04-23 08:17:064346
Sam Maiera6e76d72022-02-11 21:43:504347 for _, line in f.ChangedContents():
4348 if line.startswith('#include "'):
4349 included_file = line.split('"')[1]
4350 if _IsCPlusPlusFile(input_api, included_file):
4351 # The most common naming for external files with C++ code,
4352 # apart from standard headers, is to call them foo.inc, but
4353 # Chromium sometimes uses foo-inc.cc so allow that as well.
4354 if not included_file.endswith(('.h', '-inc.cc')):
4355 results.append(
4356 output_api.PresubmitError(
4357 'Only header files or .inc files should be included in other\n'
4358 'C++ files. Compiling the contents of a cc file more than once\n'
4359 'will cause duplicate information in the build which may later\n'
4360 'result in strange link_errors.\n' +
4361 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064362
Sam Maiera6e76d72022-02-11 21:43:504363 return results
Daniel Bratell65b033262019-04-23 08:17:064364
4365
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204366def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504367 if not isinstance(key, ast.Str):
4368 return 'Key at line %d must be a string literal' % key.lineno
4369 if not isinstance(value, ast.Dict):
4370 return 'Value at line %d must be a dict' % value.lineno
4371 if len(value.keys) != 1:
4372 return 'Dict at line %d must have single entry' % value.lineno
4373 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4374 return (
4375 'Entry at line %d must have a string literal \'filepath\' as key' %
4376 value.lineno)
4377 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134378
Takeshi Yoshinoe387aa32017-08-02 13:16:134379
Sergey Ulanov4af16052018-11-08 02:41:464380def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504381 if not isinstance(key, ast.Str):
4382 return 'Key at line %d must be a string literal' % key.lineno
4383 if not isinstance(value, ast.List):
4384 return 'Value at line %d must be a list' % value.lineno
4385 for element in value.elts:
4386 if not isinstance(element, ast.Str):
4387 return 'Watchlist elements on line %d is not a string' % key.lineno
4388 if not email_regex.match(element.s):
4389 return ('Watchlist element on line %d doesn\'t look like a valid '
4390 + 'email: %s') % (key.lineno, element.s)
4391 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134392
Takeshi Yoshinoe387aa32017-08-02 13:16:134393
Sergey Ulanov4af16052018-11-08 02:41:464394def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504395 mismatch_template = (
4396 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4397 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134398
Sam Maiera6e76d72022-02-11 21:43:504399 email_regex = input_api.re.compile(
4400 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464401
Sam Maiera6e76d72022-02-11 21:43:504402 ast = input_api.ast
4403 i = 0
4404 last_key = ''
4405 while True:
4406 if i >= len(wd_dict.keys):
4407 if i >= len(w_dict.keys):
4408 return None
4409 return mismatch_template % ('missing',
4410 'line %d' % w_dict.keys[i].lineno)
4411 elif i >= len(w_dict.keys):
4412 return (mismatch_template %
4413 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134414
Sam Maiera6e76d72022-02-11 21:43:504415 wd_key = wd_dict.keys[i]
4416 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134417
Sam Maiera6e76d72022-02-11 21:43:504418 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4419 wd_dict.values[i], ast)
4420 if result is not None:
4421 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134422
Sam Maiera6e76d72022-02-11 21:43:504423 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4424 email_regex)
4425 if result is not None:
4426 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204427
Sam Maiera6e76d72022-02-11 21:43:504428 if wd_key.s != w_key.s:
4429 return mismatch_template % ('%s at line %d' %
4430 (wd_key.s, wd_key.lineno),
4431 '%s at line %d' %
4432 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204433
Sam Maiera6e76d72022-02-11 21:43:504434 if wd_key.s < last_key:
4435 return (
4436 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4437 % (wd_key.lineno, w_key.lineno))
4438 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204439
Sam Maiera6e76d72022-02-11 21:43:504440 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204441
4442
Sergey Ulanov4af16052018-11-08 02:41:464443def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504444 ast = input_api.ast
4445 if not isinstance(expression, ast.Expression):
4446 return 'WATCHLISTS file must contain a valid expression'
4447 dictionary = expression.body
4448 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4449 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204450
Sam Maiera6e76d72022-02-11 21:43:504451 first_key = dictionary.keys[0]
4452 first_value = dictionary.values[0]
4453 second_key = dictionary.keys[1]
4454 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204455
Sam Maiera6e76d72022-02-11 21:43:504456 if (not isinstance(first_key, ast.Str)
4457 or first_key.s != 'WATCHLIST_DEFINITIONS'
4458 or not isinstance(first_value, ast.Dict)):
4459 return ('The first entry of the dict in WATCHLISTS file must be '
4460 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204461
Sam Maiera6e76d72022-02-11 21:43:504462 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4463 or not isinstance(second_value, ast.Dict)):
4464 return ('The second entry of the dict in WATCHLISTS file must be '
4465 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204466
Sam Maiera6e76d72022-02-11 21:43:504467 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134468
4469
Saagar Sanghavifceeaae2020-08-12 16:40:364470def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504471 for f in input_api.AffectedFiles(include_deletes=False):
4472 if f.LocalPath() == 'WATCHLISTS':
4473 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134474
Sam Maiera6e76d72022-02-11 21:43:504475 try:
4476 # First, make sure that it can be evaluated.
4477 input_api.ast.literal_eval(contents)
4478 # Get an AST tree for it and scan the tree for detailed style checking.
4479 expression = input_api.ast.parse(contents,
4480 filename='WATCHLISTS',
4481 mode='eval')
4482 except ValueError as e:
4483 return [
4484 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4485 long_text=repr(e))
4486 ]
4487 except SyntaxError as e:
4488 return [
4489 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4490 long_text=repr(e))
4491 ]
4492 except TypeError as e:
4493 return [
4494 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4495 long_text=repr(e))
4496 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134497
Sam Maiera6e76d72022-02-11 21:43:504498 result = _CheckWATCHLISTSSyntax(expression, input_api)
4499 if result is not None:
4500 return [output_api.PresubmitError(result)]
4501 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134502
Sam Maiera6e76d72022-02-11 21:43:504503 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134504
Sean Kaucb7c9b32022-10-25 21:25:524505def CheckGnRebasePath(input_api, output_api):
4506 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
4507
4508 Developers should use root_build_dir instead of "//" when using target_gen_dir because
4509 Chromium is sometimes built outside of the source tree.
4510 """
4511
4512 def gn_files(f):
4513 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
4514
4515 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
4516 problems = []
4517 for f in input_api.AffectedSourceFiles(gn_files):
4518 for line_num, line in f.ChangedContents():
4519 if rebase_path_regex.search(line):
4520 problems.append(
4521 'Absolute path in rebase_path() in %s:%d' %
4522 (f.LocalPath(), line_num))
4523
4524 if problems:
4525 return [
4526 output_api.PresubmitPromptWarning(
4527 'Using an absolute path in rebase_path()',
4528 items=sorted(problems),
4529 long_text=(
4530 'rebase_path() should use root_build_dir instead of "/" ',
4531 'since builds can be initiated from outside of the source ',
4532 'root.'))
4533 ]
4534 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134535
Andrew Grieve1b290e4a22020-11-24 20:07:014536def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504537 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014538
Sam Maiera6e76d72022-02-11 21:43:504539 As documented at //build/docs/writing_gn_templates.md
4540 """
Andrew Grieve1b290e4a22020-11-24 20:07:014541
Sam Maiera6e76d72022-02-11 21:43:504542 def gn_files(f):
4543 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014544
Sam Maiera6e76d72022-02-11 21:43:504545 problems = []
4546 for f in input_api.AffectedSourceFiles(gn_files):
4547 for line_num, line in f.ChangedContents():
4548 if 'forward_variables_from(invoker, "*")' in line:
4549 problems.append(
4550 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4551 (f.LocalPath(), line_num))
4552
4553 if problems:
4554 return [
4555 output_api.PresubmitPromptWarning(
4556 'forward_variables_from("*") without exclusions',
4557 items=sorted(problems),
4558 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594559 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504560 'explicitly listed in forward_variables_from(). For more '
4561 'details, see:\n'
4562 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4563 'build/docs/writing_gn_templates.md'
4564 '#Using-forward_variables_from'))
4565 ]
4566 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014567
Saagar Sanghavifceeaae2020-08-12 16:40:364568def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504569 """Checks that newly added header files have corresponding GN changes.
4570 Note that this is only a heuristic. To be precise, run script:
4571 build/check_gn_headers.py.
4572 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194573
Sam Maiera6e76d72022-02-11 21:43:504574 def headers(f):
4575 return input_api.FilterSourceFile(
4576 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194577
Sam Maiera6e76d72022-02-11 21:43:504578 new_headers = []
4579 for f in input_api.AffectedSourceFiles(headers):
4580 if f.Action() != 'A':
4581 continue
4582 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194583
Sam Maiera6e76d72022-02-11 21:43:504584 def gn_files(f):
4585 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194586
Sam Maiera6e76d72022-02-11 21:43:504587 all_gn_changed_contents = ''
4588 for f in input_api.AffectedSourceFiles(gn_files):
4589 for _, line in f.ChangedContents():
4590 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194591
Sam Maiera6e76d72022-02-11 21:43:504592 problems = []
4593 for header in new_headers:
4594 basename = input_api.os_path.basename(header)
4595 if basename not in all_gn_changed_contents:
4596 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194597
Sam Maiera6e76d72022-02-11 21:43:504598 if problems:
4599 return [
4600 output_api.PresubmitPromptWarning(
4601 'Missing GN changes for new header files',
4602 items=sorted(problems),
4603 long_text=
4604 'Please double check whether newly added header files need '
4605 'corresponding changes in gn or gni files.\nThis checking is only a '
4606 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4607 'Read https://crbug.com/661774 for more info.')
4608 ]
4609 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194610
4611
Saagar Sanghavifceeaae2020-08-12 16:40:364612def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504613 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024614
Sam Maiera6e76d72022-02-11 21:43:504615 This assumes we won't intentionally reference one product from the other
4616 product.
4617 """
4618 all_problems = []
4619 test_cases = [{
4620 "filename_postfix": "google_chrome_strings.grd",
4621 "correct_name": "Chrome",
4622 "incorrect_name": "Chromium",
4623 }, {
4624 "filename_postfix": "chromium_strings.grd",
4625 "correct_name": "Chromium",
4626 "incorrect_name": "Chrome",
4627 }]
Michael Giuffridad3bc8672018-10-25 22:48:024628
Sam Maiera6e76d72022-02-11 21:43:504629 for test_case in test_cases:
4630 problems = []
4631 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4632 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024633
Sam Maiera6e76d72022-02-11 21:43:504634 # Check each new line. Can yield false positives in multiline comments, but
4635 # easier than trying to parse the XML because messages can have nested
4636 # children, and associating message elements with affected lines is hard.
4637 for f in input_api.AffectedSourceFiles(filename_filter):
4638 for line_num, line in f.ChangedContents():
4639 if "<message" in line or "<!--" in line or "-->" in line:
4640 continue
4641 if test_case["incorrect_name"] in line:
4642 problems.append("Incorrect product name in %s:%d" %
4643 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024644
Sam Maiera6e76d72022-02-11 21:43:504645 if problems:
4646 message = (
4647 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4648 % (test_case["correct_name"], test_case["correct_name"],
4649 test_case["incorrect_name"]))
4650 all_problems.append(
4651 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024652
Sam Maiera6e76d72022-02-11 21:43:504653 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024654
4655
Saagar Sanghavifceeaae2020-08-12 16:40:364656def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504657 """Avoid large files, especially binary files, in the repository since
4658 git doesn't scale well for those. They will be in everyone's repo
4659 clones forever, forever making Chromium slower to clone and work
4660 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364661
Sam Maiera6e76d72022-02-11 21:43:504662 # Uploading files to cloud storage is not trivial so we don't want
4663 # to set the limit too low, but the upper limit for "normal" large
4664 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4665 # anything over 20 MB is exceptional.
4666 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364667
Sam Maiera6e76d72022-02-11 21:43:504668 too_large_files = []
4669 for f in input_api.AffectedFiles():
4670 # Check both added and modified files (but not deleted files).
4671 if f.Action() in ('A', 'M'):
4672 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4673 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4674 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364675
Sam Maiera6e76d72022-02-11 21:43:504676 if too_large_files:
4677 message = (
4678 'Do not commit large files to git since git scales badly for those.\n'
4679 +
4680 'Instead put the large files in cloud storage and use DEPS to\n' +
4681 'fetch them.\n' + '\n'.join(too_large_files))
4682 return [
4683 output_api.PresubmitError('Too large files found in commit',
4684 long_text=message + '\n')
4685 ]
4686 else:
4687 return []
Daniel Bratell93eb6c62019-04-29 20:13:364688
Max Morozb47503b2019-08-08 21:03:274689
Saagar Sanghavifceeaae2020-08-12 16:40:364690def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504691 """Checks specific for fuzz target sources."""
4692 EXPORTED_SYMBOLS = [
4693 'LLVMFuzzerInitialize',
4694 'LLVMFuzzerCustomMutator',
4695 'LLVMFuzzerCustomCrossOver',
4696 'LLVMFuzzerMutate',
4697 ]
Max Morozb47503b2019-08-08 21:03:274698
Sam Maiera6e76d72022-02-11 21:43:504699 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274700
Sam Maiera6e76d72022-02-11 21:43:504701 def FilterFile(affected_file):
4702 """Ignore libFuzzer source code."""
4703 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:314704 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:274705
Sam Maiera6e76d72022-02-11 21:43:504706 return input_api.FilterSourceFile(affected_file,
4707 files_to_check=[files_to_check],
4708 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274709
Sam Maiera6e76d72022-02-11 21:43:504710 files_with_missing_header = []
4711 for f in input_api.AffectedSourceFiles(FilterFile):
4712 contents = input_api.ReadFile(f, 'r')
4713 if REQUIRED_HEADER in contents:
4714 continue
Max Morozb47503b2019-08-08 21:03:274715
Sam Maiera6e76d72022-02-11 21:43:504716 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4717 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274718
Sam Maiera6e76d72022-02-11 21:43:504719 if not files_with_missing_header:
4720 return []
Max Morozb47503b2019-08-08 21:03:274721
Sam Maiera6e76d72022-02-11 21:43:504722 long_text = (
4723 'If you define any of the libFuzzer optional functions (%s), it is '
4724 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4725 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4726 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4727 'to access command line arguments passed to the fuzzer. Instead, prefer '
4728 'static initialization and shared resources as documented in '
4729 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4730 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4731 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274732
Sam Maiera6e76d72022-02-11 21:43:504733 return [
4734 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4735 REQUIRED_HEADER,
4736 items=files_with_missing_header,
4737 long_text=long_text)
4738 ]
Max Morozb47503b2019-08-08 21:03:274739
4740
Mohamed Heikald048240a2019-11-12 16:57:374741def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504742 """
4743 Warns authors who add images into the repo to make sure their images are
4744 optimized before committing.
4745 """
4746 images_added = False
4747 image_paths = []
4748 errors = []
4749 filter_lambda = lambda x: input_api.FilterSourceFile(
4750 x,
4751 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4752 DEFAULT_FILES_TO_SKIP),
4753 files_to_check=[r'.*\/(drawable|mipmap)'])
4754 for f in input_api.AffectedFiles(include_deletes=False,
4755 file_filter=filter_lambda):
4756 local_path = f.LocalPath().lower()
4757 if any(
4758 local_path.endswith(extension)
4759 for extension in _IMAGE_EXTENSIONS):
4760 images_added = True
4761 image_paths.append(f)
4762 if images_added:
4763 errors.append(
4764 output_api.PresubmitPromptWarning(
4765 'It looks like you are trying to commit some images. If these are '
4766 'non-test-only images, please make sure to read and apply the tips in '
4767 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4768 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4769 'FYI only and will not block your CL on the CQ.', image_paths))
4770 return errors
Mohamed Heikald048240a2019-11-12 16:57:374771
4772
Saagar Sanghavifceeaae2020-08-12 16:40:364773def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504774 """Groups upload checks that target android code."""
4775 results = []
4776 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4777 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4778 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4779 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4780 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4781 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4782 input_api, output_api))
4783 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4784 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4785 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4786 results.extend(_CheckNewImagesWarning(input_api, output_api))
4787 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4788 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4789 return results
4790
Becky Zhou7c69b50992018-12-10 19:37:574791
Saagar Sanghavifceeaae2020-08-12 16:40:364792def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504793 """Groups commit checks that target android code."""
4794 results = []
4795 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4796 return results
dgnaa68d5e2015-06-10 10:08:224797
Chris Hall59f8d0c72020-05-01 07:31:194798# TODO(chrishall): could we additionally match on any path owned by
4799# ui/accessibility/OWNERS ?
4800_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:314801 r"^chrome/browser.*/accessibility/",
4802 r"^chrome/browser/extensions/api/automation.*/",
4803 r"^chrome/renderer/extensions/accessibility_.*",
4804 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:174805 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:314806 r"^content/browser/accessibility/",
4807 r"^content/renderer/accessibility/",
4808 r"^content/tests/data/accessibility/",
4809 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:174810 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:314811 r"^ui/accessibility/",
4812 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:194813)
4814
Saagar Sanghavifceeaae2020-08-12 16:40:364815def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504816 """Checks that commits to accessibility code contain an AX-Relnotes field in
4817 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194818
Sam Maiera6e76d72022-02-11 21:43:504819 def FileFilter(affected_file):
4820 paths = _ACCESSIBILITY_PATHS
4821 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194822
Sam Maiera6e76d72022-02-11 21:43:504823 # Only consider changes affecting accessibility paths.
4824 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4825 return []
Akihiro Ota08108e542020-05-20 15:30:534826
Sam Maiera6e76d72022-02-11 21:43:504827 # AX-Relnotes can appear in either the description or the footer.
4828 # When searching the description, require 'AX-Relnotes:' to appear at the
4829 # beginning of a line.
4830 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4831 description_has_relnotes = any(
4832 ax_regex.match(line)
4833 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194834
Sam Maiera6e76d72022-02-11 21:43:504835 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4836 'AX-Relnotes', [])
4837 if description_has_relnotes or footer_relnotes:
4838 return []
Chris Hall59f8d0c72020-05-01 07:31:194839
Sam Maiera6e76d72022-02-11 21:43:504840 # TODO(chrishall): link to Relnotes documentation in message.
4841 message = (
4842 "Missing 'AX-Relnotes:' field required for accessibility changes"
4843 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4844 "user-facing changes"
4845 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4846 "user-facing effects"
4847 "\n if this is confusing or annoying then please contact members "
4848 "of ui/accessibility/OWNERS.")
4849
4850 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224851
Mark Schillacie5a0be22022-01-19 00:38:394852
4853_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:314854 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:394855)
4856
4857_ACCESSIBILITY_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:314858 r"^content/test/data/accessibility/accname/.*\.html",
4859 r"^content/test/data/accessibility/aria/.*\.html",
4860 r"^content/test/data/accessibility/css/.*\.html",
4861 r"^content/test/data/accessibility/html/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:394862)
4863
4864_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:314865 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394866)
4867
4868_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:314869 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394870)
4871
4872def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504873 """Checks that commits that include a newly added, renamed/moved, or deleted
4874 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4875 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394876
Sam Maiera6e76d72022-02-11 21:43:504877 def FilePathFilter(affected_file):
4878 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4879 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394880
Sam Maiera6e76d72022-02-11 21:43:504881 def AndroidFilePathFilter(affected_file):
4882 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4883 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394884
Sam Maiera6e76d72022-02-11 21:43:504885 # Only consider changes in the events test data path with html type.
4886 if not any(
4887 input_api.AffectedFiles(include_deletes=True,
4888 file_filter=FilePathFilter)):
4889 return []
Mark Schillacie5a0be22022-01-19 00:38:394890
Sam Maiera6e76d72022-02-11 21:43:504891 # If the commit contains any change to the Android test file, ignore.
4892 if any(
4893 input_api.AffectedFiles(include_deletes=True,
4894 file_filter=AndroidFilePathFilter)):
4895 return []
Mark Schillacie5a0be22022-01-19 00:38:394896
Sam Maiera6e76d72022-02-11 21:43:504897 # Only consider changes that are adding/renaming or deleting a file
4898 message = []
4899 for f in input_api.AffectedFiles(include_deletes=True,
4900 file_filter=FilePathFilter):
4901 if f.Action() == 'A' or f.Action() == 'D':
4902 message = (
4903 "It appears that you are adding, renaming or deleting"
4904 "\na dump_accessibility_events* test, but have not included"
4905 "\na corresponding change for Android."
4906 "\nPlease include (or remove) the test from:"
4907 "\n content/public/android/javatests/src/org/chromium/"
4908 "content/browser/accessibility/"
4909 "WebContentsAccessibilityEventsTest.java"
4910 "\nIf this message is confusing or annoying, please contact"
4911 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394912
Sam Maiera6e76d72022-02-11 21:43:504913 # If no message was set, return empty.
4914 if not len(message):
4915 return []
4916
4917 return [output_api.PresubmitPromptWarning(message)]
4918
Mark Schillacie5a0be22022-01-19 00:38:394919
4920def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504921 """Checks that commits that include a newly added, renamed/moved, or deleted
4922 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4923 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394924
Sam Maiera6e76d72022-02-11 21:43:504925 def FilePathFilter(affected_file):
4926 paths = _ACCESSIBILITY_TREE_TEST_PATH
4927 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394928
Sam Maiera6e76d72022-02-11 21:43:504929 def AndroidFilePathFilter(affected_file):
4930 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4931 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394932
Sam Maiera6e76d72022-02-11 21:43:504933 # Only consider changes in the various tree test data paths with html type.
4934 if not any(
4935 input_api.AffectedFiles(include_deletes=True,
4936 file_filter=FilePathFilter)):
4937 return []
Mark Schillacie5a0be22022-01-19 00:38:394938
Sam Maiera6e76d72022-02-11 21:43:504939 # If the commit contains any change to the Android test file, ignore.
4940 if any(
4941 input_api.AffectedFiles(include_deletes=True,
4942 file_filter=AndroidFilePathFilter)):
4943 return []
Mark Schillacie5a0be22022-01-19 00:38:394944
Sam Maiera6e76d72022-02-11 21:43:504945 # Only consider changes that are adding/renaming or deleting a file
4946 message = []
4947 for f in input_api.AffectedFiles(include_deletes=True,
4948 file_filter=FilePathFilter):
4949 if f.Action() == 'A' or f.Action() == 'D':
4950 message = (
4951 "It appears that you are adding, renaming or deleting"
4952 "\na dump_accessibility_tree* test, but have not included"
4953 "\na corresponding change for Android."
4954 "\nPlease include (or remove) the test from:"
4955 "\n content/public/android/javatests/src/org/chromium/"
4956 "content/browser/accessibility/"
4957 "WebContentsAccessibilityTreeTest.java"
4958 "\nIf this message is confusing or annoying, please contact"
4959 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394960
Sam Maiera6e76d72022-02-11 21:43:504961 # If no message was set, return empty.
4962 if not len(message):
4963 return []
4964
4965 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394966
4967
seanmccullough4a9356252021-04-08 19:54:094968# string pattern, sequence of strings to show when pattern matches,
4969# error flag. True if match is a presubmit error, otherwise it's a warning.
4970_NON_INCLUSIVE_TERMS = (
4971 (
4972 # Note that \b pattern in python re is pretty particular. In this
4973 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4974 # ...' will not. This may require some tweaking to catch these cases
4975 # without triggering a lot of false positives. Leaving it naive and
4976 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324977 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094978 (
4979 'Please don\'t use blacklist, whitelist, ' # nocheck
4980 'or slave in your', # nocheck
4981 'code and make every effort to use other terms. Using "// nocheck"',
4982 '"# nocheck" or "<!-- nocheck -->"',
4983 'at the end of the offending line will bypass this PRESUBMIT error',
4984 'but avoid using this whenever possible. Reach out to',
4985 '[email protected] if you have questions'),
4986 True),)
4987
Saagar Sanghavifceeaae2020-08-12 16:40:364988def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504989 """Checks common to both upload and commit."""
4990 results = []
Eric Boren6fd2b932018-01-25 15:05:084991 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504992 input_api.canned_checks.PanProjectChecks(
4993 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084994
Sam Maiera6e76d72022-02-11 21:43:504995 author = input_api.change.author_email
4996 if author and author not in _KNOWN_ROBOTS:
4997 results.extend(
4998 input_api.canned_checks.CheckAuthorizedAuthor(
4999 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:245000
Sam Maiera6e76d72022-02-11 21:43:505001 results.extend(
5002 input_api.canned_checks.CheckChangeHasNoTabs(
5003 input_api,
5004 output_api,
5005 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
5006 results.extend(
5007 input_api.RunTests(
5008 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:175009
Bruce Dawsonc8054482022-03-28 15:33:375010 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:505011 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:375012 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:505013 results.extend(
5014 input_api.RunTests(
5015 input_api.canned_checks.CheckDirMetadataFormat(
5016 input_api, output_api, dirmd_bin)))
5017 results.extend(
5018 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
5019 input_api, output_api))
5020 results.extend(
5021 input_api.canned_checks.CheckNoNewMetadataInOwners(
5022 input_api, output_api))
5023 results.extend(
5024 input_api.canned_checks.CheckInclusiveLanguage(
5025 input_api,
5026 output_api,
5027 excluded_directories_relative_path=[
5028 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
5029 ],
5030 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:595031
Aleksey Khoroshilov2978c942022-06-13 16:14:125032 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:475033 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:125034 for f in input_api.AffectedFiles(include_deletes=False,
5035 file_filter=presubmit_py_filter):
5036 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
5037 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
5038 # The PRESUBMIT.py file (and the directory containing it) might have
5039 # been affected by being moved or removed, so only try to run the tests
5040 # if they still exist.
5041 if not input_api.os_path.exists(test_file):
5042 continue
Sam Maiera6e76d72022-02-11 21:43:505043
Aleksey Khoroshilov2978c942022-06-13 16:14:125044 use_python3 = False
5045 with open(f.LocalPath()) as fp:
5046 use_python3 = any(
5047 line.startswith('USE_PYTHON3 = True')
5048 for line in fp.readlines())
5049
5050 results.extend(
5051 input_api.canned_checks.RunUnitTestsInDirectory(
5052 input_api,
5053 output_api,
5054 full_path,
5055 files_to_check=[r'^PRESUBMIT_test\.py$'],
5056 run_on_python2=not use_python3,
5057 run_on_python3=use_python3,
5058 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:505059 return results
[email protected]1f7b4172010-01-28 01:17:345060
[email protected]b337cb5b2011-01-23 21:24:055061
Saagar Sanghavifceeaae2020-08-12 16:40:365062def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505063 problems = [
5064 f.LocalPath() for f in input_api.AffectedFiles()
5065 if f.LocalPath().endswith(('.orig', '.rej'))
5066 ]
5067 # Cargo.toml.orig files are part of third-party crates downloaded from
5068 # crates.io and should be included.
5069 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5070 if problems:
5071 return [
5072 output_api.PresubmitError("Don't commit .rej and .orig files.",
5073 problems)
5074 ]
5075 else:
5076 return []
[email protected]b8079ae4a2012-12-05 19:56:495077
5078
Saagar Sanghavifceeaae2020-08-12 16:40:365079def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505080 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5081 macro_re = input_api.re.compile(
5082 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5083 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5084 input_api.re.MULTILINE)
5085 extension_re = input_api.re.compile(r'\.[a-z]+$')
5086 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005087 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505088 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005089 # The build-config macros are allowed to be used in build_config.h
5090 # without including itself.
5091 if f.LocalPath() == config_h_file:
5092 continue
Sam Maiera6e76d72022-02-11 21:43:505093 if not f.LocalPath().endswith(
5094 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5095 continue
5096 found_line_number = None
5097 found_macro = None
5098 all_lines = input_api.ReadFile(f, 'r').splitlines()
5099 for line_num, line in enumerate(all_lines):
5100 match = macro_re.search(line)
5101 if match:
5102 found_line_number = line_num
5103 found_macro = match.group(2)
5104 break
5105 if not found_line_number:
5106 continue
Kent Tamura5a8755d2017-06-29 23:37:075107
Sam Maiera6e76d72022-02-11 21:43:505108 found_include_line = -1
5109 for line_num, line in enumerate(all_lines):
5110 if include_re.search(line):
5111 found_include_line = line_num
5112 break
5113 if found_include_line >= 0 and found_include_line < found_line_number:
5114 continue
Kent Tamura5a8755d2017-06-29 23:37:075115
Sam Maiera6e76d72022-02-11 21:43:505116 if not f.LocalPath().endswith('.h'):
5117 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5118 try:
5119 content = input_api.ReadFile(primary_header_path, 'r')
5120 if include_re.search(content):
5121 continue
5122 except IOError:
5123 pass
5124 errors.append('%s:%d %s macro is used without first including build/'
5125 'build_config.h.' %
5126 (f.LocalPath(), found_line_number, found_macro))
5127 if errors:
5128 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5129 return []
Kent Tamura5a8755d2017-06-29 23:37:075130
5131
Lei Zhang1c12a22f2021-05-12 11:28:455132def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505133 stl_include_re = input_api.re.compile(r'^#include\s+<('
5134 r'algorithm|'
5135 r'array|'
5136 r'limits|'
5137 r'list|'
5138 r'map|'
5139 r'memory|'
5140 r'queue|'
5141 r'set|'
5142 r'string|'
5143 r'unordered_map|'
5144 r'unordered_set|'
5145 r'utility|'
5146 r'vector)>')
5147 std_namespace_re = input_api.re.compile(r'std::')
5148 errors = []
5149 for f in input_api.AffectedFiles():
5150 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5151 continue
Lei Zhang1c12a22f2021-05-12 11:28:455152
Sam Maiera6e76d72022-02-11 21:43:505153 uses_std_namespace = False
5154 has_stl_include = False
5155 for line in f.NewContents():
5156 if has_stl_include and uses_std_namespace:
5157 break
Lei Zhang1c12a22f2021-05-12 11:28:455158
Sam Maiera6e76d72022-02-11 21:43:505159 if not has_stl_include and stl_include_re.search(line):
5160 has_stl_include = True
5161 continue
Lei Zhang1c12a22f2021-05-12 11:28:455162
Bruce Dawson4a5579a2022-04-08 17:11:365163 if not uses_std_namespace and (std_namespace_re.search(line)
5164 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505165 uses_std_namespace = True
5166 continue
Lei Zhang1c12a22f2021-05-12 11:28:455167
Sam Maiera6e76d72022-02-11 21:43:505168 if has_stl_include and not uses_std_namespace:
5169 errors.append(
5170 '%s: Includes STL header(s) but does not reference std::' %
5171 f.LocalPath())
5172 if errors:
5173 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5174 return []
Lei Zhang1c12a22f2021-05-12 11:28:455175
5176
Xiaohan Wang42d96c22022-01-20 17:23:115177def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505178 """Check for sensible looking, totally invalid OS macros."""
5179 preprocessor_statement = input_api.re.compile(r'^\s*#')
5180 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5181 results = []
5182 for lnum, line in f.ChangedContents():
5183 if preprocessor_statement.search(line):
5184 for match in os_macro.finditer(line):
5185 results.append(
5186 ' %s:%d: %s' %
5187 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5188 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5189 return results
[email protected]b00342e7f2013-03-26 16:21:545190
5191
Xiaohan Wang42d96c22022-01-20 17:23:115192def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505193 """Check all affected files for invalid OS macros."""
5194 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005195 # The OS_ macros are allowed to be used in build/build_config.h.
5196 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505197 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005198 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5199 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505200 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:545201
Sam Maiera6e76d72022-02-11 21:43:505202 if not bad_macros:
5203 return []
[email protected]b00342e7f2013-03-26 16:21:545204
Sam Maiera6e76d72022-02-11 21:43:505205 return [
5206 output_api.PresubmitError(
5207 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5208 'defined in build_config.h):', bad_macros)
5209 ]
[email protected]b00342e7f2013-03-26 16:21:545210
lliabraa35bab3932014-10-01 12:16:445211
5212def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505213 """Check all affected files for invalid "if defined" macros."""
5214 ALWAYS_DEFINED_MACROS = (
5215 "TARGET_CPU_PPC",
5216 "TARGET_CPU_PPC64",
5217 "TARGET_CPU_68K",
5218 "TARGET_CPU_X86",
5219 "TARGET_CPU_ARM",
5220 "TARGET_CPU_MIPS",
5221 "TARGET_CPU_SPARC",
5222 "TARGET_CPU_ALPHA",
5223 "TARGET_IPHONE_SIMULATOR",
5224 "TARGET_OS_EMBEDDED",
5225 "TARGET_OS_IPHONE",
5226 "TARGET_OS_MAC",
5227 "TARGET_OS_UNIX",
5228 "TARGET_OS_WIN32",
5229 )
5230 ifdef_macro = input_api.re.compile(
5231 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5232 results = []
5233 for lnum, line in f.ChangedContents():
5234 for match in ifdef_macro.finditer(line):
5235 if match.group(1) in ALWAYS_DEFINED_MACROS:
5236 always_defined = ' %s is always defined. ' % match.group(1)
5237 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5238 results.append(
5239 ' %s:%d %s\n\t%s' %
5240 (f.LocalPath(), lnum, always_defined, did_you_mean))
5241 return results
lliabraa35bab3932014-10-01 12:16:445242
5243
Saagar Sanghavifceeaae2020-08-12 16:40:365244def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505245 """Check all affected files for invalid "if defined" macros."""
5246 bad_macros = []
5247 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5248 for f in input_api.AffectedFiles():
5249 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5250 continue
5251 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5252 bad_macros.extend(
5253 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445254
Sam Maiera6e76d72022-02-11 21:43:505255 if not bad_macros:
5256 return []
lliabraa35bab3932014-10-01 12:16:445257
Sam Maiera6e76d72022-02-11 21:43:505258 return [
5259 output_api.PresubmitError(
5260 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5261 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5262 bad_macros)
5263 ]
lliabraa35bab3932014-10-01 12:16:445264
5265
Saagar Sanghavifceeaae2020-08-12 16:40:365266def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505267 """Check for same IPC rules described in
5268 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5269 """
5270 base_pattern = r'IPC_ENUM_TRAITS\('
5271 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5272 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045273
Sam Maiera6e76d72022-02-11 21:43:505274 problems = []
5275 for f in input_api.AffectedSourceFiles(None):
5276 local_path = f.LocalPath()
5277 if not local_path.endswith('.h'):
5278 continue
5279 for line_number, line in f.ChangedContents():
5280 if inclusion_pattern.search(
5281 line) and not comment_pattern.search(line):
5282 problems.append('%s:%d\n %s' %
5283 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045284
Sam Maiera6e76d72022-02-11 21:43:505285 if problems:
5286 return [
5287 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5288 problems)
5289 ]
5290 else:
5291 return []
mlamouria82272622014-09-16 18:45:045292
[email protected]b00342e7f2013-03-26 16:21:545293
Saagar Sanghavifceeaae2020-08-12 16:40:365294def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505295 """Check to make sure no files being submitted have long paths.
5296 This causes issues on Windows.
5297 """
5298 problems = []
5299 for f in input_api.AffectedTestableFiles():
5300 local_path = f.LocalPath()
5301 # Windows has a path limit of 260 characters. Limit path length to 200 so
5302 # that we have some extra for the prefix on dev machines and the bots.
5303 if len(local_path) > 200:
5304 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055305
Sam Maiera6e76d72022-02-11 21:43:505306 if problems:
5307 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5308 else:
5309 return []
Stephen Martinis97a394142018-06-07 23:06:055310
5311
Saagar Sanghavifceeaae2020-08-12 16:40:365312def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505313 """Check that header files have proper guards against multiple inclusion.
5314 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365315 should include the string "no-include-guard-because-multiply-included" or
5316 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505317 """
Daniel Bratell8ba52722018-03-02 16:06:145318
Sam Maiera6e76d72022-02-11 21:43:505319 def is_chromium_header_file(f):
5320 # We only check header files under the control of the Chromium
5321 # project. That is, those outside third_party apart from
5322 # third_party/blink.
5323 # We also exclude *_message_generator.h headers as they use
5324 # include guards in a special, non-typical way.
5325 file_with_path = input_api.os_path.normpath(f.LocalPath())
5326 return (file_with_path.endswith('.h')
5327 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335328 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505329 and (not file_with_path.startswith('third_party')
5330 or file_with_path.startswith(
5331 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145332
Sam Maiera6e76d72022-02-11 21:43:505333 def replace_special_with_underscore(string):
5334 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145335
Sam Maiera6e76d72022-02-11 21:43:505336 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145337
Sam Maiera6e76d72022-02-11 21:43:505338 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5339 guard_name = None
5340 guard_line_number = None
5341 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145342
Sam Maiera6e76d72022-02-11 21:43:505343 file_with_path = input_api.os_path.normpath(f.LocalPath())
5344 base_file_name = input_api.os_path.splitext(
5345 input_api.os_path.basename(file_with_path))[0]
5346 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145347
Sam Maiera6e76d72022-02-11 21:43:505348 expected_guard = replace_special_with_underscore(
5349 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145350
Sam Maiera6e76d72022-02-11 21:43:505351 # For "path/elem/file_name.h" we should really only accept
5352 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5353 # are too many (1000+) files with slight deviations from the
5354 # coding style. The most important part is that the include guard
5355 # is there, and that it's unique, not the name so this check is
5356 # forgiving for existing files.
5357 #
5358 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145359
Sam Maiera6e76d72022-02-11 21:43:505360 guard_name_pattern_list = [
5361 # Anything with the right suffix (maybe with an extra _).
5362 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145363
Sam Maiera6e76d72022-02-11 21:43:505364 # To cover include guards with old Blink style.
5365 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145366
Sam Maiera6e76d72022-02-11 21:43:505367 # Anything including the uppercase name of the file.
5368 r'\w*' + input_api.re.escape(
5369 replace_special_with_underscore(upper_base_file_name)) +
5370 r'\w*',
5371 ]
5372 guard_name_pattern = '|'.join(guard_name_pattern_list)
5373 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5374 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145375
Sam Maiera6e76d72022-02-11 21:43:505376 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365377 if ('no-include-guard-because-multiply-included' in line
5378 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505379 guard_name = 'DUMMY' # To not trigger check outside the loop.
5380 break
Daniel Bratell8ba52722018-03-02 16:06:145381
Sam Maiera6e76d72022-02-11 21:43:505382 if guard_name is None:
5383 match = guard_pattern.match(line)
5384 if match:
5385 guard_name = match.group(1)
5386 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145387
Sam Maiera6e76d72022-02-11 21:43:505388 # We allow existing files to use include guards whose names
5389 # don't match the chromium style guide, but new files should
5390 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495391 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165392 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505393 errors.append(
5394 output_api.PresubmitPromptWarning(
5395 'Header using the wrong include guard name %s'
5396 % guard_name, [
5397 '%s:%d' %
5398 (f.LocalPath(), line_number + 1)
5399 ], 'Expected: %r\nFound: %r' %
5400 (expected_guard, guard_name)))
5401 else:
5402 # The line after #ifndef should have a #define of the same name.
5403 if line_number == guard_line_number + 1:
5404 expected_line = '#define %s' % guard_name
5405 if line != expected_line:
5406 errors.append(
5407 output_api.PresubmitPromptWarning(
5408 'Missing "%s" for include guard' %
5409 expected_line,
5410 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5411 'Expected: %r\nGot: %r' %
5412 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145413
Sam Maiera6e76d72022-02-11 21:43:505414 if not seen_guard_end and line == '#endif // %s' % guard_name:
5415 seen_guard_end = True
5416 elif seen_guard_end:
5417 if line.strip() != '':
5418 errors.append(
5419 output_api.PresubmitPromptWarning(
5420 'Include guard %s not covering the whole file'
5421 % (guard_name), [f.LocalPath()]))
5422 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145423
Sam Maiera6e76d72022-02-11 21:43:505424 if guard_name is None:
5425 errors.append(
5426 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495427 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505428 'Recommended name: %s\n'
5429 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365430 '"no-include-guard-because-multiply-included" or\n'
5431 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505432 % (f.LocalPath(), expected_guard)))
5433
5434 return errors
Daniel Bratell8ba52722018-03-02 16:06:145435
5436
Saagar Sanghavifceeaae2020-08-12 16:40:365437def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505438 """Check source code and known ascii text files for Windows style line
5439 endings.
5440 """
Bruce Dawson5efbdc652022-04-11 19:29:515441 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235442
Sam Maiera6e76d72022-02-11 21:43:505443 file_inclusion_pattern = (known_text_files,
5444 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5445 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235446
Sam Maiera6e76d72022-02-11 21:43:505447 problems = []
5448 source_file_filter = lambda f: input_api.FilterSourceFile(
5449 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5450 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515451 # Ignore test files that contain crlf intentionally.
5452 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345453 continue
Sam Maiera6e76d72022-02-11 21:43:505454 include_file = False
5455 for line in input_api.ReadFile(f, 'r').splitlines(True):
5456 if line.endswith('\r\n'):
5457 include_file = True
5458 if include_file:
5459 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235460
Sam Maiera6e76d72022-02-11 21:43:505461 if problems:
5462 return [
5463 output_api.PresubmitPromptWarning(
5464 'Are you sure that you want '
5465 'these files to contain Windows style line endings?\n' +
5466 '\n'.join(problems))
5467 ]
mostynbb639aca52015-01-07 20:31:235468
Sam Maiera6e76d72022-02-11 21:43:505469 return []
5470
mostynbb639aca52015-01-07 20:31:235471
Evan Stade6cfc964c12021-05-18 20:21:165472def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505473 """Check that .icon files (which are fragments of C++) have license headers.
5474 """
Evan Stade6cfc964c12021-05-18 20:21:165475
Sam Maiera6e76d72022-02-11 21:43:505476 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165477
Sam Maiera6e76d72022-02-11 21:43:505478 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5479 return input_api.canned_checks.CheckLicense(input_api,
5480 output_api,
5481 source_file_filter=icons)
5482
Evan Stade6cfc964c12021-05-18 20:21:165483
Jose Magana2b456f22021-03-09 23:26:405484def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505485 """Check source code for use of Chrome App technologies being
5486 deprecated.
5487 """
Jose Magana2b456f22021-03-09 23:26:405488
Sam Maiera6e76d72022-02-11 21:43:505489 def _CheckForDeprecatedTech(input_api,
5490 output_api,
5491 detection_list,
5492 files_to_check=None,
5493 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405494
Sam Maiera6e76d72022-02-11 21:43:505495 if (files_to_check or files_to_skip):
5496 source_file_filter = lambda f: input_api.FilterSourceFile(
5497 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5498 else:
5499 source_file_filter = None
5500
5501 problems = []
5502
5503 for f in input_api.AffectedSourceFiles(source_file_filter):
5504 if f.Action() == 'D':
5505 continue
5506 for _, line in f.ChangedContents():
5507 if any(detect in line for detect in detection_list):
5508 problems.append(f.LocalPath())
5509
5510 return problems
5511
5512 # to avoid this presubmit script triggering warnings
5513 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405514
5515 problems = []
5516
Sam Maiera6e76d72022-02-11 21:43:505517 # NMF: any files with extensions .nmf or NMF
5518 _NMF_FILES = r'\.(nmf|NMF)$'
5519 problems += _CheckForDeprecatedTech(
5520 input_api,
5521 output_api,
5522 detection_list=[''], # any change to the file will trigger warning
5523 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405524
Sam Maiera6e76d72022-02-11 21:43:505525 # MANIFEST: any manifest.json that in its diff includes "app":
5526 _MANIFEST_FILES = r'(manifest\.json)$'
5527 problems += _CheckForDeprecatedTech(
5528 input_api,
5529 output_api,
5530 detection_list=['"app":'],
5531 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405532
Sam Maiera6e76d72022-02-11 21:43:505533 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5534 problems += _CheckForDeprecatedTech(
5535 input_api,
5536 output_api,
5537 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:315538 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:405539
Gao Shenga79ebd42022-08-08 17:25:595540 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505541 problems += _CheckForDeprecatedTech(
5542 input_api,
5543 output_api,
5544 detection_list=['#include "ppapi', '#include <ppapi'],
5545 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5546 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:315547 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:405548
Sam Maiera6e76d72022-02-11 21:43:505549 if problems:
5550 return [
5551 output_api.PresubmitPromptWarning(
5552 'You are adding/modifying code'
5553 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5554 ' PNaCl, PPAPI). See this blog post for more details:\n'
5555 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5556 'and this documentation for options to replace these technologies:\n'
5557 'https://developer.chrome.com/docs/apps/migration/\n' +
5558 '\n'.join(problems))
5559 ]
Jose Magana2b456f22021-03-09 23:26:405560
Sam Maiera6e76d72022-02-11 21:43:505561 return []
Jose Magana2b456f22021-03-09 23:26:405562
mostynbb639aca52015-01-07 20:31:235563
Saagar Sanghavifceeaae2020-08-12 16:40:365564def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505565 """Checks that all source files use SYSLOG properly."""
5566 syslog_files = []
5567 for f in input_api.AffectedSourceFiles(src_file_filter):
5568 for line_number, line in f.ChangedContents():
5569 if 'SYSLOG' in line:
5570 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565571
Sam Maiera6e76d72022-02-11 21:43:505572 if syslog_files:
5573 return [
5574 output_api.PresubmitPromptWarning(
5575 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5576 ' calls.\nFiles to check:\n',
5577 items=syslog_files)
5578 ]
5579 return []
pastarmovj89f7ee12016-09-20 14:58:135580
5581
[email protected]1f7b4172010-01-28 01:17:345582def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505583 if input_api.version < [2, 0, 0]:
5584 return [
5585 output_api.PresubmitError(
5586 "Your depot_tools is out of date. "
5587 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5588 "but your version is %d.%d.%d" % tuple(input_api.version))
5589 ]
5590 results = []
5591 results.extend(
5592 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5593 return results
[email protected]ca8d19842009-02-19 16:33:125594
5595
5596def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505597 if input_api.version < [2, 0, 0]:
5598 return [
5599 output_api.PresubmitError(
5600 "Your depot_tools is out of date. "
5601 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5602 "but your version is %d.%d.%d" % tuple(input_api.version))
5603 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365604
Sam Maiera6e76d72022-02-11 21:43:505605 results = []
5606 # Make sure the tree is 'open'.
5607 results.extend(
5608 input_api.canned_checks.CheckTreeIsOpen(
5609 input_api,
5610 output_api,
5611 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275612
Sam Maiera6e76d72022-02-11 21:43:505613 results.extend(
5614 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5615 results.extend(
5616 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5617 results.extend(
5618 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5619 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505620 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145621
5622
Saagar Sanghavifceeaae2020-08-12 16:40:365623def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505624 """Check string ICU syntax validity and if translation screenshots exist."""
5625 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5626 # footer is set to true.
5627 git_footers = input_api.change.GitFootersFromDescription()
5628 skip_screenshot_check_footer = [
5629 footer.lower() for footer in git_footers.get(
5630 u'Skip-Translation-Screenshots-Check', [])
5631 ]
5632 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025633
Sam Maiera6e76d72022-02-11 21:43:505634 import os
5635 import re
5636 import sys
5637 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145638
Sam Maiera6e76d72022-02-11 21:43:505639 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5640 if (f.Action() == 'A' or f.Action() == 'M'))
5641 removed_paths = set(f.LocalPath()
5642 for f in input_api.AffectedFiles(include_deletes=True)
5643 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145644
Sam Maiera6e76d72022-02-11 21:43:505645 affected_grds = [
5646 f for f in input_api.AffectedFiles()
5647 if f.LocalPath().endswith(('.grd', '.grdp'))
5648 ]
5649 affected_grds = [
5650 f for f in affected_grds if not 'testdata' in f.LocalPath()
5651 ]
5652 if not affected_grds:
5653 return []
meacer8c0d3832019-12-26 21:46:165654
Sam Maiera6e76d72022-02-11 21:43:505655 affected_png_paths = [
5656 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5657 if (f.LocalPath().endswith('.png'))
5658 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145659
Sam Maiera6e76d72022-02-11 21:43:505660 # Check for screenshots. Developers can upload screenshots using
5661 # tools/translation/upload_screenshots.py which finds and uploads
5662 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5663 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5664 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5665 #
5666 # The logic here is as follows:
5667 #
5668 # - If the CL has a .png file under the screenshots directory for a grd
5669 # file, warn the developer. Actual images should never be checked into the
5670 # Chrome repo.
5671 #
5672 # - If the CL contains modified or new messages in grd files and doesn't
5673 # contain the corresponding .sha1 files, warn the developer to add images
5674 # and upload them via tools/translation/upload_screenshots.py.
5675 #
5676 # - If the CL contains modified or new messages in grd files and the
5677 # corresponding .sha1 files, everything looks good.
5678 #
5679 # - If the CL contains removed messages in grd files but the corresponding
5680 # .sha1 files aren't removed, warn the developer to remove them.
5681 unnecessary_screenshots = []
5682 missing_sha1 = []
5683 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145684
Sam Maiera6e76d72022-02-11 21:43:505685 # This checks verifies that the ICU syntax of messages this CL touched is
5686 # valid, and reports any found syntax errors.
5687 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5688 # without developers being aware of them. Later on, such ICU syntax errors
5689 # break message extraction for translation, hence would block Chromium
5690 # translations until they are fixed.
5691 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145692
Sam Maiera6e76d72022-02-11 21:43:505693 def _CheckScreenshotAdded(screenshots_dir, message_id):
5694 sha1_path = input_api.os_path.join(screenshots_dir,
5695 message_id + '.png.sha1')
5696 if sha1_path not in new_or_added_paths:
5697 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145698
Sam Maiera6e76d72022-02-11 21:43:505699 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5700 sha1_path = input_api.os_path.join(screenshots_dir,
5701 message_id + '.png.sha1')
5702 if input_api.os_path.exists(
5703 sha1_path) and sha1_path not in removed_paths:
5704 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145705
Sam Maiera6e76d72022-02-11 21:43:505706 def _ValidateIcuSyntax(text, level, signatures):
5707 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145708
Sam Maiera6e76d72022-02-11 21:43:505709 Check if text looks similar to ICU and checks for ICU syntax correctness
5710 in this case. Reports various issues with ICU syntax and values of
5711 variants. Supports checking of nested messages. Accumulate information of
5712 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265713
Sam Maiera6e76d72022-02-11 21:43:505714 Args:
5715 text: a string to check.
5716 level: a number of current nesting level.
5717 signatures: an accumulator, a list of tuple of (level, variable,
5718 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265719
Sam Maiera6e76d72022-02-11 21:43:505720 Returns:
5721 None if a string is not ICU or no issue detected.
5722 A tuple of (message, start index, end index) if an issue detected.
5723 """
5724 valid_types = {
5725 'plural': (frozenset(
5726 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5727 'other']), frozenset(['=1', 'other'])),
5728 'selectordinal': (frozenset(
5729 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5730 'other']), frozenset(['one', 'other'])),
5731 'select': (frozenset(), frozenset(['other'])),
5732 }
Rainhard Findlingfc31844c52020-05-15 09:58:265733
Sam Maiera6e76d72022-02-11 21:43:505734 # Check if the message looks like an attempt to use ICU
5735 # plural. If yes - check if its syntax strictly matches ICU format.
5736 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5737 text)
5738 if not like:
5739 signatures.append((level, None, None, None))
5740 return
Rainhard Findlingfc31844c52020-05-15 09:58:265741
Sam Maiera6e76d72022-02-11 21:43:505742 # Check for valid prefix and suffix
5743 m = re.match(
5744 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5745 r'(plural|selectordinal|select),\s*'
5746 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5747 if not m:
5748 return (('This message looks like an ICU plural, '
5749 'but does not follow ICU syntax.'), like.start(),
5750 like.end())
5751 starting, variable, kind, variant_pairs = m.groups()
5752 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5753 m.start(4))
5754 if depth:
5755 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5756 len(text))
5757 first = text[0]
5758 ending = text[last_pos:]
5759 if not starting:
5760 return ('Invalid ICU format. No initial opening bracket',
5761 last_pos - 1, last_pos)
5762 if not ending or '}' not in ending:
5763 return ('Invalid ICU format. No final closing bracket',
5764 last_pos - 1, last_pos)
5765 elif first != '{':
5766 return ((
5767 'Invalid ICU format. Extra characters at the start of a complex '
5768 'message (go/icu-message-migration): "%s"') % starting, 0,
5769 len(starting))
5770 elif ending != '}':
5771 return ((
5772 'Invalid ICU format. Extra characters at the end of a complex '
5773 'message (go/icu-message-migration): "%s"') % ending,
5774 last_pos - 1, len(text) - 1)
5775 if kind not in valid_types:
5776 return (('Unknown ICU message type %s. '
5777 'Valid types are: plural, select, selectordinal') % kind,
5778 0, 0)
5779 known, required = valid_types[kind]
5780 defined_variants = set()
5781 for variant, variant_range, value, value_range in variants:
5782 start, end = variant_range
5783 if variant in defined_variants:
5784 return ('Variant "%s" is defined more than once' % variant,
5785 start, end)
5786 elif known and variant not in known:
5787 return ('Variant "%s" is not valid for %s message' %
5788 (variant, kind), start, end)
5789 defined_variants.add(variant)
5790 # Check for nested structure
5791 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5792 if res:
5793 return (res[0], res[1] + value_range[0] + 1,
5794 res[2] + value_range[0] + 1)
5795 missing = required - defined_variants
5796 if missing:
5797 return ('Required variants missing: %s' % ', '.join(missing), 0,
5798 len(text))
5799 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265800
Sam Maiera6e76d72022-02-11 21:43:505801 def _ParseIcuVariants(text, offset=0):
5802 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265803
Sam Maiera6e76d72022-02-11 21:43:505804 Builds a tuple of variant names and values, as well as
5805 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265806
Sam Maiera6e76d72022-02-11 21:43:505807 Args:
5808 text: a string to parse
5809 offset: additional offset to add to positions in the text to get correct
5810 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265811
Sam Maiera6e76d72022-02-11 21:43:505812 Returns:
5813 List of tuples, each tuple consist of four fields: variant name,
5814 variant name span (tuple of two integers), variant value, value
5815 span (tuple of two integers).
5816 """
5817 depth, start, end = 0, -1, -1
5818 variants = []
5819 key = None
5820 for idx, char in enumerate(text):
5821 if char == '{':
5822 if not depth:
5823 start = idx
5824 chunk = text[end + 1:start]
5825 key = chunk.strip()
5826 pos = offset + end + 1 + chunk.find(key)
5827 span = (pos, pos + len(key))
5828 depth += 1
5829 elif char == '}':
5830 if not depth:
5831 return variants, depth, offset + idx
5832 depth -= 1
5833 if not depth:
5834 end = idx
5835 variants.append((key, span, text[start:end + 1],
5836 (offset + start, offset + end + 1)))
5837 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265838
Sam Maiera6e76d72022-02-11 21:43:505839 try:
5840 old_sys_path = sys.path
5841 sys.path = sys.path + [
5842 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5843 'translation')
5844 ]
5845 from helper import grd_helper
5846 finally:
5847 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265848
Sam Maiera6e76d72022-02-11 21:43:505849 for f in affected_grds:
5850 file_path = f.LocalPath()
5851 old_id_to_msg_map = {}
5852 new_id_to_msg_map = {}
5853 # Note that this code doesn't check if the file has been deleted. This is
5854 # OK because it only uses the old and new file contents and doesn't load
5855 # the file via its path.
5856 # It's also possible that a file's content refers to a renamed or deleted
5857 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5858 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5859 # .grdp files.
5860 if file_path.endswith('.grdp'):
5861 if f.OldContents():
5862 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5863 '\n'.join(f.OldContents()))
5864 if f.NewContents():
5865 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5866 '\n'.join(f.NewContents()))
5867 else:
5868 file_dir = input_api.os_path.dirname(file_path) or '.'
5869 if f.OldContents():
5870 old_id_to_msg_map = grd_helper.GetGrdMessages(
5871 StringIO('\n'.join(f.OldContents())), file_dir)
5872 if f.NewContents():
5873 new_id_to_msg_map = grd_helper.GetGrdMessages(
5874 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265875
Sam Maiera6e76d72022-02-11 21:43:505876 grd_name, ext = input_api.os_path.splitext(
5877 input_api.os_path.basename(file_path))
5878 screenshots_dir = input_api.os_path.join(
5879 input_api.os_path.dirname(file_path),
5880 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265881
Sam Maiera6e76d72022-02-11 21:43:505882 # Compute added, removed and modified message IDs.
5883 old_ids = set(old_id_to_msg_map)
5884 new_ids = set(new_id_to_msg_map)
5885 added_ids = new_ids - old_ids
5886 removed_ids = old_ids - new_ids
5887 modified_ids = set([])
5888 for key in old_ids.intersection(new_ids):
5889 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5890 new_id_to_msg_map[key].ContentsAsXml('', True)):
5891 # The message content itself changed. Require an updated screenshot.
5892 modified_ids.add(key)
5893 elif old_id_to_msg_map[key].attrs['meaning'] != \
5894 new_id_to_msg_map[key].attrs['meaning']:
5895 # The message meaning changed. Ensure there is a screenshot for it.
5896 sha1_path = input_api.os_path.join(screenshots_dir,
5897 key + '.png.sha1')
5898 if sha1_path not in new_or_added_paths and not \
5899 input_api.os_path.exists(sha1_path):
5900 # There is neither a previous screenshot nor is a new one added now.
5901 # Require a screenshot.
5902 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145903
Sam Maiera6e76d72022-02-11 21:43:505904 if run_screenshot_check:
5905 # Check the screenshot directory for .png files. Warn if there is any.
5906 for png_path in affected_png_paths:
5907 if png_path.startswith(screenshots_dir):
5908 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145909
Sam Maiera6e76d72022-02-11 21:43:505910 for added_id in added_ids:
5911 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095912
Sam Maiera6e76d72022-02-11 21:43:505913 for modified_id in modified_ids:
5914 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145915
Sam Maiera6e76d72022-02-11 21:43:505916 for removed_id in removed_ids:
5917 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5918
5919 # Check new and changed strings for ICU syntax errors.
5920 for key in added_ids.union(modified_ids):
5921 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5922 err = _ValidateIcuSyntax(msg, 0, [])
5923 if err is not None:
5924 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5925
5926 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265927 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505928 if unnecessary_screenshots:
5929 results.append(
5930 output_api.PresubmitError(
5931 'Do not include actual screenshots in the changelist. Run '
5932 'tools/translate/upload_screenshots.py to upload them instead:',
5933 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145934
Sam Maiera6e76d72022-02-11 21:43:505935 if missing_sha1:
5936 results.append(
5937 output_api.PresubmitError(
5938 'You are adding or modifying UI strings.\n'
5939 'To ensure the best translations, take screenshots of the relevant UI '
5940 '(https://g.co/chrome/translation) and add these files to your '
5941 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145942
Sam Maiera6e76d72022-02-11 21:43:505943 if unnecessary_sha1_files:
5944 results.append(
5945 output_api.PresubmitError(
5946 'You removed strings associated with these files. Remove:',
5947 sorted(unnecessary_sha1_files)))
5948 else:
5949 results.append(
5950 output_api.PresubmitPromptOrNotify('Skipping translation '
5951 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145952
Sam Maiera6e76d72022-02-11 21:43:505953 if icu_syntax_errors:
5954 results.append(
5955 output_api.PresubmitPromptWarning(
5956 'ICU syntax errors were found in the following strings (problems or '
5957 'feedback? Contact [email protected]):',
5958 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265959
Sam Maiera6e76d72022-02-11 21:43:505960 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125961
5962
Saagar Sanghavifceeaae2020-08-12 16:40:365963def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125964 repo_root=None,
5965 translation_expectations_path=None,
5966 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505967 import sys
5968 affected_grds = [
5969 f for f in input_api.AffectedFiles()
5970 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5971 ]
5972 if not affected_grds:
5973 return []
5974
5975 try:
5976 old_sys_path = sys.path
5977 sys.path = sys.path + [
5978 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5979 'translation')
5980 ]
5981 from helper import git_helper
5982 from helper import translation_helper
5983 finally:
5984 sys.path = old_sys_path
5985
5986 # Check that translation expectations can be parsed and we can get a list of
5987 # translatable grd files. |repo_root| and |translation_expectations_path| are
5988 # only passed by tests.
5989 if not repo_root:
5990 repo_root = input_api.PresubmitLocalPath()
5991 if not translation_expectations_path:
5992 translation_expectations_path = input_api.os_path.join(
5993 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5994 if not grd_files:
5995 grd_files = git_helper.list_grds_in_repository(repo_root)
5996
5997 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:595998 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:505999 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
6000 'tests')
6001 grd_files = [p for p in grd_files if ignore_path not in p]
6002
6003 try:
6004 translation_helper.get_translatable_grds(
6005 repo_root, grd_files, translation_expectations_path)
6006 except Exception as e:
6007 return [
6008 output_api.PresubmitNotifyResult(
6009 'Failed to get a list of translatable grd files. This happens when:\n'
6010 ' - One of the modified grd or grdp files cannot be parsed or\n'
6011 ' - %s is not updated.\n'
6012 'Stack:\n%s' % (translation_expectations_path, str(e)))
6013 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:126014 return []
6015
Ken Rockotc31f4832020-05-29 18:58:516016
Saagar Sanghavifceeaae2020-08-12 16:40:366017def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506018 """Changes to [Stable] mojom types must preserve backward-compatibility."""
6019 changed_mojoms = input_api.AffectedFiles(
6020 include_deletes=True,
6021 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:526022
Bruce Dawson344ab262022-06-04 11:35:106023 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:506024 return []
6025
6026 delta = []
6027 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:506028 delta.append({
6029 'filename': mojom.LocalPath(),
6030 'old': '\n'.join(mojom.OldContents()) or None,
6031 'new': '\n'.join(mojom.NewContents()) or None,
6032 })
6033
6034 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:216035 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:506036 input_api.os_path.join(
6037 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
6038 'check_stable_mojom_compatibility.py'), '--src-root',
6039 input_api.PresubmitLocalPath()
6040 ],
6041 stdin=input_api.subprocess.PIPE,
6042 stdout=input_api.subprocess.PIPE,
6043 stderr=input_api.subprocess.PIPE,
6044 universal_newlines=True)
6045 (x, error) = process.communicate(input=input_api.json.dumps(delta))
6046 if process.returncode:
6047 return [
6048 output_api.PresubmitError(
6049 'One or more [Stable] mojom definitions appears to have been changed '
6050 'in a way that is not backward-compatible.',
6051 long_text=error)
6052 ]
Erik Staabc734cd7a2021-11-23 03:11:526053 return []
6054
Dominic Battre645d42342020-12-04 16:14:106055def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506056 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106057
Sam Maiera6e76d72022-02-11 21:43:506058 def FilterFile(affected_file):
6059 """Accept only .cc files and the like."""
6060 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6061 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6062 input_api.DEFAULT_FILES_TO_SKIP)
6063 return input_api.FilterSourceFile(
6064 affected_file,
6065 files_to_check=file_inclusion_pattern,
6066 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106067
Sam Maiera6e76d72022-02-11 21:43:506068 def ModifiedLines(affected_file):
6069 """Returns a list of tuples (line number, line text) of added and removed
6070 lines.
Dominic Battre645d42342020-12-04 16:14:106071
Sam Maiera6e76d72022-02-11 21:43:506072 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106073
Sam Maiera6e76d72022-02-11 21:43:506074 This relies on the scm diff output describing each changed code section
6075 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106076
Sam Maiera6e76d72022-02-11 21:43:506077 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6078 """
6079 line_num = 0
6080 modified_lines = []
6081 for line in affected_file.GenerateScmDiff().splitlines():
6082 # Extract <new line num> of the patch fragment (see format above).
6083 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6084 line)
6085 if m:
6086 line_num = int(m.groups(1)[0])
6087 continue
6088 if ((line.startswith('+') and not line.startswith('++'))
6089 or (line.startswith('-') and not line.startswith('--'))):
6090 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106091
Sam Maiera6e76d72022-02-11 21:43:506092 if not line.startswith('-'):
6093 line_num += 1
6094 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106095
Sam Maiera6e76d72022-02-11 21:43:506096 def FindLineWith(lines, needle):
6097 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106098
Sam Maiera6e76d72022-02-11 21:43:506099 If 0 or >1 lines contain `needle`, -1 is returned.
6100 """
6101 matching_line_numbers = [
6102 # + 1 for 1-based counting of line numbers.
6103 i + 1 for i, line in enumerate(lines) if needle in line
6104 ]
6105 return matching_line_numbers[0] if len(
6106 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106107
Sam Maiera6e76d72022-02-11 21:43:506108 def ModifiedPrefMigration(affected_file):
6109 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6110 # Determine first and last lines of MigrateObsolete.*Pref functions.
6111 new_contents = affected_file.NewContents()
6112 range_1 = (FindLineWith(new_contents,
6113 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6114 FindLineWith(new_contents,
6115 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6116 range_2 = (FindLineWith(new_contents,
6117 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6118 FindLineWith(new_contents,
6119 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6120 if (-1 in range_1 + range_2):
6121 raise Exception(
6122 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6123 )
Dominic Battre645d42342020-12-04 16:14:106124
Sam Maiera6e76d72022-02-11 21:43:506125 # Check whether any of the modified lines are part of the
6126 # MigrateObsolete.*Pref functions.
6127 for line_nr, line in ModifiedLines(affected_file):
6128 if (range_1[0] <= line_nr <= range_1[1]
6129 or range_2[0] <= line_nr <= range_2[1]):
6130 return True
6131 return False
Dominic Battre645d42342020-12-04 16:14:106132
Sam Maiera6e76d72022-02-11 21:43:506133 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6134 browser_prefs_file_pattern = input_api.re.compile(
6135 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106136
Sam Maiera6e76d72022-02-11 21:43:506137 changes = input_api.AffectedFiles(include_deletes=True,
6138 file_filter=FilterFile)
6139 potential_problems = []
6140 for f in changes:
6141 for line in f.GenerateScmDiff().splitlines():
6142 # Check deleted lines for pref registrations.
6143 if (line.startswith('-') and not line.startswith('--')
6144 and register_pref_pattern.search(line)):
6145 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106146
Sam Maiera6e76d72022-02-11 21:43:506147 if browser_prefs_file_pattern.search(f.LocalPath()):
6148 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6149 # assume that they knew that they have to deprecate preferences and don't
6150 # warn.
6151 try:
6152 if ModifiedPrefMigration(f):
6153 return []
6154 except Exception as e:
6155 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106156
Sam Maiera6e76d72022-02-11 21:43:506157 if potential_problems:
6158 return [
6159 output_api.PresubmitPromptWarning(
6160 'Discovered possible removal of preference registrations.\n\n'
6161 'Please make sure to properly deprecate preferences by clearing their\n'
6162 'value for a couple of milestones before finally removing the code.\n'
6163 'Otherwise data may stay in the preferences files forever. See\n'
6164 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6165 'chrome/browser/prefs/README.md for examples.\n'
6166 'This may be a false positive warning (e.g. if you move preference\n'
6167 'registrations to a different place).\n', potential_problems)
6168 ]
6169 return []
6170
Matt Stark6ef08872021-07-29 01:21:466171
6172def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506173 """Changes to GRD files must be consistent for tools to read them."""
6174 changed_grds = input_api.AffectedFiles(
6175 include_deletes=False,
6176 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6177 errors = []
6178 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6179 for matcher, msg in _INVALID_GRD_FILE_LINE]
6180 for grd in changed_grds:
6181 for i, line in enumerate(grd.NewContents()):
6182 for matcher, msg in invalid_file_regexes:
6183 if matcher.search(line):
6184 errors.append(
6185 output_api.PresubmitError(
6186 'Problem on {grd}:{i} - {msg}'.format(
6187 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6188 return errors
6189
Kevin McNee967dd2d22021-11-15 16:09:296190
6191def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506192 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
6193 presence of MPArch features such as bfcache, prerendering, and fenced frames.
6194 """
Kevin McNee967dd2d22021-11-15 16:09:296195
Ian Vollickdba956c2022-04-20 23:53:456196 # Only consider top-level directories that (1) can use content APIs or
6197 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
6198 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:506199 files_to_check = (
Bruce Dawson40fece62022-09-16 19:58:316200 r'^(chrome|components|content|extensions|third_party/blink/renderer)/.+%s' %
Kevin McNee967dd2d22021-11-15 16:09:296201 _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:316202 r'^(chrome|components|content|extensions|third_party/blink/renderer)/.+%s' %
Sam Maiera6e76d72022-02-11 21:43:506203 _HEADER_EXTENSIONS,
6204 )
6205 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6206 input_api.DEFAULT_FILES_TO_SKIP)
6207 source_file_filter = lambda f: input_api.FilterSourceFile(
6208 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:296209
Kevin McNee29c0e8232022-08-05 15:36:096210 # Here we list the classes/methods we're monitoring. For the "fyi" cases,
6211 # we add the CL to the watchlist, but we don't omit a warning or have it be
6212 # included in the triage rotation.
Sam Maiera6e76d72022-02-11 21:43:506213 # Note that since these are are just regular expressions and we don't have
6214 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
6215 # could have a method named IsInMainFrame).
Kevin McNee29c0e8232022-08-05 15:36:096216 fyi_concerning_class_pattern = input_api.re.compile(
Sam Maiera6e76d72022-02-11 21:43:506217 r'WebContentsObserver|WebContentsUserData')
6218 # A subset of WebContentsObserver overrides where there's particular risk for
6219 # confusing tab and page level operations and data (e.g. incorrectly
6220 # resetting page state in DidFinishNavigation).
Kevin McNee29c0e8232022-08-05 15:36:096221 fyi_concerning_wco_methods = [
Sam Maiera6e76d72022-02-11 21:43:506222 'DidStartNavigation',
6223 'ReadyToCommitNavigation',
6224 'DidFinishNavigation',
6225 'RenderViewReady',
6226 'RenderViewDeleted',
6227 'RenderViewHostChanged',
Sam Maiera6e76d72022-02-11 21:43:506228 'DOMContentLoaded',
6229 'DidFinishLoad',
6230 ]
6231 concerning_nav_handle_methods = [
6232 'IsInMainFrame',
6233 ]
6234 concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:506235 'FromRenderFrameHost',
6236 'FromRenderViewHost',
Kevin McNee29c0e8232022-08-05 15:36:096237 ]
6238 fyi_concerning_web_contents_methods = [
Sam Maiera6e76d72022-02-11 21:43:506239 'GetRenderViewHost',
6240 ]
6241 concerning_rfh_methods = [
6242 'GetParent',
6243 'GetMainFrame',
Kevin McNee29c0e8232022-08-05 15:36:096244 ]
6245 fyi_concerning_rfh_methods = [
Sam Maiera6e76d72022-02-11 21:43:506246 'GetFrameTreeNodeId',
6247 ]
Ian Vollickc825b1f2022-04-19 14:30:156248 concerning_rfhi_methods = [
6249 'is_main_frame',
6250 ]
Ian Vollicka77a73ea2022-04-06 18:08:016251 concerning_ftn_methods = [
6252 'IsMainFrame',
6253 ]
Ian Vollickdba956c2022-04-20 23:53:456254 concerning_blink_frame_methods = [
Ian Vollick4d785d22022-06-18 00:10:026255 'IsCrossOriginToNearestMainFrame',
Ian Vollickdba956c2022-04-20 23:53:456256 ]
Sam Maiera6e76d72022-02-11 21:43:506257 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
6258 item for sublist in [
Kevin McNee29c0e8232022-08-05 15:36:096259 concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:016260 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:156261 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:456262 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:506263 ] for item in sublist) + r')\(')
Kevin McNee29c0e8232022-08-05 15:36:096264 fyi_concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
6265 item for sublist in [
6266 fyi_concerning_wco_methods, fyi_concerning_web_contents_methods,
6267 fyi_concerning_rfh_methods,
6268 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:296269
Kevin McNee4eeec792022-02-14 20:02:046270 used_apis = set()
Kevin McNee29c0e8232022-08-05 15:36:096271 used_fyi_methods = False
Sam Maiera6e76d72022-02-11 21:43:506272 for f in input_api.AffectedFiles(include_deletes=False,
6273 file_filter=source_file_filter):
6274 for line_num, line in f.ChangedContents():
Kevin McNee29c0e8232022-08-05 15:36:096275 fyi_class_match = fyi_concerning_class_pattern.search(line)
6276 if fyi_class_match:
6277 used_fyi_methods = True
6278 fyi_method_match = fyi_concerning_method_pattern.search(line)
6279 if fyi_method_match:
6280 used_fyi_methods = True
Kevin McNee4eeec792022-02-14 20:02:046281 method_match = concerning_method_pattern.search(line)
6282 if method_match:
6283 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:506284
Kevin McNee4eeec792022-02-14 20:02:046285 if not used_apis:
Kevin McNee29c0e8232022-08-05 15:36:096286 if used_fyi_methods:
6287 output_api.AppendCC('[email protected]')
6288
Kevin McNee4eeec792022-02-14 20:02:046289 return []
Kevin McNee967dd2d22021-11-15 16:09:296290
Kevin McNee4eeec792022-02-14 20:02:046291 output_api.AppendCC('[email protected]')
6292 message = ('This change uses API(s) that are ambiguous in the presence of '
6293 'MPArch features such as bfcache, prerendering, and fenced '
6294 'frames.')
Kevin McNee29c0e8232022-08-05 15:36:096295 explanation = (
Kevin McNee4eeec792022-02-14 20:02:046296 'Please double check whether new code assumes that a WebContents only '
Kevin McNee29c0e8232022-08-05 15:36:096297 'contains a single page at a time. Notably, checking whether a frame '
6298 'is the \"main frame\" is not specific enough to determine whether it '
6299 'corresponds to the document reflected in the omnibox. A WebContents '
6300 'may have additional main frames for prerendered pages, bfcached '
6301 'pages, fenced frames, etc. '
6302 'See this doc [1] and the comments on the individual APIs '
Kevin McNee4eeec792022-02-14 20:02:046303 'for guidance and this doc [2] for context. The MPArch review '
6304 'watchlist has been CC\'d on this change to help identify any issues.\n'
6305 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
6306 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
6307 )
6308 return [
6309 output_api.PresubmitNotifyResult(message,
6310 items=list(used_apis),
Kevin McNee29c0e8232022-08-05 15:36:096311 long_text=explanation)
Kevin McNee4eeec792022-02-14 20:02:046312 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:366313
6314
6315def CheckAssertAshOnlyCode(input_api, output_api):
6316 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6317 assert(is_chromeos_ash).
6318 """
6319
6320 def FileFilter(affected_file):
6321 """Includes directories known to be Ash only."""
6322 return input_api.FilterSourceFile(
6323 affected_file,
6324 files_to_check=(
6325 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6326 r'.*/ash/.*BUILD\.gn'), # Any path component.
6327 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6328
6329 errors = []
6330 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566331 for f in input_api.AffectedFiles(include_deletes=False,
6332 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366333 if (not pattern.search(input_api.ReadFile(f))):
6334 errors.append(
6335 output_api.PresubmitError(
6336 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6337 'possible, please create and issue and add a comment such '
6338 'as:\n # TODO(https://crbug.com/XXX): add '
6339 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6340 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276341
6342
6343def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506344 path = affected_file.LocalPath()
6345 if not _IsCPlusPlusFile(input_api, path):
6346 return False
6347
6348 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6349 if "/renderer/" in path:
6350 return True
6351
6352 # Blink's public/web API is only used/included by Renderer-only code. Note
6353 # that public/platform API may be used in non-Renderer processes (e.g. there
6354 # are some includes in code used by Utility, PDF, or Plugin processes).
6355 if "/blink/public/web/" in path:
6356 return True
6357
6358 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276359 return False
6360
Lukasz Anforowicz7016d05e2021-11-30 03:56:276361# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6362# by the Chromium Clang Plugin (which will be preferable because it will
6363# 1) report errors earlier - at compile-time and 2) cover more rules).
6364def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506365 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6366 errors = []
6367 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6368 # C++ comment.
6369 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6370 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6371 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6372 if raw_ptr_matcher.search(line):
6373 errors.append(
6374 output_api.PresubmitError(
6375 'Problem on {path}:{line} - '\
6376 'raw_ptr<T> should not be used in Renderer-only code '\
6377 '(as documented in the "Pointers to unprotected memory" '\
6378 'section in //base/memory/raw_ptr.md)'.format(
6379 path=f.LocalPath(), line=line_num)))
6380 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566381
6382
6383def CheckPythonShebang(input_api, output_api):
6384 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6385 system-wide python.
6386 """
6387 errors = []
6388 sources = lambda affected_file: input_api.FilterSourceFile(
6389 affected_file,
6390 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6391 r'third_party/blink/web_tests/external/') + input_api.
6392 DEFAULT_FILES_TO_SKIP),
6393 files_to_check=[r'.*\.py$'])
6394 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276395 for line_num, line in f.ChangedContents():
6396 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6397 errors.append(f.LocalPath())
6398 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566399
6400 result = []
6401 for file in errors:
6402 result.append(
6403 output_api.PresubmitError(
6404 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6405 file))
6406 return result
James Shen81cc0e22022-06-15 21:10:456407
6408
6409def CheckBatchAnnotation(input_api, output_api):
6410 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6411 is not an instrumentation test, disregard."""
6412
6413 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6414 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6415 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6416 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6417 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6418
ckitagawae8fd23b2022-06-17 15:29:386419 missing_annotation_errors = []
6420 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456421
6422 def _FilterFile(affected_file):
6423 return input_api.FilterSourceFile(
6424 affected_file,
6425 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6426 files_to_check=[r'.*Test\.java$'])
6427
6428 for f in input_api.AffectedSourceFiles(_FilterFile):
6429 batch_matched = None
6430 do_not_batch_matched = None
6431 is_instrumentation_test = True
6432 for line in f.NewContents():
6433 if robolectric_test.search(line) or uiautomator_test.search(line):
6434 # Skip Robolectric and UiAutomator tests.
6435 is_instrumentation_test = False
6436 break
6437 if not batch_matched:
6438 batch_matched = batch_annotation.search(line)
6439 if not do_not_batch_matched:
6440 do_not_batch_matched = do_not_batch_annotation.search(line)
6441 test_class_declaration_matched = test_class_declaration.search(
6442 line)
6443 if test_class_declaration_matched:
6444 break
6445 if (is_instrumentation_test and
6446 not batch_matched and
6447 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246448 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386449 if (not is_instrumentation_test and
6450 (batch_matched or
6451 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246452 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456453
6454 results = []
6455
ckitagawae8fd23b2022-06-17 15:29:386456 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456457 results.append(
6458 output_api.PresubmitPromptWarning(
6459 """
6460Instrumentation tests should use either @Batch or @DoNotBatch. If tests are not
6461safe to run in batch, please use @DoNotBatch with reasons.
ckitagawae8fd23b2022-06-17 15:29:386462""", missing_annotation_errors))
6463 if extra_annotation_errors:
6464 results.append(
6465 output_api.PresubmitPromptWarning(
6466 """
6467Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6468""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456469
6470 return results
Sam Maier4cef9242022-10-03 14:21:246471
6472
6473def CheckMockAnnotation(input_api, output_api):
6474 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6475 classes with @Mock or @Spy. If this is not an instrumentation test,
6476 disregard."""
6477
6478 # This is just trying to be approximately correct. We are not writing a
6479 # Java parser, so special cases like statically importing mock() then
6480 # calling an unrelated non-mockito spy() function will cause a false
6481 # positive.
6482 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6483 mock_static_import = input_api.re.compile(
6484 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6485 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6486 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6487 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6488 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6489 fully_qualified_mock_function = input_api.re.compile(
6490 r'Mockito\.' + mock_or_spy_function_call)
6491 statically_imported_mock_function = input_api.re.compile(
6492 r'\W' + mock_or_spy_function_call)
6493 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6494 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6495
6496 def _DoClassLookup(class_name, class_name_map, package):
6497 found = class_name_map.get(class_name)
6498 if found is not None:
6499 return found
6500 else:
6501 return package + '.' + class_name
6502
6503 def _FilterFile(affected_file):
6504 return input_api.FilterSourceFile(
6505 affected_file,
6506 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6507 files_to_check=[r'.*Test\.java$'])
6508
6509 mocked_by_function_classes = set()
6510 mocked_by_annotation_classes = set()
6511 class_to_filename = {}
6512 for f in input_api.AffectedSourceFiles(_FilterFile):
6513 mock_function_regex = fully_qualified_mock_function
6514 next_line_is_annotated = False
6515 fully_qualified_class_map = {}
6516 package = None
6517
6518 for line in f.NewContents():
6519 if robolectric_test.search(line) or uiautomator_test.search(line):
6520 # Skip Robolectric and UiAutomator tests.
6521 break
6522
6523 m = package_name.search(line)
6524 if m:
6525 package = m.group(1)
6526 continue
6527
6528 if mock_static_import.search(line):
6529 mock_function_regex = statically_imported_mock_function
6530 continue
6531
6532 m = import_class.search(line)
6533 if m:
6534 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
6535 continue
6536
6537 if next_line_is_annotated:
6538 next_line_is_annotated = False
6539 fully_qualified_class = _DoClassLookup(
6540 field_type.search(line).group(1), fully_qualified_class_map,
6541 package)
6542 mocked_by_annotation_classes.add(fully_qualified_class)
6543 continue
6544
6545 if mock_annotation.search(line):
6546 next_line_is_annotated = True
6547 continue
6548
6549 m = mock_function_regex.search(line)
6550 if m:
6551 fully_qualified_class = _DoClassLookup(m.group(1),
6552 fully_qualified_class_map, package)
6553 # Skipping builtin classes, since they don't get optimized.
6554 if fully_qualified_class.startswith(
6555 'android.') or fully_qualified_class.startswith(
6556 'java.'):
6557 continue
6558 class_to_filename[fully_qualified_class] = str(f.LocalPath())
6559 mocked_by_function_classes.add(fully_qualified_class)
6560
6561 results = []
6562 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
6563 if missed_classes:
6564 error_locations = []
6565 for c in missed_classes:
6566 error_locations.append(c + ' in ' + class_to_filename[c])
6567 results.append(
6568 output_api.PresubmitPromptWarning(
6569 """
6570Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
65711) If the mocked variable can be a class member, annotate the member with
6572 @Mock/@Spy.
65732) If the mocked variable cannot be a class member, create a dummy member
6574 variable of that type, annotated with @Mock/@Spy. This dummy does not need
6575 to be used or initialized in any way.
65763) If the mocked type is definitely not going to be optimized, whether it's a
6577 builtin type which we don't ship, or a class you know R8 will treat
6578 specially, you can ignore this warning.
6579""", error_locations))
6580
6581 return results
Mike Dougherty1b8be712022-10-20 00:15:136582
6583def CheckNoJsInIos(input_api, output_api):
6584 """Checks to make sure that JavaScript files are not used on iOS."""
6585
6586 def _FilterFile(affected_file):
6587 return input_api.FilterSourceFile(
6588 affected_file,
6589 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
6590 (r'^ios/third_party/*', r'^third_party/*'),
6591 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
6592
6593 error_paths = []
6594 warning_paths = []
6595
6596 for f in input_api.AffectedSourceFiles(_FilterFile):
6597 local_path = f.LocalPath()
6598
6599 if input_api.os_path.splitext(local_path)[1] == '.js':
6600 if f.Action() == 'A':
6601 error_paths.append(local_path)
6602 elif f.Action() != 'D':
6603 warning_paths.append(local_path)
6604
6605 results = []
6606
6607 if warning_paths:
6608 results.append(output_api.PresubmitPromptWarning(
6609 'TypeScript is now fully supported for iOS feature scripts. '
6610 'Consider converting JavaScript files to TypeScript. See '
6611 '//ios/web/public/js_messaging/README.md for more details.',
6612 warning_paths))
6613
6614 if error_paths:
6615 results.append(output_api.PresubmitError(
6616 'Do not use JavaScript on iOS as TypeScript is fully supported. '
6617 'See //ios/web/public/js_messaging/README.md for help using '
6618 'scripts on iOS.', error_paths))
6619
6620 return results