blob: be65042cd69c3b5601dd96d6910520ba1c249742 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
14from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1217
Dirk Prankee3c9c62d2021-05-18 18:35:5918# This line is 'magic' in that git-cl looks for it to decide whether to
19# use Python3 instead of Python2 when running the code in this file.
20USE_PYTHON3 = True
21
[email protected]379e7dd2010-01-28 17:39:2122_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1823 # Generated file
Bruce Dawson3bd976c2022-05-06 22:47:5224 (r"chrome[\\/]android[\\/]webapk[\\/]shell_apk[\\/]src[\\/]org[\\/]chromium"
25 r"[\\/]webapk[\\/]lib[\\/]runtime_library[\\/]IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0826 # File needs to write to stdout to emulate a tool it's replacing.
Mila Greend3fc6a42021-09-10 17:38:2327 r"chrome[\\/]updater[\\/]mac[\\/]keystone[\\/]ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4728 # Generated file.
29 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2630 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5231 # These are video files, not typescript.
32 r"^media[\\/]test[\\/]data[\\/].*.ts",
Mila Greene3aa7222021-09-07 16:34:0833 r"^native_client_sdksrc[\\/]build_tools[\\/]make_rules.py",
Egor Paskoce145c42018-09-28 19:31:0434 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
35 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
36 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
37 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4938 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0439 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4640 # sqlite is an imported third party dependency.
41 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0442 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5443 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5344 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1245 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0446 r".+[\\/]pnacl_shim\.c$",
47 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0448 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1449 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0450 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5451 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0452 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4053)
[email protected]ca8d1982009-02-19 16:33:1254
John Abd-El-Malek759fea62021-03-13 03:41:1455_EXCLUDED_SET_NO_PARENT_PATHS = (
56 # It's for historical reasons that blink isn't a top level directory, where
57 # it would be allowed to have "set noparent" to avoid top level owners
58 # accidentally +1ing changes.
59 'third_party/blink/OWNERS',
60)
61
wnwenbdc444e2016-05-25 13:44:1562
[email protected]06e6d0ff2012-12-11 01:36:4463# Fragment of a regular expression that matches C++ and Objective-C++
64# implementation files.
65_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
66
wnwenbdc444e2016-05-25 13:44:1567
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1968# Fragment of a regular expression that matches C++ and Objective-C++
69# header files.
70_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
71
72
[email protected]06e6d0ff2012-12-11 01:36:4473# Regular expression that matches code only used for test binaries
74# (best effort).
75_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0476 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4477 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1378 # Test suite files, like:
79 # foo_browsertest.cc
80 # bar_unittest_mac.cc (suffix)
81 # baz_unittests.cc (plural)
82 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1283 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1884 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2185 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0486 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4387 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0488 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4389 # Web test harness.
90 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4791 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0492 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0893 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0494 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4195 # EarlGrey app side code for tests.
96 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1797 # Views Examples code
98 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4199 # Chromium Codelab
100 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:44101)
[email protected]ca8d1982009-02-19 16:33:12102
Daniel Bratell609102be2019-03-27 20:53:21103_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15104
[email protected]eea609a2011-11-18 13:10:12105_TEST_ONLY_WARNING = (
106 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55107 'production code. If you are doing this from inside another method\n'
108 'named as *ForTesting(), then consider exposing things to have tests\n'
109 'make that same call directly.\n'
110 'If that is not possible, you may put a comment on the same line with\n'
111 ' // IN-TEST \n'
112 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
113 'method and can be ignored. Do not do this inside production code.\n'
114 'The android-binary-size trybot will block if the method exists in the\n'
115 'release apk.')
[email protected]eea609a2011-11-18 13:10:12116
117
Daniel Chenga44a1bcd2022-03-15 20:00:15118@dataclass
119class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34120 # String pattern. If the pattern begins with a slash, the pattern will be
121 # treated as a regular expression instead.
122 pattern: str
123 # Explanation as a sequence of strings. Each string in the sequence will be
124 # printed on its own line.
125 explanation: Sequence[str]
126 # Whether or not to treat this ban as a fatal error. If unspecified,
127 # defaults to true.
128 treat_as_error: Optional[bool] = None
129 # Paths that should be excluded from the ban check. Each string is a regular
130 # expression that will be matched against the path of the file being checked
131 # relative to the root of the source tree.
132 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28133
Daniel Chenga44a1bcd2022-03-15 20:00:15134
Daniel Cheng917ce542022-03-15 20:46:57135_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15136 BanRule(
137 'import java.net.URI;',
138 (
139 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
140 ),
141 excluded_paths=(
142 (r'net/android/javatests/src/org/chromium/net/'
143 'AndroidProxySelectorTest\.java'),
144 r'components/cronet/',
145 r'third_party/robolectric/local/',
146 ),
Michael Thiessen44457642020-02-06 00:24:15147 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15148 BanRule(
149 'import android.annotation.TargetApi;',
150 (
151 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
152 'RequiresApi ensures that any calls are guarded by the appropriate '
153 'SDK_INT check. See https://crbug.com/1116486.',
154 ),
155 ),
156 BanRule(
157 'import android.support.test.rule.UiThreadTestRule;',
158 (
159 'Do not use UiThreadTestRule, just use '
160 '@org.chromium.base.test.UiThreadTest on test methods that should run '
161 'on the UI thread. See https://crbug.com/1111893.',
162 ),
163 ),
164 BanRule(
165 'import android.support.test.annotation.UiThreadTest;',
166 ('Do not use android.support.test.annotation.UiThreadTest, use '
167 'org.chromium.base.test.UiThreadTest instead. See '
168 'https://crbug.com/1111893.',
169 ),
170 ),
171 BanRule(
172 'import android.support.test.rule.ActivityTestRule;',
173 (
174 'Do not use ActivityTestRule, use '
175 'org.chromium.base.test.BaseActivityTestRule instead.',
176 ),
177 excluded_paths=(
178 'components/cronet/',
179 ),
180 ),
181)
wnwenbdc444e2016-05-25 13:44:15182
Daniel Cheng917ce542022-03-15 20:46:57183_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15184 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41185 'StrictMode.allowThreadDiskReads()',
186 (
187 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
188 'directly.',
189 ),
190 False,
191 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15192 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41193 'StrictMode.allowThreadDiskWrites()',
194 (
195 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
196 'directly.',
197 ),
198 False,
199 ),
Daniel Cheng917ce542022-03-15 20:46:57200 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36201 '.waitForIdleSync()',
202 (
203 'Do not use waitForIdleSync as it masks underlying issues. There is '
204 'almost always something else you should wait on instead.',
205 ),
206 False,
207 ),
Eric Stevensona9a980972017-09-23 00:04:41208)
209
Daniel Cheng917ce542022-03-15 20:46:57210_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15211 BanRule(
[email protected]127f18ec2012-06-16 05:05:59212 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20213 (
214 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59215 'prohibited. Please use CrTrackingArea instead.',
216 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
217 ),
218 False,
219 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15220 BanRule(
[email protected]eaae1972014-04-16 04:17:26221 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20222 (
223 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59224 'instead.',
225 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
226 ),
227 False,
228 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15229 BanRule(
[email protected]127f18ec2012-06-16 05:05:59230 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20231 (
232 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59233 'Please use |convertPoint:(point) fromView:nil| instead.',
234 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
235 ),
236 True,
237 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15238 BanRule(
[email protected]127f18ec2012-06-16 05:05:59239 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20240 (
241 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59242 'Please use |convertPoint:(point) toView:nil| instead.',
243 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
244 ),
245 True,
246 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15247 BanRule(
[email protected]127f18ec2012-06-16 05:05:59248 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20249 (
250 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59251 'Please use |convertRect:(point) fromView:nil| instead.',
252 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
253 ),
254 True,
255 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15256 BanRule(
[email protected]127f18ec2012-06-16 05:05:59257 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20258 (
259 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59260 'Please use |convertRect:(point) toView:nil| instead.',
261 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
262 ),
263 True,
264 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15265 BanRule(
[email protected]127f18ec2012-06-16 05:05:59266 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20267 (
268 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59269 'Please use |convertSize:(point) fromView:nil| instead.',
270 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
271 ),
272 True,
273 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15274 BanRule(
[email protected]127f18ec2012-06-16 05:05:59275 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20276 (
277 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59278 'Please use |convertSize:(point) toView:nil| instead.',
279 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
280 ),
281 True,
282 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15283 BanRule(
jif65398702016-10-27 10:19:48284 r"/\s+UTF8String\s*]",
285 (
286 'The use of -[NSString UTF8String] is dangerous as it can return null',
287 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
288 'Please use |SysNSStringToUTF8| instead.',
289 ),
290 True,
291 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15292 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34293 r'__unsafe_unretained',
294 (
295 'The use of __unsafe_unretained is almost certainly wrong, unless',
296 'when interacting with NSFastEnumeration or NSInvocation.',
297 'Please use __weak in files build with ARC, nothing otherwise.',
298 ),
299 False,
300 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15301 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13302 'freeWhenDone:NO',
303 (
304 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
305 'Foundation types is prohibited.',
306 ),
307 True,
308 ),
[email protected]127f18ec2012-06-16 05:05:59309)
310
Sylvain Defresnea8b73d252018-02-28 15:45:54311_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15312 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54313 r'/\bTEST[(]',
314 (
315 'TEST() macro should not be used in Objective-C++ code as it does not ',
316 'drain the autorelease pool at the end of the test. Use TEST_F() ',
317 'macro instead with a fixture inheriting from PlatformTest (or a ',
318 'typedef).'
319 ),
320 True,
321 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15322 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54323 r'/\btesting::Test\b',
324 (
325 'testing::Test should not be used in Objective-C++ code as it does ',
326 'not drain the autorelease pool at the end of the test. Use ',
327 'PlatformTest instead.'
328 ),
329 True,
330 ),
331)
332
Daniel Cheng917ce542022-03-15 20:46:57333_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15334 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05335 r'/\bEXPECT_OCMOCK_VERIFY\b',
336 (
337 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
338 'it is meant for GTests. Use [mock verify] instead.'
339 ),
340 True,
341 ),
342)
343
Daniel Cheng917ce542022-03-15 20:46:57344_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15345 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04346 r'/\busing namespace ',
347 (
348 'Using directives ("using namespace x") are banned by the Google Style',
349 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
350 'Explicitly qualify symbols or use using declarations ("using x::foo").',
351 ),
352 True,
353 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
354 ),
Antonio Gomes07300d02019-03-13 20:59:57355 # Make sure that gtest's FRIEND_TEST() macro is not used; the
356 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
357 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15358 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20359 'FRIEND_TEST(',
360 (
[email protected]e3c945502012-06-26 20:01:49361 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20362 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
363 ),
364 False,
[email protected]7345da02012-11-27 14:31:49365 (),
[email protected]23e6cbc2012-06-16 18:51:20366 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15367 BanRule(
tomhudsone2c14d552016-05-26 17:07:46368 'setMatrixClip',
369 (
370 'Overriding setMatrixClip() is prohibited; ',
371 'the base function is deprecated. ',
372 ),
373 True,
374 (),
375 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15376 BanRule(
[email protected]52657f62013-05-20 05:30:31377 'SkRefPtr',
378 (
379 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22380 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31381 ),
382 True,
383 (),
384 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15385 BanRule(
[email protected]52657f62013-05-20 05:30:31386 'SkAutoRef',
387 (
388 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22389 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31390 ),
391 True,
392 (),
393 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15394 BanRule(
[email protected]52657f62013-05-20 05:30:31395 'SkAutoTUnref',
396 (
397 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22398 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31399 ),
400 True,
401 (),
402 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15403 BanRule(
[email protected]52657f62013-05-20 05:30:31404 'SkAutoUnref',
405 (
406 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
407 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22408 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31409 ),
410 True,
411 (),
412 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15413 BanRule(
[email protected]d89eec82013-12-03 14:10:59414 r'/HANDLE_EINTR\(.*close',
415 (
416 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
417 'descriptor will be closed, and it is incorrect to retry the close.',
418 'Either call close directly and ignore its return value, or wrap close',
419 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
420 ),
421 True,
422 (),
423 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15424 BanRule(
[email protected]d89eec82013-12-03 14:10:59425 r'/IGNORE_EINTR\((?!.*close)',
426 (
427 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
428 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
429 ),
430 True,
431 (
432 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04433 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
434 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59435 ),
436 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15437 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43438 r'/v8::Extension\(',
439 (
440 'Do not introduce new v8::Extensions into the code base, use',
441 'gin::Wrappable instead. See http://crbug.com/334679',
442 ),
443 True,
[email protected]f55c90ee62014-04-12 00:50:03444 (
Egor Paskoce145c42018-09-28 19:31:04445 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03446 ),
[email protected]ec5b3f02014-04-04 18:43:43447 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15448 BanRule(
jame2d1a952016-04-02 00:27:10449 '#pragma comment(lib,',
450 (
451 'Specify libraries to link with in build files and not in the source.',
452 ),
453 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41454 (
tzik3f295992018-12-04 20:32:23455 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04456 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41457 ),
jame2d1a952016-04-02 00:27:10458 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15459 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02460 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59461 (
462 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
463 ),
464 False,
465 (),
466 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15467 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02468 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59469 (
470 'Consider using THREAD_CHECKER macros instead of the class directly.',
471 ),
472 False,
473 (),
474 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15475 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06476 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
477 (
478 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
479 'deprecated (http://crbug.com/634507). Please avoid converting away',
480 'from the Time types in Chromium code, especially if any math is',
481 'being done on time values. For interfacing with platform/library',
482 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
483 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48484 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06485 'other use cases, please contact base/time/OWNERS.',
486 ),
487 False,
488 (),
489 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15490 BanRule(
dbeamb6f4fde2017-06-15 04:03:06491 'CallJavascriptFunctionUnsafe',
492 (
493 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
494 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
495 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
496 ),
497 False,
498 (
Egor Paskoce145c42018-09-28 19:31:04499 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
500 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
501 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06502 ),
503 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15504 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24505 'leveldb::DB::Open',
506 (
507 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
508 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
509 "Chrome's tracing, making their memory usage visible.",
510 ),
511 True,
512 (
513 r'^third_party/leveldatabase/.*\.(cc|h)$',
514 ),
Gabriel Charette0592c3a2017-07-26 12:02:04515 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15516 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08517 'leveldb::NewMemEnv',
518 (
519 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58520 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
521 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08522 ),
523 True,
524 (
525 r'^third_party/leveldatabase/.*\.(cc|h)$',
526 ),
527 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15528 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47529 'RunLoop::QuitCurrent',
530 (
Robert Liao64b7ab22017-08-04 23:03:43531 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
532 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47533 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41534 False,
Gabriel Charetted9839bc2017-07-29 14:17:47535 (),
Gabriel Charettea44975052017-08-21 23:14:04536 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15537 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04538 'base::ScopedMockTimeMessageLoopTaskRunner',
539 (
Gabriel Charette87cc1af2018-04-25 20:52:51540 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11541 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51542 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
543 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
544 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04545 ),
Gabriel Charette87cc1af2018-04-25 20:52:51546 False,
Gabriel Charettea44975052017-08-21 23:14:04547 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57548 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15549 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44550 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57551 (
552 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02553 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57554 ),
555 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16556 # Abseil's benchmarks never linked into chrome.
557 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38558 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15559 BanRule(
Peter Kasting991618a62019-06-17 22:00:09560 r'/\bstd::stoi\b',
561 (
562 'std::stoi uses exceptions to communicate results. ',
563 'Use base::StringToInt() instead.',
564 ),
565 True,
566 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
567 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15568 BanRule(
Peter Kasting991618a62019-06-17 22:00:09569 r'/\bstd::stol\b',
570 (
571 'std::stol uses exceptions to communicate results. ',
572 'Use base::StringToInt() instead.',
573 ),
574 True,
575 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
576 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15577 BanRule(
Peter Kasting991618a62019-06-17 22:00:09578 r'/\bstd::stoul\b',
579 (
580 'std::stoul uses exceptions to communicate results. ',
581 'Use base::StringToUint() instead.',
582 ),
583 True,
584 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
585 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15586 BanRule(
Peter Kasting991618a62019-06-17 22:00:09587 r'/\bstd::stoll\b',
588 (
589 'std::stoll uses exceptions to communicate results. ',
590 'Use base::StringToInt64() instead.',
591 ),
592 True,
593 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
594 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15595 BanRule(
Peter Kasting991618a62019-06-17 22:00:09596 r'/\bstd::stoull\b',
597 (
598 'std::stoull uses exceptions to communicate results. ',
599 'Use base::StringToUint64() instead.',
600 ),
601 True,
602 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
603 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15604 BanRule(
Peter Kasting991618a62019-06-17 22:00:09605 r'/\bstd::stof\b',
606 (
607 'std::stof uses exceptions to communicate results. ',
608 'For locale-independent values, e.g. reading numbers from disk',
609 'profiles, use base::StringToDouble().',
610 'For user-visible values, parse using ICU.',
611 ),
612 True,
613 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
614 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15615 BanRule(
Peter Kasting991618a62019-06-17 22:00:09616 r'/\bstd::stod\b',
617 (
618 'std::stod uses exceptions to communicate results. ',
619 'For locale-independent values, e.g. reading numbers from disk',
620 'profiles, use base::StringToDouble().',
621 'For user-visible values, parse using ICU.',
622 ),
623 True,
624 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
625 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15626 BanRule(
Peter Kasting991618a62019-06-17 22:00:09627 r'/\bstd::stold\b',
628 (
629 'std::stold uses exceptions to communicate results. ',
630 'For locale-independent values, e.g. reading numbers from disk',
631 'profiles, use base::StringToDouble().',
632 'For user-visible values, parse using ICU.',
633 ),
634 True,
635 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
636 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15637 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45638 r'/\bstd::to_string\b',
639 (
640 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09641 'For locale-independent strings, e.g. writing numbers to disk',
642 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45643 'For user-visible strings, use base::FormatNumber() and',
644 'the related functions in base/i18n/number_formatting.h.',
645 ),
Peter Kasting991618a62019-06-17 22:00:09646 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21647 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45648 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15649 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45650 r'/\bstd::shared_ptr\b',
651 (
652 'std::shared_ptr should not be used. Use scoped_refptr instead.',
653 ),
654 True,
Ulan Degenbaev947043882021-02-10 14:02:31655 [
656 # Needed for interop with third-party library.
657 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57658 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58659 '^third_party/blink/renderer/bindings/core/v8/' +
660 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58661 '^gin/array_buffer\.(cc|h)',
662 '^chrome/services/sharing/nearby/',
Meilin Wang00efc7c2021-05-13 01:12:42663 # gRPC provides some C++ libraries that use std::shared_ptr<>.
664 '^chromeos/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59665 '^chromecast/cast_core/grpc',
666 '^chromecast/cast_core/runtime/browser',
Wez5f56be52021-05-04 09:30:58667 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Fabrice de Gans3b875422022-04-19 19:40:26668 '^base/fuchsia/filtered_service_directory\.(cc|h)',
669 '^base/fuchsia/service_directory_test_base\.h',
Wez5f56be52021-05-04 09:30:58670 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57671 # Needed for clang plugin tests
672 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57673 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21674 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15675 BanRule(
Peter Kasting991618a62019-06-17 22:00:09676 r'/\bstd::weak_ptr\b',
677 (
678 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
679 ),
680 True,
681 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
682 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15683 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21684 r'/\blong long\b',
685 (
686 'long long is banned. Use stdint.h if you need a 64 bit number.',
687 ),
688 False, # Only a warning since it is already used.
689 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
690 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15691 BanRule(
Daniel Chengc05fcc62022-01-12 16:54:29692 r'\b(absl|std)::any\b',
693 (
Daniel Chenga44a1bcd2022-03-15 20:00:15694 'absl::any / std::any are not safe to use in a component build.',
Daniel Chengc05fcc62022-01-12 16:54:29695 ),
696 True,
697 # Not an error in third party folders, though it probably should be :)
698 [_THIRD_PARTY_EXCEPT_BLINK],
699 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15700 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21701 r'/\bstd::bind\b',
702 (
703 'std::bind is banned because of lifetime risks.',
704 'Use base::BindOnce or base::BindRepeating instead.',
705 ),
706 True,
707 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
708 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15709 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:03710 r'/\bstd::optional\b',
711 (
712 'std::optional is banned. Use absl::optional instead.',
713 ),
714 True,
715 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
716 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15717 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21718 r'/\b#include <chrono>\b',
719 (
720 '<chrono> overlaps with Time APIs in base. Keep using',
721 'base classes.',
722 ),
723 True,
724 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
725 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15726 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21727 r'/\b#include <exception>\b',
728 (
729 'Exceptions are banned and disabled in Chromium.',
730 ),
731 True,
732 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
733 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15734 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21735 r'/\bstd::function\b',
736 (
Colin Blundellea615d422021-05-12 09:35:41737 'std::function is banned. Instead use base::OnceCallback or ',
738 'base::RepeatingCallback, which directly support Chromium\'s weak ',
739 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21740 ),
Peter Kasting991618a62019-06-17 22:00:09741 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21742 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
743 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15744 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21745 r'/\b#include <random>\b',
746 (
747 'Do not use any random number engines from <random>. Instead',
748 'use base::RandomBitGenerator.',
749 ),
750 True,
751 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
752 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15753 BanRule(
Tom Andersona95e12042020-09-09 23:08:00754 r'/\b#include <X11/',
755 (
756 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
757 ),
758 True,
759 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
760 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15761 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21762 r'/\bstd::ratio\b',
763 (
764 'std::ratio is banned by the Google Style Guide.',
765 ),
766 True,
767 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45768 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15769 BanRule(
Gabriel Charetted90bcc92021-09-21 00:23:10770 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:38771 (
Gabriel Charetted90bcc92021-09-21 00:23:10772 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:38773 ),
Gabriel Charette04b138f2018-08-06 00:03:22774 False,
Francois Doray43670e32017-09-27 12:40:38775 (),
776 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15777 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:58778 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19779 (
780 'RunMessageLoop is deprecated, use RunLoop instead.',
781 ),
782 False,
783 (),
784 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15785 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44786 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19787 (
788 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
789 ),
790 False,
791 (),
792 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15793 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44794 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19795 (
796 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
797 "if you're convinced you need this.",
798 ),
799 False,
800 (),
801 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15802 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44803 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19804 (
805 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04806 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19807 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
808 'async events instead of flushing threads.',
809 ),
810 False,
811 (),
812 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15813 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:19814 r'MessageLoopRunner',
815 (
816 'MessageLoopRunner is deprecated, use RunLoop instead.',
817 ),
818 False,
819 (),
820 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15821 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44822 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19823 (
824 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
825 "gab@ if you found a use case where this is the only solution.",
826 ),
827 False,
828 (),
829 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15830 BanRule(
Victor Costane48a2e82019-03-15 22:02:34831 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16832 (
Victor Costane48a2e82019-03-15 22:02:34833 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16834 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
835 ),
836 True,
837 (
838 r'^sql/initialization\.(cc|h)$',
839 r'^third_party/sqlite/.*\.(c|cc|h)$',
840 ),
841 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15842 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44843 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47844 (
845 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
846 'base::RandomShuffle instead.'
847 ),
848 True,
849 (),
850 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15851 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24852 'ios/web/public/test/http_server',
853 (
854 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
855 ),
856 False,
857 (),
858 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15859 BanRule(
Robert Liao764c9492019-01-24 18:46:28860 'GetAddressOf',
861 (
862 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53863 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11864 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53865 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28866 ),
867 True,
868 (),
869 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15870 BanRule(
Ben Lewisa9514602019-04-29 17:53:05871 'SHFileOperation',
872 (
873 'SHFileOperation was deprecated in Windows Vista, and there are less ',
874 'complex functions to achieve the same goals. Use IFileOperation for ',
875 'any esoteric actions instead.'
876 ),
877 True,
878 (),
879 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15880 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:51881 'StringFromGUID2',
882 (
883 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24884 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51885 ),
886 True,
887 (
Daniel Chenga44a1bcd2022-03-15 20:00:15888 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:51889 ),
890 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15891 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:51892 'StringFromCLSID',
893 (
894 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24895 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51896 ),
897 True,
898 (
Daniel Chenga44a1bcd2022-03-15 20:00:15899 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:51900 ),
901 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15902 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13903 'kCFAllocatorNull',
904 (
905 'The use of kCFAllocatorNull with the NoCopy creation of ',
906 'CoreFoundation types is prohibited.',
907 ),
908 True,
909 (),
910 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15911 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:29912 'mojo::ConvertTo',
913 (
914 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
915 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
916 'StringTraits if you would like to convert between custom types and',
917 'the wire format of mojom types.'
918 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22919 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29920 (
Wezf89dec092019-09-11 19:38:33921 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
922 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29923 r'^third_party/blink/.*\.(cc|h)$',
924 r'^content/renderer/.*\.(cc|h)$',
925 ),
926 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15927 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:16928 'GetInterfaceProvider',
929 (
930 'InterfaceProvider is deprecated.',
931 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
932 'or Platform::GetBrowserInterfaceBroker.'
933 ),
934 False,
935 (),
936 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15937 BanRule(
Robert Liao1d78df52019-11-11 20:02:01938 'CComPtr',
939 (
940 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
941 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
942 'details.'
943 ),
944 False,
945 (),
946 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15947 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:20948 r'/\b(IFACE|STD)METHOD_?\(',
949 (
950 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
951 'Instead, always use IFACEMETHODIMP in the declaration.'
952 ),
953 False,
954 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
955 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15956 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:47957 'set_owned_by_client',
958 (
959 'set_owned_by_client is deprecated.',
960 'views::View already owns the child views by default. This introduces ',
961 'a competing ownership model which makes the code difficult to reason ',
962 'about. See http://crbug.com/1044687 for more details.'
963 ),
964 False,
965 (),
966 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15967 BanRule(
Peter Boström7ff41522021-07-29 03:43:27968 'RemoveAllChildViewsWithoutDeleting',
969 (
970 'RemoveAllChildViewsWithoutDeleting is deprecated.',
971 'This method is deemed dangerous as, unless raw pointers are re-added,',
972 'calls to this method introduce memory leaks.'
973 ),
974 False,
975 (),
976 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15977 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:12978 r'/\bTRACE_EVENT_ASYNC_',
979 (
980 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
981 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
982 ),
983 False,
984 (
985 r'^base/trace_event/.*',
986 r'^base/tracing/.*',
987 ),
988 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15989 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:43990 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
991 (
992 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
993 'dumps and may spam crash reports. Consider if the throttled',
994 'variants suffice instead.',
995 ),
996 False,
997 (),
998 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15999 BanRule(
Robert Liao22f66a52021-04-10 00:57:521000 'RoInitialize',
1001 (
Robert Liao48018922021-04-16 23:03:021002 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521003 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1004 'instead. See http://crbug.com/1197722 for more information.'
1005 ),
1006 True,
Robert Liao48018922021-04-16 23:03:021007 (
Daniel Chenga44a1bcd2022-03-15 20:00:151008 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021009 ),
Robert Liao22f66a52021-04-10 00:57:521010 ),
[email protected]127f18ec2012-06-16 05:05:591011)
1012
Daniel Cheng92c15e32022-03-16 17:48:221013_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1014 BanRule(
1015 'handle<shared_buffer>',
1016 (
1017 'Please use one of the more specific shared memory types instead:',
1018 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1019 ' mojo_base.mojom.WritableSharedMemoryRegion',
1020 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1021 ),
1022 True,
1023 ),
1024)
1025
mlamouria82272622014-09-16 18:45:041026_IPC_ENUM_TRAITS_DEPRECATED = (
1027 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501028 'See http://www.chromium.org/Home/chromium-security/education/'
1029 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041030
Stephen Martinis97a394142018-06-07 23:06:051031_LONG_PATH_ERROR = (
1032 'Some files included in this CL have file names that are too long (> 200'
1033 ' characters). If committed, these files will cause issues on Windows. See'
1034 ' https://crbug.com/612667 for more details.'
1035)
1036
Shenghua Zhangbfaa38b82017-11-16 21:58:021037_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041038 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041039 r".*[\\/]BuildHooksAndroidImpl\.java",
1040 r".*[\\/]LicenseContentProvider\.java",
1041 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281042 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021043]
[email protected]127f18ec2012-06-16 05:05:591044
Mohamed Heikald048240a2019-11-12 16:57:371045# List of image extensions that are used as resources in chromium.
1046_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1047
Sean Kau46e29bc2017-08-28 16:31:161048# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401049_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041050 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401051 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041052 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1053 r'^third_party[\\/]protobuf[\\/]',
Bruce Dawson49a3db522022-05-05 23:54:331054 r'^third_party[\\/]blink[\\/]perf_tests[\\/]speedometer[\\/]resources[\\/]todomvc[\\/]learn.json',
Egor Paskoce145c42018-09-28 19:31:041055 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431056 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
John Chen288dee02022-04-28 17:37:061057 r'^tools[\\/]perf[\\/]',
Bruce Dawson49a3db522022-05-05 23:54:331058 r'^tools[\\/]traceline[\\/]svgui[\\/]startup-release.json',
Sean Kau46e29bc2017-08-28 16:31:161059]
1060
Andrew Grieveb773bad2020-06-05 18:00:381061# These are not checked on the public chromium-presubmit trybot.
1062# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041063# checkouts.
agrievef32bcc72016-04-04 14:57:401064_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381065 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381066]
1067
1068
1069_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101070 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041071 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361072 'base/android/jni_generator/jni_generator.pydeps',
1073 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361074 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041075 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361076 'build/android/gyp/aar.pydeps',
1077 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271078 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361079 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381080 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361081 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021082 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221083 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111084 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361085 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361086 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361087 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111088 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041089 'build/android/gyp/create_app_bundle_apks.pydeps',
1090 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361091 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121092 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091093 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221094 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001095 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361096 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421097 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041098 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361099 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361100 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211101 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361102 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361103 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361104 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581105 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361106 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141107 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261108 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471109 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011110 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041111 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361112 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361113 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101114 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361115 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221116 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361117 'build/android/gyp/proguard.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101118 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461119 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301120 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241121 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361122 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461123 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561124 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361125 'build/android/incremental_install/generate_android_manifest.pydeps',
1126 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041127 'build/android/resource_sizes.pydeps',
1128 'build/android/test_runner.pydeps',
1129 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361130 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361131 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321132 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271133 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1134 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041135 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001136 'components/cronet/tools/generate_javadoc.pydeps',
1137 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381138 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001139 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381140 'net/tools/testserver/testserver.pydeps',
Jonathan Lee10c06dea2022-05-02 23:13:321141 'testing/scripts/run_wpt_tests.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181142 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411143 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1144 'testing/merge_scripts/standard_gtest_merge.pydeps',
1145 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1146 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041147 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421148 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1149 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131150 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501151 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411152 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1153 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061154 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221155 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401156]
1157
wnwenbdc444e2016-05-25 13:44:151158
agrievef32bcc72016-04-04 14:57:401159_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1160
1161
Eric Boren6fd2b932018-01-25 15:05:081162# Bypass the AUTHORS check for these accounts.
1163_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591164 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451165 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591166 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521167 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231168 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471169 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Jieting Yang668bde92022-01-27 18:40:431170 'infra-try-recipes-tester', 'lacros-tracking-roller')
Eric Boren835d71f2018-09-07 21:09:041171 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271172 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041173 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161174 for s in ('chromium-internal-autoroll',)
1175 ) | set('%[email protected]' % s
1176 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081177
Matt Stark6ef08872021-07-29 01:21:461178_INVALID_GRD_FILE_LINE = [
1179 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1180]
Eric Boren6fd2b932018-01-25 15:05:081181
Daniel Bratell65b033262019-04-23 08:17:061182def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501183 """Returns True if this file contains C++-like code (and not Python,
1184 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061185
Sam Maiera6e76d72022-02-11 21:43:501186 ext = input_api.os_path.splitext(file_path)[1]
1187 # This list is compatible with CppChecker.IsCppFile but we should
1188 # consider adding ".c" to it. If we do that we can use this function
1189 # at more places in the code.
1190 return ext in (
1191 '.h',
1192 '.cc',
1193 '.cpp',
1194 '.m',
1195 '.mm',
1196 )
1197
Daniel Bratell65b033262019-04-23 08:17:061198
1199def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501200 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061201
1202
1203def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501204 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061205
1206
1207def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501208 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061209
Mohamed Heikal5e5b7922020-10-29 18:57:591210
Erik Staabc734cd7a2021-11-23 03:11:521211def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501212 ext = input_api.os_path.splitext(file_path)[1]
1213 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521214
1215
Mohamed Heikal5e5b7922020-10-29 18:57:591216def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501217 """Prevent additions of dependencies from the upstream repo on //clank."""
1218 # clank can depend on clank
1219 if input_api.change.RepositoryRoot().endswith('clank'):
1220 return []
1221 build_file_patterns = [
1222 r'(.+/)?BUILD\.gn',
1223 r'.+\.gni',
1224 ]
1225 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1226 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591227
Sam Maiera6e76d72022-02-11 21:43:501228 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591229
Sam Maiera6e76d72022-02-11 21:43:501230 def FilterFile(affected_file):
1231 return input_api.FilterSourceFile(affected_file,
1232 files_to_check=build_file_patterns,
1233 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591234
Sam Maiera6e76d72022-02-11 21:43:501235 problems = []
1236 for f in input_api.AffectedSourceFiles(FilterFile):
1237 local_path = f.LocalPath()
1238 for line_number, line in f.ChangedContents():
1239 if (bad_pattern.search(line)):
1240 problems.append('%s:%d\n %s' %
1241 (local_path, line_number, line.strip()))
1242 if problems:
1243 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1244 else:
1245 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591246
1247
Saagar Sanghavifceeaae2020-08-12 16:40:361248def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501249 """Attempts to prevent use of functions intended only for testing in
1250 non-testing code. For now this is just a best-effort implementation
1251 that ignores header files and may have some false positives. A
1252 better implementation would probably need a proper C++ parser.
1253 """
1254 # We only scan .cc files and the like, as the declaration of
1255 # for-testing functions in header files are hard to distinguish from
1256 # calls to such functions without a proper C++ parser.
1257 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191258
Sam Maiera6e76d72022-02-11 21:43:501259 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1260 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1261 base_function_pattern)
1262 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1263 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1264 exclusion_pattern = input_api.re.compile(
1265 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1266 (base_function_pattern, base_function_pattern))
1267 # Avoid a false positive in this case, where the method name, the ::, and
1268 # the closing { are all on different lines due to line wrapping.
1269 # HelperClassForTesting::
1270 # HelperClassForTesting(
1271 # args)
1272 # : member(0) {}
1273 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191274
Sam Maiera6e76d72022-02-11 21:43:501275 def FilterFile(affected_file):
1276 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1277 input_api.DEFAULT_FILES_TO_SKIP)
1278 return input_api.FilterSourceFile(
1279 affected_file,
1280 files_to_check=file_inclusion_pattern,
1281 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191282
Sam Maiera6e76d72022-02-11 21:43:501283 problems = []
1284 for f in input_api.AffectedSourceFiles(FilterFile):
1285 local_path = f.LocalPath()
1286 in_method_defn = False
1287 for line_number, line in f.ChangedContents():
1288 if (inclusion_pattern.search(line)
1289 and not comment_pattern.search(line)
1290 and not exclusion_pattern.search(line)
1291 and not allowlist_pattern.search(line)
1292 and not in_method_defn):
1293 problems.append('%s:%d\n %s' %
1294 (local_path, line_number, line.strip()))
1295 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191296
Sam Maiera6e76d72022-02-11 21:43:501297 if problems:
1298 return [
1299 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1300 ]
1301 else:
1302 return []
[email protected]55459852011-08-10 15:17:191303
1304
Saagar Sanghavifceeaae2020-08-12 16:40:361305def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501306 """This is a simplified version of
1307 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1308 """
1309 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1310 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1311 name_pattern = r'ForTest(s|ing)?'
1312 # Describes an occurrence of "ForTest*" inside a // comment.
1313 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1314 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1315 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1316 # Catch calls.
1317 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1318 # Ignore definitions. (Comments are ignored separately.)
1319 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231320
Sam Maiera6e76d72022-02-11 21:43:501321 problems = []
1322 sources = lambda x: input_api.FilterSourceFile(
1323 x,
1324 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1325 DEFAULT_FILES_TO_SKIP),
1326 files_to_check=[r'.*\.java$'])
1327 for f in input_api.AffectedFiles(include_deletes=False,
1328 file_filter=sources):
1329 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231330 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501331 for line_number, line in f.ChangedContents():
1332 if is_inside_javadoc and javadoc_end_re.search(line):
1333 is_inside_javadoc = False
1334 if not is_inside_javadoc and javadoc_start_re.search(line):
1335 is_inside_javadoc = True
1336 if is_inside_javadoc:
1337 continue
1338 if (inclusion_re.search(line) and not comment_re.search(line)
1339 and not annotation_re.search(line)
1340 and not exclusion_re.search(line)):
1341 problems.append('%s:%d\n %s' %
1342 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231343
Sam Maiera6e76d72022-02-11 21:43:501344 if problems:
1345 return [
1346 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1347 ]
1348 else:
1349 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231350
1351
Saagar Sanghavifceeaae2020-08-12 16:40:361352def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501353 """Checks to make sure no .h files include <iostream>."""
1354 files = []
1355 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1356 input_api.re.MULTILINE)
1357 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1358 if not f.LocalPath().endswith('.h'):
1359 continue
1360 contents = input_api.ReadFile(f)
1361 if pattern.search(contents):
1362 files.append(f)
[email protected]10689ca2011-09-02 02:31:541363
Sam Maiera6e76d72022-02-11 21:43:501364 if len(files):
1365 return [
1366 output_api.PresubmitError(
1367 'Do not #include <iostream> in header files, since it inserts static '
1368 'initialization into every file including the header. Instead, '
1369 '#include <ostream>. See http://crbug.com/94794', files)
1370 ]
1371 return []
1372
[email protected]10689ca2011-09-02 02:31:541373
Danil Chapovalov3518f362018-08-11 16:13:431374def _CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501375 """Checks no windows headers with StrCat redefined are included directly."""
1376 files = []
1377 pattern_deny = input_api.re.compile(
1378 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1379 input_api.re.MULTILINE)
1380 pattern_allow = input_api.re.compile(
1381 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
1382 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1383 contents = input_api.ReadFile(f)
1384 if pattern_deny.search(
1385 contents) and not pattern_allow.search(contents):
1386 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431387
Sam Maiera6e76d72022-02-11 21:43:501388 if len(files):
1389 return [
1390 output_api.PresubmitError(
1391 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1392 'directly since they pollute code with StrCat macro. Instead, '
1393 'include matching header from base/win. See http://crbug.com/856536',
1394 files)
1395 ]
1396 return []
Danil Chapovalov3518f362018-08-11 16:13:431397
[email protected]10689ca2011-09-02 02:31:541398
Saagar Sanghavifceeaae2020-08-12 16:40:361399def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501400 """Checks to make sure no source files use UNIT_TEST."""
1401 problems = []
1402 for f in input_api.AffectedFiles():
1403 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1404 continue
[email protected]72df4e782012-06-21 16:28:181405
Sam Maiera6e76d72022-02-11 21:43:501406 for line_num, line in f.ChangedContents():
1407 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1408 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181409
Sam Maiera6e76d72022-02-11 21:43:501410 if not problems:
1411 return []
1412 return [
1413 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1414 '\n'.join(problems))
1415 ]
1416
[email protected]72df4e782012-06-21 16:28:181417
Saagar Sanghavifceeaae2020-08-12 16:40:361418def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501419 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341420
Sam Maiera6e76d72022-02-11 21:43:501421 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1422 instead of DISABLED_. To filter false positives, reports are only generated
1423 if a corresponding MAYBE_ line exists.
1424 """
1425 problems = []
Dominic Battre033531052018-09-24 15:45:341426
Sam Maiera6e76d72022-02-11 21:43:501427 # The following two patterns are looked for in tandem - is a test labeled
1428 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1429 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1430 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341431
Sam Maiera6e76d72022-02-11 21:43:501432 # This is for the case that a test is disabled on all platforms.
1433 full_disable_pattern = input_api.re.compile(
1434 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1435 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341436
Sam Maiera6e76d72022-02-11 21:43:501437 for f in input_api.AffectedFiles(False):
1438 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1439 continue
Dominic Battre033531052018-09-24 15:45:341440
Sam Maiera6e76d72022-02-11 21:43:501441 # Search for MABYE_, DISABLE_ pairs.
1442 disable_lines = {} # Maps of test name to line number.
1443 maybe_lines = {}
1444 for line_num, line in f.ChangedContents():
1445 disable_match = disable_pattern.search(line)
1446 if disable_match:
1447 disable_lines[disable_match.group(1)] = line_num
1448 maybe_match = maybe_pattern.search(line)
1449 if maybe_match:
1450 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341451
Sam Maiera6e76d72022-02-11 21:43:501452 # Search for DISABLE_ occurrences within a TEST() macro.
1453 disable_tests = set(disable_lines.keys())
1454 maybe_tests = set(maybe_lines.keys())
1455 for test in disable_tests.intersection(maybe_tests):
1456 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341457
Sam Maiera6e76d72022-02-11 21:43:501458 contents = input_api.ReadFile(f)
1459 full_disable_match = full_disable_pattern.search(contents)
1460 if full_disable_match:
1461 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341462
Sam Maiera6e76d72022-02-11 21:43:501463 if not problems:
1464 return []
1465 return [
1466 output_api.PresubmitPromptWarning(
1467 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1468 '\n'.join(problems))
1469 ]
1470
Dominic Battre033531052018-09-24 15:45:341471
Nina Satragnof7660532021-09-20 18:03:351472def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501473 """Checks to make sure tests disabled conditionally are not missing a
1474 corresponding MAYBE_ prefix.
1475 """
1476 # Expect at least a lowercase character in the test name. This helps rule out
1477 # false positives with macros wrapping the actual tests name.
1478 define_maybe_pattern = input_api.re.compile(
1479 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191480 # The test_maybe_pattern needs to handle all of these forms. The standard:
1481 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1482 # With a wrapper macro around the test name:
1483 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1484 # And the odd-ball NACL_BROWSER_TEST_f format:
1485 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1486 # The optional E2E_ENABLED-style is handled with (\w*\()?
1487 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1488 # trailing ')'.
1489 test_maybe_pattern = (
1490 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501491 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1492 warnings = []
Nina Satragnof7660532021-09-20 18:03:351493
Sam Maiera6e76d72022-02-11 21:43:501494 # Read the entire files. We can't just read the affected lines, forgetting to
1495 # add MAYBE_ on a change would not show up otherwise.
1496 for f in input_api.AffectedFiles(False):
1497 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1498 continue
1499 contents = input_api.ReadFile(f)
1500 lines = contents.splitlines(True)
1501 current_position = 0
1502 warning_test_names = set()
1503 for line_num, line in enumerate(lines, start=1):
1504 current_position += len(line)
1505 maybe_match = define_maybe_pattern.search(line)
1506 if maybe_match:
1507 test_name = maybe_match.group('test_name')
1508 # Do not warn twice for the same test.
1509 if (test_name in warning_test_names):
1510 continue
1511 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351512
Sam Maiera6e76d72022-02-11 21:43:501513 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1514 # the current position.
1515 test_match = input_api.re.compile(
1516 test_maybe_pattern.format(test_name=test_name),
1517 input_api.re.MULTILINE).search(contents, current_position)
1518 suite_match = input_api.re.compile(
1519 suite_maybe_pattern.format(test_name=test_name),
1520 input_api.re.MULTILINE).search(contents, current_position)
1521 if not test_match and not suite_match:
1522 warnings.append(
1523 output_api.PresubmitPromptWarning(
1524 '%s:%d found MAYBE_ defined without corresponding test %s'
1525 % (f.LocalPath(), line_num, test_name)))
1526 return warnings
1527
[email protected]72df4e782012-06-21 16:28:181528
Saagar Sanghavifceeaae2020-08-12 16:40:361529def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501530 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1531 errors = []
1532 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
1533 input_api.re.MULTILINE)
1534 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1535 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1536 continue
1537 for lnum, line in f.ChangedContents():
1538 if input_api.re.search(pattern, line):
1539 errors.append(
1540 output_api.PresubmitError((
1541 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1542 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1543 (f.LocalPath(), lnum)))
1544 return errors
danakj61c1aa22015-10-26 19:55:521545
1546
Weilun Shia487fad2020-10-28 00:10:341547# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1548# more reliable way. See
1549# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191550
wnwenbdc444e2016-05-25 13:44:151551
Saagar Sanghavifceeaae2020-08-12 16:40:361552def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501553 """Check that FlakyTest annotation is our own instead of the android one"""
1554 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1555 files = []
1556 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1557 if f.LocalPath().endswith('Test.java'):
1558 if pattern.search(input_api.ReadFile(f)):
1559 files.append(f)
1560 if len(files):
1561 return [
1562 output_api.PresubmitError(
1563 'Use org.chromium.base.test.util.FlakyTest instead of '
1564 'android.test.FlakyTest', files)
1565 ]
1566 return []
mcasasb7440c282015-02-04 14:52:191567
wnwenbdc444e2016-05-25 13:44:151568
Saagar Sanghavifceeaae2020-08-12 16:40:361569def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501570 """Make sure .DEPS.git is never modified manually."""
1571 if any(f.LocalPath().endswith('.DEPS.git')
1572 for f in input_api.AffectedFiles()):
1573 return [
1574 output_api.PresubmitError(
1575 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1576 'automated system based on what\'s in DEPS and your changes will be\n'
1577 'overwritten.\n'
1578 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1579 'get-the-code#Rolling_DEPS\n'
1580 'for more information')
1581 ]
1582 return []
[email protected]2a8ac9c2011-10-19 17:20:441583
1584
Saagar Sanghavifceeaae2020-08-12 16:40:361585def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501586 """Checks that DEPS file deps are from allowed_hosts."""
1587 # Run only if DEPS file has been modified to annoy fewer bystanders.
1588 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1589 return []
1590 # Outsource work to gclient verify
1591 try:
1592 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
1593 'third_party', 'depot_tools',
1594 'gclient.py')
1595 input_api.subprocess.check_output(
1596 [input_api.python_executable, gclient_path, 'verify'],
1597 stderr=input_api.subprocess.STDOUT)
1598 return []
1599 except input_api.subprocess.CalledProcessError as error:
1600 return [
1601 output_api.PresubmitError(
1602 'DEPS file must have only git dependencies.',
1603 long_text=error.output)
1604 ]
tandriief664692014-09-23 14:51:471605
1606
Mario Sanchez Prada2472cab2019-09-18 10:58:311607def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151608 ban_rule):
Sam Maiera6e76d72022-02-11 21:43:501609 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311610
Sam Maiera6e76d72022-02-11 21:43:501611 Returns an string composed of the name of the file, the line number where the
1612 match has been found and the additional text passed as |message| in case the
1613 target type name matches the text inside the line passed as parameter.
1614 """
1615 result = []
Peng Huang9c5949a02020-06-11 19:20:541616
Daniel Chenga44a1bcd2022-03-15 20:00:151617 # Ignore comments about banned types.
1618 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:501619 return result
Daniel Chenga44a1bcd2022-03-15 20:00:151620 # A // nocheck comment will bypass this error.
1621 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:501622 return result
1623
1624 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:151625 if ban_rule.pattern[0:1] == '/':
1626 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:501627 if input_api.re.search(regex, line):
1628 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:151629 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:501630 matched = True
1631
1632 if matched:
1633 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:151634 for line in ban_rule.explanation:
1635 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:501636
danakjd18e8892020-12-17 17:42:011637 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:311638
1639
Saagar Sanghavifceeaae2020-08-12 16:40:361640def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501641 """Make sure that banned functions are not used."""
1642 warnings = []
1643 errors = []
[email protected]127f18ec2012-06-16 05:05:591644
Sam Maiera6e76d72022-02-11 21:43:501645 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:151646 if not excluded_paths:
1647 return False
1648
Sam Maiera6e76d72022-02-11 21:43:501649 local_path = affected_file.LocalPath()
1650 for item in excluded_paths:
1651 if input_api.re.match(item, local_path):
1652 return True
1653 return False
wnwenbdc444e2016-05-25 13:44:151654
Sam Maiera6e76d72022-02-11 21:43:501655 def IsIosObjcFile(affected_file):
1656 local_path = affected_file.LocalPath()
1657 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
1658 '.h'):
1659 return False
1660 basename = input_api.os_path.basename(local_path)
1661 if 'ios' in basename.split('_'):
1662 return True
1663 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1664 if sep and 'ios' in local_path.split(sep):
1665 return True
1666 return False
Sylvain Defresnea8b73d252018-02-28 15:45:541667
Daniel Chenga44a1bcd2022-03-15 20:00:151668 def CheckForMatch(affected_file, line_num: int, line: str,
1669 ban_rule: BanRule):
1670 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
1671 return
1672
Sam Maiera6e76d72022-02-11 21:43:501673 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151674 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501675 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:151676 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:501677 errors.extend(problems)
1678 else:
1679 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151680
Sam Maiera6e76d72022-02-11 21:43:501681 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1682 for f in input_api.AffectedFiles(file_filter=file_filter):
1683 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151684 for ban_rule in _BANNED_JAVA_FUNCTIONS:
1685 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:411686
Sam Maiera6e76d72022-02-11 21:43:501687 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1688 for f in input_api.AffectedFiles(file_filter=file_filter):
1689 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151690 for ban_rule in _BANNED_OBJC_FUNCTIONS:
1691 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591692
Sam Maiera6e76d72022-02-11 21:43:501693 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
1694 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151695 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
1696 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:541697
Sam Maiera6e76d72022-02-11 21:43:501698 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1699 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1700 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151701 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
1702 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:051703
Sam Maiera6e76d72022-02-11 21:43:501704 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1705 for f in input_api.AffectedFiles(file_filter=file_filter):
1706 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151707 for ban_rule in _BANNED_CPP_FUNCTIONS:
1708 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591709
Daniel Cheng92c15e32022-03-16 17:48:221710 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
1711 for f in input_api.AffectedFiles(file_filter=file_filter):
1712 for line_num, line in f.ChangedContents():
1713 for ban_rule in _BANNED_MOJOM_PATTERNS:
1714 CheckForMatch(f, line_num, line, ban_rule)
1715
1716
Sam Maiera6e76d72022-02-11 21:43:501717 result = []
1718 if (warnings):
1719 result.append(
1720 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
1721 '\n'.join(warnings)))
1722 if (errors):
1723 result.append(
1724 output_api.PresubmitError('Banned functions were used.\n' +
1725 '\n'.join(errors)))
1726 return result
[email protected]127f18ec2012-06-16 05:05:591727
1728
Michael Thiessen44457642020-02-06 00:24:151729def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501730 """Make sure that banned java imports are not used."""
1731 errors = []
Michael Thiessen44457642020-02-06 00:24:151732
Sam Maiera6e76d72022-02-11 21:43:501733 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1734 for f in input_api.AffectedFiles(file_filter=file_filter):
1735 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151736 for ban_rule in _BANNED_JAVA_IMPORTS:
1737 # Consider merging this into the above function. There is no
1738 # real difference anymore other than helping with a little
1739 # bit of boilerplate text. Doing so means things like
1740 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:501741 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:151742 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501743 if problems:
1744 errors.extend(problems)
1745 result = []
1746 if (errors):
1747 result.append(
1748 output_api.PresubmitError('Banned imports were used.\n' +
1749 '\n'.join(errors)))
1750 return result
Michael Thiessen44457642020-02-06 00:24:151751
1752
Saagar Sanghavifceeaae2020-08-12 16:40:361753def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501754 """Make sure that banned functions are not used."""
1755 files = []
1756 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
1757 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1758 if not f.LocalPath().endswith('.h'):
1759 continue
Bruce Dawson4c4c2922022-05-02 18:07:331760 if f.LocalPath().endswith('com_imported_mstscax.h'):
1761 continue
Sam Maiera6e76d72022-02-11 21:43:501762 contents = input_api.ReadFile(f)
1763 if pattern.search(contents):
1764 files.append(f)
[email protected]6c063c62012-07-11 19:11:061765
Sam Maiera6e76d72022-02-11 21:43:501766 if files:
1767 return [
1768 output_api.PresubmitError(
1769 'Do not use #pragma once in header files.\n'
1770 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1771 files)
1772 ]
1773 return []
[email protected]6c063c62012-07-11 19:11:061774
[email protected]127f18ec2012-06-16 05:05:591775
Saagar Sanghavifceeaae2020-08-12 16:40:361776def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501777 """Checks to make sure we don't introduce use of foo ? true : false."""
1778 problems = []
1779 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1780 for f in input_api.AffectedFiles():
1781 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1782 continue
[email protected]e7479052012-09-19 00:26:121783
Sam Maiera6e76d72022-02-11 21:43:501784 for line_num, line in f.ChangedContents():
1785 if pattern.match(line):
1786 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:121787
Sam Maiera6e76d72022-02-11 21:43:501788 if not problems:
1789 return []
1790 return [
1791 output_api.PresubmitPromptWarning(
1792 'Please consider avoiding the "? true : false" pattern if possible.\n'
1793 + '\n'.join(problems))
1794 ]
[email protected]e7479052012-09-19 00:26:121795
1796
Saagar Sanghavifceeaae2020-08-12 16:40:361797def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501798 """Runs checkdeps on #include and import statements added in this
1799 change. Breaking - rules is an error, breaking ! rules is a
1800 warning.
1801 """
1802 # Return early if no relevant file types were modified.
1803 for f in input_api.AffectedFiles():
1804 path = f.LocalPath()
1805 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
1806 or _IsJavaFile(input_api, path)):
1807 break
[email protected]55f9f382012-07-31 11:02:181808 else:
Sam Maiera6e76d72022-02-11 21:43:501809 return []
rhalavati08acd232017-04-03 07:23:281810
Sam Maiera6e76d72022-02-11 21:43:501811 import sys
1812 # We need to wait until we have an input_api object and use this
1813 # roundabout construct to import checkdeps because this file is
1814 # eval-ed and thus doesn't have __file__.
1815 original_sys_path = sys.path
1816 try:
1817 sys.path = sys.path + [
1818 input_api.os_path.join(input_api.PresubmitLocalPath(),
1819 'buildtools', 'checkdeps')
1820 ]
1821 import checkdeps
1822 from rules import Rule
1823 finally:
1824 # Restore sys.path to what it was before.
1825 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:181826
Sam Maiera6e76d72022-02-11 21:43:501827 added_includes = []
1828 added_imports = []
1829 added_java_imports = []
1830 for f in input_api.AffectedFiles():
1831 if _IsCPlusPlusFile(input_api, f.LocalPath()):
1832 changed_lines = [line for _, line in f.ChangedContents()]
1833 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
1834 elif _IsProtoFile(input_api, f.LocalPath()):
1835 changed_lines = [line for _, line in f.ChangedContents()]
1836 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
1837 elif _IsJavaFile(input_api, f.LocalPath()):
1838 changed_lines = [line for _, line in f.ChangedContents()]
1839 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241840
Sam Maiera6e76d72022-02-11 21:43:501841 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
1842
1843 error_descriptions = []
1844 warning_descriptions = []
1845 error_subjects = set()
1846 warning_subjects = set()
1847
1848 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1849 added_includes):
1850 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1851 description_with_path = '%s\n %s' % (path, rule_description)
1852 if rule_type == Rule.DISALLOW:
1853 error_descriptions.append(description_with_path)
1854 error_subjects.add("#includes")
1855 else:
1856 warning_descriptions.append(description_with_path)
1857 warning_subjects.add("#includes")
1858
1859 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1860 added_imports):
1861 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1862 description_with_path = '%s\n %s' % (path, rule_description)
1863 if rule_type == Rule.DISALLOW:
1864 error_descriptions.append(description_with_path)
1865 error_subjects.add("imports")
1866 else:
1867 warning_descriptions.append(description_with_path)
1868 warning_subjects.add("imports")
1869
1870 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
1871 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
1872 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1873 description_with_path = '%s\n %s' % (path, rule_description)
1874 if rule_type == Rule.DISALLOW:
1875 error_descriptions.append(description_with_path)
1876 error_subjects.add("imports")
1877 else:
1878 warning_descriptions.append(description_with_path)
1879 warning_subjects.add("imports")
1880
1881 results = []
1882 if error_descriptions:
1883 results.append(
1884 output_api.PresubmitError(
1885 'You added one or more %s that violate checkdeps rules.' %
1886 " and ".join(error_subjects), error_descriptions))
1887 if warning_descriptions:
1888 results.append(
1889 output_api.PresubmitPromptOrNotify(
1890 'You added one or more %s of files that are temporarily\n'
1891 'allowed but being removed. Can you avoid introducing the\n'
1892 '%s? See relevant DEPS file(s) for details and contacts.' %
1893 (" and ".join(warning_subjects), "/".join(warning_subjects)),
1894 warning_descriptions))
1895 return results
[email protected]55f9f382012-07-31 11:02:181896
1897
Saagar Sanghavifceeaae2020-08-12 16:40:361898def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501899 """Check that all files have their permissions properly set."""
1900 if input_api.platform == 'win32':
1901 return []
1902 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
1903 'tools', 'checkperms',
1904 'checkperms.py')
1905 args = [
1906 input_api.python_executable, checkperms_tool, '--root',
1907 input_api.change.RepositoryRoot()
1908 ]
1909 with input_api.CreateTemporaryFile() as file_list:
1910 for f in input_api.AffectedFiles():
1911 # checkperms.py file/directory arguments must be relative to the
1912 # repository.
1913 file_list.write((f.LocalPath() + '\n').encode('utf8'))
1914 file_list.close()
1915 args += ['--file-list', file_list.name]
1916 try:
1917 input_api.subprocess.check_output(args)
1918 return []
1919 except input_api.subprocess.CalledProcessError as error:
1920 return [
1921 output_api.PresubmitError('checkperms.py failed:',
1922 long_text=error.output.decode(
1923 'utf-8', 'ignore'))
1924 ]
[email protected]fbcafe5a2012-08-08 15:31:221925
1926
Saagar Sanghavifceeaae2020-08-12 16:40:361927def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501928 """Makes sure we don't include ui/aura/window_property.h
1929 in header files.
1930 """
1931 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1932 errors = []
1933 for f in input_api.AffectedFiles():
1934 if not f.LocalPath().endswith('.h'):
1935 continue
1936 for line_num, line in f.ChangedContents():
1937 if pattern.match(line):
1938 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:491939
Sam Maiera6e76d72022-02-11 21:43:501940 results = []
1941 if errors:
1942 results.append(
1943 output_api.PresubmitError(
1944 'Header files should not include ui/aura/window_property.h',
1945 errors))
1946 return results
[email protected]c8278b32012-10-30 20:35:491947
1948
Omer Katzcc77ea92021-04-26 10:23:281949def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501950 """Makes sure we don't include any headers from
1951 third_party/blink/renderer/platform/heap/impl or
1952 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1953 third_party/blink/renderer/platform/heap
1954 """
1955 impl_pattern = input_api.re.compile(
1956 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1957 v8_wrapper_pattern = input_api.re.compile(
1958 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
1959 )
1960 file_filter = lambda f: not input_api.re.match(
1961 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1962 f.LocalPath())
1963 errors = []
Omer Katzcc77ea92021-04-26 10:23:281964
Sam Maiera6e76d72022-02-11 21:43:501965 for f in input_api.AffectedFiles(file_filter=file_filter):
1966 for line_num, line in f.ChangedContents():
1967 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1968 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:281969
Sam Maiera6e76d72022-02-11 21:43:501970 results = []
1971 if errors:
1972 results.append(
1973 output_api.PresubmitError(
1974 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1975 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1976 'relevant counterparts from third_party/blink/renderer/platform/heap',
1977 errors))
1978 return results
Omer Katzcc77ea92021-04-26 10:23:281979
1980
[email protected]70ca77752012-11-20 03:45:031981def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:501982 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1983 errors = []
1984 for line_num, line in f.ChangedContents():
1985 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
1986 # First-level headers in markdown look a lot like version control
1987 # conflict markers. http://daringfireball.net/projects/markdown/basics
1988 continue
1989 if pattern.match(line):
1990 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1991 return errors
[email protected]70ca77752012-11-20 03:45:031992
1993
Saagar Sanghavifceeaae2020-08-12 16:40:361994def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501995 """Usually this is not intentional and will cause a compile failure."""
1996 errors = []
1997 for f in input_api.AffectedFiles():
1998 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:031999
Sam Maiera6e76d72022-02-11 21:43:502000 results = []
2001 if errors:
2002 results.append(
2003 output_api.PresubmitError(
2004 'Version control conflict markers found, please resolve.',
2005 errors))
2006 return results
[email protected]70ca77752012-11-20 03:45:032007
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202008
Saagar Sanghavifceeaae2020-08-12 16:40:362009def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502010 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2011 errors = []
2012 for f in input_api.AffectedFiles():
2013 for line_num, line in f.ChangedContents():
2014 if pattern.search(line):
2015 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162016
Sam Maiera6e76d72022-02-11 21:43:502017 results = []
2018 if errors:
2019 results.append(
2020 output_api.PresubmitPromptWarning(
2021 'Found Google support URL addressed by answer number. Please replace '
2022 'with a p= identifier instead. See crbug.com/679462\n',
2023 errors))
2024 return results
estadee17314a02017-01-12 16:22:162025
[email protected]70ca77752012-11-20 03:45:032026
Saagar Sanghavifceeaae2020-08-12 16:40:362027def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502028 def FilterFile(affected_file):
2029 """Filter function for use with input_api.AffectedSourceFiles,
2030 below. This filters out everything except non-test files from
2031 top-level directories that generally speaking should not hard-code
2032 service URLs (e.g. src/android_webview/, src/content/ and others).
2033 """
2034 return input_api.FilterSourceFile(
2035 affected_file,
2036 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2037 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2038 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442039
Sam Maiera6e76d72022-02-11 21:43:502040 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2041 '\.(com|net)[^"]*"')
2042 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2043 pattern = input_api.re.compile(base_pattern)
2044 problems = [] # items are (filename, line_number, line)
2045 for f in input_api.AffectedSourceFiles(FilterFile):
2046 for line_num, line in f.ChangedContents():
2047 if not comment_pattern.search(line) and pattern.search(line):
2048 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442049
Sam Maiera6e76d72022-02-11 21:43:502050 if problems:
2051 return [
2052 output_api.PresubmitPromptOrNotify(
2053 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2054 'Are you sure this is correct?', [
2055 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2056 for problem in problems
2057 ])
2058 ]
2059 else:
2060 return []
[email protected]06e6d0ff2012-12-11 01:36:442061
2062
Saagar Sanghavifceeaae2020-08-12 16:40:362063def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502064 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292065
Sam Maiera6e76d72022-02-11 21:43:502066 def FileFilter(affected_file):
2067 """Includes directories known to be Chrome OS only."""
2068 return input_api.FilterSourceFile(
2069 affected_file,
2070 files_to_check=(
2071 '^ash/',
2072 '^chromeos/', # Top-level src/chromeos.
2073 '.*/chromeos/', # Any path component.
2074 '^components/arc',
2075 '^components/exo'),
2076 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292077
Sam Maiera6e76d72022-02-11 21:43:502078 prefs = []
2079 priority_prefs = []
2080 for f in input_api.AffectedFiles(file_filter=FileFilter):
2081 for line_num, line in f.ChangedContents():
2082 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2083 line):
2084 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2085 prefs.append(' %s' % line)
2086 if input_api.re.search(
2087 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2088 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2089 priority_prefs.append(' %s' % line)
2090
2091 results = []
2092 if (prefs):
2093 results.append(
2094 output_api.PresubmitPromptWarning(
2095 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2096 'by browser sync settings. If these prefs should be controlled by OS '
2097 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2098 '\n'.join(prefs)))
2099 if (priority_prefs):
2100 results.append(
2101 output_api.PresubmitPromptWarning(
2102 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2103 'controlled by browser sync settings. If these prefs should be '
2104 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2105 'instead.\n' + '\n'.join(prefs)))
2106 return results
James Cook6b6597c2019-11-06 22:05:292107
2108
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492109# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362110def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502111 """Makes sure there are no abbreviations in the name of PNG files.
2112 The native_client_sdk directory is excluded because it has auto-generated PNG
2113 files for documentation.
2114 """
2115 errors = []
2116 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Bruce Dawson3db456212022-05-02 05:34:182117 files_to_skip = [r'^native_client_sdk[\\/]',
2118 r'^services[\\/]test[\\/]',
2119 r'^third_party[\\/]blink[\\/]web_tests[\\/]',
2120 ]
Sam Maiera6e76d72022-02-11 21:43:502121 file_filter = lambda f: input_api.FilterSourceFile(
2122 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2123 for f in input_api.AffectedFiles(include_deletes=False,
2124 file_filter=file_filter):
2125 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272126
Sam Maiera6e76d72022-02-11 21:43:502127 results = []
2128 if errors:
2129 results.append(
2130 output_api.PresubmitError(
2131 'The name of PNG files should not have abbreviations. \n'
2132 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2133 'Contact [email protected] if you have questions.', errors))
2134 return results
[email protected]d2530012013-01-25 16:39:272135
2136
Daniel Cheng4dcdb6b2017-04-13 08:30:172137def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502138 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172139
Sam Maiera6e76d72022-02-11 21:43:502140 Args:
2141 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2142 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172143 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502144 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172145 if rule.startswith('+') or rule.startswith('!')
2146 ])
Sam Maiera6e76d72022-02-11 21:43:502147 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2148 add_rules.update([
2149 rule[1:] for rule in rules
2150 if rule.startswith('+') or rule.startswith('!')
2151 ])
2152 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172153
2154
2155def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502156 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172157
Sam Maiera6e76d72022-02-11 21:43:502158 # Stubs for handling special syntax in the root DEPS file.
2159 class _VarImpl:
2160 def __init__(self, local_scope):
2161 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172162
Sam Maiera6e76d72022-02-11 21:43:502163 def Lookup(self, var_name):
2164 """Implements the Var syntax."""
2165 try:
2166 return self._local_scope['vars'][var_name]
2167 except KeyError:
2168 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172169
Sam Maiera6e76d72022-02-11 21:43:502170 local_scope = {}
2171 global_scope = {
2172 'Var': _VarImpl(local_scope).Lookup,
2173 'Str': str,
2174 }
Dirk Pranke1b9e06382021-05-14 01:16:222175
Sam Maiera6e76d72022-02-11 21:43:502176 exec(contents, global_scope, local_scope)
2177 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172178
2179
2180def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502181 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2182 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412183
Sam Maiera6e76d72022-02-11 21:43:502184 For a directory (rather than a specific filename) we fake a path to
2185 a specific filename by adding /DEPS. This is chosen as a file that
2186 will seldom or never be subject to per-file include_rules.
2187 """
2188 # We ignore deps entries on auto-generated directories.
2189 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082190
Sam Maiera6e76d72022-02-11 21:43:502191 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2192 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172193
Sam Maiera6e76d72022-02-11 21:43:502194 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172195
Sam Maiera6e76d72022-02-11 21:43:502196 results = set()
2197 for added_dep in added_deps:
2198 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2199 continue
2200 # Assume that a rule that ends in .h is a rule for a specific file.
2201 if added_dep.endswith('.h'):
2202 results.add(added_dep)
2203 else:
2204 results.add(os_path.join(added_dep, 'DEPS'))
2205 return results
[email protected]f32e2d1e2013-07-26 21:39:082206
2207
Saagar Sanghavifceeaae2020-08-12 16:40:362208def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502209 """When a dependency prefixed with + is added to a DEPS file, we
2210 want to make sure that the change is reviewed by an OWNER of the
2211 target file or directory, to avoid layering violations from being
2212 introduced. This check verifies that this happens.
2213 """
2214 # We rely on Gerrit's code-owners to check approvals.
2215 # input_api.gerrit is always set for Chromium, but other projects
2216 # might not use Gerrit.
2217 if not input_api.gerrit:
2218 return []
2219 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2220 input_api.change.issue)):
2221 # Skip OWNERS check when Owners-Override label is approved. This is intended
2222 # for global owners, trusted bots, and on-call sheriffs. Review is still
2223 # required for these changes.
2224 return []
Edward Lesmes6fba51082021-01-20 04:20:232225
Sam Maiera6e76d72022-02-11 21:43:502226 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242227
Sam Maiera6e76d72022-02-11 21:43:502228 file_filter = lambda f: not input_api.re.match(
2229 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
2230 for f in input_api.AffectedFiles(include_deletes=False,
2231 file_filter=file_filter):
2232 filename = input_api.os_path.basename(f.LocalPath())
2233 if filename == 'DEPS':
2234 virtual_depended_on_files.update(
2235 _CalculateAddedDeps(input_api.os_path,
2236 '\n'.join(f.OldContents()),
2237 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552238
Sam Maiera6e76d72022-02-11 21:43:502239 if not virtual_depended_on_files:
2240 return []
[email protected]e871964c2013-05-13 14:14:552241
Sam Maiera6e76d72022-02-11 21:43:502242 if input_api.is_committing:
2243 if input_api.tbr:
2244 return [
2245 output_api.PresubmitNotifyResult(
2246 '--tbr was specified, skipping OWNERS check for DEPS additions'
2247 )
2248 ]
Daniel Cheng3008dc12022-05-13 04:02:112249 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2250 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502251 if input_api.dry_run:
2252 return [
2253 output_api.PresubmitNotifyResult(
2254 'This is a dry run, skipping OWNERS check for DEPS additions'
2255 )
2256 ]
2257 if not input_api.change.issue:
2258 return [
2259 output_api.PresubmitError(
2260 "DEPS approval by OWNERS check failed: this change has "
2261 "no change number, so we can't check it for approvals.")
2262 ]
2263 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412264 else:
Sam Maiera6e76d72022-02-11 21:43:502265 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552266
Sam Maiera6e76d72022-02-11 21:43:502267 owner_email, reviewers = (
2268 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2269 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552270
Sam Maiera6e76d72022-02-11 21:43:502271 owner_email = owner_email or input_api.change.author_email
2272
2273 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2274 virtual_depended_on_files, reviewers.union([owner_email]), [])
2275 missing_files = [
2276 f for f in virtual_depended_on_files
2277 if approval_status[f] != input_api.owners_client.APPROVED
2278 ]
2279
2280 # We strip the /DEPS part that was added by
2281 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2282 # directory.
2283 def StripDeps(path):
2284 start_deps = path.rfind('/DEPS')
2285 if start_deps != -1:
2286 return path[:start_deps]
2287 else:
2288 return path
2289
2290 unapproved_dependencies = [
2291 "'+%s'," % StripDeps(path) for path in missing_files
2292 ]
2293
2294 if unapproved_dependencies:
2295 output_list = [
2296 output(
2297 'You need LGTM from owners of depends-on paths in DEPS that were '
2298 'modified in this CL:\n %s' %
2299 '\n '.join(sorted(unapproved_dependencies)))
2300 ]
2301 suggested_owners = input_api.owners_client.SuggestOwners(
2302 missing_files, exclude=[owner_email])
2303 output_list.append(
2304 output('Suggested missing target path OWNERS:\n %s' %
2305 '\n '.join(suggested_owners or [])))
2306 return output_list
2307
2308 return []
[email protected]e871964c2013-05-13 14:14:552309
2310
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492311# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362312def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502313 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2314 files_to_skip = (
2315 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2316 input_api.DEFAULT_FILES_TO_SKIP + (
2317 r"^base[\\/]logging\.h$",
2318 r"^base[\\/]logging\.cc$",
2319 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2320 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2321 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2322 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2323 r"startup_browser_creator\.cc$",
2324 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2325 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2326 r"diagnostics_writer\.cc$",
2327 r"^chrome[\\/]chrome_cleaner[\\/].*",
2328 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2329 r"dll_hash_main\.cc$",
2330 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2331 r"^chromecast[\\/]",
Sam Maiera6e76d72022-02-11 21:43:502332 r"^components[\\/]browser_watcher[\\/]"
2333 r"dump_stability_report_main_win.cc$",
2334 r"^components[\\/]media_control[\\/]renderer[\\/]"
2335 r"media_playback_options\.cc$",
2336 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2337 r"overlay_strategy_underlay_cast\.cc$",
2338 r"^components[\\/]zucchini[\\/].*",
2339 # TODO(peter): Remove exception. https://crbug.com/534537
2340 r"^content[\\/]browser[\\/]notifications[\\/]"
2341 r"notification_event_dispatcher_impl\.cc$",
2342 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2343 r"gl_helper_benchmark\.cc$",
2344 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2345 r"^courgette[\\/]courgette_tool\.cc$",
2346 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2347 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
2348 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2349 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
2350 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2351 r"^ipc[\\/]ipc_logging\.cc$",
2352 r"^native_client_sdk[\\/]",
2353 r"^remoting[\\/]base[\\/]logging\.h$",
2354 r"^remoting[\\/]host[\\/].*",
2355 r"^sandbox[\\/]linux[\\/].*",
2356 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2357 r"dump_file_system.cc$",
2358 r"^tools[\\/]",
2359 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2360 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2361 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2362 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2363 r"xwmstartupcheck\.cc$"))
2364 source_file_filter = lambda x: input_api.FilterSourceFile(
2365 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402366
Sam Maiera6e76d72022-02-11 21:43:502367 log_info = set([])
2368 printf = set([])
[email protected]85218562013-11-22 07:41:402369
Sam Maiera6e76d72022-02-11 21:43:502370 for f in input_api.AffectedSourceFiles(source_file_filter):
2371 for _, line in f.ChangedContents():
2372 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2373 log_info.add(f.LocalPath())
2374 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2375 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372376
Sam Maiera6e76d72022-02-11 21:43:502377 if input_api.re.search(r"\bprintf\(", line):
2378 printf.add(f.LocalPath())
2379 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2380 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402381
Sam Maiera6e76d72022-02-11 21:43:502382 if log_info:
2383 return [
2384 output_api.PresubmitError(
2385 'These files spam the console log with LOG(INFO):',
2386 items=log_info)
2387 ]
2388 if printf:
2389 return [
2390 output_api.PresubmitError(
2391 'These files spam the console log with printf/fprintf:',
2392 items=printf)
2393 ]
2394 return []
[email protected]85218562013-11-22 07:41:402395
2396
Saagar Sanghavifceeaae2020-08-12 16:40:362397def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502398 """These types are all expected to hold locks while in scope and
2399 so should never be anonymous (which causes them to be immediately
2400 destroyed)."""
2401 they_who_must_be_named = [
2402 'base::AutoLock',
2403 'base::AutoReset',
2404 'base::AutoUnlock',
2405 'SkAutoAlphaRestore',
2406 'SkAutoBitmapShaderInstall',
2407 'SkAutoBlitterChoose',
2408 'SkAutoBounderCommit',
2409 'SkAutoCallProc',
2410 'SkAutoCanvasRestore',
2411 'SkAutoCommentBlock',
2412 'SkAutoDescriptor',
2413 'SkAutoDisableDirectionCheck',
2414 'SkAutoDisableOvalCheck',
2415 'SkAutoFree',
2416 'SkAutoGlyphCache',
2417 'SkAutoHDC',
2418 'SkAutoLockColors',
2419 'SkAutoLockPixels',
2420 'SkAutoMalloc',
2421 'SkAutoMaskFreeImage',
2422 'SkAutoMutexAcquire',
2423 'SkAutoPathBoundsUpdate',
2424 'SkAutoPDFRelease',
2425 'SkAutoRasterClipValidate',
2426 'SkAutoRef',
2427 'SkAutoTime',
2428 'SkAutoTrace',
2429 'SkAutoUnref',
2430 ]
2431 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2432 # bad: base::AutoLock(lock.get());
2433 # not bad: base::AutoLock lock(lock.get());
2434 bad_pattern = input_api.re.compile(anonymous)
2435 # good: new base::AutoLock(lock.get())
2436 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2437 errors = []
[email protected]49aa76a2013-12-04 06:59:162438
Sam Maiera6e76d72022-02-11 21:43:502439 for f in input_api.AffectedFiles():
2440 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2441 continue
2442 for linenum, line in f.ChangedContents():
2443 if bad_pattern.search(line) and not good_pattern.search(line):
2444 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162445
Sam Maiera6e76d72022-02-11 21:43:502446 if errors:
2447 return [
2448 output_api.PresubmitError(
2449 'These lines create anonymous variables that need to be named:',
2450 items=errors)
2451 ]
2452 return []
[email protected]49aa76a2013-12-04 06:59:162453
2454
Saagar Sanghavifceeaae2020-08-12 16:40:362455def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502456 # Returns whether |template_str| is of the form <T, U...> for some types T
2457 # and U. Assumes that |template_str| is already in the form <...>.
2458 def HasMoreThanOneArg(template_str):
2459 # Level of <...> nesting.
2460 nesting = 0
2461 for c in template_str:
2462 if c == '<':
2463 nesting += 1
2464 elif c == '>':
2465 nesting -= 1
2466 elif c == ',' and nesting == 1:
2467 return True
2468 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532469
Sam Maiera6e76d72022-02-11 21:43:502470 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2471 sources = lambda affected_file: input_api.FilterSourceFile(
2472 affected_file,
2473 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2474 DEFAULT_FILES_TO_SKIP),
2475 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552476
Sam Maiera6e76d72022-02-11 21:43:502477 # Pattern to capture a single "<...>" block of template arguments. It can
2478 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2479 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2480 # latter would likely require counting that < and > match, which is not
2481 # expressible in regular languages. Should the need arise, one can introduce
2482 # limited counting (matching up to a total number of nesting depth), which
2483 # should cover all practical cases for already a low nesting limit.
2484 template_arg_pattern = (
2485 r'<[^>]*' # Opening block of <.
2486 r'>([^<]*>)?') # Closing block of >.
2487 # Prefix expressing that whatever follows is not already inside a <...>
2488 # block.
2489 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2490 null_construct_pattern = input_api.re.compile(
2491 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2492 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552493
Sam Maiera6e76d72022-02-11 21:43:502494 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2495 template_arg_no_array_pattern = (
2496 r'<[^>]*[^]]' # Opening block of <.
2497 r'>([^(<]*[^]]>)?') # Closing block of >.
2498 # Prefix saying that what follows is the start of an expression.
2499 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2500 # Suffix saying that what follows are call parentheses with a non-empty list
2501 # of arguments.
2502 nonempty_arg_list_pattern = r'\(([^)]|$)'
2503 # Put the template argument into a capture group for deeper examination later.
2504 return_construct_pattern = input_api.re.compile(
2505 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2506 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552507
Sam Maiera6e76d72022-02-11 21:43:502508 problems_constructor = []
2509 problems_nullptr = []
2510 for f in input_api.AffectedSourceFiles(sources):
2511 for line_number, line in f.ChangedContents():
2512 # Disallow:
2513 # return std::unique_ptr<T>(foo);
2514 # bar = std::unique_ptr<T>(foo);
2515 # But allow:
2516 # return std::unique_ptr<T[]>(foo);
2517 # bar = std::unique_ptr<T[]>(foo);
2518 # And also allow cases when the second template argument is present. Those
2519 # cases cannot be handled by std::make_unique:
2520 # return std::unique_ptr<T, U>(foo);
2521 # bar = std::unique_ptr<T, U>(foo);
2522 local_path = f.LocalPath()
2523 return_construct_result = return_construct_pattern.search(line)
2524 if return_construct_result and not HasMoreThanOneArg(
2525 return_construct_result.group('template_arg')):
2526 problems_constructor.append(
2527 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2528 # Disallow:
2529 # std::unique_ptr<T>()
2530 if null_construct_pattern.search(line):
2531 problems_nullptr.append(
2532 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052533
Sam Maiera6e76d72022-02-11 21:43:502534 errors = []
2535 if problems_nullptr:
2536 errors.append(
2537 output_api.PresubmitPromptWarning(
2538 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2539 problems_nullptr))
2540 if problems_constructor:
2541 errors.append(
2542 output_api.PresubmitError(
2543 'The following files use explicit std::unique_ptr constructor. '
2544 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2545 'std::make_unique is not an option.', problems_constructor))
2546 return errors
Peter Kasting4844e46e2018-02-23 07:27:102547
2548
Saagar Sanghavifceeaae2020-08-12 16:40:362549def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502550 """Checks if any new user action has been added."""
2551 if any('actions.xml' == input_api.os_path.basename(f)
2552 for f in input_api.LocalPaths()):
2553 # If actions.xml is already included in the changelist, the PRESUBMIT
2554 # for actions.xml will do a more complete presubmit check.
2555 return []
2556
2557 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2558 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2559 input_api.DEFAULT_FILES_TO_SKIP)
2560 file_filter = lambda f: input_api.FilterSourceFile(
2561 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2562
2563 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2564 current_actions = None
2565 for f in input_api.AffectedFiles(file_filter=file_filter):
2566 for line_num, line in f.ChangedContents():
2567 match = input_api.re.search(action_re, line)
2568 if match:
2569 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2570 # loaded only once.
2571 if not current_actions:
2572 with open(
2573 'tools/metrics/actions/actions.xml') as actions_f:
2574 current_actions = actions_f.read()
2575 # Search for the matched user action name in |current_actions|.
2576 for action_name in match.groups():
2577 action = 'name="{0}"'.format(action_name)
2578 if action not in current_actions:
2579 return [
2580 output_api.PresubmitPromptWarning(
2581 'File %s line %d: %s is missing in '
2582 'tools/metrics/actions/actions.xml. Please run '
2583 'tools/metrics/actions/extract_actions.py to update.'
2584 % (f.LocalPath(), line_num, action_name))
2585 ]
[email protected]999261d2014-03-03 20:08:082586 return []
2587
[email protected]999261d2014-03-03 20:08:082588
Daniel Cheng13ca61a882017-08-25 15:11:252589def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502590 import sys
2591 sys.path = sys.path + [
2592 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2593 'json_comment_eater')
2594 ]
2595 import json_comment_eater
2596 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252597
2598
[email protected]99171a92014-06-03 08:44:472599def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172600 try:
Sam Maiera6e76d72022-02-11 21:43:502601 contents = input_api.ReadFile(filename)
2602 if eat_comments:
2603 json_comment_eater = _ImportJSONCommentEater(input_api)
2604 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172605
Sam Maiera6e76d72022-02-11 21:43:502606 input_api.json.loads(contents)
2607 except ValueError as e:
2608 return e
Andrew Grieve4deedb12022-02-03 21:34:502609 return None
2610
2611
Sam Maiera6e76d72022-02-11 21:43:502612def _GetIDLParseError(input_api, filename):
2613 try:
2614 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:282615 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:342616 if not char.isascii():
2617 return (
2618 'Non-ascii character "%s" (ord %d) found at offset %d.' %
2619 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:502620 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2621 'tools', 'json_schema_compiler',
2622 'idl_schema.py')
2623 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282624 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502625 stdin=input_api.subprocess.PIPE,
2626 stdout=input_api.subprocess.PIPE,
2627 stderr=input_api.subprocess.PIPE,
2628 universal_newlines=True)
2629 (_, error) = process.communicate(input=contents)
2630 return error or None
2631 except ValueError as e:
2632 return e
agrievef32bcc72016-04-04 14:57:402633
agrievef32bcc72016-04-04 14:57:402634
Sam Maiera6e76d72022-02-11 21:43:502635def CheckParseErrors(input_api, output_api):
2636 """Check that IDL and JSON files do not contain syntax errors."""
2637 actions = {
2638 '.idl': _GetIDLParseError,
2639 '.json': _GetJSONParseError,
2640 }
2641 # Most JSON files are preprocessed and support comments, but these do not.
2642 json_no_comments_patterns = [
2643 r'^testing[\\/]',
2644 ]
2645 # Only run IDL checker on files in these directories.
2646 idl_included_patterns = [
2647 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2648 r'^extensions[\\/]common[\\/]api[\\/]',
2649 ]
agrievef32bcc72016-04-04 14:57:402650
Sam Maiera6e76d72022-02-11 21:43:502651 def get_action(affected_file):
2652 filename = affected_file.LocalPath()
2653 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:402654
Sam Maiera6e76d72022-02-11 21:43:502655 def FilterFile(affected_file):
2656 action = get_action(affected_file)
2657 if not action:
2658 return False
2659 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:402660
Sam Maiera6e76d72022-02-11 21:43:502661 if _MatchesFile(input_api,
2662 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
2663 return False
2664
2665 if (action == _GetIDLParseError
2666 and not _MatchesFile(input_api, idl_included_patterns, path)):
2667 return False
2668 return True
2669
2670 results = []
2671 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
2672 include_deletes=False):
2673 action = get_action(affected_file)
2674 kwargs = {}
2675 if (action == _GetJSONParseError
2676 and _MatchesFile(input_api, json_no_comments_patterns,
2677 affected_file.LocalPath())):
2678 kwargs['eat_comments'] = False
2679 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
2680 **kwargs)
2681 if parse_error:
2682 results.append(
2683 output_api.PresubmitError(
2684 '%s could not be parsed: %s' %
2685 (affected_file.LocalPath(), parse_error)))
2686 return results
2687
2688
2689def CheckJavaStyle(input_api, output_api):
2690 """Runs checkstyle on changed java files and returns errors if any exist."""
2691
2692 # Return early if no java files were modified.
2693 if not any(
2694 _IsJavaFile(input_api, f.LocalPath())
2695 for f in input_api.AffectedFiles()):
2696 return []
2697
2698 import sys
2699 original_sys_path = sys.path
2700 try:
2701 sys.path = sys.path + [
2702 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2703 'android', 'checkstyle')
2704 ]
2705 import checkstyle
2706 finally:
2707 # Restore sys.path to what it was before.
2708 sys.path = original_sys_path
2709
2710 return checkstyle.RunCheckstyle(
2711 input_api,
2712 output_api,
2713 'tools/android/checkstyle/chromium-style-5.0.xml',
2714 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
2715
2716
2717def CheckPythonDevilInit(input_api, output_api):
2718 """Checks to make sure devil is initialized correctly in python scripts."""
2719 script_common_initialize_pattern = input_api.re.compile(
2720 r'script_common\.InitializeEnvironment\(')
2721 devil_env_config_initialize = input_api.re.compile(
2722 r'devil_env\.config\.Initialize\(')
2723
2724 errors = []
2725
2726 sources = lambda affected_file: input_api.FilterSourceFile(
2727 affected_file,
2728 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
2729 r'^build[\\/]android[\\/]devil_chromium\.py',
2730 r'^third_party[\\/].*',
2731 )),
2732 files_to_check=[r'.*\.py$'])
2733
2734 for f in input_api.AffectedSourceFiles(sources):
2735 for line_num, line in f.ChangedContents():
2736 if (script_common_initialize_pattern.search(line)
2737 or devil_env_config_initialize.search(line)):
2738 errors.append("%s:%d" % (f.LocalPath(), line_num))
2739
2740 results = []
2741
2742 if errors:
2743 results.append(
2744 output_api.PresubmitError(
2745 'Devil initialization should always be done using '
2746 'devil_chromium.Initialize() in the chromium project, to use better '
2747 'defaults for dependencies (ex. up-to-date version of adb).',
2748 errors))
2749
2750 return results
2751
2752
2753def _MatchesFile(input_api, patterns, path):
2754 for pattern in patterns:
2755 if input_api.re.search(pattern, path):
2756 return True
2757 return False
2758
2759
Daniel Chenga37c03db2022-05-12 17:20:342760def _ChangeHasSecurityReviewer(input_api, owners_file):
2761 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:502762
Daniel Chenga37c03db2022-05-12 17:20:342763 Args:
2764 input_api: The presubmit input API.
2765 owners_file: OWNERS file with required reviewers. Typically, this is
2766 something like ipc/SECURITY_OWNERS.
2767
2768 Note: if the presubmit is running for commit rather than for upload, this
2769 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:502770 """
Daniel Chenga37c03db2022-05-12 17:20:342771 owner_email, reviewers = (
2772 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:112773 input_api,
2774 None,
2775 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:502776
Daniel Chenga37c03db2022-05-12 17:20:342777 security_owners = input_api.owners_client.ListOwners(owners_file)
2778 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:502779
Daniel Chenga37c03db2022-05-12 17:20:342780
2781@dataclass
2782class _MissingSecurityOwnersResult:
2783 owners_file_errors: Sequence[str]
2784 has_security_sensitive_files: bool
2785 missing_reviewer_errors: Sequence[str]
2786
2787
2788def _FindMissingSecurityOwners(input_api,
2789 output_api,
2790 file_patterns: Sequence[str],
2791 excluded_patterns: Sequence[str],
2792 required_owners_file: str,
2793 custom_rule_function: Optional[Callable] = None
2794 ) -> _MissingSecurityOwnersResult:
2795 """Find OWNERS files missing per-file rules for security-sensitive files.
2796
2797 Args:
2798 input_api: the PRESUBMIT input API object.
2799 output_api: the PRESUBMIT output API object.
2800 file_patterns: basename patterns that require a corresponding per-file
2801 security restriction.
2802 excluded_patterns: path patterns that should be exempted from
2803 requiring a security restriction.
2804 required_owners_file: path to the required OWNERS file, e.g.
2805 ipc/SECURITY_OWNERS
2806 cc_alias: If not None, email that will be CCed automatically if the
2807 change contains security-sensitive files, as determined by
2808 `file_patterns` and `excluded_patterns`.
2809 custom_rule_function: If not None, will be called with `input_api` and
2810 the current file under consideration. Returning True will add an
2811 exact match per-file rule check for the current file.
2812 """
2813
2814 # `to_check` is a mapping of an OWNERS file path to Patterns.
2815 #
2816 # Patterns is a dictionary mapping glob patterns (suitable for use in
2817 # per-file rules) to a PatternEntry.
2818 #
Sam Maiera6e76d72022-02-11 21:43:502819 # PatternEntry is a dictionary with two keys:
2820 # - 'files': the files that are matched by this pattern
2821 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:342822 #
Sam Maiera6e76d72022-02-11 21:43:502823 # For example, if we expect OWNERS file to contain rules for *.mojom and
2824 # *_struct_traits*.*, Patterns might look like this:
2825 # {
2826 # '*.mojom': {
2827 # 'files': ...,
2828 # 'rules': [
2829 # 'per-file *.mojom=set noparent',
2830 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2831 # ],
2832 # },
2833 # '*_struct_traits*.*': {
2834 # 'files': ...,
2835 # 'rules': [
2836 # 'per-file *_struct_traits*.*=set noparent',
2837 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2838 # ],
2839 # },
2840 # }
2841 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:342842 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:502843
Daniel Chenga37c03db2022-05-12 17:20:342844 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:502845 owners_file = input_api.os_path.join(
Daniel Chenga37c03db2022-05-12 17:20:342846 input_api.os_path.dirname(file.AbsoluteLocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:502847 if owners_file not in to_check:
2848 to_check[owners_file] = {}
2849 if pattern not in to_check[owners_file]:
2850 to_check[owners_file][pattern] = {
2851 'files': [],
2852 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:342853 f'per-file {pattern}=set noparent',
2854 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:502855 ]
2856 }
Daniel Chenga37c03db2022-05-12 17:20:342857 to_check[owners_file][pattern]['files'].append(file)
2858 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:502859
Daniel Chenga37c03db2022-05-12 17:20:342860 # Only enforce security OWNERS rules for a directory if that directory has a
2861 # file that matches `file_patterns`. For example, if a directory only
2862 # contains *.mojom files and no *_messages*.h files, the check should only
2863 # ensure that rules for *.mojom files are present.
2864 for file in input_api.AffectedFiles(include_deletes=False):
2865 file_basename = input_api.os_path.basename(file.LocalPath())
2866 if custom_rule_function is not None and custom_rule_function(
2867 input_api, file):
2868 AddPatternToCheck(file, file_basename)
2869 continue
Sam Maiera6e76d72022-02-11 21:43:502870
Daniel Chenga37c03db2022-05-12 17:20:342871 if any(
2872 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
2873 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:502874 continue
2875
2876 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:342877 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
2878 # file's basename.
2879 if input_api.fnmatch.fnmatch(file_basename, pattern):
2880 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:502881 break
2882
Daniel Chenga37c03db2022-05-12 17:20:342883 has_security_sensitive_files = bool(to_check)
2884 missing_reviewer_errors = []
2885 if files_to_review and not _ChangeHasSecurityReviewer(
2886 input_api, required_owners_file):
2887 joined_files_to_review = '\n'.join(f' {file}'
2888 for file in files_to_review)
2889 missing_reviewer_errors.append(
2890 f'Code review from an owner in //{required_owners_file} is required '
2891 'for this change for the following files:\n'
2892 f'{joined_files_to_review}')
Sam Maiera6e76d72022-02-11 21:43:502893
2894 # Go through the OWNERS files to check, filtering out rules that are already
2895 # present in that OWNERS file.
2896 for owners_file, patterns in to_check.items():
2897 try:
2898 with open(owners_file) as f:
2899 lines = set(f.read().splitlines())
2900 for entry in patterns.values():
2901 entry['rules'] = [
2902 rule for rule in entry['rules'] if rule not in lines
2903 ]
2904 except IOError:
2905 # No OWNERS file, so all the rules are definitely missing.
2906 continue
2907
2908 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Chenga37c03db2022-05-12 17:20:342909 owners_file_errors = []
2910
Sam Maiera6e76d72022-02-11 21:43:502911 for owners_file, patterns in to_check.items():
2912 missing_lines = []
2913 files = []
2914 for _, entry in patterns.items():
2915 missing_lines.extend(entry['rules'])
Daniel Chenga37c03db2022-05-12 17:20:342916 files.extend(
2917 [' %s' % file.LocalPath() for file in entry['files']])
Sam Maiera6e76d72022-02-11 21:43:502918 if missing_lines:
Daniel Chenga37c03db2022-05-12 17:20:342919 joined_files = '\n'.join(files)
2920 joined_missing_lines = '\n'.join(missing_lines)
2921 owners_file_errors.append(
2922 f'Because of the presence of files:\n{joined_files}\n\n'
2923 f'{owners_file} needs the following {len(missing_lines)} '
2924 'line(s) added:\n\n'
2925 f'{joined_missing_lines}')
2926
2927 return _MissingSecurityOwnersResult(owners_file_errors,
2928 has_security_sensitive_files,
2929 missing_reviewer_errors)
2930
2931
2932def _CheckChangeForIpcSecurityOwners(input_api, output_api):
2933 # Whether or not a file affects IPC is (mostly) determined by a simple list
2934 # of filename patterns.
2935 file_patterns = [
2936 # Legacy IPC:
2937 '*_messages.cc',
2938 '*_messages*.h',
2939 '*_param_traits*.*',
2940 # Mojo IPC:
2941 '*.mojom',
2942 '*_mojom_traits*.*',
2943 '*_type_converter*.*',
2944 # Android native IPC:
2945 '*.aidl',
2946 ]
2947
Daniel Chenga37c03db2022-05-12 17:20:342948 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:462949 # These third_party directories do not contain IPCs, but contain files
2950 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:342951 'third_party/crashpad/*',
2952 'third_party/blink/renderer/platform/bindings/*',
2953 'third_party/protobuf/benchmarks/python/*',
2954 'third_party/win_build_output/*',
Daniel Cheng518943f2022-05-12 22:15:462955 # Enums used for web metrics, so no security review needed.
2956 'third_party/blink/public/mojom/use_counter/css_property_id.mojom',
2957 'third_party/blink/public/mojom/web_feature/web_feature.mojom',
Daniel Chenga37c03db2022-05-12 17:20:342958 # These files are just used to communicate between class loaders running
2959 # in the same process.
2960 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
2961 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2962 ]
2963
2964 def IsMojoServiceManifestFile(input_api, file):
2965 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2966 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2967 if not manifest_pattern.search(file.LocalPath()):
2968 return False
2969
2970 if test_manifest_pattern.search(file.LocalPath()):
2971 return False
2972
2973 # All actual service manifest files should contain at least one
2974 # qualified reference to service_manager::Manifest.
2975 return any('service_manager::Manifest' in line
2976 for line in file.NewContents())
2977
2978 return _FindMissingSecurityOwners(
2979 input_api,
2980 output_api,
2981 file_patterns,
2982 excluded_patterns,
2983 'ipc/SECURITY_OWNERS',
2984 custom_rule_function=IsMojoServiceManifestFile)
2985
2986
2987def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
2988 file_patterns = [
2989 # Component specifications.
2990 '*.cml', # Component Framework v2.
2991 '*.cmx', # Component Framework v1.
2992
2993 # Fuchsia IDL protocol specifications.
2994 '*.fidl',
2995 ]
2996
2997 # Don't check for owners files for changes in these directories.
2998 excluded_patterns = [
2999 'third_party/crashpad/*',
3000 ]
3001
3002 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3003 excluded_patterns,
3004 'build/fuchsia/SECURITY_OWNERS')
3005
3006
3007def CheckSecurityOwners(input_api, output_api):
3008 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3009 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3010 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3011 input_api, output_api)
3012
3013 if ipc_results.has_security_sensitive_files:
3014 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503015
3016 results = []
Daniel Chenga37c03db2022-05-12 17:20:343017
3018 # Ensure that a security reviewer is included as a CL reviewer. This is a
3019 # hack, but is needed because the OWNERS check (by design) ignores new
3020 # OWNERS entries; otherwise, a non-owner could add someone as a new OWNER
3021 # and have that newly-added OWNER self-approve their own addition.
3022 missing_reviewer_errors = []
3023 missing_reviewer_errors.extend(ipc_results.missing_reviewer_errors)
3024 missing_reviewer_errors.extend(fuchsia_results.missing_reviewer_errors)
3025
3026 if missing_reviewer_errors:
Daniel Cheng3008dc12022-05-13 04:02:113027 # Missing reviewers are only a warning at upload time; otherwise, it'd
3028 # be impossible to upload a change.
3029 if input_api.is_committing:
3030 make_presubmit_message = output_api.PresubmitError
3031 else:
3032 make_presubmit_message = output_api.PresubmitPromptWarning
Sam Maiera6e76d72022-02-11 21:43:503033 results.append(
Daniel Chenga37c03db2022-05-12 17:20:343034 make_presubmit_message(
3035 'Found missing security reviewers:',
3036 long_text='\n\n'.join(missing_reviewer_errors)))
3037
3038 owners_file_errors = []
3039 owners_file_errors.extend(ipc_results.owners_file_errors)
3040 owners_file_errors.extend(fuchsia_results.owners_file_errors)
3041
3042 if owners_file_errors:
Daniel Cheng3008dc12022-05-13 04:02:113043 # Missing per-file rules are always an error. While swarming and caching
3044 # means that uploading a patchset with updated OWNERS files and sending
3045 # it to the CQ again should not have a large incremental cost, it is
3046 # still frustrating to discover the error only after the change has
3047 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343048 results.append(
Daniel Cheng3008dc12022-05-13 04:02:113049 output_api.PresubmitError(
Daniel Chenga37c03db2022-05-12 17:20:343050 'Found OWNERS files with missing per-file rules for '
3051 'security-sensitive files.\nPlease update the OWNERS files '
3052 'below to add the missing rules:',
3053 long_text='\n\n'.join(owners_file_errors)))
Sam Maiera6e76d72022-02-11 21:43:503054
3055 return results
3056
3057
3058def _GetFilesUsingSecurityCriticalFunctions(input_api):
3059 """Checks affected files for changes to security-critical calls. This
3060 function checks the full change diff, to catch both additions/changes
3061 and removals.
3062
3063 Returns a dict keyed by file name, and the value is a set of detected
3064 functions.
3065 """
3066 # Map of function pretty name (displayed in an error) to the pattern to
3067 # match it with.
3068 _PATTERNS_TO_CHECK = {
3069 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3070 }
3071 _PATTERNS_TO_CHECK = {
3072 k: input_api.re.compile(v)
3073 for k, v in _PATTERNS_TO_CHECK.items()
3074 }
3075
Sam Maiera6e76d72022-02-11 21:43:503076 # We don't want to trigger on strings within this file.
3077 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343078 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503079
3080 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3081 files_to_functions = {}
3082 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3083 diff = f.GenerateScmDiff()
3084 for line in diff.split('\n'):
3085 # Not using just RightHandSideLines() because removing a
3086 # call to a security-critical function can be just as important
3087 # as adding or changing the arguments.
3088 if line.startswith('-') or (line.startswith('+')
3089 and not line.startswith('++')):
3090 for name, pattern in _PATTERNS_TO_CHECK.items():
3091 if pattern.search(line):
3092 path = f.LocalPath()
3093 if not path in files_to_functions:
3094 files_to_functions[path] = set()
3095 files_to_functions[path].add(name)
3096 return files_to_functions
3097
3098
3099def CheckSecurityChanges(input_api, output_api):
3100 """Checks that changes involving security-critical functions are reviewed
3101 by the security team.
3102 """
3103 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3104 if not len(files_to_functions):
3105 return []
3106
Sam Maiera6e76d72022-02-11 21:43:503107 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343108 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503109 return []
3110
Daniel Chenga37c03db2022-05-12 17:20:343111 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503112 'that need to be reviewed by {}.\n'.format(owners_file)
3113 for path, names in files_to_functions.items():
3114 msg += ' {}\n'.format(path)
3115 for name in names:
3116 msg += ' {}\n'.format(name)
3117 msg += '\n'
3118
3119 if input_api.is_committing:
3120 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033121 else:
Sam Maiera6e76d72022-02-11 21:43:503122 output = output_api.PresubmitNotifyResult
3123 return [output(msg)]
3124
3125
3126def CheckSetNoParent(input_api, output_api):
3127 """Checks that set noparent is only used together with an OWNERS file in
3128 //build/OWNERS.setnoparent (see also
3129 //docs/code_reviews.md#owners-files-details)
3130 """
3131 # Return early if no OWNERS files were modified.
3132 if not any(f.LocalPath().endswith('OWNERS')
3133 for f in input_api.AffectedFiles(include_deletes=False)):
3134 return []
3135
3136 errors = []
3137
3138 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3139 allowed_owners_files = set()
3140 with open(allowed_owners_files_file, 'r') as f:
3141 for line in f:
3142 line = line.strip()
3143 if not line or line.startswith('#'):
3144 continue
3145 allowed_owners_files.add(line)
3146
3147 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3148
3149 for f in input_api.AffectedFiles(include_deletes=False):
3150 if not f.LocalPath().endswith('OWNERS'):
3151 continue
3152
3153 found_owners_files = set()
3154 found_set_noparent_lines = dict()
3155
3156 # Parse the OWNERS file.
3157 for lineno, line in enumerate(f.NewContents(), 1):
3158 line = line.strip()
3159 if line.startswith('set noparent'):
3160 found_set_noparent_lines[''] = lineno
3161 if line.startswith('file://'):
3162 if line in allowed_owners_files:
3163 found_owners_files.add('')
3164 if line.startswith('per-file'):
3165 match = per_file_pattern.match(line)
3166 if match:
3167 glob = match.group(1).strip()
3168 directive = match.group(2).strip()
3169 if directive == 'set noparent':
3170 found_set_noparent_lines[glob] = lineno
3171 if directive.startswith('file://'):
3172 if directive in allowed_owners_files:
3173 found_owners_files.add(glob)
3174
3175 # Check that every set noparent line has a corresponding file:// line
3176 # listed in build/OWNERS.setnoparent. An exception is made for top level
3177 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493178 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3179 if (linux_path.count('/') != 1
3180 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503181 for set_noparent_line in found_set_noparent_lines:
3182 if set_noparent_line in found_owners_files:
3183 continue
3184 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493185 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503186 found_set_noparent_lines[set_noparent_line]))
3187
3188 results = []
3189 if errors:
3190 if input_api.is_committing:
3191 output = output_api.PresubmitError
3192 else:
3193 output = output_api.PresubmitPromptWarning
3194 results.append(
3195 output(
3196 'Found the following "set noparent" restrictions in OWNERS files that '
3197 'do not include owners from build/OWNERS.setnoparent:',
3198 long_text='\n\n'.join(errors)))
3199 return results
3200
3201
3202def CheckUselessForwardDeclarations(input_api, output_api):
3203 """Checks that added or removed lines in non third party affected
3204 header files do not lead to new useless class or struct forward
3205 declaration.
3206 """
3207 results = []
3208 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3209 input_api.re.MULTILINE)
3210 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3211 input_api.re.MULTILINE)
3212 for f in input_api.AffectedFiles(include_deletes=False):
3213 if (f.LocalPath().startswith('third_party')
3214 and not f.LocalPath().startswith('third_party/blink')
3215 and not f.LocalPath().startswith('third_party\\blink')):
3216 continue
3217
3218 if not f.LocalPath().endswith('.h'):
3219 continue
3220
3221 contents = input_api.ReadFile(f)
3222 fwd_decls = input_api.re.findall(class_pattern, contents)
3223 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3224
3225 useless_fwd_decls = []
3226 for decl in fwd_decls:
3227 count = sum(1 for _ in input_api.re.finditer(
3228 r'\b%s\b' % input_api.re.escape(decl), contents))
3229 if count == 1:
3230 useless_fwd_decls.append(decl)
3231
3232 if not useless_fwd_decls:
3233 continue
3234
3235 for line in f.GenerateScmDiff().splitlines():
3236 if (line.startswith('-') and not line.startswith('--')
3237 or line.startswith('+') and not line.startswith('++')):
3238 for decl in useless_fwd_decls:
3239 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3240 results.append(
3241 output_api.PresubmitPromptWarning(
3242 '%s: %s forward declaration is no longer needed'
3243 % (f.LocalPath(), decl)))
3244 useless_fwd_decls.remove(decl)
3245
3246 return results
3247
3248
3249def _CheckAndroidDebuggableBuild(input_api, output_api):
3250 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3251 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3252 this is a debuggable build of Android.
3253 """
3254 build_type_check_pattern = input_api.re.compile(
3255 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3256
3257 errors = []
3258
3259 sources = lambda affected_file: input_api.FilterSourceFile(
3260 affected_file,
3261 files_to_skip=(
3262 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3263 DEFAULT_FILES_TO_SKIP + (
3264 r"^android_webview[\\/]support_library[\\/]"
3265 "boundary_interfaces[\\/]",
3266 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3267 r'^third_party[\\/].*',
3268 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3269 r"webview[\\/]chromium[\\/]License.*",
3270 )),
3271 files_to_check=[r'.*\.java$'])
3272
3273 for f in input_api.AffectedSourceFiles(sources):
3274 for line_num, line in f.ChangedContents():
3275 if build_type_check_pattern.search(line):
3276 errors.append("%s:%d" % (f.LocalPath(), line_num))
3277
3278 results = []
3279
3280 if errors:
3281 results.append(
3282 output_api.PresubmitPromptWarning(
3283 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3284 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3285
3286 return results
3287
3288# TODO: add unit tests
3289def _CheckAndroidToastUsage(input_api, output_api):
3290 """Checks that code uses org.chromium.ui.widget.Toast instead of
3291 android.widget.Toast (Chromium Toast doesn't force hardware
3292 acceleration on low-end devices, saving memory).
3293 """
3294 toast_import_pattern = input_api.re.compile(
3295 r'^import android\.widget\.Toast;$')
3296
3297 errors = []
3298
3299 sources = lambda affected_file: input_api.FilterSourceFile(
3300 affected_file,
3301 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3302 DEFAULT_FILES_TO_SKIP + (r'^chromecast[\\/].*',
3303 r'^remoting[\\/].*')),
3304 files_to_check=[r'.*\.java$'])
3305
3306 for f in input_api.AffectedSourceFiles(sources):
3307 for line_num, line in f.ChangedContents():
3308 if toast_import_pattern.search(line):
3309 errors.append("%s:%d" % (f.LocalPath(), line_num))
3310
3311 results = []
3312
3313 if errors:
3314 results.append(
3315 output_api.PresubmitError(
3316 'android.widget.Toast usage is detected. Android toasts use hardware'
3317 ' acceleration, and can be\ncostly on low-end devices. Please use'
3318 ' org.chromium.ui.widget.Toast instead.\n'
3319 'Contact [email protected] if you have any questions.',
3320 errors))
3321
3322 return results
3323
3324
3325def _CheckAndroidCrLogUsage(input_api, output_api):
3326 """Checks that new logs using org.chromium.base.Log:
3327 - Are using 'TAG' as variable name for the tags (warn)
3328 - Are using a tag that is shorter than 20 characters (error)
3329 """
3330
3331 # Do not check format of logs in the given files
3332 cr_log_check_excluded_paths = [
3333 # //chrome/android/webapk cannot depend on //base
3334 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3335 # WebView license viewer code cannot depend on //base; used in stub APK.
3336 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3337 r"webview[\\/]chromium[\\/]License.*",
3338 # The customtabs_benchmark is a small app that does not depend on Chromium
3339 # java pieces.
3340 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3341 ]
3342
3343 cr_log_import_pattern = input_api.re.compile(
3344 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3345 class_in_base_pattern = input_api.re.compile(
3346 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3347 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3348 input_api.re.MULTILINE)
3349 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3350 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3351 log_decl_pattern = input_api.re.compile(
3352 r'static final String TAG = "(?P<name>(.*))"')
3353 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3354
3355 REF_MSG = ('See docs/android_logging.md for more info.')
3356 sources = lambda x: input_api.FilterSourceFile(
3357 x,
3358 files_to_check=[r'.*\.java$'],
3359 files_to_skip=cr_log_check_excluded_paths)
3360
3361 tag_decl_errors = []
3362 tag_length_errors = []
3363 tag_errors = []
3364 tag_with_dot_errors = []
3365 util_log_errors = []
3366
3367 for f in input_api.AffectedSourceFiles(sources):
3368 file_content = input_api.ReadFile(f)
3369 has_modified_logs = False
3370 # Per line checks
3371 if (cr_log_import_pattern.search(file_content)
3372 or (class_in_base_pattern.search(file_content)
3373 and not has_some_log_import_pattern.search(file_content))):
3374 # Checks to run for files using cr log
3375 for line_num, line in f.ChangedContents():
3376 if rough_log_decl_pattern.search(line):
3377 has_modified_logs = True
3378
3379 # Check if the new line is doing some logging
3380 match = log_call_pattern.search(line)
3381 if match:
3382 has_modified_logs = True
3383
3384 # Make sure it uses "TAG"
3385 if not match.group('tag') == 'TAG':
3386 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3387 else:
3388 # Report non cr Log function calls in changed lines
3389 for line_num, line in f.ChangedContents():
3390 if log_call_pattern.search(line):
3391 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3392
3393 # Per file checks
3394 if has_modified_logs:
3395 # Make sure the tag is using the "cr" prefix and is not too long
3396 match = log_decl_pattern.search(file_content)
3397 tag_name = match.group('name') if match else None
3398 if not tag_name:
3399 tag_decl_errors.append(f.LocalPath())
3400 elif len(tag_name) > 20:
3401 tag_length_errors.append(f.LocalPath())
3402 elif '.' in tag_name:
3403 tag_with_dot_errors.append(f.LocalPath())
3404
3405 results = []
3406 if tag_decl_errors:
3407 results.append(
3408 output_api.PresubmitPromptWarning(
3409 'Please define your tags using the suggested format: .\n'
3410 '"private static final String TAG = "<package tag>".\n'
3411 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3412 tag_decl_errors))
3413
3414 if tag_length_errors:
3415 results.append(
3416 output_api.PresubmitError(
3417 'The tag length is restricted by the system to be at most '
3418 '20 characters.\n' + REF_MSG, tag_length_errors))
3419
3420 if tag_errors:
3421 results.append(
3422 output_api.PresubmitPromptWarning(
3423 'Please use a variable named "TAG" for your log tags.\n' +
3424 REF_MSG, tag_errors))
3425
3426 if util_log_errors:
3427 results.append(
3428 output_api.PresubmitPromptWarning(
3429 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3430 util_log_errors))
3431
3432 if tag_with_dot_errors:
3433 results.append(
3434 output_api.PresubmitPromptWarning(
3435 'Dot in log tags cause them to be elided in crash reports.\n' +
3436 REF_MSG, tag_with_dot_errors))
3437
3438 return results
3439
3440
3441def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3442 """Checks that junit.framework.* is no longer used."""
3443 deprecated_junit_framework_pattern = input_api.re.compile(
3444 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3445 sources = lambda x: input_api.FilterSourceFile(
3446 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3447 errors = []
3448 for f in input_api.AffectedFiles(file_filter=sources):
3449 for line_num, line in f.ChangedContents():
3450 if deprecated_junit_framework_pattern.search(line):
3451 errors.append("%s:%d" % (f.LocalPath(), line_num))
3452
3453 results = []
3454 if errors:
3455 results.append(
3456 output_api.PresubmitError(
3457 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3458 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3459 ' if you have any question.', errors))
3460 return results
3461
3462
3463def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3464 """Checks that if new Java test classes have inheritance.
3465 Either the new test class is JUnit3 test or it is a JUnit4 test class
3466 with a base class, either case is undesirable.
3467 """
3468 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3469
3470 sources = lambda x: input_api.FilterSourceFile(
3471 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3472 errors = []
3473 for f in input_api.AffectedFiles(file_filter=sources):
3474 if not f.OldContents():
3475 class_declaration_start_flag = False
3476 for line_num, line in f.ChangedContents():
3477 if class_declaration_pattern.search(line):
3478 class_declaration_start_flag = True
3479 if class_declaration_start_flag and ' extends ' in line:
3480 errors.append('%s:%d' % (f.LocalPath(), line_num))
3481 if '{' in line:
3482 class_declaration_start_flag = False
3483
3484 results = []
3485 if errors:
3486 results.append(
3487 output_api.PresubmitPromptWarning(
3488 'The newly created files include Test classes that inherits from base'
3489 ' class. Please do not use inheritance in JUnit4 tests or add new'
3490 ' JUnit3 tests. Contact [email protected] if you have any'
3491 ' questions.', errors))
3492 return results
3493
3494
3495def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3496 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3497 deprecated_annotation_import_pattern = input_api.re.compile(
3498 r'^import android\.test\.suitebuilder\.annotation\..*;',
3499 input_api.re.MULTILINE)
3500 sources = lambda x: input_api.FilterSourceFile(
3501 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3502 errors = []
3503 for f in input_api.AffectedFiles(file_filter=sources):
3504 for line_num, line in f.ChangedContents():
3505 if deprecated_annotation_import_pattern.search(line):
3506 errors.append("%s:%d" % (f.LocalPath(), line_num))
3507
3508 results = []
3509 if errors:
3510 results.append(
3511 output_api.PresubmitError(
3512 'Annotations in android.test.suitebuilder.annotation have been'
3513 ' deprecated since API level 24. Please use android.support.test.filters'
3514 ' from //third_party/android_support_test_runner:runner_java instead.'
3515 ' Contact [email protected] if you have any questions.',
3516 errors))
3517 return results
3518
3519
3520def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3521 """Checks if MDPI assets are placed in a correct directory."""
3522 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3523 ('/res/drawable/' in f.LocalPath() or
3524 '/res/drawable-ldrtl/' in f.LocalPath()))
3525 errors = []
3526 for f in input_api.AffectedFiles(include_deletes=False,
3527 file_filter=file_filter):
3528 errors.append(' %s' % f.LocalPath())
3529
3530 results = []
3531 if errors:
3532 results.append(
3533 output_api.PresubmitError(
3534 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3535 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3536 '/res/drawable-ldrtl/.\n'
3537 'Contact [email protected] if you have questions.', errors))
3538 return results
3539
3540
3541def _CheckAndroidWebkitImports(input_api, output_api):
3542 """Checks that code uses org.chromium.base.Callback instead of
3543 android.webview.ValueCallback except in the WebView glue layer
3544 and WebLayer.
3545 """
3546 valuecallback_import_pattern = input_api.re.compile(
3547 r'^import android\.webkit\.ValueCallback;$')
3548
3549 errors = []
3550
3551 sources = lambda affected_file: input_api.FilterSourceFile(
3552 affected_file,
3553 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3554 DEFAULT_FILES_TO_SKIP + (
3555 r'^android_webview[\\/]glue[\\/].*',
3556 r'^weblayer[\\/].*',
3557 )),
3558 files_to_check=[r'.*\.java$'])
3559
3560 for f in input_api.AffectedSourceFiles(sources):
3561 for line_num, line in f.ChangedContents():
3562 if valuecallback_import_pattern.search(line):
3563 errors.append("%s:%d" % (f.LocalPath(), line_num))
3564
3565 results = []
3566
3567 if errors:
3568 results.append(
3569 output_api.PresubmitError(
3570 'android.webkit.ValueCallback usage is detected outside of the glue'
3571 ' layer. To stay compatible with the support library, android.webkit.*'
3572 ' classes should only be used inside the glue layer and'
3573 ' org.chromium.base.Callback should be used instead.', errors))
3574
3575 return results
3576
3577
3578def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3579 """Checks Android XML styles """
3580
3581 # Return early if no relevant files were modified.
3582 if not any(
3583 _IsXmlOrGrdFile(input_api, f.LocalPath())
3584 for f in input_api.AffectedFiles(include_deletes=False)):
3585 return []
3586
3587 import sys
3588 original_sys_path = sys.path
3589 try:
3590 sys.path = sys.path + [
3591 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3592 'android', 'checkxmlstyle')
3593 ]
3594 import checkxmlstyle
3595 finally:
3596 # Restore sys.path to what it was before.
3597 sys.path = original_sys_path
3598
3599 if is_check_on_upload:
3600 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3601 else:
3602 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3603
3604
3605def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3606 """Checks Android Infobar Deprecation """
3607
3608 import sys
3609 original_sys_path = sys.path
3610 try:
3611 sys.path = sys.path + [
3612 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3613 'android', 'infobar_deprecation')
3614 ]
3615 import infobar_deprecation
3616 finally:
3617 # Restore sys.path to what it was before.
3618 sys.path = original_sys_path
3619
3620 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3621
3622
3623class _PydepsCheckerResult:
3624 def __init__(self, cmd, pydeps_path, process, old_contents):
3625 self._cmd = cmd
3626 self._pydeps_path = pydeps_path
3627 self._process = process
3628 self._old_contents = old_contents
3629
3630 def GetError(self):
3631 """Returns an error message, or None."""
3632 import difflib
3633 if self._process.wait() != 0:
3634 # STDERR should already be printed.
3635 return 'Command failed: ' + self._cmd
3636 new_contents = self._process.stdout.read().splitlines()[2:]
3637 if self._old_contents != new_contents:
3638 diff = '\n'.join(
3639 difflib.context_diff(self._old_contents, new_contents))
3640 return ('File is stale: {}\n'
3641 'Diff (apply to fix):\n'
3642 '{}\n'
3643 'To regenerate, run:\n\n'
3644 ' {}').format(self._pydeps_path, diff, self._cmd)
3645 return None
3646
3647
3648class PydepsChecker:
3649 def __init__(self, input_api, pydeps_files):
3650 self._file_cache = {}
3651 self._input_api = input_api
3652 self._pydeps_files = pydeps_files
3653
3654 def _LoadFile(self, path):
3655 """Returns the list of paths within a .pydeps file relative to //."""
3656 if path not in self._file_cache:
3657 with open(path, encoding='utf-8') as f:
3658 self._file_cache[path] = f.read()
3659 return self._file_cache[path]
3660
3661 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3662 """Returns an interable of paths within the .pydep, relativized to //."""
3663 pydeps_data = self._LoadFile(pydeps_path)
3664 uses_gn_paths = '--gn-paths' in pydeps_data
3665 entries = (l for l in pydeps_data.splitlines()
3666 if not l.startswith('#'))
3667 if uses_gn_paths:
3668 # Paths look like: //foo/bar/baz
3669 return (e[2:] for e in entries)
3670 else:
3671 # Paths look like: path/relative/to/file.pydeps
3672 os_path = self._input_api.os_path
3673 pydeps_dir = os_path.dirname(pydeps_path)
3674 return (os_path.normpath(os_path.join(pydeps_dir, e))
3675 for e in entries)
3676
3677 def _CreateFilesToPydepsMap(self):
3678 """Returns a map of local_path -> list_of_pydeps."""
3679 ret = {}
3680 for pydep_local_path in self._pydeps_files:
3681 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3682 ret.setdefault(path, []).append(pydep_local_path)
3683 return ret
3684
3685 def ComputeAffectedPydeps(self):
3686 """Returns an iterable of .pydeps files that might need regenerating."""
3687 affected_pydeps = set()
3688 file_to_pydeps_map = None
3689 for f in self._input_api.AffectedFiles(include_deletes=True):
3690 local_path = f.LocalPath()
3691 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3692 # subrepositories. We can't figure out which files change, so re-check
3693 # all files.
3694 # Changes to print_python_deps.py affect all .pydeps.
3695 if local_path in ('DEPS', 'PRESUBMIT.py'
3696 ) or local_path.endswith('print_python_deps.py'):
3697 return self._pydeps_files
3698 elif local_path.endswith('.pydeps'):
3699 if local_path in self._pydeps_files:
3700 affected_pydeps.add(local_path)
3701 elif local_path.endswith('.py'):
3702 if file_to_pydeps_map is None:
3703 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3704 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3705 return affected_pydeps
3706
3707 def DetermineIfStaleAsync(self, pydeps_path):
3708 """Runs print_python_deps.py to see if the files is stale."""
3709 import os
3710
3711 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3712 if old_pydeps_data:
3713 cmd = old_pydeps_data[1][1:].strip()
3714 if '--output' not in cmd:
3715 cmd += ' --output ' + pydeps_path
3716 old_contents = old_pydeps_data[2:]
3717 else:
3718 # A default cmd that should work in most cases (as long as pydeps filename
3719 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3720 # file is empty/new.
3721 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3722 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3723 old_contents = []
3724 env = dict(os.environ)
3725 env['PYTHONDONTWRITEBYTECODE'] = '1'
3726 process = self._input_api.subprocess.Popen(
3727 cmd + ' --output ""',
3728 shell=True,
3729 env=env,
3730 stdout=self._input_api.subprocess.PIPE,
3731 encoding='utf-8')
3732 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:403733
3734
Tibor Goldschwendt360793f72019-06-25 18:23:493735def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:503736 args = {}
3737 with open('build/config/gclient_args.gni', 'r') as f:
3738 for line in f:
3739 line = line.strip()
3740 if not line or line.startswith('#'):
3741 continue
3742 attribute, value = line.split('=')
3743 args[attribute.strip()] = value.strip()
3744 return args
Tibor Goldschwendt360793f72019-06-25 18:23:493745
3746
Saagar Sanghavifceeaae2020-08-12 16:40:363747def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:503748 """Checks if a .pydeps file needs to be regenerated."""
3749 # This check is for Python dependency lists (.pydeps files), and involves
3750 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3751 # doesn't work on Windows and Mac, so skip it on other platforms.
3752 if not input_api.platform.startswith('linux'):
3753 return []
Erik Staabc734cd7a2021-11-23 03:11:523754
Sam Maiera6e76d72022-02-11 21:43:503755 results = []
3756 # First, check for new / deleted .pydeps.
3757 for f in input_api.AffectedFiles(include_deletes=True):
3758 # Check whether we are running the presubmit check for a file in src.
3759 # f.LocalPath is relative to repo (src, or internal repo).
3760 # os_path.exists is relative to src repo.
3761 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3762 # to src and we can conclude that the pydeps is in src.
3763 if f.LocalPath().endswith('.pydeps'):
3764 if input_api.os_path.exists(f.LocalPath()):
3765 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3766 results.append(
3767 output_api.PresubmitError(
3768 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3769 'remove %s' % f.LocalPath()))
3770 elif f.Action() != 'D' and f.LocalPath(
3771 ) not in _ALL_PYDEPS_FILES:
3772 results.append(
3773 output_api.PresubmitError(
3774 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3775 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403776
Sam Maiera6e76d72022-02-11 21:43:503777 if results:
3778 return results
3779
3780 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
3781 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3782 affected_pydeps = set(checker.ComputeAffectedPydeps())
3783 affected_android_pydeps = affected_pydeps.intersection(
3784 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3785 if affected_android_pydeps and not is_android:
3786 results.append(
3787 output_api.PresubmitPromptOrNotify(
3788 'You have changed python files that may affect pydeps for android\n'
3789 'specific scripts. However, the relevant presumbit check cannot be\n'
3790 'run because you are not using an Android checkout. To validate that\n'
3791 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3792 'use the android-internal-presubmit optional trybot.\n'
3793 'Possibly stale pydeps files:\n{}'.format(
3794 '\n'.join(affected_android_pydeps))))
3795
3796 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3797 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
3798 # Process these concurrently, as each one takes 1-2 seconds.
3799 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
3800 for result in pydep_results:
3801 error_msg = result.GetError()
3802 if error_msg:
3803 results.append(output_api.PresubmitError(error_msg))
3804
agrievef32bcc72016-04-04 14:57:403805 return results
3806
agrievef32bcc72016-04-04 14:57:403807
Saagar Sanghavifceeaae2020-08-12 16:40:363808def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503809 """Checks to make sure no header files have |Singleton<|."""
3810
3811 def FileFilter(affected_file):
3812 # It's ok for base/memory/singleton.h to have |Singleton<|.
3813 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
3814 (r"^base[\\/]memory[\\/]singleton\.h$",
3815 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
James Cook24a504192020-07-23 00:08:443816 r"quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:503817 return input_api.FilterSourceFile(affected_file,
3818 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433819
Sam Maiera6e76d72022-02-11 21:43:503820 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
3821 files = []
3822 for f in input_api.AffectedSourceFiles(FileFilter):
3823 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
3824 or f.LocalPath().endswith('.hpp')
3825 or f.LocalPath().endswith('.inl')):
3826 contents = input_api.ReadFile(f)
3827 for line in contents.splitlines(False):
3828 if (not line.lstrip().startswith('//')
3829 and # Strip C++ comment.
3830 pattern.search(line)):
3831 files.append(f)
3832 break
glidere61efad2015-02-18 17:39:433833
Sam Maiera6e76d72022-02-11 21:43:503834 if files:
3835 return [
3836 output_api.PresubmitError(
3837 'Found base::Singleton<T> in the following header files.\n' +
3838 'Please move them to an appropriate source file so that the ' +
3839 'template gets instantiated in a single compilation unit.',
3840 files)
3841 ]
3842 return []
glidere61efad2015-02-18 17:39:433843
3844
[email protected]fd20b902014-05-09 02:14:533845_DEPRECATED_CSS = [
3846 # Values
3847 ( "-webkit-box", "flex" ),
3848 ( "-webkit-inline-box", "inline-flex" ),
3849 ( "-webkit-flex", "flex" ),
3850 ( "-webkit-inline-flex", "inline-flex" ),
3851 ( "-webkit-min-content", "min-content" ),
3852 ( "-webkit-max-content", "max-content" ),
3853
3854 # Properties
3855 ( "-webkit-background-clip", "background-clip" ),
3856 ( "-webkit-background-origin", "background-origin" ),
3857 ( "-webkit-background-size", "background-size" ),
3858 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443859 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533860
3861 # Functions
3862 ( "-webkit-gradient", "gradient" ),
3863 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3864 ( "-webkit-linear-gradient", "linear-gradient" ),
3865 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3866 ( "-webkit-radial-gradient", "radial-gradient" ),
3867 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3868]
3869
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203870
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493871# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363872def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503873 """ Make sure that we don't use deprecated CSS
3874 properties, functions or values. Our external
3875 documentation and iOS CSS for dom distiller
3876 (reader mode) are ignored by the hooks as it
3877 needs to be consumed by WebKit. """
3878 results = []
3879 file_inclusion_pattern = [r".+\.css$"]
3880 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3881 input_api.DEFAULT_FILES_TO_SKIP +
3882 (r"^chrome/common/extensions/docs", r"^chrome/docs",
3883 r"^native_client_sdk"))
3884 file_filter = lambda f: input_api.FilterSourceFile(
3885 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3886 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3887 for line_num, line in fpath.ChangedContents():
3888 for (deprecated_value, value) in _DEPRECATED_CSS:
3889 if deprecated_value in line:
3890 results.append(
3891 output_api.PresubmitError(
3892 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3893 (fpath.LocalPath(), line_num, deprecated_value,
3894 value)))
3895 return results
[email protected]fd20b902014-05-09 02:14:533896
mohan.reddyf21db962014-10-16 12:26:473897
Saagar Sanghavifceeaae2020-08-12 16:40:363898def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503899 bad_files = {}
3900 for f in input_api.AffectedFiles(include_deletes=False):
3901 if (f.LocalPath().startswith('third_party')
3902 and not f.LocalPath().startswith('third_party/blink')
3903 and not f.LocalPath().startswith('third_party\\blink')):
3904 continue
rlanday6802cf632017-05-30 17:48:363905
Sam Maiera6e76d72022-02-11 21:43:503906 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3907 continue
rlanday6802cf632017-05-30 17:48:363908
Sam Maiera6e76d72022-02-11 21:43:503909 relative_includes = [
3910 line for _, line in f.ChangedContents()
3911 if "#include" in line and "../" in line
3912 ]
3913 if not relative_includes:
3914 continue
3915 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:363916
Sam Maiera6e76d72022-02-11 21:43:503917 if not bad_files:
3918 return []
rlanday6802cf632017-05-30 17:48:363919
Sam Maiera6e76d72022-02-11 21:43:503920 error_descriptions = []
3921 for file_path, bad_lines in bad_files.items():
3922 error_description = file_path
3923 for line in bad_lines:
3924 error_description += '\n ' + line
3925 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:363926
Sam Maiera6e76d72022-02-11 21:43:503927 results = []
3928 results.append(
3929 output_api.PresubmitError(
3930 'You added one or more relative #include paths (including "../").\n'
3931 'These shouldn\'t be used because they can be used to include headers\n'
3932 'from code that\'s not correctly specified as a dependency in the\n'
3933 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:363934
Sam Maiera6e76d72022-02-11 21:43:503935 return results
rlanday6802cf632017-05-30 17:48:363936
Takeshi Yoshinoe387aa32017-08-02 13:16:133937
Saagar Sanghavifceeaae2020-08-12 16:40:363938def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503939 """Check that nobody tries to include a cc file. It's a relatively
3940 common error which results in duplicate symbols in object
3941 files. This may not always break the build until someone later gets
3942 very confusing linking errors."""
3943 results = []
3944 for f in input_api.AffectedFiles(include_deletes=False):
3945 # We let third_party code do whatever it wants
3946 if (f.LocalPath().startswith('third_party')
3947 and not f.LocalPath().startswith('third_party/blink')
3948 and not f.LocalPath().startswith('third_party\\blink')):
3949 continue
Daniel Bratell65b033262019-04-23 08:17:063950
Sam Maiera6e76d72022-02-11 21:43:503951 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3952 continue
Daniel Bratell65b033262019-04-23 08:17:063953
Sam Maiera6e76d72022-02-11 21:43:503954 for _, line in f.ChangedContents():
3955 if line.startswith('#include "'):
3956 included_file = line.split('"')[1]
3957 if _IsCPlusPlusFile(input_api, included_file):
3958 # The most common naming for external files with C++ code,
3959 # apart from standard headers, is to call them foo.inc, but
3960 # Chromium sometimes uses foo-inc.cc so allow that as well.
3961 if not included_file.endswith(('.h', '-inc.cc')):
3962 results.append(
3963 output_api.PresubmitError(
3964 'Only header files or .inc files should be included in other\n'
3965 'C++ files. Compiling the contents of a cc file more than once\n'
3966 'will cause duplicate information in the build which may later\n'
3967 'result in strange link_errors.\n' +
3968 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:063969
Sam Maiera6e76d72022-02-11 21:43:503970 return results
Daniel Bratell65b033262019-04-23 08:17:063971
3972
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203973def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:503974 if not isinstance(key, ast.Str):
3975 return 'Key at line %d must be a string literal' % key.lineno
3976 if not isinstance(value, ast.Dict):
3977 return 'Value at line %d must be a dict' % value.lineno
3978 if len(value.keys) != 1:
3979 return 'Dict at line %d must have single entry' % value.lineno
3980 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3981 return (
3982 'Entry at line %d must have a string literal \'filepath\' as key' %
3983 value.lineno)
3984 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133985
Takeshi Yoshinoe387aa32017-08-02 13:16:133986
Sergey Ulanov4af16052018-11-08 02:41:463987def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:503988 if not isinstance(key, ast.Str):
3989 return 'Key at line %d must be a string literal' % key.lineno
3990 if not isinstance(value, ast.List):
3991 return 'Value at line %d must be a list' % value.lineno
3992 for element in value.elts:
3993 if not isinstance(element, ast.Str):
3994 return 'Watchlist elements on line %d is not a string' % key.lineno
3995 if not email_regex.match(element.s):
3996 return ('Watchlist element on line %d doesn\'t look like a valid '
3997 + 'email: %s') % (key.lineno, element.s)
3998 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133999
Takeshi Yoshinoe387aa32017-08-02 13:16:134000
Sergey Ulanov4af16052018-11-08 02:41:464001def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504002 mismatch_template = (
4003 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4004 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134005
Sam Maiera6e76d72022-02-11 21:43:504006 email_regex = input_api.re.compile(
4007 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464008
Sam Maiera6e76d72022-02-11 21:43:504009 ast = input_api.ast
4010 i = 0
4011 last_key = ''
4012 while True:
4013 if i >= len(wd_dict.keys):
4014 if i >= len(w_dict.keys):
4015 return None
4016 return mismatch_template % ('missing',
4017 'line %d' % w_dict.keys[i].lineno)
4018 elif i >= len(w_dict.keys):
4019 return (mismatch_template %
4020 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134021
Sam Maiera6e76d72022-02-11 21:43:504022 wd_key = wd_dict.keys[i]
4023 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134024
Sam Maiera6e76d72022-02-11 21:43:504025 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4026 wd_dict.values[i], ast)
4027 if result is not None:
4028 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134029
Sam Maiera6e76d72022-02-11 21:43:504030 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4031 email_regex)
4032 if result is not None:
4033 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204034
Sam Maiera6e76d72022-02-11 21:43:504035 if wd_key.s != w_key.s:
4036 return mismatch_template % ('%s at line %d' %
4037 (wd_key.s, wd_key.lineno),
4038 '%s at line %d' %
4039 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204040
Sam Maiera6e76d72022-02-11 21:43:504041 if wd_key.s < last_key:
4042 return (
4043 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4044 % (wd_key.lineno, w_key.lineno))
4045 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204046
Sam Maiera6e76d72022-02-11 21:43:504047 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204048
4049
Sergey Ulanov4af16052018-11-08 02:41:464050def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504051 ast = input_api.ast
4052 if not isinstance(expression, ast.Expression):
4053 return 'WATCHLISTS file must contain a valid expression'
4054 dictionary = expression.body
4055 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4056 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204057
Sam Maiera6e76d72022-02-11 21:43:504058 first_key = dictionary.keys[0]
4059 first_value = dictionary.values[0]
4060 second_key = dictionary.keys[1]
4061 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204062
Sam Maiera6e76d72022-02-11 21:43:504063 if (not isinstance(first_key, ast.Str)
4064 or first_key.s != 'WATCHLIST_DEFINITIONS'
4065 or not isinstance(first_value, ast.Dict)):
4066 return ('The first entry of the dict in WATCHLISTS file must be '
4067 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204068
Sam Maiera6e76d72022-02-11 21:43:504069 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4070 or not isinstance(second_value, ast.Dict)):
4071 return ('The second entry of the dict in WATCHLISTS file must be '
4072 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204073
Sam Maiera6e76d72022-02-11 21:43:504074 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134075
4076
Saagar Sanghavifceeaae2020-08-12 16:40:364077def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504078 for f in input_api.AffectedFiles(include_deletes=False):
4079 if f.LocalPath() == 'WATCHLISTS':
4080 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134081
Sam Maiera6e76d72022-02-11 21:43:504082 try:
4083 # First, make sure that it can be evaluated.
4084 input_api.ast.literal_eval(contents)
4085 # Get an AST tree for it and scan the tree for detailed style checking.
4086 expression = input_api.ast.parse(contents,
4087 filename='WATCHLISTS',
4088 mode='eval')
4089 except ValueError as e:
4090 return [
4091 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4092 long_text=repr(e))
4093 ]
4094 except SyntaxError as e:
4095 return [
4096 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4097 long_text=repr(e))
4098 ]
4099 except TypeError as e:
4100 return [
4101 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4102 long_text=repr(e))
4103 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134104
Sam Maiera6e76d72022-02-11 21:43:504105 result = _CheckWATCHLISTSSyntax(expression, input_api)
4106 if result is not None:
4107 return [output_api.PresubmitError(result)]
4108 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134109
Sam Maiera6e76d72022-02-11 21:43:504110 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134111
4112
Andrew Grieve1b290e4a22020-11-24 20:07:014113def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504114 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014115
Sam Maiera6e76d72022-02-11 21:43:504116 As documented at //build/docs/writing_gn_templates.md
4117 """
Andrew Grieve1b290e4a22020-11-24 20:07:014118
Sam Maiera6e76d72022-02-11 21:43:504119 def gn_files(f):
4120 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014121
Sam Maiera6e76d72022-02-11 21:43:504122 problems = []
4123 for f in input_api.AffectedSourceFiles(gn_files):
4124 for line_num, line in f.ChangedContents():
4125 if 'forward_variables_from(invoker, "*")' in line:
4126 problems.append(
4127 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4128 (f.LocalPath(), line_num))
4129
4130 if problems:
4131 return [
4132 output_api.PresubmitPromptWarning(
4133 'forward_variables_from("*") without exclusions',
4134 items=sorted(problems),
4135 long_text=(
4136 'The variables "visibilty" and "test_only" should be '
4137 'explicitly listed in forward_variables_from(). For more '
4138 'details, see:\n'
4139 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4140 'build/docs/writing_gn_templates.md'
4141 '#Using-forward_variables_from'))
4142 ]
4143 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014144
4145
Saagar Sanghavifceeaae2020-08-12 16:40:364146def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504147 """Checks that newly added header files have corresponding GN changes.
4148 Note that this is only a heuristic. To be precise, run script:
4149 build/check_gn_headers.py.
4150 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194151
Sam Maiera6e76d72022-02-11 21:43:504152 def headers(f):
4153 return input_api.FilterSourceFile(
4154 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194155
Sam Maiera6e76d72022-02-11 21:43:504156 new_headers = []
4157 for f in input_api.AffectedSourceFiles(headers):
4158 if f.Action() != 'A':
4159 continue
4160 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194161
Sam Maiera6e76d72022-02-11 21:43:504162 def gn_files(f):
4163 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194164
Sam Maiera6e76d72022-02-11 21:43:504165 all_gn_changed_contents = ''
4166 for f in input_api.AffectedSourceFiles(gn_files):
4167 for _, line in f.ChangedContents():
4168 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194169
Sam Maiera6e76d72022-02-11 21:43:504170 problems = []
4171 for header in new_headers:
4172 basename = input_api.os_path.basename(header)
4173 if basename not in all_gn_changed_contents:
4174 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194175
Sam Maiera6e76d72022-02-11 21:43:504176 if problems:
4177 return [
4178 output_api.PresubmitPromptWarning(
4179 'Missing GN changes for new header files',
4180 items=sorted(problems),
4181 long_text=
4182 'Please double check whether newly added header files need '
4183 'corresponding changes in gn or gni files.\nThis checking is only a '
4184 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4185 'Read https://crbug.com/661774 for more info.')
4186 ]
4187 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194188
4189
Saagar Sanghavifceeaae2020-08-12 16:40:364190def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504191 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024192
Sam Maiera6e76d72022-02-11 21:43:504193 This assumes we won't intentionally reference one product from the other
4194 product.
4195 """
4196 all_problems = []
4197 test_cases = [{
4198 "filename_postfix": "google_chrome_strings.grd",
4199 "correct_name": "Chrome",
4200 "incorrect_name": "Chromium",
4201 }, {
4202 "filename_postfix": "chromium_strings.grd",
4203 "correct_name": "Chromium",
4204 "incorrect_name": "Chrome",
4205 }]
Michael Giuffridad3bc8672018-10-25 22:48:024206
Sam Maiera6e76d72022-02-11 21:43:504207 for test_case in test_cases:
4208 problems = []
4209 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4210 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024211
Sam Maiera6e76d72022-02-11 21:43:504212 # Check each new line. Can yield false positives in multiline comments, but
4213 # easier than trying to parse the XML because messages can have nested
4214 # children, and associating message elements with affected lines is hard.
4215 for f in input_api.AffectedSourceFiles(filename_filter):
4216 for line_num, line in f.ChangedContents():
4217 if "<message" in line or "<!--" in line or "-->" in line:
4218 continue
4219 if test_case["incorrect_name"] in line:
4220 problems.append("Incorrect product name in %s:%d" %
4221 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024222
Sam Maiera6e76d72022-02-11 21:43:504223 if problems:
4224 message = (
4225 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4226 % (test_case["correct_name"], test_case["correct_name"],
4227 test_case["incorrect_name"]))
4228 all_problems.append(
4229 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024230
Sam Maiera6e76d72022-02-11 21:43:504231 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024232
4233
Saagar Sanghavifceeaae2020-08-12 16:40:364234def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504235 """Avoid large files, especially binary files, in the repository since
4236 git doesn't scale well for those. They will be in everyone's repo
4237 clones forever, forever making Chromium slower to clone and work
4238 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364239
Sam Maiera6e76d72022-02-11 21:43:504240 # Uploading files to cloud storage is not trivial so we don't want
4241 # to set the limit too low, but the upper limit for "normal" large
4242 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4243 # anything over 20 MB is exceptional.
4244 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364245
Sam Maiera6e76d72022-02-11 21:43:504246 too_large_files = []
4247 for f in input_api.AffectedFiles():
4248 # Check both added and modified files (but not deleted files).
4249 if f.Action() in ('A', 'M'):
4250 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4251 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4252 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364253
Sam Maiera6e76d72022-02-11 21:43:504254 if too_large_files:
4255 message = (
4256 'Do not commit large files to git since git scales badly for those.\n'
4257 +
4258 'Instead put the large files in cloud storage and use DEPS to\n' +
4259 'fetch them.\n' + '\n'.join(too_large_files))
4260 return [
4261 output_api.PresubmitError('Too large files found in commit',
4262 long_text=message + '\n')
4263 ]
4264 else:
4265 return []
Daniel Bratell93eb6c62019-04-29 20:13:364266
Max Morozb47503b2019-08-08 21:03:274267
Saagar Sanghavifceeaae2020-08-12 16:40:364268def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504269 """Checks specific for fuzz target sources."""
4270 EXPORTED_SYMBOLS = [
4271 'LLVMFuzzerInitialize',
4272 'LLVMFuzzerCustomMutator',
4273 'LLVMFuzzerCustomCrossOver',
4274 'LLVMFuzzerMutate',
4275 ]
Max Morozb47503b2019-08-08 21:03:274276
Sam Maiera6e76d72022-02-11 21:43:504277 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274278
Sam Maiera6e76d72022-02-11 21:43:504279 def FilterFile(affected_file):
4280 """Ignore libFuzzer source code."""
4281 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4282 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274283
Sam Maiera6e76d72022-02-11 21:43:504284 return input_api.FilterSourceFile(affected_file,
4285 files_to_check=[files_to_check],
4286 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274287
Sam Maiera6e76d72022-02-11 21:43:504288 files_with_missing_header = []
4289 for f in input_api.AffectedSourceFiles(FilterFile):
4290 contents = input_api.ReadFile(f, 'r')
4291 if REQUIRED_HEADER in contents:
4292 continue
Max Morozb47503b2019-08-08 21:03:274293
Sam Maiera6e76d72022-02-11 21:43:504294 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4295 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274296
Sam Maiera6e76d72022-02-11 21:43:504297 if not files_with_missing_header:
4298 return []
Max Morozb47503b2019-08-08 21:03:274299
Sam Maiera6e76d72022-02-11 21:43:504300 long_text = (
4301 'If you define any of the libFuzzer optional functions (%s), it is '
4302 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4303 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4304 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4305 'to access command line arguments passed to the fuzzer. Instead, prefer '
4306 'static initialization and shared resources as documented in '
4307 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4308 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4309 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274310
Sam Maiera6e76d72022-02-11 21:43:504311 return [
4312 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4313 REQUIRED_HEADER,
4314 items=files_with_missing_header,
4315 long_text=long_text)
4316 ]
Max Morozb47503b2019-08-08 21:03:274317
4318
Mohamed Heikald048240a2019-11-12 16:57:374319def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504320 """
4321 Warns authors who add images into the repo to make sure their images are
4322 optimized before committing.
4323 """
4324 images_added = False
4325 image_paths = []
4326 errors = []
4327 filter_lambda = lambda x: input_api.FilterSourceFile(
4328 x,
4329 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4330 DEFAULT_FILES_TO_SKIP),
4331 files_to_check=[r'.*\/(drawable|mipmap)'])
4332 for f in input_api.AffectedFiles(include_deletes=False,
4333 file_filter=filter_lambda):
4334 local_path = f.LocalPath().lower()
4335 if any(
4336 local_path.endswith(extension)
4337 for extension in _IMAGE_EXTENSIONS):
4338 images_added = True
4339 image_paths.append(f)
4340 if images_added:
4341 errors.append(
4342 output_api.PresubmitPromptWarning(
4343 'It looks like you are trying to commit some images. If these are '
4344 'non-test-only images, please make sure to read and apply the tips in '
4345 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4346 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4347 'FYI only and will not block your CL on the CQ.', image_paths))
4348 return errors
Mohamed Heikald048240a2019-11-12 16:57:374349
4350
Saagar Sanghavifceeaae2020-08-12 16:40:364351def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504352 """Groups upload checks that target android code."""
4353 results = []
4354 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4355 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4356 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4357 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4358 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4359 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4360 input_api, output_api))
4361 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4362 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4363 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4364 results.extend(_CheckNewImagesWarning(input_api, output_api))
4365 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4366 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4367 return results
4368
Becky Zhou7c69b50992018-12-10 19:37:574369
Saagar Sanghavifceeaae2020-08-12 16:40:364370def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504371 """Groups commit checks that target android code."""
4372 results = []
4373 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4374 return results
dgnaa68d5e2015-06-10 10:08:224375
Chris Hall59f8d0c72020-05-01 07:31:194376# TODO(chrishall): could we additionally match on any path owned by
4377# ui/accessibility/OWNERS ?
4378_ACCESSIBILITY_PATHS = (
4379 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4380 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4381 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4382 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4383 r"^content[\\/]browser[\\/]accessibility[\\/]",
4384 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4385 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4386 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4387 r"^ui[\\/]accessibility[\\/]",
4388 r"^ui[\\/]views[\\/]accessibility[\\/]",
4389)
4390
Saagar Sanghavifceeaae2020-08-12 16:40:364391def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504392 """Checks that commits to accessibility code contain an AX-Relnotes field in
4393 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194394
Sam Maiera6e76d72022-02-11 21:43:504395 def FileFilter(affected_file):
4396 paths = _ACCESSIBILITY_PATHS
4397 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194398
Sam Maiera6e76d72022-02-11 21:43:504399 # Only consider changes affecting accessibility paths.
4400 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4401 return []
Akihiro Ota08108e542020-05-20 15:30:534402
Sam Maiera6e76d72022-02-11 21:43:504403 # AX-Relnotes can appear in either the description or the footer.
4404 # When searching the description, require 'AX-Relnotes:' to appear at the
4405 # beginning of a line.
4406 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4407 description_has_relnotes = any(
4408 ax_regex.match(line)
4409 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194410
Sam Maiera6e76d72022-02-11 21:43:504411 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4412 'AX-Relnotes', [])
4413 if description_has_relnotes or footer_relnotes:
4414 return []
Chris Hall59f8d0c72020-05-01 07:31:194415
Sam Maiera6e76d72022-02-11 21:43:504416 # TODO(chrishall): link to Relnotes documentation in message.
4417 message = (
4418 "Missing 'AX-Relnotes:' field required for accessibility changes"
4419 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4420 "user-facing changes"
4421 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4422 "user-facing effects"
4423 "\n if this is confusing or annoying then please contact members "
4424 "of ui/accessibility/OWNERS.")
4425
4426 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224427
Mark Schillacie5a0be22022-01-19 00:38:394428
4429_ACCESSIBILITY_EVENTS_TEST_PATH = (
4430 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]event[\\/].*\.html",
4431)
4432
4433_ACCESSIBILITY_TREE_TEST_PATH = (
4434 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]accname[\\/].*\.html",
4435 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]aria[\\/].*\.html",
4436 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]css[\\/].*\.html",
4437 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]html[\\/].*\.html",
4438)
4439
4440_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
4441 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4442)
4443
4444_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Mark Schillaci6f568a52022-02-17 18:41:444445 r"^.*[\\/]WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394446)
4447
4448def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504449 """Checks that commits that include a newly added, renamed/moved, or deleted
4450 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4451 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394452
Sam Maiera6e76d72022-02-11 21:43:504453 def FilePathFilter(affected_file):
4454 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4455 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394456
Sam Maiera6e76d72022-02-11 21:43:504457 def AndroidFilePathFilter(affected_file):
4458 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4459 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394460
Sam Maiera6e76d72022-02-11 21:43:504461 # Only consider changes in the events test data path with html type.
4462 if not any(
4463 input_api.AffectedFiles(include_deletes=True,
4464 file_filter=FilePathFilter)):
4465 return []
Mark Schillacie5a0be22022-01-19 00:38:394466
Sam Maiera6e76d72022-02-11 21:43:504467 # If the commit contains any change to the Android test file, ignore.
4468 if any(
4469 input_api.AffectedFiles(include_deletes=True,
4470 file_filter=AndroidFilePathFilter)):
4471 return []
Mark Schillacie5a0be22022-01-19 00:38:394472
Sam Maiera6e76d72022-02-11 21:43:504473 # Only consider changes that are adding/renaming or deleting a file
4474 message = []
4475 for f in input_api.AffectedFiles(include_deletes=True,
4476 file_filter=FilePathFilter):
4477 if f.Action() == 'A' or f.Action() == 'D':
4478 message = (
4479 "It appears that you are adding, renaming or deleting"
4480 "\na dump_accessibility_events* test, but have not included"
4481 "\na corresponding change for Android."
4482 "\nPlease include (or remove) the test from:"
4483 "\n content/public/android/javatests/src/org/chromium/"
4484 "content/browser/accessibility/"
4485 "WebContentsAccessibilityEventsTest.java"
4486 "\nIf this message is confusing or annoying, please contact"
4487 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394488
Sam Maiera6e76d72022-02-11 21:43:504489 # If no message was set, return empty.
4490 if not len(message):
4491 return []
4492
4493 return [output_api.PresubmitPromptWarning(message)]
4494
Mark Schillacie5a0be22022-01-19 00:38:394495
4496def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504497 """Checks that commits that include a newly added, renamed/moved, or deleted
4498 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4499 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394500
Sam Maiera6e76d72022-02-11 21:43:504501 def FilePathFilter(affected_file):
4502 paths = _ACCESSIBILITY_TREE_TEST_PATH
4503 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394504
Sam Maiera6e76d72022-02-11 21:43:504505 def AndroidFilePathFilter(affected_file):
4506 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4507 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394508
Sam Maiera6e76d72022-02-11 21:43:504509 # Only consider changes in the various tree test data paths with html type.
4510 if not any(
4511 input_api.AffectedFiles(include_deletes=True,
4512 file_filter=FilePathFilter)):
4513 return []
Mark Schillacie5a0be22022-01-19 00:38:394514
Sam Maiera6e76d72022-02-11 21:43:504515 # If the commit contains any change to the Android test file, ignore.
4516 if any(
4517 input_api.AffectedFiles(include_deletes=True,
4518 file_filter=AndroidFilePathFilter)):
4519 return []
Mark Schillacie5a0be22022-01-19 00:38:394520
Sam Maiera6e76d72022-02-11 21:43:504521 # Only consider changes that are adding/renaming or deleting a file
4522 message = []
4523 for f in input_api.AffectedFiles(include_deletes=True,
4524 file_filter=FilePathFilter):
4525 if f.Action() == 'A' or f.Action() == 'D':
4526 message = (
4527 "It appears that you are adding, renaming or deleting"
4528 "\na dump_accessibility_tree* test, but have not included"
4529 "\na corresponding change for Android."
4530 "\nPlease include (or remove) the test from:"
4531 "\n content/public/android/javatests/src/org/chromium/"
4532 "content/browser/accessibility/"
4533 "WebContentsAccessibilityTreeTest.java"
4534 "\nIf this message is confusing or annoying, please contact"
4535 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394536
Sam Maiera6e76d72022-02-11 21:43:504537 # If no message was set, return empty.
4538 if not len(message):
4539 return []
4540
4541 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394542
4543
seanmccullough4a9356252021-04-08 19:54:094544# string pattern, sequence of strings to show when pattern matches,
4545# error flag. True if match is a presubmit error, otherwise it's a warning.
4546_NON_INCLUSIVE_TERMS = (
4547 (
4548 # Note that \b pattern in python re is pretty particular. In this
4549 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4550 # ...' will not. This may require some tweaking to catch these cases
4551 # without triggering a lot of false positives. Leaving it naive and
4552 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324553 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094554 (
4555 'Please don\'t use blacklist, whitelist, ' # nocheck
4556 'or slave in your', # nocheck
4557 'code and make every effort to use other terms. Using "// nocheck"',
4558 '"# nocheck" or "<!-- nocheck -->"',
4559 'at the end of the offending line will bypass this PRESUBMIT error',
4560 'but avoid using this whenever possible. Reach out to',
4561 '[email protected] if you have questions'),
4562 True),)
4563
Saagar Sanghavifceeaae2020-08-12 16:40:364564def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504565 """Checks common to both upload and commit."""
4566 results = []
Eric Boren6fd2b932018-01-25 15:05:084567 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504568 input_api.canned_checks.PanProjectChecks(
4569 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084570
Sam Maiera6e76d72022-02-11 21:43:504571 author = input_api.change.author_email
4572 if author and author not in _KNOWN_ROBOTS:
4573 results.extend(
4574 input_api.canned_checks.CheckAuthorizedAuthor(
4575 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244576
Sam Maiera6e76d72022-02-11 21:43:504577 results.extend(
4578 input_api.canned_checks.CheckChangeHasNoTabs(
4579 input_api,
4580 output_api,
4581 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
4582 results.extend(
4583 input_api.RunTests(
4584 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:174585
Bruce Dawsonc8054482022-03-28 15:33:374586 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:504587 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:374588 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:504589 results.extend(
4590 input_api.RunTests(
4591 input_api.canned_checks.CheckDirMetadataFormat(
4592 input_api, output_api, dirmd_bin)))
4593 results.extend(
4594 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4595 input_api, output_api))
4596 results.extend(
4597 input_api.canned_checks.CheckNoNewMetadataInOwners(
4598 input_api, output_api))
4599 results.extend(
4600 input_api.canned_checks.CheckInclusiveLanguage(
4601 input_api,
4602 output_api,
4603 excluded_directories_relative_path=[
4604 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
4605 ],
4606 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:594607
Sam Maiera6e76d72022-02-11 21:43:504608 for f in input_api.AffectedFiles():
4609 path, name = input_api.os_path.split(f.LocalPath())
4610 if name == 'PRESUBMIT.py':
4611 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
4612 path)
4613 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4614 if f.Action() != 'D' and input_api.os_path.exists(test_file):
4615 # The PRESUBMIT.py file (and the directory containing it) might
4616 # have been affected by being moved or removed, so only try to
4617 # run the tests if they still exist.
4618 use_python3 = False
4619 with open(f.LocalPath()) as fp:
4620 use_python3 = any(
4621 line.startswith('USE_PYTHON3 = True')
4622 for line in fp.readlines())
4623
4624 results.extend(
4625 input_api.canned_checks.RunUnitTestsInDirectory(
4626 input_api,
4627 output_api,
4628 full_path,
4629 files_to_check=[r'^PRESUBMIT_test\.py$'],
4630 run_on_python2=not use_python3,
4631 run_on_python3=use_python3,
4632 skip_shebang_check=True))
4633 return results
[email protected]1f7b4172010-01-28 01:17:344634
[email protected]b337cb5b2011-01-23 21:24:054635
Saagar Sanghavifceeaae2020-08-12 16:40:364636def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504637 problems = [
4638 f.LocalPath() for f in input_api.AffectedFiles()
4639 if f.LocalPath().endswith(('.orig', '.rej'))
4640 ]
4641 # Cargo.toml.orig files are part of third-party crates downloaded from
4642 # crates.io and should be included.
4643 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
4644 if problems:
4645 return [
4646 output_api.PresubmitError("Don't commit .rej and .orig files.",
4647 problems)
4648 ]
4649 else:
4650 return []
[email protected]b8079ae4a2012-12-05 19:56:494651
4652
Saagar Sanghavifceeaae2020-08-12 16:40:364653def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504654 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4655 macro_re = input_api.re.compile(
4656 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
4657 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
4658 input_api.re.MULTILINE)
4659 extension_re = input_api.re.compile(r'\.[a-z]+$')
4660 errors = []
4661 for f in input_api.AffectedFiles(include_deletes=False):
4662 if not f.LocalPath().endswith(
4663 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4664 continue
4665 found_line_number = None
4666 found_macro = None
4667 all_lines = input_api.ReadFile(f, 'r').splitlines()
4668 for line_num, line in enumerate(all_lines):
4669 match = macro_re.search(line)
4670 if match:
4671 found_line_number = line_num
4672 found_macro = match.group(2)
4673 break
4674 if not found_line_number:
4675 continue
Kent Tamura5a8755d2017-06-29 23:37:074676
Sam Maiera6e76d72022-02-11 21:43:504677 found_include_line = -1
4678 for line_num, line in enumerate(all_lines):
4679 if include_re.search(line):
4680 found_include_line = line_num
4681 break
4682 if found_include_line >= 0 and found_include_line < found_line_number:
4683 continue
Kent Tamura5a8755d2017-06-29 23:37:074684
Sam Maiera6e76d72022-02-11 21:43:504685 if not f.LocalPath().endswith('.h'):
4686 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4687 try:
4688 content = input_api.ReadFile(primary_header_path, 'r')
4689 if include_re.search(content):
4690 continue
4691 except IOError:
4692 pass
4693 errors.append('%s:%d %s macro is used without first including build/'
4694 'build_config.h.' %
4695 (f.LocalPath(), found_line_number, found_macro))
4696 if errors:
4697 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4698 return []
Kent Tamura5a8755d2017-06-29 23:37:074699
4700
Lei Zhang1c12a22f2021-05-12 11:28:454701def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504702 stl_include_re = input_api.re.compile(r'^#include\s+<('
4703 r'algorithm|'
4704 r'array|'
4705 r'limits|'
4706 r'list|'
4707 r'map|'
4708 r'memory|'
4709 r'queue|'
4710 r'set|'
4711 r'string|'
4712 r'unordered_map|'
4713 r'unordered_set|'
4714 r'utility|'
4715 r'vector)>')
4716 std_namespace_re = input_api.re.compile(r'std::')
4717 errors = []
4718 for f in input_api.AffectedFiles():
4719 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4720 continue
Lei Zhang1c12a22f2021-05-12 11:28:454721
Sam Maiera6e76d72022-02-11 21:43:504722 uses_std_namespace = False
4723 has_stl_include = False
4724 for line in f.NewContents():
4725 if has_stl_include and uses_std_namespace:
4726 break
Lei Zhang1c12a22f2021-05-12 11:28:454727
Sam Maiera6e76d72022-02-11 21:43:504728 if not has_stl_include and stl_include_re.search(line):
4729 has_stl_include = True
4730 continue
Lei Zhang1c12a22f2021-05-12 11:28:454731
Bruce Dawson4a5579a2022-04-08 17:11:364732 if not uses_std_namespace and (std_namespace_re.search(line)
4733 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504734 uses_std_namespace = True
4735 continue
Lei Zhang1c12a22f2021-05-12 11:28:454736
Sam Maiera6e76d72022-02-11 21:43:504737 if has_stl_include and not uses_std_namespace:
4738 errors.append(
4739 '%s: Includes STL header(s) but does not reference std::' %
4740 f.LocalPath())
4741 if errors:
4742 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4743 return []
Lei Zhang1c12a22f2021-05-12 11:28:454744
4745
Xiaohan Wang42d96c22022-01-20 17:23:114746def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504747 """Check for sensible looking, totally invalid OS macros."""
4748 preprocessor_statement = input_api.re.compile(r'^\s*#')
4749 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
4750 results = []
4751 for lnum, line in f.ChangedContents():
4752 if preprocessor_statement.search(line):
4753 for match in os_macro.finditer(line):
4754 results.append(
4755 ' %s:%d: %s' %
4756 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
4757 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
4758 return results
[email protected]b00342e7f2013-03-26 16:21:544759
4760
Xiaohan Wang42d96c22022-01-20 17:23:114761def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504762 """Check all affected files for invalid OS macros."""
4763 bad_macros = []
4764 for f in input_api.AffectedSourceFiles(None):
4765 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
4766 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:544767
Sam Maiera6e76d72022-02-11 21:43:504768 if not bad_macros:
4769 return []
[email protected]b00342e7f2013-03-26 16:21:544770
Sam Maiera6e76d72022-02-11 21:43:504771 return [
4772 output_api.PresubmitError(
4773 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
4774 'defined in build_config.h):', bad_macros)
4775 ]
[email protected]b00342e7f2013-03-26 16:21:544776
lliabraa35bab3932014-10-01 12:16:444777
4778def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504779 """Check all affected files for invalid "if defined" macros."""
4780 ALWAYS_DEFINED_MACROS = (
4781 "TARGET_CPU_PPC",
4782 "TARGET_CPU_PPC64",
4783 "TARGET_CPU_68K",
4784 "TARGET_CPU_X86",
4785 "TARGET_CPU_ARM",
4786 "TARGET_CPU_MIPS",
4787 "TARGET_CPU_SPARC",
4788 "TARGET_CPU_ALPHA",
4789 "TARGET_IPHONE_SIMULATOR",
4790 "TARGET_OS_EMBEDDED",
4791 "TARGET_OS_IPHONE",
4792 "TARGET_OS_MAC",
4793 "TARGET_OS_UNIX",
4794 "TARGET_OS_WIN32",
4795 )
4796 ifdef_macro = input_api.re.compile(
4797 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4798 results = []
4799 for lnum, line in f.ChangedContents():
4800 for match in ifdef_macro.finditer(line):
4801 if match.group(1) in ALWAYS_DEFINED_MACROS:
4802 always_defined = ' %s is always defined. ' % match.group(1)
4803 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4804 results.append(
4805 ' %s:%d %s\n\t%s' %
4806 (f.LocalPath(), lnum, always_defined, did_you_mean))
4807 return results
lliabraa35bab3932014-10-01 12:16:444808
4809
Saagar Sanghavifceeaae2020-08-12 16:40:364810def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504811 """Check all affected files for invalid "if defined" macros."""
4812 bad_macros = []
4813 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
4814 for f in input_api.AffectedFiles():
4815 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
4816 continue
4817 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4818 bad_macros.extend(
4819 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:444820
Sam Maiera6e76d72022-02-11 21:43:504821 if not bad_macros:
4822 return []
lliabraa35bab3932014-10-01 12:16:444823
Sam Maiera6e76d72022-02-11 21:43:504824 return [
4825 output_api.PresubmitError(
4826 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4827 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4828 bad_macros)
4829 ]
lliabraa35bab3932014-10-01 12:16:444830
4831
Saagar Sanghavifceeaae2020-08-12 16:40:364832def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504833 """Check for same IPC rules described in
4834 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4835 """
4836 base_pattern = r'IPC_ENUM_TRAITS\('
4837 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4838 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:044839
Sam Maiera6e76d72022-02-11 21:43:504840 problems = []
4841 for f in input_api.AffectedSourceFiles(None):
4842 local_path = f.LocalPath()
4843 if not local_path.endswith('.h'):
4844 continue
4845 for line_number, line in f.ChangedContents():
4846 if inclusion_pattern.search(
4847 line) and not comment_pattern.search(line):
4848 problems.append('%s:%d\n %s' %
4849 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:044850
Sam Maiera6e76d72022-02-11 21:43:504851 if problems:
4852 return [
4853 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
4854 problems)
4855 ]
4856 else:
4857 return []
mlamouria82272622014-09-16 18:45:044858
[email protected]b00342e7f2013-03-26 16:21:544859
Saagar Sanghavifceeaae2020-08-12 16:40:364860def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504861 """Check to make sure no files being submitted have long paths.
4862 This causes issues on Windows.
4863 """
4864 problems = []
4865 for f in input_api.AffectedTestableFiles():
4866 local_path = f.LocalPath()
4867 # Windows has a path limit of 260 characters. Limit path length to 200 so
4868 # that we have some extra for the prefix on dev machines and the bots.
4869 if len(local_path) > 200:
4870 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:054871
Sam Maiera6e76d72022-02-11 21:43:504872 if problems:
4873 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4874 else:
4875 return []
Stephen Martinis97a394142018-06-07 23:06:054876
4877
Saagar Sanghavifceeaae2020-08-12 16:40:364878def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504879 """Check that header files have proper guards against multiple inclusion.
4880 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:364881 should include the string "no-include-guard-because-multiply-included" or
4882 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:504883 """
Daniel Bratell8ba52722018-03-02 16:06:144884
Sam Maiera6e76d72022-02-11 21:43:504885 def is_chromium_header_file(f):
4886 # We only check header files under the control of the Chromium
4887 # project. That is, those outside third_party apart from
4888 # third_party/blink.
4889 # We also exclude *_message_generator.h headers as they use
4890 # include guards in a special, non-typical way.
4891 file_with_path = input_api.os_path.normpath(f.LocalPath())
4892 return (file_with_path.endswith('.h')
4893 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:334894 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:504895 and (not file_with_path.startswith('third_party')
4896 or file_with_path.startswith(
4897 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144898
Sam Maiera6e76d72022-02-11 21:43:504899 def replace_special_with_underscore(string):
4900 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144901
Sam Maiera6e76d72022-02-11 21:43:504902 errors = []
Daniel Bratell8ba52722018-03-02 16:06:144903
Sam Maiera6e76d72022-02-11 21:43:504904 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
4905 guard_name = None
4906 guard_line_number = None
4907 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:144908
Sam Maiera6e76d72022-02-11 21:43:504909 file_with_path = input_api.os_path.normpath(f.LocalPath())
4910 base_file_name = input_api.os_path.splitext(
4911 input_api.os_path.basename(file_with_path))[0]
4912 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:144913
Sam Maiera6e76d72022-02-11 21:43:504914 expected_guard = replace_special_with_underscore(
4915 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144916
Sam Maiera6e76d72022-02-11 21:43:504917 # For "path/elem/file_name.h" we should really only accept
4918 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4919 # are too many (1000+) files with slight deviations from the
4920 # coding style. The most important part is that the include guard
4921 # is there, and that it's unique, not the name so this check is
4922 # forgiving for existing files.
4923 #
4924 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:144925
Sam Maiera6e76d72022-02-11 21:43:504926 guard_name_pattern_list = [
4927 # Anything with the right suffix (maybe with an extra _).
4928 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:144929
Sam Maiera6e76d72022-02-11 21:43:504930 # To cover include guards with old Blink style.
4931 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:144932
Sam Maiera6e76d72022-02-11 21:43:504933 # Anything including the uppercase name of the file.
4934 r'\w*' + input_api.re.escape(
4935 replace_special_with_underscore(upper_base_file_name)) +
4936 r'\w*',
4937 ]
4938 guard_name_pattern = '|'.join(guard_name_pattern_list)
4939 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
4940 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:144941
Sam Maiera6e76d72022-02-11 21:43:504942 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:364943 if ('no-include-guard-because-multiply-included' in line
4944 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504945 guard_name = 'DUMMY' # To not trigger check outside the loop.
4946 break
Daniel Bratell8ba52722018-03-02 16:06:144947
Sam Maiera6e76d72022-02-11 21:43:504948 if guard_name is None:
4949 match = guard_pattern.match(line)
4950 if match:
4951 guard_name = match.group(1)
4952 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:144953
Sam Maiera6e76d72022-02-11 21:43:504954 # We allow existing files to use include guards whose names
4955 # don't match the chromium style guide, but new files should
4956 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:494957 if guard_name != expected_guard:
4958 if not f.OldContents():
Sam Maiera6e76d72022-02-11 21:43:504959 errors.append(
4960 output_api.PresubmitPromptWarning(
4961 'Header using the wrong include guard name %s'
4962 % guard_name, [
4963 '%s:%d' %
4964 (f.LocalPath(), line_number + 1)
4965 ], 'Expected: %r\nFound: %r' %
4966 (expected_guard, guard_name)))
4967 else:
4968 # The line after #ifndef should have a #define of the same name.
4969 if line_number == guard_line_number + 1:
4970 expected_line = '#define %s' % guard_name
4971 if line != expected_line:
4972 errors.append(
4973 output_api.PresubmitPromptWarning(
4974 'Missing "%s" for include guard' %
4975 expected_line,
4976 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4977 'Expected: %r\nGot: %r' %
4978 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:144979
Sam Maiera6e76d72022-02-11 21:43:504980 if not seen_guard_end and line == '#endif // %s' % guard_name:
4981 seen_guard_end = True
4982 elif seen_guard_end:
4983 if line.strip() != '':
4984 errors.append(
4985 output_api.PresubmitPromptWarning(
4986 'Include guard %s not covering the whole file'
4987 % (guard_name), [f.LocalPath()]))
4988 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:144989
Sam Maiera6e76d72022-02-11 21:43:504990 if guard_name is None:
4991 errors.append(
4992 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:494993 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:504994 'Recommended name: %s\n'
4995 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:364996 '"no-include-guard-because-multiply-included" or\n'
4997 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:504998 % (f.LocalPath(), expected_guard)))
4999
5000 return errors
Daniel Bratell8ba52722018-03-02 16:06:145001
5002
Saagar Sanghavifceeaae2020-08-12 16:40:365003def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505004 """Check source code and known ascii text files for Windows style line
5005 endings.
5006 """
Bruce Dawson5efbdc652022-04-11 19:29:515007 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235008
Sam Maiera6e76d72022-02-11 21:43:505009 file_inclusion_pattern = (known_text_files,
5010 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5011 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235012
Sam Maiera6e76d72022-02-11 21:43:505013 problems = []
5014 source_file_filter = lambda f: input_api.FilterSourceFile(
5015 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5016 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515017 # Ignore test files that contain crlf intentionally.
5018 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345019 continue
Sam Maiera6e76d72022-02-11 21:43:505020 include_file = False
5021 for line in input_api.ReadFile(f, 'r').splitlines(True):
5022 if line.endswith('\r\n'):
5023 include_file = True
5024 if include_file:
5025 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235026
Sam Maiera6e76d72022-02-11 21:43:505027 if problems:
5028 return [
5029 output_api.PresubmitPromptWarning(
5030 'Are you sure that you want '
5031 'these files to contain Windows style line endings?\n' +
5032 '\n'.join(problems))
5033 ]
mostynbb639aca52015-01-07 20:31:235034
Sam Maiera6e76d72022-02-11 21:43:505035 return []
5036
mostynbb639aca52015-01-07 20:31:235037
Evan Stade6cfc964c12021-05-18 20:21:165038def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505039 """Check that .icon files (which are fragments of C++) have license headers.
5040 """
Evan Stade6cfc964c12021-05-18 20:21:165041
Sam Maiera6e76d72022-02-11 21:43:505042 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165043
Sam Maiera6e76d72022-02-11 21:43:505044 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5045 return input_api.canned_checks.CheckLicense(input_api,
5046 output_api,
5047 source_file_filter=icons)
5048
Evan Stade6cfc964c12021-05-18 20:21:165049
Jose Magana2b456f22021-03-09 23:26:405050def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505051 """Check source code for use of Chrome App technologies being
5052 deprecated.
5053 """
Jose Magana2b456f22021-03-09 23:26:405054
Sam Maiera6e76d72022-02-11 21:43:505055 def _CheckForDeprecatedTech(input_api,
5056 output_api,
5057 detection_list,
5058 files_to_check=None,
5059 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405060
Sam Maiera6e76d72022-02-11 21:43:505061 if (files_to_check or files_to_skip):
5062 source_file_filter = lambda f: input_api.FilterSourceFile(
5063 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5064 else:
5065 source_file_filter = None
5066
5067 problems = []
5068
5069 for f in input_api.AffectedSourceFiles(source_file_filter):
5070 if f.Action() == 'D':
5071 continue
5072 for _, line in f.ChangedContents():
5073 if any(detect in line for detect in detection_list):
5074 problems.append(f.LocalPath())
5075
5076 return problems
5077
5078 # to avoid this presubmit script triggering warnings
5079 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405080
5081 problems = []
5082
Sam Maiera6e76d72022-02-11 21:43:505083 # NMF: any files with extensions .nmf or NMF
5084 _NMF_FILES = r'\.(nmf|NMF)$'
5085 problems += _CheckForDeprecatedTech(
5086 input_api,
5087 output_api,
5088 detection_list=[''], # any change to the file will trigger warning
5089 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405090
Sam Maiera6e76d72022-02-11 21:43:505091 # MANIFEST: any manifest.json that in its diff includes "app":
5092 _MANIFEST_FILES = r'(manifest\.json)$'
5093 problems += _CheckForDeprecatedTech(
5094 input_api,
5095 output_api,
5096 detection_list=['"app":'],
5097 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405098
Sam Maiera6e76d72022-02-11 21:43:505099 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5100 problems += _CheckForDeprecatedTech(
5101 input_api,
5102 output_api,
5103 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
5104 files_to_skip=files_to_skip + [r"^native_client_sdk[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405105
Sam Maiera6e76d72022-02-11 21:43:505106 # PPAPI: any C/C++ file that in its diff includes a ppappi library
5107 problems += _CheckForDeprecatedTech(
5108 input_api,
5109 output_api,
5110 detection_list=['#include "ppapi', '#include <ppapi'],
5111 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5112 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
5113 files_to_skip=[r"^ppapi[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405114
Sam Maiera6e76d72022-02-11 21:43:505115 if problems:
5116 return [
5117 output_api.PresubmitPromptWarning(
5118 'You are adding/modifying code'
5119 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5120 ' PNaCl, PPAPI). See this blog post for more details:\n'
5121 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5122 'and this documentation for options to replace these technologies:\n'
5123 'https://developer.chrome.com/docs/apps/migration/\n' +
5124 '\n'.join(problems))
5125 ]
Jose Magana2b456f22021-03-09 23:26:405126
Sam Maiera6e76d72022-02-11 21:43:505127 return []
Jose Magana2b456f22021-03-09 23:26:405128
mostynbb639aca52015-01-07 20:31:235129
Saagar Sanghavifceeaae2020-08-12 16:40:365130def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505131 """Checks that all source files use SYSLOG properly."""
5132 syslog_files = []
5133 for f in input_api.AffectedSourceFiles(src_file_filter):
5134 for line_number, line in f.ChangedContents():
5135 if 'SYSLOG' in line:
5136 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565137
Sam Maiera6e76d72022-02-11 21:43:505138 if syslog_files:
5139 return [
5140 output_api.PresubmitPromptWarning(
5141 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5142 ' calls.\nFiles to check:\n',
5143 items=syslog_files)
5144 ]
5145 return []
pastarmovj89f7ee12016-09-20 14:58:135146
5147
[email protected]1f7b4172010-01-28 01:17:345148def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505149 if input_api.version < [2, 0, 0]:
5150 return [
5151 output_api.PresubmitError(
5152 "Your depot_tools is out of date. "
5153 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5154 "but your version is %d.%d.%d" % tuple(input_api.version))
5155 ]
5156 results = []
5157 results.extend(
5158 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5159 return results
[email protected]ca8d1982009-02-19 16:33:125160
5161
5162def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505163 if input_api.version < [2, 0, 0]:
5164 return [
5165 output_api.PresubmitError(
5166 "Your depot_tools is out of date. "
5167 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5168 "but your version is %d.%d.%d" % tuple(input_api.version))
5169 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365170
Sam Maiera6e76d72022-02-11 21:43:505171 results = []
5172 # Make sure the tree is 'open'.
5173 results.extend(
5174 input_api.canned_checks.CheckTreeIsOpen(
5175 input_api,
5176 output_api,
5177 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275178
Sam Maiera6e76d72022-02-11 21:43:505179 results.extend(
5180 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5181 results.extend(
5182 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5183 results.extend(
5184 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5185 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505186 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145187
5188
Saagar Sanghavifceeaae2020-08-12 16:40:365189def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505190 """Check string ICU syntax validity and if translation screenshots exist."""
5191 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5192 # footer is set to true.
5193 git_footers = input_api.change.GitFootersFromDescription()
5194 skip_screenshot_check_footer = [
5195 footer.lower() for footer in git_footers.get(
5196 u'Skip-Translation-Screenshots-Check', [])
5197 ]
5198 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025199
Sam Maiera6e76d72022-02-11 21:43:505200 import os
5201 import re
5202 import sys
5203 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145204
Sam Maiera6e76d72022-02-11 21:43:505205 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5206 if (f.Action() == 'A' or f.Action() == 'M'))
5207 removed_paths = set(f.LocalPath()
5208 for f in input_api.AffectedFiles(include_deletes=True)
5209 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145210
Sam Maiera6e76d72022-02-11 21:43:505211 affected_grds = [
5212 f for f in input_api.AffectedFiles()
5213 if f.LocalPath().endswith(('.grd', '.grdp'))
5214 ]
5215 affected_grds = [
5216 f for f in affected_grds if not 'testdata' in f.LocalPath()
5217 ]
5218 if not affected_grds:
5219 return []
meacer8c0d3832019-12-26 21:46:165220
Sam Maiera6e76d72022-02-11 21:43:505221 affected_png_paths = [
5222 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5223 if (f.LocalPath().endswith('.png'))
5224 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145225
Sam Maiera6e76d72022-02-11 21:43:505226 # Check for screenshots. Developers can upload screenshots using
5227 # tools/translation/upload_screenshots.py which finds and uploads
5228 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5229 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5230 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5231 #
5232 # The logic here is as follows:
5233 #
5234 # - If the CL has a .png file under the screenshots directory for a grd
5235 # file, warn the developer. Actual images should never be checked into the
5236 # Chrome repo.
5237 #
5238 # - If the CL contains modified or new messages in grd files and doesn't
5239 # contain the corresponding .sha1 files, warn the developer to add images
5240 # and upload them via tools/translation/upload_screenshots.py.
5241 #
5242 # - If the CL contains modified or new messages in grd files and the
5243 # corresponding .sha1 files, everything looks good.
5244 #
5245 # - If the CL contains removed messages in grd files but the corresponding
5246 # .sha1 files aren't removed, warn the developer to remove them.
5247 unnecessary_screenshots = []
5248 missing_sha1 = []
5249 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145250
Sam Maiera6e76d72022-02-11 21:43:505251 # This checks verifies that the ICU syntax of messages this CL touched is
5252 # valid, and reports any found syntax errors.
5253 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5254 # without developers being aware of them. Later on, such ICU syntax errors
5255 # break message extraction for translation, hence would block Chromium
5256 # translations until they are fixed.
5257 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145258
Sam Maiera6e76d72022-02-11 21:43:505259 def _CheckScreenshotAdded(screenshots_dir, message_id):
5260 sha1_path = input_api.os_path.join(screenshots_dir,
5261 message_id + '.png.sha1')
5262 if sha1_path not in new_or_added_paths:
5263 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145264
Sam Maiera6e76d72022-02-11 21:43:505265 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5266 sha1_path = input_api.os_path.join(screenshots_dir,
5267 message_id + '.png.sha1')
5268 if input_api.os_path.exists(
5269 sha1_path) and sha1_path not in removed_paths:
5270 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145271
Sam Maiera6e76d72022-02-11 21:43:505272 def _ValidateIcuSyntax(text, level, signatures):
5273 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145274
Sam Maiera6e76d72022-02-11 21:43:505275 Check if text looks similar to ICU and checks for ICU syntax correctness
5276 in this case. Reports various issues with ICU syntax and values of
5277 variants. Supports checking of nested messages. Accumulate information of
5278 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265279
Sam Maiera6e76d72022-02-11 21:43:505280 Args:
5281 text: a string to check.
5282 level: a number of current nesting level.
5283 signatures: an accumulator, a list of tuple of (level, variable,
5284 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265285
Sam Maiera6e76d72022-02-11 21:43:505286 Returns:
5287 None if a string is not ICU or no issue detected.
5288 A tuple of (message, start index, end index) if an issue detected.
5289 """
5290 valid_types = {
5291 'plural': (frozenset(
5292 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5293 'other']), frozenset(['=1', 'other'])),
5294 'selectordinal': (frozenset(
5295 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5296 'other']), frozenset(['one', 'other'])),
5297 'select': (frozenset(), frozenset(['other'])),
5298 }
Rainhard Findlingfc31844c52020-05-15 09:58:265299
Sam Maiera6e76d72022-02-11 21:43:505300 # Check if the message looks like an attempt to use ICU
5301 # plural. If yes - check if its syntax strictly matches ICU format.
5302 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5303 text)
5304 if not like:
5305 signatures.append((level, None, None, None))
5306 return
Rainhard Findlingfc31844c52020-05-15 09:58:265307
Sam Maiera6e76d72022-02-11 21:43:505308 # Check for valid prefix and suffix
5309 m = re.match(
5310 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5311 r'(plural|selectordinal|select),\s*'
5312 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5313 if not m:
5314 return (('This message looks like an ICU plural, '
5315 'but does not follow ICU syntax.'), like.start(),
5316 like.end())
5317 starting, variable, kind, variant_pairs = m.groups()
5318 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5319 m.start(4))
5320 if depth:
5321 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5322 len(text))
5323 first = text[0]
5324 ending = text[last_pos:]
5325 if not starting:
5326 return ('Invalid ICU format. No initial opening bracket',
5327 last_pos - 1, last_pos)
5328 if not ending or '}' not in ending:
5329 return ('Invalid ICU format. No final closing bracket',
5330 last_pos - 1, last_pos)
5331 elif first != '{':
5332 return ((
5333 'Invalid ICU format. Extra characters at the start of a complex '
5334 'message (go/icu-message-migration): "%s"') % starting, 0,
5335 len(starting))
5336 elif ending != '}':
5337 return ((
5338 'Invalid ICU format. Extra characters at the end of a complex '
5339 'message (go/icu-message-migration): "%s"') % ending,
5340 last_pos - 1, len(text) - 1)
5341 if kind not in valid_types:
5342 return (('Unknown ICU message type %s. '
5343 'Valid types are: plural, select, selectordinal') % kind,
5344 0, 0)
5345 known, required = valid_types[kind]
5346 defined_variants = set()
5347 for variant, variant_range, value, value_range in variants:
5348 start, end = variant_range
5349 if variant in defined_variants:
5350 return ('Variant "%s" is defined more than once' % variant,
5351 start, end)
5352 elif known and variant not in known:
5353 return ('Variant "%s" is not valid for %s message' %
5354 (variant, kind), start, end)
5355 defined_variants.add(variant)
5356 # Check for nested structure
5357 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5358 if res:
5359 return (res[0], res[1] + value_range[0] + 1,
5360 res[2] + value_range[0] + 1)
5361 missing = required - defined_variants
5362 if missing:
5363 return ('Required variants missing: %s' % ', '.join(missing), 0,
5364 len(text))
5365 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265366
Sam Maiera6e76d72022-02-11 21:43:505367 def _ParseIcuVariants(text, offset=0):
5368 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265369
Sam Maiera6e76d72022-02-11 21:43:505370 Builds a tuple of variant names and values, as well as
5371 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265372
Sam Maiera6e76d72022-02-11 21:43:505373 Args:
5374 text: a string to parse
5375 offset: additional offset to add to positions in the text to get correct
5376 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265377
Sam Maiera6e76d72022-02-11 21:43:505378 Returns:
5379 List of tuples, each tuple consist of four fields: variant name,
5380 variant name span (tuple of two integers), variant value, value
5381 span (tuple of two integers).
5382 """
5383 depth, start, end = 0, -1, -1
5384 variants = []
5385 key = None
5386 for idx, char in enumerate(text):
5387 if char == '{':
5388 if not depth:
5389 start = idx
5390 chunk = text[end + 1:start]
5391 key = chunk.strip()
5392 pos = offset + end + 1 + chunk.find(key)
5393 span = (pos, pos + len(key))
5394 depth += 1
5395 elif char == '}':
5396 if not depth:
5397 return variants, depth, offset + idx
5398 depth -= 1
5399 if not depth:
5400 end = idx
5401 variants.append((key, span, text[start:end + 1],
5402 (offset + start, offset + end + 1)))
5403 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265404
Sam Maiera6e76d72022-02-11 21:43:505405 try:
5406 old_sys_path = sys.path
5407 sys.path = sys.path + [
5408 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5409 'translation')
5410 ]
5411 from helper import grd_helper
5412 finally:
5413 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265414
Sam Maiera6e76d72022-02-11 21:43:505415 for f in affected_grds:
5416 file_path = f.LocalPath()
5417 old_id_to_msg_map = {}
5418 new_id_to_msg_map = {}
5419 # Note that this code doesn't check if the file has been deleted. This is
5420 # OK because it only uses the old and new file contents and doesn't load
5421 # the file via its path.
5422 # It's also possible that a file's content refers to a renamed or deleted
5423 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5424 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5425 # .grdp files.
5426 if file_path.endswith('.grdp'):
5427 if f.OldContents():
5428 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5429 '\n'.join(f.OldContents()))
5430 if f.NewContents():
5431 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5432 '\n'.join(f.NewContents()))
5433 else:
5434 file_dir = input_api.os_path.dirname(file_path) or '.'
5435 if f.OldContents():
5436 old_id_to_msg_map = grd_helper.GetGrdMessages(
5437 StringIO('\n'.join(f.OldContents())), file_dir)
5438 if f.NewContents():
5439 new_id_to_msg_map = grd_helper.GetGrdMessages(
5440 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265441
Sam Maiera6e76d72022-02-11 21:43:505442 grd_name, ext = input_api.os_path.splitext(
5443 input_api.os_path.basename(file_path))
5444 screenshots_dir = input_api.os_path.join(
5445 input_api.os_path.dirname(file_path),
5446 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265447
Sam Maiera6e76d72022-02-11 21:43:505448 # Compute added, removed and modified message IDs.
5449 old_ids = set(old_id_to_msg_map)
5450 new_ids = set(new_id_to_msg_map)
5451 added_ids = new_ids - old_ids
5452 removed_ids = old_ids - new_ids
5453 modified_ids = set([])
5454 for key in old_ids.intersection(new_ids):
5455 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5456 new_id_to_msg_map[key].ContentsAsXml('', True)):
5457 # The message content itself changed. Require an updated screenshot.
5458 modified_ids.add(key)
5459 elif old_id_to_msg_map[key].attrs['meaning'] != \
5460 new_id_to_msg_map[key].attrs['meaning']:
5461 # The message meaning changed. Ensure there is a screenshot for it.
5462 sha1_path = input_api.os_path.join(screenshots_dir,
5463 key + '.png.sha1')
5464 if sha1_path not in new_or_added_paths and not \
5465 input_api.os_path.exists(sha1_path):
5466 # There is neither a previous screenshot nor is a new one added now.
5467 # Require a screenshot.
5468 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145469
Sam Maiera6e76d72022-02-11 21:43:505470 if run_screenshot_check:
5471 # Check the screenshot directory for .png files. Warn if there is any.
5472 for png_path in affected_png_paths:
5473 if png_path.startswith(screenshots_dir):
5474 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145475
Sam Maiera6e76d72022-02-11 21:43:505476 for added_id in added_ids:
5477 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095478
Sam Maiera6e76d72022-02-11 21:43:505479 for modified_id in modified_ids:
5480 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145481
Sam Maiera6e76d72022-02-11 21:43:505482 for removed_id in removed_ids:
5483 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5484
5485 # Check new and changed strings for ICU syntax errors.
5486 for key in added_ids.union(modified_ids):
5487 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5488 err = _ValidateIcuSyntax(msg, 0, [])
5489 if err is not None:
5490 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5491
5492 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265493 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505494 if unnecessary_screenshots:
5495 results.append(
5496 output_api.PresubmitError(
5497 'Do not include actual screenshots in the changelist. Run '
5498 'tools/translate/upload_screenshots.py to upload them instead:',
5499 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145500
Sam Maiera6e76d72022-02-11 21:43:505501 if missing_sha1:
5502 results.append(
5503 output_api.PresubmitError(
5504 'You are adding or modifying UI strings.\n'
5505 'To ensure the best translations, take screenshots of the relevant UI '
5506 '(https://g.co/chrome/translation) and add these files to your '
5507 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145508
Sam Maiera6e76d72022-02-11 21:43:505509 if unnecessary_sha1_files:
5510 results.append(
5511 output_api.PresubmitError(
5512 'You removed strings associated with these files. Remove:',
5513 sorted(unnecessary_sha1_files)))
5514 else:
5515 results.append(
5516 output_api.PresubmitPromptOrNotify('Skipping translation '
5517 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145518
Sam Maiera6e76d72022-02-11 21:43:505519 if icu_syntax_errors:
5520 results.append(
5521 output_api.PresubmitPromptWarning(
5522 'ICU syntax errors were found in the following strings (problems or '
5523 'feedback? Contact [email protected]):',
5524 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265525
Sam Maiera6e76d72022-02-11 21:43:505526 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125527
5528
Saagar Sanghavifceeaae2020-08-12 16:40:365529def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125530 repo_root=None,
5531 translation_expectations_path=None,
5532 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505533 import sys
5534 affected_grds = [
5535 f for f in input_api.AffectedFiles()
5536 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5537 ]
5538 if not affected_grds:
5539 return []
5540
5541 try:
5542 old_sys_path = sys.path
5543 sys.path = sys.path + [
5544 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5545 'translation')
5546 ]
5547 from helper import git_helper
5548 from helper import translation_helper
5549 finally:
5550 sys.path = old_sys_path
5551
5552 # Check that translation expectations can be parsed and we can get a list of
5553 # translatable grd files. |repo_root| and |translation_expectations_path| are
5554 # only passed by tests.
5555 if not repo_root:
5556 repo_root = input_api.PresubmitLocalPath()
5557 if not translation_expectations_path:
5558 translation_expectations_path = input_api.os_path.join(
5559 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5560 if not grd_files:
5561 grd_files = git_helper.list_grds_in_repository(repo_root)
5562
5563 # Ignore bogus grd files used only for testing
5564 # ui/webui/resoucres/tools/generate_grd.py.
5565 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
5566 'tests')
5567 grd_files = [p for p in grd_files if ignore_path not in p]
5568
5569 try:
5570 translation_helper.get_translatable_grds(
5571 repo_root, grd_files, translation_expectations_path)
5572 except Exception as e:
5573 return [
5574 output_api.PresubmitNotifyResult(
5575 'Failed to get a list of translatable grd files. This happens when:\n'
5576 ' - One of the modified grd or grdp files cannot be parsed or\n'
5577 ' - %s is not updated.\n'
5578 'Stack:\n%s' % (translation_expectations_path, str(e)))
5579 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:125580 return []
5581
Ken Rockotc31f4832020-05-29 18:58:515582
Saagar Sanghavifceeaae2020-08-12 16:40:365583def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505584 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5585 changed_mojoms = input_api.AffectedFiles(
5586 include_deletes=True,
5587 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525588
Sam Maiera6e76d72022-02-11 21:43:505589 if not changed_mojoms:
5590 return []
5591
5592 delta = []
5593 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:505594 delta.append({
5595 'filename': mojom.LocalPath(),
5596 'old': '\n'.join(mojom.OldContents()) or None,
5597 'new': '\n'.join(mojom.NewContents()) or None,
5598 })
5599
5600 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:215601 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:505602 input_api.os_path.join(
5603 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
5604 'check_stable_mojom_compatibility.py'), '--src-root',
5605 input_api.PresubmitLocalPath()
5606 ],
5607 stdin=input_api.subprocess.PIPE,
5608 stdout=input_api.subprocess.PIPE,
5609 stderr=input_api.subprocess.PIPE,
5610 universal_newlines=True)
5611 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5612 if process.returncode:
5613 return [
5614 output_api.PresubmitError(
5615 'One or more [Stable] mojom definitions appears to have been changed '
5616 'in a way that is not backward-compatible.',
5617 long_text=error)
5618 ]
Erik Staabc734cd7a2021-11-23 03:11:525619 return []
5620
Dominic Battre645d42342020-12-04 16:14:105621def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505622 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:105623
Sam Maiera6e76d72022-02-11 21:43:505624 def FilterFile(affected_file):
5625 """Accept only .cc files and the like."""
5626 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5627 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5628 input_api.DEFAULT_FILES_TO_SKIP)
5629 return input_api.FilterSourceFile(
5630 affected_file,
5631 files_to_check=file_inclusion_pattern,
5632 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:105633
Sam Maiera6e76d72022-02-11 21:43:505634 def ModifiedLines(affected_file):
5635 """Returns a list of tuples (line number, line text) of added and removed
5636 lines.
Dominic Battre645d42342020-12-04 16:14:105637
Sam Maiera6e76d72022-02-11 21:43:505638 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:105639
Sam Maiera6e76d72022-02-11 21:43:505640 This relies on the scm diff output describing each changed code section
5641 with a line of the form
Dominic Battre645d42342020-12-04 16:14:105642
Sam Maiera6e76d72022-02-11 21:43:505643 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5644 """
5645 line_num = 0
5646 modified_lines = []
5647 for line in affected_file.GenerateScmDiff().splitlines():
5648 # Extract <new line num> of the patch fragment (see format above).
5649 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
5650 line)
5651 if m:
5652 line_num = int(m.groups(1)[0])
5653 continue
5654 if ((line.startswith('+') and not line.startswith('++'))
5655 or (line.startswith('-') and not line.startswith('--'))):
5656 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:105657
Sam Maiera6e76d72022-02-11 21:43:505658 if not line.startswith('-'):
5659 line_num += 1
5660 return modified_lines
Dominic Battre645d42342020-12-04 16:14:105661
Sam Maiera6e76d72022-02-11 21:43:505662 def FindLineWith(lines, needle):
5663 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:105664
Sam Maiera6e76d72022-02-11 21:43:505665 If 0 or >1 lines contain `needle`, -1 is returned.
5666 """
5667 matching_line_numbers = [
5668 # + 1 for 1-based counting of line numbers.
5669 i + 1 for i, line in enumerate(lines) if needle in line
5670 ]
5671 return matching_line_numbers[0] if len(
5672 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:105673
Sam Maiera6e76d72022-02-11 21:43:505674 def ModifiedPrefMigration(affected_file):
5675 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5676 # Determine first and last lines of MigrateObsolete.*Pref functions.
5677 new_contents = affected_file.NewContents()
5678 range_1 = (FindLineWith(new_contents,
5679 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5680 FindLineWith(new_contents,
5681 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5682 range_2 = (FindLineWith(new_contents,
5683 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5684 FindLineWith(new_contents,
5685 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5686 if (-1 in range_1 + range_2):
5687 raise Exception(
5688 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
5689 )
Dominic Battre645d42342020-12-04 16:14:105690
Sam Maiera6e76d72022-02-11 21:43:505691 # Check whether any of the modified lines are part of the
5692 # MigrateObsolete.*Pref functions.
5693 for line_nr, line in ModifiedLines(affected_file):
5694 if (range_1[0] <= line_nr <= range_1[1]
5695 or range_2[0] <= line_nr <= range_2[1]):
5696 return True
5697 return False
Dominic Battre645d42342020-12-04 16:14:105698
Sam Maiera6e76d72022-02-11 21:43:505699 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5700 browser_prefs_file_pattern = input_api.re.compile(
5701 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:105702
Sam Maiera6e76d72022-02-11 21:43:505703 changes = input_api.AffectedFiles(include_deletes=True,
5704 file_filter=FilterFile)
5705 potential_problems = []
5706 for f in changes:
5707 for line in f.GenerateScmDiff().splitlines():
5708 # Check deleted lines for pref registrations.
5709 if (line.startswith('-') and not line.startswith('--')
5710 and register_pref_pattern.search(line)):
5711 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:105712
Sam Maiera6e76d72022-02-11 21:43:505713 if browser_prefs_file_pattern.search(f.LocalPath()):
5714 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5715 # assume that they knew that they have to deprecate preferences and don't
5716 # warn.
5717 try:
5718 if ModifiedPrefMigration(f):
5719 return []
5720 except Exception as e:
5721 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:105722
Sam Maiera6e76d72022-02-11 21:43:505723 if potential_problems:
5724 return [
5725 output_api.PresubmitPromptWarning(
5726 'Discovered possible removal of preference registrations.\n\n'
5727 'Please make sure to properly deprecate preferences by clearing their\n'
5728 'value for a couple of milestones before finally removing the code.\n'
5729 'Otherwise data may stay in the preferences files forever. See\n'
5730 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5731 'chrome/browser/prefs/README.md for examples.\n'
5732 'This may be a false positive warning (e.g. if you move preference\n'
5733 'registrations to a different place).\n', potential_problems)
5734 ]
5735 return []
5736
Matt Stark6ef08872021-07-29 01:21:465737
5738def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505739 """Changes to GRD files must be consistent for tools to read them."""
5740 changed_grds = input_api.AffectedFiles(
5741 include_deletes=False,
5742 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5743 errors = []
5744 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5745 for matcher, msg in _INVALID_GRD_FILE_LINE]
5746 for grd in changed_grds:
5747 for i, line in enumerate(grd.NewContents()):
5748 for matcher, msg in invalid_file_regexes:
5749 if matcher.search(line):
5750 errors.append(
5751 output_api.PresubmitError(
5752 'Problem on {grd}:{i} - {msg}'.format(
5753 grd=grd.LocalPath(), i=i + 1, msg=msg)))
5754 return errors
5755
Kevin McNee967dd2d22021-11-15 16:09:295756
5757def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505758 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5759 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5760 """
Kevin McNee967dd2d22021-11-15 16:09:295761
Ian Vollickdba956c2022-04-20 23:53:455762 # Only consider top-level directories that (1) can use content APIs or
5763 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
5764 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:505765 files_to_check = (
Ian Vollickdba956c2022-04-20 23:53:455766 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Kevin McNee967dd2d22021-11-15 16:09:295767 _IMPLEMENTATION_EXTENSIONS,
Ian Vollickdba956c2022-04-20 23:53:455768 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Sam Maiera6e76d72022-02-11 21:43:505769 _HEADER_EXTENSIONS,
5770 )
5771 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5772 input_api.DEFAULT_FILES_TO_SKIP)
5773 source_file_filter = lambda f: input_api.FilterSourceFile(
5774 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:295775
Sam Maiera6e76d72022-02-11 21:43:505776 # Note that since these are are just regular expressions and we don't have
5777 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5778 # could have a method named IsInMainFrame).
5779 concerning_class_pattern = input_api.re.compile(
5780 r'WebContentsObserver|WebContentsUserData')
5781 # A subset of WebContentsObserver overrides where there's particular risk for
5782 # confusing tab and page level operations and data (e.g. incorrectly
5783 # resetting page state in DidFinishNavigation).
5784 concerning_wco_methods = [
5785 'DidStartNavigation',
5786 'ReadyToCommitNavigation',
5787 'DidFinishNavigation',
5788 'RenderViewReady',
5789 'RenderViewDeleted',
5790 'RenderViewHostChanged',
5791 'PrimaryMainDocumentElementAvailable',
5792 'DocumentOnLoadCompletedInPrimaryMainFrame',
5793 'DOMContentLoaded',
5794 'DidFinishLoad',
5795 ]
5796 concerning_nav_handle_methods = [
5797 'IsInMainFrame',
5798 ]
5799 concerning_web_contents_methods = [
5800 'ForEachFrame',
5801 'GetAllFrames',
5802 'FromRenderFrameHost',
5803 'FromRenderViewHost',
5804 'GetMainFrame',
5805 'GetRenderViewHost',
5806 ]
5807 concerning_rfh_methods = [
5808 'GetParent',
5809 'GetMainFrame',
5810 'GetFrameTreeNodeId',
5811 ]
Ian Vollickc825b1f2022-04-19 14:30:155812 concerning_rfhi_methods = [
5813 'is_main_frame',
5814 ]
Ian Vollicka77a73ea2022-04-06 18:08:015815 concerning_ftn_methods = [
5816 'IsMainFrame',
5817 ]
Ian Vollickdba956c2022-04-20 23:53:455818 concerning_blink_frame_methods = [
5819 'IsCrossOriginToMainFrame',
5820 ]
Sam Maiera6e76d72022-02-11 21:43:505821 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5822 item for sublist in [
5823 concerning_wco_methods, concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:015824 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:155825 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:455826 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:505827 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:295828
Kevin McNee4eeec792022-02-14 20:02:045829 used_apis = set()
Sam Maiera6e76d72022-02-11 21:43:505830 for f in input_api.AffectedFiles(include_deletes=False,
5831 file_filter=source_file_filter):
5832 for line_num, line in f.ChangedContents():
Kevin McNee4eeec792022-02-14 20:02:045833 class_match = concerning_class_pattern.search(line)
5834 if class_match:
5835 used_apis.add(class_match[0])
5836 method_match = concerning_method_pattern.search(line)
5837 if method_match:
5838 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:505839
Kevin McNee4eeec792022-02-14 20:02:045840 if not used_apis:
5841 return []
Kevin McNee967dd2d22021-11-15 16:09:295842
Kevin McNee4eeec792022-02-14 20:02:045843 output_api.AppendCC('[email protected]')
5844 message = ('This change uses API(s) that are ambiguous in the presence of '
5845 'MPArch features such as bfcache, prerendering, and fenced '
5846 'frames.')
5847 explaination = (
5848 'Please double check whether new code assumes that a WebContents only '
5849 'contains a single page at a time. For example, it is discouraged to '
5850 'reset per-document state in response to the observation of a '
5851 'navigation. See this doc [1] and the comments on the individual APIs '
5852 'for guidance and this doc [2] for context. The MPArch review '
5853 'watchlist has been CC\'d on this change to help identify any issues.\n'
5854 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
5855 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
5856 )
5857 return [
5858 output_api.PresubmitNotifyResult(message,
5859 items=list(used_apis),
5860 long_text=explaination)
5861 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:365862
5863
5864def CheckAssertAshOnlyCode(input_api, output_api):
5865 """Errors if a BUILD.gn file in an ash/ directory doesn't include
5866 assert(is_chromeos_ash).
5867 """
5868
5869 def FileFilter(affected_file):
5870 """Includes directories known to be Ash only."""
5871 return input_api.FilterSourceFile(
5872 affected_file,
5873 files_to_check=(
5874 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
5875 r'.*/ash/.*BUILD\.gn'), # Any path component.
5876 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
5877
5878 errors = []
5879 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:565880 for f in input_api.AffectedFiles(include_deletes=False,
5881 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:365882 if (not pattern.search(input_api.ReadFile(f))):
5883 errors.append(
5884 output_api.PresubmitError(
5885 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
5886 'possible, please create and issue and add a comment such '
5887 'as:\n # TODO(https://crbug.com/XXX): add '
5888 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
5889 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:275890
5891
5892def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:505893 path = affected_file.LocalPath()
5894 if not _IsCPlusPlusFile(input_api, path):
5895 return False
5896
5897 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
5898 if "/renderer/" in path:
5899 return True
5900
5901 # Blink's public/web API is only used/included by Renderer-only code. Note
5902 # that public/platform API may be used in non-Renderer processes (e.g. there
5903 # are some includes in code used by Utility, PDF, or Plugin processes).
5904 if "/blink/public/web/" in path:
5905 return True
5906
5907 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:275908 return False
5909
Lukasz Anforowicz7016d05e2021-11-30 03:56:275910# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
5911# by the Chromium Clang Plugin (which will be preferable because it will
5912# 1) report errors earlier - at compile-time and 2) cover more rules).
5913def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505914 """Rough checks that raw_ptr<T> usage guidelines are followed."""
5915 errors = []
5916 # The regex below matches "raw_ptr<" following a word boundary, but not in a
5917 # C++ comment.
5918 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
5919 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
5920 for f, line_num, line in input_api.RightHandSideLines(file_filter):
5921 if raw_ptr_matcher.search(line):
5922 errors.append(
5923 output_api.PresubmitError(
5924 'Problem on {path}:{line} - '\
5925 'raw_ptr<T> should not be used in Renderer-only code '\
5926 '(as documented in the "Pointers to unprotected memory" '\
5927 'section in //base/memory/raw_ptr.md)'.format(
5928 path=f.LocalPath(), line=line_num)))
5929 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:565930
5931
5932def CheckPythonShebang(input_api, output_api):
5933 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
5934 system-wide python.
5935 """
5936 errors = []
5937 sources = lambda affected_file: input_api.FilterSourceFile(
5938 affected_file,
5939 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
5940 r'third_party/blink/web_tests/external/') + input_api.
5941 DEFAULT_FILES_TO_SKIP),
5942 files_to_check=[r'.*\.py$'])
5943 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:275944 for line_num, line in f.ChangedContents():
5945 if line_num == 1 and line.startswith('#!/usr/bin/python'):
5946 errors.append(f.LocalPath())
5947 break
Henrique Ferreirof9819f2e32021-11-30 13:31:565948
5949 result = []
5950 for file in errors:
5951 result.append(
5952 output_api.PresubmitError(
5953 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
5954 file))
5955 return result