blob: 34b41e74efe9477b180757c1b56cbdd3ad55353d [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
11from typing import Optional
12from typing import Sequence
13from dataclasses import dataclass
14
Saagar Sanghavifceeaae2020-08-12 16:40:3615PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1216
Dirk Prankee3c9c62d2021-05-18 18:35:5917# This line is 'magic' in that git-cl looks for it to decide whether to
18# use Python3 instead of Python2 when running the code in this file.
19USE_PYTHON3 = True
20
[email protected]379e7dd2010-01-28 17:39:2121_EXCLUDED_PATHS = (
Mila Greene3aa7222021-09-07 16:34:0822 # File needs to write to stdout to emulate a tool it's replacing.
Mila Greend3fc6a42021-09-10 17:38:2323 r"chrome[\\/]updater[\\/]mac[\\/]keystone[\\/]ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4724 # Generated file.
25 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2626 r"client_variations.js"),
Mila Greene3aa7222021-09-07 16:34:0827 r"^native_client_sdksrc[\\/]build_tools[\\/]make_rules.py",
Egor Paskoce145c42018-09-28 19:31:0428 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
29 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
30 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
31 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4932 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0433 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4634 # sqlite is an imported third party dependency.
35 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0436 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5437 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5338 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1239 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0440 r".+[\\/]pnacl_shim\.c$",
41 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0442 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1443 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0444 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5445 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0446 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4047)
[email protected]ca8d1982009-02-19 16:33:1248
John Abd-El-Malek759fea62021-03-13 03:41:1449_EXCLUDED_SET_NO_PARENT_PATHS = (
50 # It's for historical reasons that blink isn't a top level directory, where
51 # it would be allowed to have "set noparent" to avoid top level owners
52 # accidentally +1ing changes.
53 'third_party/blink/OWNERS',
54)
55
wnwenbdc444e2016-05-25 13:44:1556
[email protected]06e6d0ff2012-12-11 01:36:4457# Fragment of a regular expression that matches C++ and Objective-C++
58# implementation files.
59_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
60
wnwenbdc444e2016-05-25 13:44:1561
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1962# Fragment of a regular expression that matches C++ and Objective-C++
63# header files.
64_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
65
66
[email protected]06e6d0ff2012-12-11 01:36:4467# Regular expression that matches code only used for test binaries
68# (best effort).
69_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0470 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4471 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1372 # Test suite files, like:
73 # foo_browsertest.cc
74 # bar_unittest_mac.cc (suffix)
75 # baz_unittests.cc (plural)
76 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1277 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1878 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2179 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0480 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4381 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0482 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4383 # Web test harness.
84 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4785 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0486 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0887 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0488 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4189 # EarlGrey app side code for tests.
90 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1791 # Views Examples code
92 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4193 # Chromium Codelab
94 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4495)
[email protected]ca8d1982009-02-19 16:33:1296
Daniel Bratell609102be2019-03-27 20:53:2197_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1598
[email protected]eea609a2011-11-18 13:10:1299_TEST_ONLY_WARNING = (
100 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55101 'production code. If you are doing this from inside another method\n'
102 'named as *ForTesting(), then consider exposing things to have tests\n'
103 'make that same call directly.\n'
104 'If that is not possible, you may put a comment on the same line with\n'
105 ' // IN-TEST \n'
106 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
107 'method and can be ignored. Do not do this inside production code.\n'
108 'The android-binary-size trybot will block if the method exists in the\n'
109 'release apk.')
[email protected]eea609a2011-11-18 13:10:12110
111
Daniel Chenga44a1bcd2022-03-15 20:00:15112@dataclass
113class BanRule:
114 # String pattern. If the pattern begins with a slash, the pattern will be
115 # treated as a regular expression instead.
116 pattern: str
117 # Explanation as a sequence of strings. Each string in the sequence will be
118 # printed on its own line.
119 explanation: Sequence[str]
120 # Whether or not to treat this ban as a fatal error. If unspecified, defaults
121 # to true.
122 treat_as_error: Optional[bool] = None
123 # Paths that should be excluded from the ban check. Each string is a regular
124 # expression that will be matched against the path of the file being checked
125 # relative to the root of the source tree.
126 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28127
Daniel Chenga44a1bcd2022-03-15 20:00:15128
Daniel Cheng917ce542022-03-15 20:46:57129_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15130 BanRule(
131 'import java.net.URI;',
132 (
133 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
134 ),
135 excluded_paths=(
136 (r'net/android/javatests/src/org/chromium/net/'
137 'AndroidProxySelectorTest\.java'),
138 r'components/cronet/',
139 r'third_party/robolectric/local/',
140 ),
Michael Thiessen44457642020-02-06 00:24:15141 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15142 BanRule(
143 'import android.annotation.TargetApi;',
144 (
145 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
146 'RequiresApi ensures that any calls are guarded by the appropriate '
147 'SDK_INT check. See https://crbug.com/1116486.',
148 ),
149 ),
150 BanRule(
151 'import android.support.test.rule.UiThreadTestRule;',
152 (
153 'Do not use UiThreadTestRule, just use '
154 '@org.chromium.base.test.UiThreadTest on test methods that should run '
155 'on the UI thread. See https://crbug.com/1111893.',
156 ),
157 ),
158 BanRule(
159 'import android.support.test.annotation.UiThreadTest;',
160 ('Do not use android.support.test.annotation.UiThreadTest, use '
161 'org.chromium.base.test.UiThreadTest instead. See '
162 'https://crbug.com/1111893.',
163 ),
164 ),
165 BanRule(
166 'import android.support.test.rule.ActivityTestRule;',
167 (
168 'Do not use ActivityTestRule, use '
169 'org.chromium.base.test.BaseActivityTestRule instead.',
170 ),
171 excluded_paths=(
172 'components/cronet/',
173 ),
174 ),
175)
wnwenbdc444e2016-05-25 13:44:15176
Daniel Cheng917ce542022-03-15 20:46:57177_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15178 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41179 'StrictMode.allowThreadDiskReads()',
180 (
181 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
182 'directly.',
183 ),
184 False,
185 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15186 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41187 'StrictMode.allowThreadDiskWrites()',
188 (
189 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
190 'directly.',
191 ),
192 False,
193 ),
Daniel Cheng917ce542022-03-15 20:46:57194 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36195 '.waitForIdleSync()',
196 (
197 'Do not use waitForIdleSync as it masks underlying issues. There is '
198 'almost always something else you should wait on instead.',
199 ),
200 False,
201 ),
Eric Stevensona9a980972017-09-23 00:04:41202)
203
Daniel Cheng917ce542022-03-15 20:46:57204_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15205 BanRule(
[email protected]127f18ec2012-06-16 05:05:59206 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20207 (
208 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59209 'prohibited. Please use CrTrackingArea instead.',
210 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
211 ),
212 False,
213 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15214 BanRule(
[email protected]eaae1972014-04-16 04:17:26215 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20216 (
217 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59218 'instead.',
219 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
220 ),
221 False,
222 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15223 BanRule(
[email protected]127f18ec2012-06-16 05:05:59224 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20225 (
226 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59227 'Please use |convertPoint:(point) fromView:nil| instead.',
228 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
229 ),
230 True,
231 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15232 BanRule(
[email protected]127f18ec2012-06-16 05:05:59233 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20234 (
235 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59236 'Please use |convertPoint:(point) toView:nil| instead.',
237 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
238 ),
239 True,
240 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15241 BanRule(
[email protected]127f18ec2012-06-16 05:05:59242 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20243 (
244 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59245 'Please use |convertRect:(point) fromView:nil| instead.',
246 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
247 ),
248 True,
249 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15250 BanRule(
[email protected]127f18ec2012-06-16 05:05:59251 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20252 (
253 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59254 'Please use |convertRect:(point) toView:nil| instead.',
255 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
256 ),
257 True,
258 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15259 BanRule(
[email protected]127f18ec2012-06-16 05:05:59260 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20261 (
262 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59263 'Please use |convertSize:(point) fromView:nil| instead.',
264 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
265 ),
266 True,
267 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15268 BanRule(
[email protected]127f18ec2012-06-16 05:05:59269 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20270 (
271 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59272 'Please use |convertSize:(point) toView:nil| instead.',
273 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
274 ),
275 True,
276 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15277 BanRule(
jif65398702016-10-27 10:19:48278 r"/\s+UTF8String\s*]",
279 (
280 'The use of -[NSString UTF8String] is dangerous as it can return null',
281 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
282 'Please use |SysNSStringToUTF8| instead.',
283 ),
284 True,
285 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15286 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34287 r'__unsafe_unretained',
288 (
289 'The use of __unsafe_unretained is almost certainly wrong, unless',
290 'when interacting with NSFastEnumeration or NSInvocation.',
291 'Please use __weak in files build with ARC, nothing otherwise.',
292 ),
293 False,
294 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15295 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13296 'freeWhenDone:NO',
297 (
298 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
299 'Foundation types is prohibited.',
300 ),
301 True,
302 ),
[email protected]127f18ec2012-06-16 05:05:59303)
304
Sylvain Defresnea8b73d252018-02-28 15:45:54305_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15306 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54307 r'/\bTEST[(]',
308 (
309 'TEST() macro should not be used in Objective-C++ code as it does not ',
310 'drain the autorelease pool at the end of the test. Use TEST_F() ',
311 'macro instead with a fixture inheriting from PlatformTest (or a ',
312 'typedef).'
313 ),
314 True,
315 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15316 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54317 r'/\btesting::Test\b',
318 (
319 'testing::Test should not be used in Objective-C++ code as it does ',
320 'not drain the autorelease pool at the end of the test. Use ',
321 'PlatformTest instead.'
322 ),
323 True,
324 ),
325)
326
Daniel Cheng917ce542022-03-15 20:46:57327_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15328 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05329 r'/\bEXPECT_OCMOCK_VERIFY\b',
330 (
331 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
332 'it is meant for GTests. Use [mock verify] instead.'
333 ),
334 True,
335 ),
336)
337
Daniel Cheng917ce542022-03-15 20:46:57338_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15339 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04340 r'/\busing namespace ',
341 (
342 'Using directives ("using namespace x") are banned by the Google Style',
343 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
344 'Explicitly qualify symbols or use using declarations ("using x::foo").',
345 ),
346 True,
347 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
348 ),
Antonio Gomes07300d02019-03-13 20:59:57349 # Make sure that gtest's FRIEND_TEST() macro is not used; the
350 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
351 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15352 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20353 'FRIEND_TEST(',
354 (
[email protected]e3c945502012-06-26 20:01:49355 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20356 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
357 ),
358 False,
[email protected]7345da02012-11-27 14:31:49359 (),
[email protected]23e6cbc2012-06-16 18:51:20360 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15361 BanRule(
tomhudsone2c14d552016-05-26 17:07:46362 'setMatrixClip',
363 (
364 'Overriding setMatrixClip() is prohibited; ',
365 'the base function is deprecated. ',
366 ),
367 True,
368 (),
369 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15370 BanRule(
[email protected]52657f62013-05-20 05:30:31371 'SkRefPtr',
372 (
373 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22374 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31375 ),
376 True,
377 (),
378 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15379 BanRule(
[email protected]52657f62013-05-20 05:30:31380 'SkAutoRef',
381 (
382 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22383 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31384 ),
385 True,
386 (),
387 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15388 BanRule(
[email protected]52657f62013-05-20 05:30:31389 'SkAutoTUnref',
390 (
391 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22392 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31393 ),
394 True,
395 (),
396 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15397 BanRule(
[email protected]52657f62013-05-20 05:30:31398 'SkAutoUnref',
399 (
400 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
401 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22402 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31403 ),
404 True,
405 (),
406 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15407 BanRule(
[email protected]d89eec82013-12-03 14:10:59408 r'/HANDLE_EINTR\(.*close',
409 (
410 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
411 'descriptor will be closed, and it is incorrect to retry the close.',
412 'Either call close directly and ignore its return value, or wrap close',
413 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
414 ),
415 True,
416 (),
417 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15418 BanRule(
[email protected]d89eec82013-12-03 14:10:59419 r'/IGNORE_EINTR\((?!.*close)',
420 (
421 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
422 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
423 ),
424 True,
425 (
426 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04427 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
428 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59429 ),
430 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15431 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43432 r'/v8::Extension\(',
433 (
434 'Do not introduce new v8::Extensions into the code base, use',
435 'gin::Wrappable instead. See http://crbug.com/334679',
436 ),
437 True,
[email protected]f55c90ee62014-04-12 00:50:03438 (
Egor Paskoce145c42018-09-28 19:31:04439 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03440 ),
[email protected]ec5b3f02014-04-04 18:43:43441 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15442 BanRule(
jame2d1a952016-04-02 00:27:10443 '#pragma comment(lib,',
444 (
445 'Specify libraries to link with in build files and not in the source.',
446 ),
447 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41448 (
tzik3f295992018-12-04 20:32:23449 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04450 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41451 ),
jame2d1a952016-04-02 00:27:10452 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15453 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02454 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59455 (
456 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
457 ),
458 False,
459 (),
460 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15461 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02462 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59463 (
464 'Consider using THREAD_CHECKER macros instead of the class directly.',
465 ),
466 False,
467 (),
468 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15469 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06470 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
471 (
472 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
473 'deprecated (http://crbug.com/634507). Please avoid converting away',
474 'from the Time types in Chromium code, especially if any math is',
475 'being done on time values. For interfacing with platform/library',
476 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
477 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48478 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06479 'other use cases, please contact base/time/OWNERS.',
480 ),
481 False,
482 (),
483 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15484 BanRule(
dbeamb6f4fde2017-06-15 04:03:06485 'CallJavascriptFunctionUnsafe',
486 (
487 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
488 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
489 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
490 ),
491 False,
492 (
Egor Paskoce145c42018-09-28 19:31:04493 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
494 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
495 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06496 ),
497 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15498 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24499 'leveldb::DB::Open',
500 (
501 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
502 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
503 "Chrome's tracing, making their memory usage visible.",
504 ),
505 True,
506 (
507 r'^third_party/leveldatabase/.*\.(cc|h)$',
508 ),
Gabriel Charette0592c3a2017-07-26 12:02:04509 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15510 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08511 'leveldb::NewMemEnv',
512 (
513 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58514 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
515 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08516 ),
517 True,
518 (
519 r'^third_party/leveldatabase/.*\.(cc|h)$',
520 ),
521 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15522 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47523 'RunLoop::QuitCurrent',
524 (
Robert Liao64b7ab22017-08-04 23:03:43525 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
526 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47527 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41528 False,
Gabriel Charetted9839bc2017-07-29 14:17:47529 (),
Gabriel Charettea44975052017-08-21 23:14:04530 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15531 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04532 'base::ScopedMockTimeMessageLoopTaskRunner',
533 (
Gabriel Charette87cc1af2018-04-25 20:52:51534 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11535 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51536 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
537 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
538 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04539 ),
Gabriel Charette87cc1af2018-04-25 20:52:51540 False,
Gabriel Charettea44975052017-08-21 23:14:04541 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15543 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44544 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57545 (
546 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02547 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57548 ),
549 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16550 # Abseil's benchmarks never linked into chrome.
551 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38552 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15553 BanRule(
Peter Kasting991618a62019-06-17 22:00:09554 r'/\bstd::stoi\b',
555 (
556 'std::stoi uses exceptions to communicate results. ',
557 'Use base::StringToInt() instead.',
558 ),
559 True,
560 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
561 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15562 BanRule(
Peter Kasting991618a62019-06-17 22:00:09563 r'/\bstd::stol\b',
564 (
565 'std::stol uses exceptions to communicate results. ',
566 'Use base::StringToInt() instead.',
567 ),
568 True,
569 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
570 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15571 BanRule(
Peter Kasting991618a62019-06-17 22:00:09572 r'/\bstd::stoul\b',
573 (
574 'std::stoul uses exceptions to communicate results. ',
575 'Use base::StringToUint() instead.',
576 ),
577 True,
578 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
579 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15580 BanRule(
Peter Kasting991618a62019-06-17 22:00:09581 r'/\bstd::stoll\b',
582 (
583 'std::stoll uses exceptions to communicate results. ',
584 'Use base::StringToInt64() instead.',
585 ),
586 True,
587 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
588 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15589 BanRule(
Peter Kasting991618a62019-06-17 22:00:09590 r'/\bstd::stoull\b',
591 (
592 'std::stoull uses exceptions to communicate results. ',
593 'Use base::StringToUint64() instead.',
594 ),
595 True,
596 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
597 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15598 BanRule(
Peter Kasting991618a62019-06-17 22:00:09599 r'/\bstd::stof\b',
600 (
601 'std::stof uses exceptions to communicate results. ',
602 'For locale-independent values, e.g. reading numbers from disk',
603 'profiles, use base::StringToDouble().',
604 'For user-visible values, parse using ICU.',
605 ),
606 True,
607 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
608 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15609 BanRule(
Peter Kasting991618a62019-06-17 22:00:09610 r'/\bstd::stod\b',
611 (
612 'std::stod uses exceptions to communicate results. ',
613 'For locale-independent values, e.g. reading numbers from disk',
614 'profiles, use base::StringToDouble().',
615 'For user-visible values, parse using ICU.',
616 ),
617 True,
618 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
619 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15620 BanRule(
Peter Kasting991618a62019-06-17 22:00:09621 r'/\bstd::stold\b',
622 (
623 'std::stold uses exceptions to communicate results. ',
624 'For locale-independent values, e.g. reading numbers from disk',
625 'profiles, use base::StringToDouble().',
626 'For user-visible values, parse using ICU.',
627 ),
628 True,
629 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
630 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15631 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45632 r'/\bstd::to_string\b',
633 (
634 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09635 'For locale-independent strings, e.g. writing numbers to disk',
636 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45637 'For user-visible strings, use base::FormatNumber() and',
638 'the related functions in base/i18n/number_formatting.h.',
639 ),
Peter Kasting991618a62019-06-17 22:00:09640 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21641 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45642 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15643 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45644 r'/\bstd::shared_ptr\b',
645 (
646 'std::shared_ptr should not be used. Use scoped_refptr instead.',
647 ),
648 True,
Ulan Degenbaev947043882021-02-10 14:02:31649 [
650 # Needed for interop with third-party library.
651 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57652 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58653 '^third_party/blink/renderer/bindings/core/v8/' +
654 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58655 '^gin/array_buffer\.(cc|h)',
656 '^chrome/services/sharing/nearby/',
Meilin Wang00efc7c2021-05-13 01:12:42657 # gRPC provides some C++ libraries that use std::shared_ptr<>.
658 '^chromeos/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59659 '^chromecast/cast_core/grpc',
660 '^chromecast/cast_core/runtime/browser',
Wez5f56be52021-05-04 09:30:58661 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Fabrice de Gans3b875422022-04-19 19:40:26662 '^base/fuchsia/filtered_service_directory\.(cc|h)',
663 '^base/fuchsia/service_directory_test_base\.h',
Wez5f56be52021-05-04 09:30:58664 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57665 # Needed for clang plugin tests
666 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57667 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21668 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15669 BanRule(
Peter Kasting991618a62019-06-17 22:00:09670 r'/\bstd::weak_ptr\b',
671 (
672 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
673 ),
674 True,
675 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
676 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15677 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21678 r'/\blong long\b',
679 (
680 'long long is banned. Use stdint.h if you need a 64 bit number.',
681 ),
682 False, # Only a warning since it is already used.
683 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
684 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15685 BanRule(
Daniel Chengc05fcc62022-01-12 16:54:29686 r'\b(absl|std)::any\b',
687 (
Daniel Chenga44a1bcd2022-03-15 20:00:15688 'absl::any / std::any are not safe to use in a component build.',
Daniel Chengc05fcc62022-01-12 16:54:29689 ),
690 True,
691 # Not an error in third party folders, though it probably should be :)
692 [_THIRD_PARTY_EXCEPT_BLINK],
693 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15694 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21695 r'/\bstd::bind\b',
696 (
697 'std::bind is banned because of lifetime risks.',
698 'Use base::BindOnce or base::BindRepeating instead.',
699 ),
700 True,
701 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
702 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15703 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:03704 r'/\bstd::optional\b',
705 (
706 'std::optional is banned. Use absl::optional instead.',
707 ),
708 True,
709 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
710 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15711 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21712 r'/\b#include <chrono>\b',
713 (
714 '<chrono> overlaps with Time APIs in base. Keep using',
715 'base classes.',
716 ),
717 True,
718 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
719 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15720 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21721 r'/\b#include <exception>\b',
722 (
723 'Exceptions are banned and disabled in Chromium.',
724 ),
725 True,
726 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
727 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15728 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21729 r'/\bstd::function\b',
730 (
Colin Blundellea615d422021-05-12 09:35:41731 'std::function is banned. Instead use base::OnceCallback or ',
732 'base::RepeatingCallback, which directly support Chromium\'s weak ',
733 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21734 ),
Peter Kasting991618a62019-06-17 22:00:09735 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21736 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
737 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15738 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21739 r'/\b#include <random>\b',
740 (
741 'Do not use any random number engines from <random>. Instead',
742 'use base::RandomBitGenerator.',
743 ),
744 True,
745 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
746 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15747 BanRule(
Tom Andersona95e12042020-09-09 23:08:00748 r'/\b#include <X11/',
749 (
750 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
751 ),
752 True,
753 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
754 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15755 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21756 r'/\bstd::ratio\b',
757 (
758 'std::ratio is banned by the Google Style Guide.',
759 ),
760 True,
761 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45762 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15763 BanRule(
Gabriel Charetted90bcc92021-09-21 00:23:10764 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:38765 (
Gabriel Charetted90bcc92021-09-21 00:23:10766 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:38767 ),
Gabriel Charette04b138f2018-08-06 00:03:22768 False,
Francois Doray43670e32017-09-27 12:40:38769 (),
770 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15771 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:58772 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19773 (
774 'RunMessageLoop is deprecated, use RunLoop instead.',
775 ),
776 False,
777 (),
778 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15779 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44780 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19781 (
782 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
783 ),
784 False,
785 (),
786 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15787 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44788 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19789 (
790 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
791 "if you're convinced you need this.",
792 ),
793 False,
794 (),
795 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15796 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44797 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19798 (
799 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04800 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19801 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
802 'async events instead of flushing threads.',
803 ),
804 False,
805 (),
806 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15807 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:19808 r'MessageLoopRunner',
809 (
810 'MessageLoopRunner is deprecated, use RunLoop instead.',
811 ),
812 False,
813 (),
814 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15815 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44816 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19817 (
818 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
819 "gab@ if you found a use case where this is the only solution.",
820 ),
821 False,
822 (),
823 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15824 BanRule(
Victor Costane48a2e82019-03-15 22:02:34825 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16826 (
Victor Costane48a2e82019-03-15 22:02:34827 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16828 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
829 ),
830 True,
831 (
832 r'^sql/initialization\.(cc|h)$',
833 r'^third_party/sqlite/.*\.(c|cc|h)$',
834 ),
835 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15836 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44837 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47838 (
839 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
840 'base::RandomShuffle instead.'
841 ),
842 True,
843 (),
844 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15845 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24846 'ios/web/public/test/http_server',
847 (
848 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
849 ),
850 False,
851 (),
852 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15853 BanRule(
Robert Liao764c9492019-01-24 18:46:28854 'GetAddressOf',
855 (
856 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53857 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11858 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53859 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28860 ),
861 True,
862 (),
863 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15864 BanRule(
Ben Lewisa9514602019-04-29 17:53:05865 'SHFileOperation',
866 (
867 'SHFileOperation was deprecated in Windows Vista, and there are less ',
868 'complex functions to achieve the same goals. Use IFileOperation for ',
869 'any esoteric actions instead.'
870 ),
871 True,
872 (),
873 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15874 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:51875 'StringFromGUID2',
876 (
877 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24878 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51879 ),
880 True,
881 (
Daniel Chenga44a1bcd2022-03-15 20:00:15882 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:51883 ),
884 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15885 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:51886 'StringFromCLSID',
887 (
888 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24889 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51890 ),
891 True,
892 (
Daniel Chenga44a1bcd2022-03-15 20:00:15893 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:51894 ),
895 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15896 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13897 'kCFAllocatorNull',
898 (
899 'The use of kCFAllocatorNull with the NoCopy creation of ',
900 'CoreFoundation types is prohibited.',
901 ),
902 True,
903 (),
904 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15905 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:29906 'mojo::ConvertTo',
907 (
908 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
909 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
910 'StringTraits if you would like to convert between custom types and',
911 'the wire format of mojom types.'
912 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22913 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29914 (
Wezf89dec092019-09-11 19:38:33915 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
916 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29917 r'^third_party/blink/.*\.(cc|h)$',
918 r'^content/renderer/.*\.(cc|h)$',
919 ),
920 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15921 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:16922 'GetInterfaceProvider',
923 (
924 'InterfaceProvider is deprecated.',
925 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
926 'or Platform::GetBrowserInterfaceBroker.'
927 ),
928 False,
929 (),
930 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15931 BanRule(
Robert Liao1d78df52019-11-11 20:02:01932 'CComPtr',
933 (
934 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
935 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
936 'details.'
937 ),
938 False,
939 (),
940 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15941 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:20942 r'/\b(IFACE|STD)METHOD_?\(',
943 (
944 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
945 'Instead, always use IFACEMETHODIMP in the declaration.'
946 ),
947 False,
948 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
949 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15950 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:47951 'set_owned_by_client',
952 (
953 'set_owned_by_client is deprecated.',
954 'views::View already owns the child views by default. This introduces ',
955 'a competing ownership model which makes the code difficult to reason ',
956 'about. See http://crbug.com/1044687 for more details.'
957 ),
958 False,
959 (),
960 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15961 BanRule(
Peter Boström7ff41522021-07-29 03:43:27962 'RemoveAllChildViewsWithoutDeleting',
963 (
964 'RemoveAllChildViewsWithoutDeleting is deprecated.',
965 'This method is deemed dangerous as, unless raw pointers are re-added,',
966 'calls to this method introduce memory leaks.'
967 ),
968 False,
969 (),
970 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15971 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:12972 r'/\bTRACE_EVENT_ASYNC_',
973 (
974 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
975 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
976 ),
977 False,
978 (
979 r'^base/trace_event/.*',
980 r'^base/tracing/.*',
981 ),
982 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15983 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:43984 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
985 (
986 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
987 'dumps and may spam crash reports. Consider if the throttled',
988 'variants suffice instead.',
989 ),
990 False,
991 (),
992 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15993 BanRule(
Robert Liao22f66a52021-04-10 00:57:52994 'RoInitialize',
995 (
Robert Liao48018922021-04-16 23:03:02996 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:52997 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
998 'instead. See http://crbug.com/1197722 for more information.'
999 ),
1000 True,
Robert Liao48018922021-04-16 23:03:021001 (
Daniel Chenga44a1bcd2022-03-15 20:00:151002 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021003 ),
Robert Liao22f66a52021-04-10 00:57:521004 ),
[email protected]127f18ec2012-06-16 05:05:591005)
1006
Daniel Cheng92c15e32022-03-16 17:48:221007_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1008 BanRule(
1009 'handle<shared_buffer>',
1010 (
1011 'Please use one of the more specific shared memory types instead:',
1012 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1013 ' mojo_base.mojom.WritableSharedMemoryRegion',
1014 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1015 ),
1016 True,
1017 ),
1018)
1019
mlamouria82272622014-09-16 18:45:041020_IPC_ENUM_TRAITS_DEPRECATED = (
1021 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501022 'See http://www.chromium.org/Home/chromium-security/education/'
1023 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041024
Stephen Martinis97a394142018-06-07 23:06:051025_LONG_PATH_ERROR = (
1026 'Some files included in this CL have file names that are too long (> 200'
1027 ' characters). If committed, these files will cause issues on Windows. See'
1028 ' https://crbug.com/612667 for more details.'
1029)
1030
Shenghua Zhangbfaa38b82017-11-16 21:58:021031_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041032 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041033 r".*[\\/]BuildHooksAndroidImpl\.java",
1034 r".*[\\/]LicenseContentProvider\.java",
1035 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281036 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021037]
[email protected]127f18ec2012-06-16 05:05:591038
Mohamed Heikald048240a2019-11-12 16:57:371039# List of image extensions that are used as resources in chromium.
1040_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1041
Sean Kau46e29bc2017-08-28 16:31:161042# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401043_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041044 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401045 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041046 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1047 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041048 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431049 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
John Chen288dee02022-04-28 17:37:061050 r'^tools[\\/]perf[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161051]
1052
Andrew Grieveb773bad2020-06-05 18:00:381053# These are not checked on the public chromium-presubmit trybot.
1054# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041055# checkouts.
agrievef32bcc72016-04-04 14:57:401056_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381057 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381058]
1059
1060
1061_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101062 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041063 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361064 'base/android/jni_generator/jni_generator.pydeps',
1065 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361066 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041067 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361068 'build/android/gyp/aar.pydeps',
1069 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271070 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361071 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381072 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361073 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021074 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221075 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111076 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361077 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361078 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361079 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111080 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041081 'build/android/gyp/create_app_bundle_apks.pydeps',
1082 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361083 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121084 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091085 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221086 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001087 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361088 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421089 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041090 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361091 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361092 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211093 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361094 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361095 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361096 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581097 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361098 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141099 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261100 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471101 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011102 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041103 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361104 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361105 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101106 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361107 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221108 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361109 'build/android/gyp/proguard.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101110 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461111 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301112 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241113 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361114 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461115 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561116 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361117 'build/android/incremental_install/generate_android_manifest.pydeps',
1118 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041119 'build/android/resource_sizes.pydeps',
1120 'build/android/test_runner.pydeps',
1121 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361122 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361123 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321124 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271125 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1126 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041127 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001128 'components/cronet/tools/generate_javadoc.pydeps',
1129 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381130 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001131 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381132 'net/tools/testserver/testserver.pydeps',
Jonathan Lee10c06dea2022-05-02 23:13:321133 'testing/scripts/run_wpt_tests.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181134 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411135 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1136 'testing/merge_scripts/standard_gtest_merge.pydeps',
1137 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1138 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041139 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421140 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1141 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131142 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501143 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411144 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1145 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061146 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221147 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401148]
1149
wnwenbdc444e2016-05-25 13:44:151150
agrievef32bcc72016-04-04 14:57:401151_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1152
1153
Eric Boren6fd2b932018-01-25 15:05:081154# Bypass the AUTHORS check for these accounts.
1155_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591156 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451157 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591158 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521159 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231160 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471161 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Jieting Yang668bde92022-01-27 18:40:431162 'infra-try-recipes-tester', 'lacros-tracking-roller')
Eric Boren835d71f2018-09-07 21:09:041163 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271164 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041165 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161166 for s in ('chromium-internal-autoroll',)
1167 ) | set('%[email protected]' % s
1168 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081169
Matt Stark6ef08872021-07-29 01:21:461170_INVALID_GRD_FILE_LINE = [
1171 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1172]
Eric Boren6fd2b932018-01-25 15:05:081173
Daniel Bratell65b033262019-04-23 08:17:061174def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501175 """Returns True if this file contains C++-like code (and not Python,
1176 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061177
Sam Maiera6e76d72022-02-11 21:43:501178 ext = input_api.os_path.splitext(file_path)[1]
1179 # This list is compatible with CppChecker.IsCppFile but we should
1180 # consider adding ".c" to it. If we do that we can use this function
1181 # at more places in the code.
1182 return ext in (
1183 '.h',
1184 '.cc',
1185 '.cpp',
1186 '.m',
1187 '.mm',
1188 )
1189
Daniel Bratell65b033262019-04-23 08:17:061190
1191def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501192 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061193
1194
1195def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501196 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061197
1198
1199def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501200 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061201
Mohamed Heikal5e5b7922020-10-29 18:57:591202
Erik Staabc734cd7a2021-11-23 03:11:521203def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501204 ext = input_api.os_path.splitext(file_path)[1]
1205 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521206
1207
Mohamed Heikal5e5b7922020-10-29 18:57:591208def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501209 """Prevent additions of dependencies from the upstream repo on //clank."""
1210 # clank can depend on clank
1211 if input_api.change.RepositoryRoot().endswith('clank'):
1212 return []
1213 build_file_patterns = [
1214 r'(.+/)?BUILD\.gn',
1215 r'.+\.gni',
1216 ]
1217 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1218 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591219
Sam Maiera6e76d72022-02-11 21:43:501220 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591221
Sam Maiera6e76d72022-02-11 21:43:501222 def FilterFile(affected_file):
1223 return input_api.FilterSourceFile(affected_file,
1224 files_to_check=build_file_patterns,
1225 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591226
Sam Maiera6e76d72022-02-11 21:43:501227 problems = []
1228 for f in input_api.AffectedSourceFiles(FilterFile):
1229 local_path = f.LocalPath()
1230 for line_number, line in f.ChangedContents():
1231 if (bad_pattern.search(line)):
1232 problems.append('%s:%d\n %s' %
1233 (local_path, line_number, line.strip()))
1234 if problems:
1235 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1236 else:
1237 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591238
1239
Saagar Sanghavifceeaae2020-08-12 16:40:361240def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501241 """Attempts to prevent use of functions intended only for testing in
1242 non-testing code. For now this is just a best-effort implementation
1243 that ignores header files and may have some false positives. A
1244 better implementation would probably need a proper C++ parser.
1245 """
1246 # We only scan .cc files and the like, as the declaration of
1247 # for-testing functions in header files are hard to distinguish from
1248 # calls to such functions without a proper C++ parser.
1249 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191250
Sam Maiera6e76d72022-02-11 21:43:501251 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1252 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1253 base_function_pattern)
1254 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1255 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1256 exclusion_pattern = input_api.re.compile(
1257 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1258 (base_function_pattern, base_function_pattern))
1259 # Avoid a false positive in this case, where the method name, the ::, and
1260 # the closing { are all on different lines due to line wrapping.
1261 # HelperClassForTesting::
1262 # HelperClassForTesting(
1263 # args)
1264 # : member(0) {}
1265 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191266
Sam Maiera6e76d72022-02-11 21:43:501267 def FilterFile(affected_file):
1268 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1269 input_api.DEFAULT_FILES_TO_SKIP)
1270 return input_api.FilterSourceFile(
1271 affected_file,
1272 files_to_check=file_inclusion_pattern,
1273 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191274
Sam Maiera6e76d72022-02-11 21:43:501275 problems = []
1276 for f in input_api.AffectedSourceFiles(FilterFile):
1277 local_path = f.LocalPath()
1278 in_method_defn = False
1279 for line_number, line in f.ChangedContents():
1280 if (inclusion_pattern.search(line)
1281 and not comment_pattern.search(line)
1282 and not exclusion_pattern.search(line)
1283 and not allowlist_pattern.search(line)
1284 and not in_method_defn):
1285 problems.append('%s:%d\n %s' %
1286 (local_path, line_number, line.strip()))
1287 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191288
Sam Maiera6e76d72022-02-11 21:43:501289 if problems:
1290 return [
1291 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1292 ]
1293 else:
1294 return []
[email protected]55459852011-08-10 15:17:191295
1296
Saagar Sanghavifceeaae2020-08-12 16:40:361297def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501298 """This is a simplified version of
1299 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1300 """
1301 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1302 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1303 name_pattern = r'ForTest(s|ing)?'
1304 # Describes an occurrence of "ForTest*" inside a // comment.
1305 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1306 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1307 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1308 # Catch calls.
1309 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1310 # Ignore definitions. (Comments are ignored separately.)
1311 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231312
Sam Maiera6e76d72022-02-11 21:43:501313 problems = []
1314 sources = lambda x: input_api.FilterSourceFile(
1315 x,
1316 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1317 DEFAULT_FILES_TO_SKIP),
1318 files_to_check=[r'.*\.java$'])
1319 for f in input_api.AffectedFiles(include_deletes=False,
1320 file_filter=sources):
1321 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231322 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501323 for line_number, line in f.ChangedContents():
1324 if is_inside_javadoc and javadoc_end_re.search(line):
1325 is_inside_javadoc = False
1326 if not is_inside_javadoc and javadoc_start_re.search(line):
1327 is_inside_javadoc = True
1328 if is_inside_javadoc:
1329 continue
1330 if (inclusion_re.search(line) and not comment_re.search(line)
1331 and not annotation_re.search(line)
1332 and not exclusion_re.search(line)):
1333 problems.append('%s:%d\n %s' %
1334 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231335
Sam Maiera6e76d72022-02-11 21:43:501336 if problems:
1337 return [
1338 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1339 ]
1340 else:
1341 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231342
1343
Saagar Sanghavifceeaae2020-08-12 16:40:361344def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501345 """Checks to make sure no .h files include <iostream>."""
1346 files = []
1347 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1348 input_api.re.MULTILINE)
1349 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1350 if not f.LocalPath().endswith('.h'):
1351 continue
1352 contents = input_api.ReadFile(f)
1353 if pattern.search(contents):
1354 files.append(f)
[email protected]10689ca2011-09-02 02:31:541355
Sam Maiera6e76d72022-02-11 21:43:501356 if len(files):
1357 return [
1358 output_api.PresubmitError(
1359 'Do not #include <iostream> in header files, since it inserts static '
1360 'initialization into every file including the header. Instead, '
1361 '#include <ostream>. See http://crbug.com/94794', files)
1362 ]
1363 return []
1364
[email protected]10689ca2011-09-02 02:31:541365
Danil Chapovalov3518f362018-08-11 16:13:431366def _CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501367 """Checks no windows headers with StrCat redefined are included directly."""
1368 files = []
1369 pattern_deny = input_api.re.compile(
1370 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1371 input_api.re.MULTILINE)
1372 pattern_allow = input_api.re.compile(
1373 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
1374 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1375 contents = input_api.ReadFile(f)
1376 if pattern_deny.search(
1377 contents) and not pattern_allow.search(contents):
1378 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431379
Sam Maiera6e76d72022-02-11 21:43:501380 if len(files):
1381 return [
1382 output_api.PresubmitError(
1383 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1384 'directly since they pollute code with StrCat macro. Instead, '
1385 'include matching header from base/win. See http://crbug.com/856536',
1386 files)
1387 ]
1388 return []
Danil Chapovalov3518f362018-08-11 16:13:431389
[email protected]10689ca2011-09-02 02:31:541390
Saagar Sanghavifceeaae2020-08-12 16:40:361391def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501392 """Checks to make sure no source files use UNIT_TEST."""
1393 problems = []
1394 for f in input_api.AffectedFiles():
1395 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1396 continue
[email protected]72df4e782012-06-21 16:28:181397
Sam Maiera6e76d72022-02-11 21:43:501398 for line_num, line in f.ChangedContents():
1399 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1400 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181401
Sam Maiera6e76d72022-02-11 21:43:501402 if not problems:
1403 return []
1404 return [
1405 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1406 '\n'.join(problems))
1407 ]
1408
[email protected]72df4e782012-06-21 16:28:181409
Saagar Sanghavifceeaae2020-08-12 16:40:361410def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501411 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341412
Sam Maiera6e76d72022-02-11 21:43:501413 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1414 instead of DISABLED_. To filter false positives, reports are only generated
1415 if a corresponding MAYBE_ line exists.
1416 """
1417 problems = []
Dominic Battre033531052018-09-24 15:45:341418
Sam Maiera6e76d72022-02-11 21:43:501419 # The following two patterns are looked for in tandem - is a test labeled
1420 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1421 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1422 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341423
Sam Maiera6e76d72022-02-11 21:43:501424 # This is for the case that a test is disabled on all platforms.
1425 full_disable_pattern = input_api.re.compile(
1426 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1427 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341428
Sam Maiera6e76d72022-02-11 21:43:501429 for f in input_api.AffectedFiles(False):
1430 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1431 continue
Dominic Battre033531052018-09-24 15:45:341432
Sam Maiera6e76d72022-02-11 21:43:501433 # Search for MABYE_, DISABLE_ pairs.
1434 disable_lines = {} # Maps of test name to line number.
1435 maybe_lines = {}
1436 for line_num, line in f.ChangedContents():
1437 disable_match = disable_pattern.search(line)
1438 if disable_match:
1439 disable_lines[disable_match.group(1)] = line_num
1440 maybe_match = maybe_pattern.search(line)
1441 if maybe_match:
1442 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341443
Sam Maiera6e76d72022-02-11 21:43:501444 # Search for DISABLE_ occurrences within a TEST() macro.
1445 disable_tests = set(disable_lines.keys())
1446 maybe_tests = set(maybe_lines.keys())
1447 for test in disable_tests.intersection(maybe_tests):
1448 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341449
Sam Maiera6e76d72022-02-11 21:43:501450 contents = input_api.ReadFile(f)
1451 full_disable_match = full_disable_pattern.search(contents)
1452 if full_disable_match:
1453 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341454
Sam Maiera6e76d72022-02-11 21:43:501455 if not problems:
1456 return []
1457 return [
1458 output_api.PresubmitPromptWarning(
1459 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1460 '\n'.join(problems))
1461 ]
1462
Dominic Battre033531052018-09-24 15:45:341463
Nina Satragnof7660532021-09-20 18:03:351464def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501465 """Checks to make sure tests disabled conditionally are not missing a
1466 corresponding MAYBE_ prefix.
1467 """
1468 # Expect at least a lowercase character in the test name. This helps rule out
1469 # false positives with macros wrapping the actual tests name.
1470 define_maybe_pattern = input_api.re.compile(
1471 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191472 # The test_maybe_pattern needs to handle all of these forms. The standard:
1473 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1474 # With a wrapper macro around the test name:
1475 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1476 # And the odd-ball NACL_BROWSER_TEST_f format:
1477 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1478 # The optional E2E_ENABLED-style is handled with (\w*\()?
1479 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1480 # trailing ')'.
1481 test_maybe_pattern = (
1482 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501483 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1484 warnings = []
Nina Satragnof7660532021-09-20 18:03:351485
Sam Maiera6e76d72022-02-11 21:43:501486 # Read the entire files. We can't just read the affected lines, forgetting to
1487 # add MAYBE_ on a change would not show up otherwise.
1488 for f in input_api.AffectedFiles(False):
1489 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1490 continue
1491 contents = input_api.ReadFile(f)
1492 lines = contents.splitlines(True)
1493 current_position = 0
1494 warning_test_names = set()
1495 for line_num, line in enumerate(lines, start=1):
1496 current_position += len(line)
1497 maybe_match = define_maybe_pattern.search(line)
1498 if maybe_match:
1499 test_name = maybe_match.group('test_name')
1500 # Do not warn twice for the same test.
1501 if (test_name in warning_test_names):
1502 continue
1503 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351504
Sam Maiera6e76d72022-02-11 21:43:501505 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1506 # the current position.
1507 test_match = input_api.re.compile(
1508 test_maybe_pattern.format(test_name=test_name),
1509 input_api.re.MULTILINE).search(contents, current_position)
1510 suite_match = input_api.re.compile(
1511 suite_maybe_pattern.format(test_name=test_name),
1512 input_api.re.MULTILINE).search(contents, current_position)
1513 if not test_match and not suite_match:
1514 warnings.append(
1515 output_api.PresubmitPromptWarning(
1516 '%s:%d found MAYBE_ defined without corresponding test %s'
1517 % (f.LocalPath(), line_num, test_name)))
1518 return warnings
1519
[email protected]72df4e782012-06-21 16:28:181520
Saagar Sanghavifceeaae2020-08-12 16:40:361521def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501522 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1523 errors = []
1524 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
1525 input_api.re.MULTILINE)
1526 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1527 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1528 continue
1529 for lnum, line in f.ChangedContents():
1530 if input_api.re.search(pattern, line):
1531 errors.append(
1532 output_api.PresubmitError((
1533 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1534 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1535 (f.LocalPath(), lnum)))
1536 return errors
danakj61c1aa22015-10-26 19:55:521537
1538
Weilun Shia487fad2020-10-28 00:10:341539# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1540# more reliable way. See
1541# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191542
wnwenbdc444e2016-05-25 13:44:151543
Saagar Sanghavifceeaae2020-08-12 16:40:361544def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501545 """Check that FlakyTest annotation is our own instead of the android one"""
1546 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1547 files = []
1548 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1549 if f.LocalPath().endswith('Test.java'):
1550 if pattern.search(input_api.ReadFile(f)):
1551 files.append(f)
1552 if len(files):
1553 return [
1554 output_api.PresubmitError(
1555 'Use org.chromium.base.test.util.FlakyTest instead of '
1556 'android.test.FlakyTest', files)
1557 ]
1558 return []
mcasasb7440c282015-02-04 14:52:191559
wnwenbdc444e2016-05-25 13:44:151560
Saagar Sanghavifceeaae2020-08-12 16:40:361561def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501562 """Make sure .DEPS.git is never modified manually."""
1563 if any(f.LocalPath().endswith('.DEPS.git')
1564 for f in input_api.AffectedFiles()):
1565 return [
1566 output_api.PresubmitError(
1567 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1568 'automated system based on what\'s in DEPS and your changes will be\n'
1569 'overwritten.\n'
1570 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1571 'get-the-code#Rolling_DEPS\n'
1572 'for more information')
1573 ]
1574 return []
[email protected]2a8ac9c2011-10-19 17:20:441575
1576
Saagar Sanghavifceeaae2020-08-12 16:40:361577def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501578 """Checks that DEPS file deps are from allowed_hosts."""
1579 # Run only if DEPS file has been modified to annoy fewer bystanders.
1580 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1581 return []
1582 # Outsource work to gclient verify
1583 try:
1584 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
1585 'third_party', 'depot_tools',
1586 'gclient.py')
1587 input_api.subprocess.check_output(
1588 [input_api.python_executable, gclient_path, 'verify'],
1589 stderr=input_api.subprocess.STDOUT)
1590 return []
1591 except input_api.subprocess.CalledProcessError as error:
1592 return [
1593 output_api.PresubmitError(
1594 'DEPS file must have only git dependencies.',
1595 long_text=error.output)
1596 ]
tandriief664692014-09-23 14:51:471597
1598
Mario Sanchez Prada2472cab2019-09-18 10:58:311599def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151600 ban_rule):
Sam Maiera6e76d72022-02-11 21:43:501601 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311602
Sam Maiera6e76d72022-02-11 21:43:501603 Returns an string composed of the name of the file, the line number where the
1604 match has been found and the additional text passed as |message| in case the
1605 target type name matches the text inside the line passed as parameter.
1606 """
1607 result = []
Peng Huang9c5949a02020-06-11 19:20:541608
Daniel Chenga44a1bcd2022-03-15 20:00:151609 # Ignore comments about banned types.
1610 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:501611 return result
Daniel Chenga44a1bcd2022-03-15 20:00:151612 # A // nocheck comment will bypass this error.
1613 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:501614 return result
1615
1616 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:151617 if ban_rule.pattern[0:1] == '/':
1618 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:501619 if input_api.re.search(regex, line):
1620 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:151621 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:501622 matched = True
1623
1624 if matched:
1625 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:151626 for line in ban_rule.explanation:
1627 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:501628
danakjd18e8892020-12-17 17:42:011629 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:311630
1631
Saagar Sanghavifceeaae2020-08-12 16:40:361632def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501633 """Make sure that banned functions are not used."""
1634 warnings = []
1635 errors = []
[email protected]127f18ec2012-06-16 05:05:591636
Sam Maiera6e76d72022-02-11 21:43:501637 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:151638 if not excluded_paths:
1639 return False
1640
Sam Maiera6e76d72022-02-11 21:43:501641 local_path = affected_file.LocalPath()
1642 for item in excluded_paths:
1643 if input_api.re.match(item, local_path):
1644 return True
1645 return False
wnwenbdc444e2016-05-25 13:44:151646
Sam Maiera6e76d72022-02-11 21:43:501647 def IsIosObjcFile(affected_file):
1648 local_path = affected_file.LocalPath()
1649 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
1650 '.h'):
1651 return False
1652 basename = input_api.os_path.basename(local_path)
1653 if 'ios' in basename.split('_'):
1654 return True
1655 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1656 if sep and 'ios' in local_path.split(sep):
1657 return True
1658 return False
Sylvain Defresnea8b73d252018-02-28 15:45:541659
Daniel Chenga44a1bcd2022-03-15 20:00:151660 def CheckForMatch(affected_file, line_num: int, line: str,
1661 ban_rule: BanRule):
1662 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
1663 return
1664
Sam Maiera6e76d72022-02-11 21:43:501665 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151666 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501667 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:151668 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:501669 errors.extend(problems)
1670 else:
1671 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151672
Sam Maiera6e76d72022-02-11 21:43:501673 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1674 for f in input_api.AffectedFiles(file_filter=file_filter):
1675 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151676 for ban_rule in _BANNED_JAVA_FUNCTIONS:
1677 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:411678
Sam Maiera6e76d72022-02-11 21:43:501679 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1680 for f in input_api.AffectedFiles(file_filter=file_filter):
1681 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151682 for ban_rule in _BANNED_OBJC_FUNCTIONS:
1683 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591684
Sam Maiera6e76d72022-02-11 21:43:501685 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
1686 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151687 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
1688 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:541689
Sam Maiera6e76d72022-02-11 21:43:501690 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1691 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1692 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151693 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
1694 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:051695
Sam Maiera6e76d72022-02-11 21:43:501696 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1697 for f in input_api.AffectedFiles(file_filter=file_filter):
1698 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151699 for ban_rule in _BANNED_CPP_FUNCTIONS:
1700 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591701
Daniel Cheng92c15e32022-03-16 17:48:221702 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
1703 for f in input_api.AffectedFiles(file_filter=file_filter):
1704 for line_num, line in f.ChangedContents():
1705 for ban_rule in _BANNED_MOJOM_PATTERNS:
1706 CheckForMatch(f, line_num, line, ban_rule)
1707
1708
Sam Maiera6e76d72022-02-11 21:43:501709 result = []
1710 if (warnings):
1711 result.append(
1712 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
1713 '\n'.join(warnings)))
1714 if (errors):
1715 result.append(
1716 output_api.PresubmitError('Banned functions were used.\n' +
1717 '\n'.join(errors)))
1718 return result
[email protected]127f18ec2012-06-16 05:05:591719
1720
Michael Thiessen44457642020-02-06 00:24:151721def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501722 """Make sure that banned java imports are not used."""
1723 errors = []
Michael Thiessen44457642020-02-06 00:24:151724
Sam Maiera6e76d72022-02-11 21:43:501725 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1726 for f in input_api.AffectedFiles(file_filter=file_filter):
1727 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151728 for ban_rule in _BANNED_JAVA_IMPORTS:
1729 # Consider merging this into the above function. There is no
1730 # real difference anymore other than helping with a little
1731 # bit of boilerplate text. Doing so means things like
1732 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:501733 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:151734 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501735 if problems:
1736 errors.extend(problems)
1737 result = []
1738 if (errors):
1739 result.append(
1740 output_api.PresubmitError('Banned imports were used.\n' +
1741 '\n'.join(errors)))
1742 return result
Michael Thiessen44457642020-02-06 00:24:151743
1744
Saagar Sanghavifceeaae2020-08-12 16:40:361745def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501746 """Make sure that banned functions are not used."""
1747 files = []
1748 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
1749 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1750 if not f.LocalPath().endswith('.h'):
1751 continue
Bruce Dawson4c4c2922022-05-02 18:07:331752 if f.LocalPath().endswith('com_imported_mstscax.h'):
1753 continue
Sam Maiera6e76d72022-02-11 21:43:501754 contents = input_api.ReadFile(f)
1755 if pattern.search(contents):
1756 files.append(f)
[email protected]6c063c62012-07-11 19:11:061757
Sam Maiera6e76d72022-02-11 21:43:501758 if files:
1759 return [
1760 output_api.PresubmitError(
1761 'Do not use #pragma once in header files.\n'
1762 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1763 files)
1764 ]
1765 return []
[email protected]6c063c62012-07-11 19:11:061766
[email protected]127f18ec2012-06-16 05:05:591767
Saagar Sanghavifceeaae2020-08-12 16:40:361768def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501769 """Checks to make sure we don't introduce use of foo ? true : false."""
1770 problems = []
1771 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1772 for f in input_api.AffectedFiles():
1773 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1774 continue
[email protected]e7479052012-09-19 00:26:121775
Sam Maiera6e76d72022-02-11 21:43:501776 for line_num, line in f.ChangedContents():
1777 if pattern.match(line):
1778 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:121779
Sam Maiera6e76d72022-02-11 21:43:501780 if not problems:
1781 return []
1782 return [
1783 output_api.PresubmitPromptWarning(
1784 'Please consider avoiding the "? true : false" pattern if possible.\n'
1785 + '\n'.join(problems))
1786 ]
[email protected]e7479052012-09-19 00:26:121787
1788
Saagar Sanghavifceeaae2020-08-12 16:40:361789def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501790 """Runs checkdeps on #include and import statements added in this
1791 change. Breaking - rules is an error, breaking ! rules is a
1792 warning.
1793 """
1794 # Return early if no relevant file types were modified.
1795 for f in input_api.AffectedFiles():
1796 path = f.LocalPath()
1797 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
1798 or _IsJavaFile(input_api, path)):
1799 break
[email protected]55f9f382012-07-31 11:02:181800 else:
Sam Maiera6e76d72022-02-11 21:43:501801 return []
rhalavati08acd232017-04-03 07:23:281802
Sam Maiera6e76d72022-02-11 21:43:501803 import sys
1804 # We need to wait until we have an input_api object and use this
1805 # roundabout construct to import checkdeps because this file is
1806 # eval-ed and thus doesn't have __file__.
1807 original_sys_path = sys.path
1808 try:
1809 sys.path = sys.path + [
1810 input_api.os_path.join(input_api.PresubmitLocalPath(),
1811 'buildtools', 'checkdeps')
1812 ]
1813 import checkdeps
1814 from rules import Rule
1815 finally:
1816 # Restore sys.path to what it was before.
1817 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:181818
Sam Maiera6e76d72022-02-11 21:43:501819 added_includes = []
1820 added_imports = []
1821 added_java_imports = []
1822 for f in input_api.AffectedFiles():
1823 if _IsCPlusPlusFile(input_api, f.LocalPath()):
1824 changed_lines = [line for _, line in f.ChangedContents()]
1825 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
1826 elif _IsProtoFile(input_api, f.LocalPath()):
1827 changed_lines = [line for _, line in f.ChangedContents()]
1828 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
1829 elif _IsJavaFile(input_api, f.LocalPath()):
1830 changed_lines = [line for _, line in f.ChangedContents()]
1831 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241832
Sam Maiera6e76d72022-02-11 21:43:501833 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
1834
1835 error_descriptions = []
1836 warning_descriptions = []
1837 error_subjects = set()
1838 warning_subjects = set()
1839
1840 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1841 added_includes):
1842 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1843 description_with_path = '%s\n %s' % (path, rule_description)
1844 if rule_type == Rule.DISALLOW:
1845 error_descriptions.append(description_with_path)
1846 error_subjects.add("#includes")
1847 else:
1848 warning_descriptions.append(description_with_path)
1849 warning_subjects.add("#includes")
1850
1851 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1852 added_imports):
1853 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1854 description_with_path = '%s\n %s' % (path, rule_description)
1855 if rule_type == Rule.DISALLOW:
1856 error_descriptions.append(description_with_path)
1857 error_subjects.add("imports")
1858 else:
1859 warning_descriptions.append(description_with_path)
1860 warning_subjects.add("imports")
1861
1862 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
1863 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
1864 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1865 description_with_path = '%s\n %s' % (path, rule_description)
1866 if rule_type == Rule.DISALLOW:
1867 error_descriptions.append(description_with_path)
1868 error_subjects.add("imports")
1869 else:
1870 warning_descriptions.append(description_with_path)
1871 warning_subjects.add("imports")
1872
1873 results = []
1874 if error_descriptions:
1875 results.append(
1876 output_api.PresubmitError(
1877 'You added one or more %s that violate checkdeps rules.' %
1878 " and ".join(error_subjects), error_descriptions))
1879 if warning_descriptions:
1880 results.append(
1881 output_api.PresubmitPromptOrNotify(
1882 'You added one or more %s of files that are temporarily\n'
1883 'allowed but being removed. Can you avoid introducing the\n'
1884 '%s? See relevant DEPS file(s) for details and contacts.' %
1885 (" and ".join(warning_subjects), "/".join(warning_subjects)),
1886 warning_descriptions))
1887 return results
[email protected]55f9f382012-07-31 11:02:181888
1889
Saagar Sanghavifceeaae2020-08-12 16:40:361890def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501891 """Check that all files have their permissions properly set."""
1892 if input_api.platform == 'win32':
1893 return []
1894 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
1895 'tools', 'checkperms',
1896 'checkperms.py')
1897 args = [
1898 input_api.python_executable, checkperms_tool, '--root',
1899 input_api.change.RepositoryRoot()
1900 ]
1901 with input_api.CreateTemporaryFile() as file_list:
1902 for f in input_api.AffectedFiles():
1903 # checkperms.py file/directory arguments must be relative to the
1904 # repository.
1905 file_list.write((f.LocalPath() + '\n').encode('utf8'))
1906 file_list.close()
1907 args += ['--file-list', file_list.name]
1908 try:
1909 input_api.subprocess.check_output(args)
1910 return []
1911 except input_api.subprocess.CalledProcessError as error:
1912 return [
1913 output_api.PresubmitError('checkperms.py failed:',
1914 long_text=error.output.decode(
1915 'utf-8', 'ignore'))
1916 ]
[email protected]fbcafe5a2012-08-08 15:31:221917
1918
Saagar Sanghavifceeaae2020-08-12 16:40:361919def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501920 """Makes sure we don't include ui/aura/window_property.h
1921 in header files.
1922 """
1923 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1924 errors = []
1925 for f in input_api.AffectedFiles():
1926 if not f.LocalPath().endswith('.h'):
1927 continue
1928 for line_num, line in f.ChangedContents():
1929 if pattern.match(line):
1930 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:491931
Sam Maiera6e76d72022-02-11 21:43:501932 results = []
1933 if errors:
1934 results.append(
1935 output_api.PresubmitError(
1936 'Header files should not include ui/aura/window_property.h',
1937 errors))
1938 return results
[email protected]c8278b32012-10-30 20:35:491939
1940
Omer Katzcc77ea92021-04-26 10:23:281941def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501942 """Makes sure we don't include any headers from
1943 third_party/blink/renderer/platform/heap/impl or
1944 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1945 third_party/blink/renderer/platform/heap
1946 """
1947 impl_pattern = input_api.re.compile(
1948 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1949 v8_wrapper_pattern = input_api.re.compile(
1950 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
1951 )
1952 file_filter = lambda f: not input_api.re.match(
1953 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1954 f.LocalPath())
1955 errors = []
Omer Katzcc77ea92021-04-26 10:23:281956
Sam Maiera6e76d72022-02-11 21:43:501957 for f in input_api.AffectedFiles(file_filter=file_filter):
1958 for line_num, line in f.ChangedContents():
1959 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1960 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:281961
Sam Maiera6e76d72022-02-11 21:43:501962 results = []
1963 if errors:
1964 results.append(
1965 output_api.PresubmitError(
1966 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1967 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1968 'relevant counterparts from third_party/blink/renderer/platform/heap',
1969 errors))
1970 return results
Omer Katzcc77ea92021-04-26 10:23:281971
1972
[email protected]70ca77752012-11-20 03:45:031973def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:501974 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1975 errors = []
1976 for line_num, line in f.ChangedContents():
1977 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
1978 # First-level headers in markdown look a lot like version control
1979 # conflict markers. http://daringfireball.net/projects/markdown/basics
1980 continue
1981 if pattern.match(line):
1982 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1983 return errors
[email protected]70ca77752012-11-20 03:45:031984
1985
Saagar Sanghavifceeaae2020-08-12 16:40:361986def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501987 """Usually this is not intentional and will cause a compile failure."""
1988 errors = []
1989 for f in input_api.AffectedFiles():
1990 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:031991
Sam Maiera6e76d72022-02-11 21:43:501992 results = []
1993 if errors:
1994 results.append(
1995 output_api.PresubmitError(
1996 'Version control conflict markers found, please resolve.',
1997 errors))
1998 return results
[email protected]70ca77752012-11-20 03:45:031999
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202000
Saagar Sanghavifceeaae2020-08-12 16:40:362001def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502002 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2003 errors = []
2004 for f in input_api.AffectedFiles():
2005 for line_num, line in f.ChangedContents():
2006 if pattern.search(line):
2007 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162008
Sam Maiera6e76d72022-02-11 21:43:502009 results = []
2010 if errors:
2011 results.append(
2012 output_api.PresubmitPromptWarning(
2013 'Found Google support URL addressed by answer number. Please replace '
2014 'with a p= identifier instead. See crbug.com/679462\n',
2015 errors))
2016 return results
estadee17314a02017-01-12 16:22:162017
[email protected]70ca77752012-11-20 03:45:032018
Saagar Sanghavifceeaae2020-08-12 16:40:362019def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502020 def FilterFile(affected_file):
2021 """Filter function for use with input_api.AffectedSourceFiles,
2022 below. This filters out everything except non-test files from
2023 top-level directories that generally speaking should not hard-code
2024 service URLs (e.g. src/android_webview/, src/content/ and others).
2025 """
2026 return input_api.FilterSourceFile(
2027 affected_file,
2028 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2029 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2030 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442031
Sam Maiera6e76d72022-02-11 21:43:502032 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2033 '\.(com|net)[^"]*"')
2034 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2035 pattern = input_api.re.compile(base_pattern)
2036 problems = [] # items are (filename, line_number, line)
2037 for f in input_api.AffectedSourceFiles(FilterFile):
2038 for line_num, line in f.ChangedContents():
2039 if not comment_pattern.search(line) and pattern.search(line):
2040 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442041
Sam Maiera6e76d72022-02-11 21:43:502042 if problems:
2043 return [
2044 output_api.PresubmitPromptOrNotify(
2045 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2046 'Are you sure this is correct?', [
2047 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2048 for problem in problems
2049 ])
2050 ]
2051 else:
2052 return []
[email protected]06e6d0ff2012-12-11 01:36:442053
2054
Saagar Sanghavifceeaae2020-08-12 16:40:362055def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502056 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292057
Sam Maiera6e76d72022-02-11 21:43:502058 def FileFilter(affected_file):
2059 """Includes directories known to be Chrome OS only."""
2060 return input_api.FilterSourceFile(
2061 affected_file,
2062 files_to_check=(
2063 '^ash/',
2064 '^chromeos/', # Top-level src/chromeos.
2065 '.*/chromeos/', # Any path component.
2066 '^components/arc',
2067 '^components/exo'),
2068 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292069
Sam Maiera6e76d72022-02-11 21:43:502070 prefs = []
2071 priority_prefs = []
2072 for f in input_api.AffectedFiles(file_filter=FileFilter):
2073 for line_num, line in f.ChangedContents():
2074 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2075 line):
2076 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2077 prefs.append(' %s' % line)
2078 if input_api.re.search(
2079 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2080 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2081 priority_prefs.append(' %s' % line)
2082
2083 results = []
2084 if (prefs):
2085 results.append(
2086 output_api.PresubmitPromptWarning(
2087 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2088 'by browser sync settings. If these prefs should be controlled by OS '
2089 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2090 '\n'.join(prefs)))
2091 if (priority_prefs):
2092 results.append(
2093 output_api.PresubmitPromptWarning(
2094 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2095 'controlled by browser sync settings. If these prefs should be '
2096 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2097 'instead.\n' + '\n'.join(prefs)))
2098 return results
James Cook6b6597c2019-11-06 22:05:292099
2100
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492101# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362102def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502103 """Makes sure there are no abbreviations in the name of PNG files.
2104 The native_client_sdk directory is excluded because it has auto-generated PNG
2105 files for documentation.
2106 """
2107 errors = []
2108 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Bruce Dawson3db456212022-05-02 05:34:182109 files_to_skip = [r'^native_client_sdk[\\/]',
2110 r'^services[\\/]test[\\/]',
2111 r'^third_party[\\/]blink[\\/]web_tests[\\/]',
2112 ]
Sam Maiera6e76d72022-02-11 21:43:502113 file_filter = lambda f: input_api.FilterSourceFile(
2114 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2115 for f in input_api.AffectedFiles(include_deletes=False,
2116 file_filter=file_filter):
2117 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272118
Sam Maiera6e76d72022-02-11 21:43:502119 results = []
2120 if errors:
2121 results.append(
2122 output_api.PresubmitError(
2123 'The name of PNG files should not have abbreviations. \n'
2124 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2125 'Contact [email protected] if you have questions.', errors))
2126 return results
[email protected]d2530012013-01-25 16:39:272127
2128
Daniel Cheng4dcdb6b2017-04-13 08:30:172129def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502130 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172131
Sam Maiera6e76d72022-02-11 21:43:502132 Args:
2133 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2134 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172135 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502136 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172137 if rule.startswith('+') or rule.startswith('!')
2138 ])
Sam Maiera6e76d72022-02-11 21:43:502139 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2140 add_rules.update([
2141 rule[1:] for rule in rules
2142 if rule.startswith('+') or rule.startswith('!')
2143 ])
2144 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172145
2146
2147def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502148 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172149
Sam Maiera6e76d72022-02-11 21:43:502150 # Stubs for handling special syntax in the root DEPS file.
2151 class _VarImpl:
2152 def __init__(self, local_scope):
2153 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172154
Sam Maiera6e76d72022-02-11 21:43:502155 def Lookup(self, var_name):
2156 """Implements the Var syntax."""
2157 try:
2158 return self._local_scope['vars'][var_name]
2159 except KeyError:
2160 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172161
Sam Maiera6e76d72022-02-11 21:43:502162 local_scope = {}
2163 global_scope = {
2164 'Var': _VarImpl(local_scope).Lookup,
2165 'Str': str,
2166 }
Dirk Pranke1b9e06382021-05-14 01:16:222167
Sam Maiera6e76d72022-02-11 21:43:502168 exec(contents, global_scope, local_scope)
2169 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172170
2171
2172def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502173 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2174 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412175
Sam Maiera6e76d72022-02-11 21:43:502176 For a directory (rather than a specific filename) we fake a path to
2177 a specific filename by adding /DEPS. This is chosen as a file that
2178 will seldom or never be subject to per-file include_rules.
2179 """
2180 # We ignore deps entries on auto-generated directories.
2181 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082182
Sam Maiera6e76d72022-02-11 21:43:502183 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2184 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172185
Sam Maiera6e76d72022-02-11 21:43:502186 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172187
Sam Maiera6e76d72022-02-11 21:43:502188 results = set()
2189 for added_dep in added_deps:
2190 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2191 continue
2192 # Assume that a rule that ends in .h is a rule for a specific file.
2193 if added_dep.endswith('.h'):
2194 results.add(added_dep)
2195 else:
2196 results.add(os_path.join(added_dep, 'DEPS'))
2197 return results
[email protected]f32e2d1e2013-07-26 21:39:082198
2199
Saagar Sanghavifceeaae2020-08-12 16:40:362200def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502201 """When a dependency prefixed with + is added to a DEPS file, we
2202 want to make sure that the change is reviewed by an OWNER of the
2203 target file or directory, to avoid layering violations from being
2204 introduced. This check verifies that this happens.
2205 """
2206 # We rely on Gerrit's code-owners to check approvals.
2207 # input_api.gerrit is always set for Chromium, but other projects
2208 # might not use Gerrit.
2209 if not input_api.gerrit:
2210 return []
2211 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2212 input_api.change.issue)):
2213 # Skip OWNERS check when Owners-Override label is approved. This is intended
2214 # for global owners, trusted bots, and on-call sheriffs. Review is still
2215 # required for these changes.
2216 return []
Edward Lesmes6fba51082021-01-20 04:20:232217
Sam Maiera6e76d72022-02-11 21:43:502218 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242219
Sam Maiera6e76d72022-02-11 21:43:502220 file_filter = lambda f: not input_api.re.match(
2221 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
2222 for f in input_api.AffectedFiles(include_deletes=False,
2223 file_filter=file_filter):
2224 filename = input_api.os_path.basename(f.LocalPath())
2225 if filename == 'DEPS':
2226 virtual_depended_on_files.update(
2227 _CalculateAddedDeps(input_api.os_path,
2228 '\n'.join(f.OldContents()),
2229 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552230
Sam Maiera6e76d72022-02-11 21:43:502231 if not virtual_depended_on_files:
2232 return []
[email protected]e871964c2013-05-13 14:14:552233
Sam Maiera6e76d72022-02-11 21:43:502234 if input_api.is_committing:
2235 if input_api.tbr:
2236 return [
2237 output_api.PresubmitNotifyResult(
2238 '--tbr was specified, skipping OWNERS check for DEPS additions'
2239 )
2240 ]
2241 if input_api.dry_run:
2242 return [
2243 output_api.PresubmitNotifyResult(
2244 'This is a dry run, skipping OWNERS check for DEPS additions'
2245 )
2246 ]
2247 if not input_api.change.issue:
2248 return [
2249 output_api.PresubmitError(
2250 "DEPS approval by OWNERS check failed: this change has "
2251 "no change number, so we can't check it for approvals.")
2252 ]
2253 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412254 else:
Sam Maiera6e76d72022-02-11 21:43:502255 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552256
Sam Maiera6e76d72022-02-11 21:43:502257 owner_email, reviewers = (
2258 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2259 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552260
Sam Maiera6e76d72022-02-11 21:43:502261 owner_email = owner_email or input_api.change.author_email
2262
2263 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2264 virtual_depended_on_files, reviewers.union([owner_email]), [])
2265 missing_files = [
2266 f for f in virtual_depended_on_files
2267 if approval_status[f] != input_api.owners_client.APPROVED
2268 ]
2269
2270 # We strip the /DEPS part that was added by
2271 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2272 # directory.
2273 def StripDeps(path):
2274 start_deps = path.rfind('/DEPS')
2275 if start_deps != -1:
2276 return path[:start_deps]
2277 else:
2278 return path
2279
2280 unapproved_dependencies = [
2281 "'+%s'," % StripDeps(path) for path in missing_files
2282 ]
2283
2284 if unapproved_dependencies:
2285 output_list = [
2286 output(
2287 'You need LGTM from owners of depends-on paths in DEPS that were '
2288 'modified in this CL:\n %s' %
2289 '\n '.join(sorted(unapproved_dependencies)))
2290 ]
2291 suggested_owners = input_api.owners_client.SuggestOwners(
2292 missing_files, exclude=[owner_email])
2293 output_list.append(
2294 output('Suggested missing target path OWNERS:\n %s' %
2295 '\n '.join(suggested_owners or [])))
2296 return output_list
2297
2298 return []
[email protected]e871964c2013-05-13 14:14:552299
2300
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492301# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362302def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502303 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2304 files_to_skip = (
2305 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2306 input_api.DEFAULT_FILES_TO_SKIP + (
2307 r"^base[\\/]logging\.h$",
2308 r"^base[\\/]logging\.cc$",
2309 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2310 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2311 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2312 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2313 r"startup_browser_creator\.cc$",
2314 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2315 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2316 r"diagnostics_writer\.cc$",
2317 r"^chrome[\\/]chrome_cleaner[\\/].*",
2318 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2319 r"dll_hash_main\.cc$",
2320 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2321 r"^chromecast[\\/]",
Sam Maiera6e76d72022-02-11 21:43:502322 r"^components[\\/]browser_watcher[\\/]"
2323 r"dump_stability_report_main_win.cc$",
2324 r"^components[\\/]media_control[\\/]renderer[\\/]"
2325 r"media_playback_options\.cc$",
2326 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2327 r"overlay_strategy_underlay_cast\.cc$",
2328 r"^components[\\/]zucchini[\\/].*",
2329 # TODO(peter): Remove exception. https://crbug.com/534537
2330 r"^content[\\/]browser[\\/]notifications[\\/]"
2331 r"notification_event_dispatcher_impl\.cc$",
2332 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2333 r"gl_helper_benchmark\.cc$",
2334 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2335 r"^courgette[\\/]courgette_tool\.cc$",
2336 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2337 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
2338 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2339 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
2340 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2341 r"^ipc[\\/]ipc_logging\.cc$",
2342 r"^native_client_sdk[\\/]",
2343 r"^remoting[\\/]base[\\/]logging\.h$",
2344 r"^remoting[\\/]host[\\/].*",
2345 r"^sandbox[\\/]linux[\\/].*",
2346 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2347 r"dump_file_system.cc$",
2348 r"^tools[\\/]",
2349 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2350 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2351 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2352 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2353 r"xwmstartupcheck\.cc$"))
2354 source_file_filter = lambda x: input_api.FilterSourceFile(
2355 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402356
Sam Maiera6e76d72022-02-11 21:43:502357 log_info = set([])
2358 printf = set([])
[email protected]85218562013-11-22 07:41:402359
Sam Maiera6e76d72022-02-11 21:43:502360 for f in input_api.AffectedSourceFiles(source_file_filter):
2361 for _, line in f.ChangedContents():
2362 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2363 log_info.add(f.LocalPath())
2364 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2365 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372366
Sam Maiera6e76d72022-02-11 21:43:502367 if input_api.re.search(r"\bprintf\(", line):
2368 printf.add(f.LocalPath())
2369 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2370 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402371
Sam Maiera6e76d72022-02-11 21:43:502372 if log_info:
2373 return [
2374 output_api.PresubmitError(
2375 'These files spam the console log with LOG(INFO):',
2376 items=log_info)
2377 ]
2378 if printf:
2379 return [
2380 output_api.PresubmitError(
2381 'These files spam the console log with printf/fprintf:',
2382 items=printf)
2383 ]
2384 return []
[email protected]85218562013-11-22 07:41:402385
2386
Saagar Sanghavifceeaae2020-08-12 16:40:362387def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502388 """These types are all expected to hold locks while in scope and
2389 so should never be anonymous (which causes them to be immediately
2390 destroyed)."""
2391 they_who_must_be_named = [
2392 'base::AutoLock',
2393 'base::AutoReset',
2394 'base::AutoUnlock',
2395 'SkAutoAlphaRestore',
2396 'SkAutoBitmapShaderInstall',
2397 'SkAutoBlitterChoose',
2398 'SkAutoBounderCommit',
2399 'SkAutoCallProc',
2400 'SkAutoCanvasRestore',
2401 'SkAutoCommentBlock',
2402 'SkAutoDescriptor',
2403 'SkAutoDisableDirectionCheck',
2404 'SkAutoDisableOvalCheck',
2405 'SkAutoFree',
2406 'SkAutoGlyphCache',
2407 'SkAutoHDC',
2408 'SkAutoLockColors',
2409 'SkAutoLockPixels',
2410 'SkAutoMalloc',
2411 'SkAutoMaskFreeImage',
2412 'SkAutoMutexAcquire',
2413 'SkAutoPathBoundsUpdate',
2414 'SkAutoPDFRelease',
2415 'SkAutoRasterClipValidate',
2416 'SkAutoRef',
2417 'SkAutoTime',
2418 'SkAutoTrace',
2419 'SkAutoUnref',
2420 ]
2421 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2422 # bad: base::AutoLock(lock.get());
2423 # not bad: base::AutoLock lock(lock.get());
2424 bad_pattern = input_api.re.compile(anonymous)
2425 # good: new base::AutoLock(lock.get())
2426 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2427 errors = []
[email protected]49aa76a2013-12-04 06:59:162428
Sam Maiera6e76d72022-02-11 21:43:502429 for f in input_api.AffectedFiles():
2430 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2431 continue
2432 for linenum, line in f.ChangedContents():
2433 if bad_pattern.search(line) and not good_pattern.search(line):
2434 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162435
Sam Maiera6e76d72022-02-11 21:43:502436 if errors:
2437 return [
2438 output_api.PresubmitError(
2439 'These lines create anonymous variables that need to be named:',
2440 items=errors)
2441 ]
2442 return []
[email protected]49aa76a2013-12-04 06:59:162443
2444
Saagar Sanghavifceeaae2020-08-12 16:40:362445def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502446 # Returns whether |template_str| is of the form <T, U...> for some types T
2447 # and U. Assumes that |template_str| is already in the form <...>.
2448 def HasMoreThanOneArg(template_str):
2449 # Level of <...> nesting.
2450 nesting = 0
2451 for c in template_str:
2452 if c == '<':
2453 nesting += 1
2454 elif c == '>':
2455 nesting -= 1
2456 elif c == ',' and nesting == 1:
2457 return True
2458 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532459
Sam Maiera6e76d72022-02-11 21:43:502460 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2461 sources = lambda affected_file: input_api.FilterSourceFile(
2462 affected_file,
2463 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2464 DEFAULT_FILES_TO_SKIP),
2465 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552466
Sam Maiera6e76d72022-02-11 21:43:502467 # Pattern to capture a single "<...>" block of template arguments. It can
2468 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2469 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2470 # latter would likely require counting that < and > match, which is not
2471 # expressible in regular languages. Should the need arise, one can introduce
2472 # limited counting (matching up to a total number of nesting depth), which
2473 # should cover all practical cases for already a low nesting limit.
2474 template_arg_pattern = (
2475 r'<[^>]*' # Opening block of <.
2476 r'>([^<]*>)?') # Closing block of >.
2477 # Prefix expressing that whatever follows is not already inside a <...>
2478 # block.
2479 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2480 null_construct_pattern = input_api.re.compile(
2481 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2482 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552483
Sam Maiera6e76d72022-02-11 21:43:502484 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2485 template_arg_no_array_pattern = (
2486 r'<[^>]*[^]]' # Opening block of <.
2487 r'>([^(<]*[^]]>)?') # Closing block of >.
2488 # Prefix saying that what follows is the start of an expression.
2489 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2490 # Suffix saying that what follows are call parentheses with a non-empty list
2491 # of arguments.
2492 nonempty_arg_list_pattern = r'\(([^)]|$)'
2493 # Put the template argument into a capture group for deeper examination later.
2494 return_construct_pattern = input_api.re.compile(
2495 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2496 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552497
Sam Maiera6e76d72022-02-11 21:43:502498 problems_constructor = []
2499 problems_nullptr = []
2500 for f in input_api.AffectedSourceFiles(sources):
2501 for line_number, line in f.ChangedContents():
2502 # Disallow:
2503 # return std::unique_ptr<T>(foo);
2504 # bar = std::unique_ptr<T>(foo);
2505 # But allow:
2506 # return std::unique_ptr<T[]>(foo);
2507 # bar = std::unique_ptr<T[]>(foo);
2508 # And also allow cases when the second template argument is present. Those
2509 # cases cannot be handled by std::make_unique:
2510 # return std::unique_ptr<T, U>(foo);
2511 # bar = std::unique_ptr<T, U>(foo);
2512 local_path = f.LocalPath()
2513 return_construct_result = return_construct_pattern.search(line)
2514 if return_construct_result and not HasMoreThanOneArg(
2515 return_construct_result.group('template_arg')):
2516 problems_constructor.append(
2517 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2518 # Disallow:
2519 # std::unique_ptr<T>()
2520 if null_construct_pattern.search(line):
2521 problems_nullptr.append(
2522 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052523
Sam Maiera6e76d72022-02-11 21:43:502524 errors = []
2525 if problems_nullptr:
2526 errors.append(
2527 output_api.PresubmitPromptWarning(
2528 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2529 problems_nullptr))
2530 if problems_constructor:
2531 errors.append(
2532 output_api.PresubmitError(
2533 'The following files use explicit std::unique_ptr constructor. '
2534 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2535 'std::make_unique is not an option.', problems_constructor))
2536 return errors
Peter Kasting4844e46e2018-02-23 07:27:102537
2538
Saagar Sanghavifceeaae2020-08-12 16:40:362539def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502540 """Checks if any new user action has been added."""
2541 if any('actions.xml' == input_api.os_path.basename(f)
2542 for f in input_api.LocalPaths()):
2543 # If actions.xml is already included in the changelist, the PRESUBMIT
2544 # for actions.xml will do a more complete presubmit check.
2545 return []
2546
2547 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2548 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2549 input_api.DEFAULT_FILES_TO_SKIP)
2550 file_filter = lambda f: input_api.FilterSourceFile(
2551 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2552
2553 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2554 current_actions = None
2555 for f in input_api.AffectedFiles(file_filter=file_filter):
2556 for line_num, line in f.ChangedContents():
2557 match = input_api.re.search(action_re, line)
2558 if match:
2559 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2560 # loaded only once.
2561 if not current_actions:
2562 with open(
2563 'tools/metrics/actions/actions.xml') as actions_f:
2564 current_actions = actions_f.read()
2565 # Search for the matched user action name in |current_actions|.
2566 for action_name in match.groups():
2567 action = 'name="{0}"'.format(action_name)
2568 if action not in current_actions:
2569 return [
2570 output_api.PresubmitPromptWarning(
2571 'File %s line %d: %s is missing in '
2572 'tools/metrics/actions/actions.xml. Please run '
2573 'tools/metrics/actions/extract_actions.py to update.'
2574 % (f.LocalPath(), line_num, action_name))
2575 ]
[email protected]999261d2014-03-03 20:08:082576 return []
2577
[email protected]999261d2014-03-03 20:08:082578
Daniel Cheng13ca61a882017-08-25 15:11:252579def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502580 import sys
2581 sys.path = sys.path + [
2582 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2583 'json_comment_eater')
2584 ]
2585 import json_comment_eater
2586 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252587
2588
[email protected]99171a92014-06-03 08:44:472589def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172590 try:
Sam Maiera6e76d72022-02-11 21:43:502591 contents = input_api.ReadFile(filename)
2592 if eat_comments:
2593 json_comment_eater = _ImportJSONCommentEater(input_api)
2594 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172595
Sam Maiera6e76d72022-02-11 21:43:502596 input_api.json.loads(contents)
2597 except ValueError as e:
2598 return e
Andrew Grieve4deedb12022-02-03 21:34:502599 return None
2600
2601
Sam Maiera6e76d72022-02-11 21:43:502602def _GetIDLParseError(input_api, filename):
2603 try:
2604 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:282605 for i, char in enumerate(contents):
2606 if not char.isascii():
2607 return ('Non-ascii character "%s" (ord %d) found at offset %d.'
2608 % (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:502609 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2610 'tools', 'json_schema_compiler',
2611 'idl_schema.py')
2612 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282613 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502614 stdin=input_api.subprocess.PIPE,
2615 stdout=input_api.subprocess.PIPE,
2616 stderr=input_api.subprocess.PIPE,
2617 universal_newlines=True)
2618 (_, error) = process.communicate(input=contents)
2619 return error or None
2620 except ValueError as e:
2621 return e
agrievef32bcc72016-04-04 14:57:402622
agrievef32bcc72016-04-04 14:57:402623
Sam Maiera6e76d72022-02-11 21:43:502624def CheckParseErrors(input_api, output_api):
2625 """Check that IDL and JSON files do not contain syntax errors."""
2626 actions = {
2627 '.idl': _GetIDLParseError,
2628 '.json': _GetJSONParseError,
2629 }
2630 # Most JSON files are preprocessed and support comments, but these do not.
2631 json_no_comments_patterns = [
2632 r'^testing[\\/]',
2633 ]
2634 # Only run IDL checker on files in these directories.
2635 idl_included_patterns = [
2636 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2637 r'^extensions[\\/]common[\\/]api[\\/]',
2638 ]
agrievef32bcc72016-04-04 14:57:402639
Sam Maiera6e76d72022-02-11 21:43:502640 def get_action(affected_file):
2641 filename = affected_file.LocalPath()
2642 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:402643
Sam Maiera6e76d72022-02-11 21:43:502644 def FilterFile(affected_file):
2645 action = get_action(affected_file)
2646 if not action:
2647 return False
2648 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:402649
Sam Maiera6e76d72022-02-11 21:43:502650 if _MatchesFile(input_api,
2651 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
2652 return False
2653
2654 if (action == _GetIDLParseError
2655 and not _MatchesFile(input_api, idl_included_patterns, path)):
2656 return False
2657 return True
2658
2659 results = []
2660 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
2661 include_deletes=False):
2662 action = get_action(affected_file)
2663 kwargs = {}
2664 if (action == _GetJSONParseError
2665 and _MatchesFile(input_api, json_no_comments_patterns,
2666 affected_file.LocalPath())):
2667 kwargs['eat_comments'] = False
2668 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
2669 **kwargs)
2670 if parse_error:
2671 results.append(
2672 output_api.PresubmitError(
2673 '%s could not be parsed: %s' %
2674 (affected_file.LocalPath(), parse_error)))
2675 return results
2676
2677
2678def CheckJavaStyle(input_api, output_api):
2679 """Runs checkstyle on changed java files and returns errors if any exist."""
2680
2681 # Return early if no java files were modified.
2682 if not any(
2683 _IsJavaFile(input_api, f.LocalPath())
2684 for f in input_api.AffectedFiles()):
2685 return []
2686
2687 import sys
2688 original_sys_path = sys.path
2689 try:
2690 sys.path = sys.path + [
2691 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2692 'android', 'checkstyle')
2693 ]
2694 import checkstyle
2695 finally:
2696 # Restore sys.path to what it was before.
2697 sys.path = original_sys_path
2698
2699 return checkstyle.RunCheckstyle(
2700 input_api,
2701 output_api,
2702 'tools/android/checkstyle/chromium-style-5.0.xml',
2703 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
2704
2705
2706def CheckPythonDevilInit(input_api, output_api):
2707 """Checks to make sure devil is initialized correctly in python scripts."""
2708 script_common_initialize_pattern = input_api.re.compile(
2709 r'script_common\.InitializeEnvironment\(')
2710 devil_env_config_initialize = input_api.re.compile(
2711 r'devil_env\.config\.Initialize\(')
2712
2713 errors = []
2714
2715 sources = lambda affected_file: input_api.FilterSourceFile(
2716 affected_file,
2717 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
2718 r'^build[\\/]android[\\/]devil_chromium\.py',
2719 r'^third_party[\\/].*',
2720 )),
2721 files_to_check=[r'.*\.py$'])
2722
2723 for f in input_api.AffectedSourceFiles(sources):
2724 for line_num, line in f.ChangedContents():
2725 if (script_common_initialize_pattern.search(line)
2726 or devil_env_config_initialize.search(line)):
2727 errors.append("%s:%d" % (f.LocalPath(), line_num))
2728
2729 results = []
2730
2731 if errors:
2732 results.append(
2733 output_api.PresubmitError(
2734 'Devil initialization should always be done using '
2735 'devil_chromium.Initialize() in the chromium project, to use better '
2736 'defaults for dependencies (ex. up-to-date version of adb).',
2737 errors))
2738
2739 return results
2740
2741
2742def _MatchesFile(input_api, patterns, path):
2743 for pattern in patterns:
2744 if input_api.re.search(pattern, path):
2745 return True
2746 return False
2747
2748
2749def _GetOwnersFilesToCheckForIpcOwners(input_api):
2750 """Gets a list of OWNERS files to check for correct security owners.
2751
2752 Returns:
2753 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2754 contain to cover IPC-related files with noparent reviewer rules.
2755 """
2756 # Whether or not a file affects IPC is (mostly) determined by a simple list
2757 # of filename patterns.
2758 file_patterns = [
2759 # Legacy IPC:
2760 '*_messages.cc',
2761 '*_messages*.h',
2762 '*_param_traits*.*',
2763 # Mojo IPC:
2764 '*.mojom',
2765 '*_mojom_traits*.*',
2766 '*_struct_traits*.*',
2767 '*_type_converter*.*',
2768 '*.typemap',
2769 # Android native IPC:
2770 '*.aidl',
2771 # Blink uses a different file naming convention:
2772 '*EnumTraits*.*',
2773 "*MojomTraits*.*",
2774 '*StructTraits*.*',
2775 '*TypeConverter*.*',
2776 ]
2777
2778 # These third_party directories do not contain IPCs, but contain files
2779 # matching the above patterns, which trigger false positives.
2780 exclude_paths = [
2781 'third_party/crashpad/*',
2782 'third_party/blink/renderer/platform/bindings/*',
2783 'third_party/protobuf/benchmarks/python/*',
2784 'third_party/win_build_output/*',
2785 # These files are just used to communicate between class loaders running
2786 # in the same process.
2787 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
2788 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2789 ]
2790
2791 # Dictionary mapping an OWNERS file path to Patterns.
2792 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2793 # rules ) to a PatternEntry.
2794 # PatternEntry is a dictionary with two keys:
2795 # - 'files': the files that are matched by this pattern
2796 # - 'rules': the per-file rules needed for this pattern
2797 # For example, if we expect OWNERS file to contain rules for *.mojom and
2798 # *_struct_traits*.*, Patterns might look like this:
2799 # {
2800 # '*.mojom': {
2801 # 'files': ...,
2802 # 'rules': [
2803 # 'per-file *.mojom=set noparent',
2804 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2805 # ],
2806 # },
2807 # '*_struct_traits*.*': {
2808 # 'files': ...,
2809 # 'rules': [
2810 # 'per-file *_struct_traits*.*=set noparent',
2811 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2812 # ],
2813 # },
2814 # }
2815 to_check = {}
2816
2817 def AddPatternToCheck(input_file, pattern):
2818 owners_file = input_api.os_path.join(
2819 input_api.os_path.dirname(input_file.AbsoluteLocalPath()),
2820 'OWNERS')
2821 if owners_file not in to_check:
2822 to_check[owners_file] = {}
2823 if pattern not in to_check[owners_file]:
2824 to_check[owners_file][pattern] = {
2825 'files': [],
2826 'rules': [
2827 'per-file %s=set noparent' % pattern,
2828 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2829 ]
2830 }
2831 to_check[owners_file][pattern]['files'].append(input_file)
2832
2833 # Iterate through the affected files to see what we actually need to check
2834 # for. We should only nag patch authors about per-file rules if a file in that
2835 # directory would match that pattern. If a directory only contains *.mojom
2836 # files and no *_messages*.h files, we should only nag about rules for
2837 # *.mojom files.
2838 for f in input_api.AffectedFiles(include_deletes=False):
2839 # Manifest files don't have a strong naming convention. Instead, try to find
2840 # affected .cc and .h files which look like they contain a manifest
2841 # definition.
2842 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2843 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2844 if (manifest_pattern.search(f.LocalPath())
2845 and not test_manifest_pattern.search(f.LocalPath())):
2846 # We expect all actual service manifest files to contain at least one
2847 # qualified reference to service_manager::Manifest.
2848 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2849 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
2850 for pattern in file_patterns:
2851 if input_api.fnmatch.fnmatch(
2852 input_api.os_path.basename(f.LocalPath()), pattern):
2853 skip = False
2854 for exclude in exclude_paths:
2855 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2856 skip = True
2857 break
2858 if skip:
2859 continue
2860 AddPatternToCheck(f, pattern)
2861 break
2862
2863 return to_check
2864
2865
2866def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2867 """Adds OWNERS files to check for correct Fuchsia security owners."""
2868
2869 file_patterns = [
2870 # Component specifications.
2871 '*.cml', # Component Framework v2.
2872 '*.cmx', # Component Framework v1.
2873
2874 # Fuchsia IDL protocol specifications.
2875 '*.fidl',
2876 ]
2877
2878 # Don't check for owners files for changes in these directories.
2879 exclude_paths = [
2880 'third_party/crashpad/*',
2881 ]
2882
2883 def AddPatternToCheck(input_file, pattern):
2884 owners_file = input_api.os_path.join(
2885 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2886 if owners_file not in to_check:
2887 to_check[owners_file] = {}
2888 if pattern not in to_check[owners_file]:
2889 to_check[owners_file][pattern] = {
2890 'files': [],
2891 'rules': [
2892 'per-file %s=set noparent' % pattern,
2893 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2894 ]
2895 }
2896 to_check[owners_file][pattern]['files'].append(input_file)
2897
2898 # Iterate through the affected files to see what we actually need to check
2899 # for. We should only nag patch authors about per-file rules if a file in that
2900 # directory would match that pattern.
2901 for f in input_api.AffectedFiles(include_deletes=False):
2902 skip = False
2903 for exclude in exclude_paths:
2904 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2905 skip = True
2906 if skip:
2907 continue
2908
2909 for pattern in file_patterns:
2910 if input_api.fnmatch.fnmatch(
2911 input_api.os_path.basename(f.LocalPath()), pattern):
2912 AddPatternToCheck(f, pattern)
2913 break
2914
2915 return to_check
2916
2917
2918def CheckSecurityOwners(input_api, output_api):
2919 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2920 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2921 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
2922
2923 if to_check:
2924 # If there are any OWNERS files to check, there are IPC-related changes in
2925 # this CL. Auto-CC the review list.
2926 output_api.AppendCC('[email protected]')
2927
2928 # Go through the OWNERS files to check, filtering out rules that are already
2929 # present in that OWNERS file.
2930 for owners_file, patterns in to_check.items():
2931 try:
2932 with open(owners_file) as f:
2933 lines = set(f.read().splitlines())
2934 for entry in patterns.values():
2935 entry['rules'] = [
2936 rule for rule in entry['rules'] if rule not in lines
2937 ]
2938 except IOError:
2939 # No OWNERS file, so all the rules are definitely missing.
2940 continue
2941
2942 # All the remaining lines weren't found in OWNERS files, so emit an error.
2943 errors = []
2944 for owners_file, patterns in to_check.items():
2945 missing_lines = []
2946 files = []
2947 for _, entry in patterns.items():
2948 missing_lines.extend(entry['rules'])
2949 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2950 if missing_lines:
2951 errors.append('Because of the presence of files:\n%s\n\n'
2952 '%s needs the following %d lines added:\n\n%s' %
2953 ('\n'.join(files), owners_file, len(missing_lines),
2954 '\n'.join(missing_lines)))
2955
2956 results = []
2957 if errors:
2958 if input_api.is_committing:
2959 output = output_api.PresubmitError
2960 else:
2961 output = output_api.PresubmitPromptWarning
2962 results.append(
2963 output(
2964 'Found OWNERS files that need to be updated for IPC security '
2965 + 'review coverage.\nPlease update the OWNERS files below:',
2966 long_text='\n\n'.join(errors)))
2967
2968 return results
2969
2970
2971def _GetFilesUsingSecurityCriticalFunctions(input_api):
2972 """Checks affected files for changes to security-critical calls. This
2973 function checks the full change diff, to catch both additions/changes
2974 and removals.
2975
2976 Returns a dict keyed by file name, and the value is a set of detected
2977 functions.
2978 """
2979 # Map of function pretty name (displayed in an error) to the pattern to
2980 # match it with.
2981 _PATTERNS_TO_CHECK = {
2982 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
2983 }
2984 _PATTERNS_TO_CHECK = {
2985 k: input_api.re.compile(v)
2986 for k, v in _PATTERNS_TO_CHECK.items()
2987 }
2988
John Budorick47ca3fe2018-02-10 00:53:102989 import os
2990
Sam Maiera6e76d72022-02-11 21:43:502991 # We don't want to trigger on strings within this file.
2992 def presubmit_file_filter(f):
2993 return 'PRESUBMIT.py' != os.path.split(f.LocalPath())[1]
2994
2995 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2996 files_to_functions = {}
2997 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
2998 diff = f.GenerateScmDiff()
2999 for line in diff.split('\n'):
3000 # Not using just RightHandSideLines() because removing a
3001 # call to a security-critical function can be just as important
3002 # as adding or changing the arguments.
3003 if line.startswith('-') or (line.startswith('+')
3004 and not line.startswith('++')):
3005 for name, pattern in _PATTERNS_TO_CHECK.items():
3006 if pattern.search(line):
3007 path = f.LocalPath()
3008 if not path in files_to_functions:
3009 files_to_functions[path] = set()
3010 files_to_functions[path].add(name)
3011 return files_to_functions
3012
3013
3014def CheckSecurityChanges(input_api, output_api):
3015 """Checks that changes involving security-critical functions are reviewed
3016 by the security team.
3017 """
3018 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3019 if not len(files_to_functions):
3020 return []
3021
3022 owner_email, reviewers = (
3023 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3024 input_api, None, approval_needed=input_api.is_committing))
3025
3026 # Load the OWNERS file for security changes.
3027 owners_file = 'ipc/SECURITY_OWNERS'
3028 security_owners = input_api.owners_client.ListOwners(owners_file)
3029 has_security_owner = any([owner in reviewers for owner in security_owners])
3030 if has_security_owner:
3031 return []
3032
3033 msg = 'The following files change calls to security-sensive functions\n' \
3034 'that need to be reviewed by {}.\n'.format(owners_file)
3035 for path, names in files_to_functions.items():
3036 msg += ' {}\n'.format(path)
3037 for name in names:
3038 msg += ' {}\n'.format(name)
3039 msg += '\n'
3040
3041 if input_api.is_committing:
3042 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033043 else:
Sam Maiera6e76d72022-02-11 21:43:503044 output = output_api.PresubmitNotifyResult
3045 return [output(msg)]
3046
3047
3048def CheckSetNoParent(input_api, output_api):
3049 """Checks that set noparent is only used together with an OWNERS file in
3050 //build/OWNERS.setnoparent (see also
3051 //docs/code_reviews.md#owners-files-details)
3052 """
3053 # Return early if no OWNERS files were modified.
3054 if not any(f.LocalPath().endswith('OWNERS')
3055 for f in input_api.AffectedFiles(include_deletes=False)):
3056 return []
3057
3058 errors = []
3059
3060 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3061 allowed_owners_files = set()
3062 with open(allowed_owners_files_file, 'r') as f:
3063 for line in f:
3064 line = line.strip()
3065 if not line or line.startswith('#'):
3066 continue
3067 allowed_owners_files.add(line)
3068
3069 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3070
3071 for f in input_api.AffectedFiles(include_deletes=False):
3072 if not f.LocalPath().endswith('OWNERS'):
3073 continue
3074
3075 found_owners_files = set()
3076 found_set_noparent_lines = dict()
3077
3078 # Parse the OWNERS file.
3079 for lineno, line in enumerate(f.NewContents(), 1):
3080 line = line.strip()
3081 if line.startswith('set noparent'):
3082 found_set_noparent_lines[''] = lineno
3083 if line.startswith('file://'):
3084 if line in allowed_owners_files:
3085 found_owners_files.add('')
3086 if line.startswith('per-file'):
3087 match = per_file_pattern.match(line)
3088 if match:
3089 glob = match.group(1).strip()
3090 directive = match.group(2).strip()
3091 if directive == 'set noparent':
3092 found_set_noparent_lines[glob] = lineno
3093 if directive.startswith('file://'):
3094 if directive in allowed_owners_files:
3095 found_owners_files.add(glob)
3096
3097 # Check that every set noparent line has a corresponding file:// line
3098 # listed in build/OWNERS.setnoparent. An exception is made for top level
3099 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493100 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3101 if (linux_path.count('/') != 1
3102 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503103 for set_noparent_line in found_set_noparent_lines:
3104 if set_noparent_line in found_owners_files:
3105 continue
3106 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493107 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503108 found_set_noparent_lines[set_noparent_line]))
3109
3110 results = []
3111 if errors:
3112 if input_api.is_committing:
3113 output = output_api.PresubmitError
3114 else:
3115 output = output_api.PresubmitPromptWarning
3116 results.append(
3117 output(
3118 'Found the following "set noparent" restrictions in OWNERS files that '
3119 'do not include owners from build/OWNERS.setnoparent:',
3120 long_text='\n\n'.join(errors)))
3121 return results
3122
3123
3124def CheckUselessForwardDeclarations(input_api, output_api):
3125 """Checks that added or removed lines in non third party affected
3126 header files do not lead to new useless class or struct forward
3127 declaration.
3128 """
3129 results = []
3130 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3131 input_api.re.MULTILINE)
3132 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3133 input_api.re.MULTILINE)
3134 for f in input_api.AffectedFiles(include_deletes=False):
3135 if (f.LocalPath().startswith('third_party')
3136 and not f.LocalPath().startswith('third_party/blink')
3137 and not f.LocalPath().startswith('third_party\\blink')):
3138 continue
3139
3140 if not f.LocalPath().endswith('.h'):
3141 continue
3142
3143 contents = input_api.ReadFile(f)
3144 fwd_decls = input_api.re.findall(class_pattern, contents)
3145 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3146
3147 useless_fwd_decls = []
3148 for decl in fwd_decls:
3149 count = sum(1 for _ in input_api.re.finditer(
3150 r'\b%s\b' % input_api.re.escape(decl), contents))
3151 if count == 1:
3152 useless_fwd_decls.append(decl)
3153
3154 if not useless_fwd_decls:
3155 continue
3156
3157 for line in f.GenerateScmDiff().splitlines():
3158 if (line.startswith('-') and not line.startswith('--')
3159 or line.startswith('+') and not line.startswith('++')):
3160 for decl in useless_fwd_decls:
3161 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3162 results.append(
3163 output_api.PresubmitPromptWarning(
3164 '%s: %s forward declaration is no longer needed'
3165 % (f.LocalPath(), decl)))
3166 useless_fwd_decls.remove(decl)
3167
3168 return results
3169
3170
3171def _CheckAndroidDebuggableBuild(input_api, output_api):
3172 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3173 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3174 this is a debuggable build of Android.
3175 """
3176 build_type_check_pattern = input_api.re.compile(
3177 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3178
3179 errors = []
3180
3181 sources = lambda affected_file: input_api.FilterSourceFile(
3182 affected_file,
3183 files_to_skip=(
3184 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3185 DEFAULT_FILES_TO_SKIP + (
3186 r"^android_webview[\\/]support_library[\\/]"
3187 "boundary_interfaces[\\/]",
3188 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3189 r'^third_party[\\/].*',
3190 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3191 r"webview[\\/]chromium[\\/]License.*",
3192 )),
3193 files_to_check=[r'.*\.java$'])
3194
3195 for f in input_api.AffectedSourceFiles(sources):
3196 for line_num, line in f.ChangedContents():
3197 if build_type_check_pattern.search(line):
3198 errors.append("%s:%d" % (f.LocalPath(), line_num))
3199
3200 results = []
3201
3202 if errors:
3203 results.append(
3204 output_api.PresubmitPromptWarning(
3205 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3206 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3207
3208 return results
3209
3210# TODO: add unit tests
3211def _CheckAndroidToastUsage(input_api, output_api):
3212 """Checks that code uses org.chromium.ui.widget.Toast instead of
3213 android.widget.Toast (Chromium Toast doesn't force hardware
3214 acceleration on low-end devices, saving memory).
3215 """
3216 toast_import_pattern = input_api.re.compile(
3217 r'^import android\.widget\.Toast;$')
3218
3219 errors = []
3220
3221 sources = lambda affected_file: input_api.FilterSourceFile(
3222 affected_file,
3223 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3224 DEFAULT_FILES_TO_SKIP + (r'^chromecast[\\/].*',
3225 r'^remoting[\\/].*')),
3226 files_to_check=[r'.*\.java$'])
3227
3228 for f in input_api.AffectedSourceFiles(sources):
3229 for line_num, line in f.ChangedContents():
3230 if toast_import_pattern.search(line):
3231 errors.append("%s:%d" % (f.LocalPath(), line_num))
3232
3233 results = []
3234
3235 if errors:
3236 results.append(
3237 output_api.PresubmitError(
3238 'android.widget.Toast usage is detected. Android toasts use hardware'
3239 ' acceleration, and can be\ncostly on low-end devices. Please use'
3240 ' org.chromium.ui.widget.Toast instead.\n'
3241 'Contact [email protected] if you have any questions.',
3242 errors))
3243
3244 return results
3245
3246
3247def _CheckAndroidCrLogUsage(input_api, output_api):
3248 """Checks that new logs using org.chromium.base.Log:
3249 - Are using 'TAG' as variable name for the tags (warn)
3250 - Are using a tag that is shorter than 20 characters (error)
3251 """
3252
3253 # Do not check format of logs in the given files
3254 cr_log_check_excluded_paths = [
3255 # //chrome/android/webapk cannot depend on //base
3256 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3257 # WebView license viewer code cannot depend on //base; used in stub APK.
3258 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3259 r"webview[\\/]chromium[\\/]License.*",
3260 # The customtabs_benchmark is a small app that does not depend on Chromium
3261 # java pieces.
3262 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3263 ]
3264
3265 cr_log_import_pattern = input_api.re.compile(
3266 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3267 class_in_base_pattern = input_api.re.compile(
3268 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3269 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3270 input_api.re.MULTILINE)
3271 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3272 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3273 log_decl_pattern = input_api.re.compile(
3274 r'static final String TAG = "(?P<name>(.*))"')
3275 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3276
3277 REF_MSG = ('See docs/android_logging.md for more info.')
3278 sources = lambda x: input_api.FilterSourceFile(
3279 x,
3280 files_to_check=[r'.*\.java$'],
3281 files_to_skip=cr_log_check_excluded_paths)
3282
3283 tag_decl_errors = []
3284 tag_length_errors = []
3285 tag_errors = []
3286 tag_with_dot_errors = []
3287 util_log_errors = []
3288
3289 for f in input_api.AffectedSourceFiles(sources):
3290 file_content = input_api.ReadFile(f)
3291 has_modified_logs = False
3292 # Per line checks
3293 if (cr_log_import_pattern.search(file_content)
3294 or (class_in_base_pattern.search(file_content)
3295 and not has_some_log_import_pattern.search(file_content))):
3296 # Checks to run for files using cr log
3297 for line_num, line in f.ChangedContents():
3298 if rough_log_decl_pattern.search(line):
3299 has_modified_logs = True
3300
3301 # Check if the new line is doing some logging
3302 match = log_call_pattern.search(line)
3303 if match:
3304 has_modified_logs = True
3305
3306 # Make sure it uses "TAG"
3307 if not match.group('tag') == 'TAG':
3308 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3309 else:
3310 # Report non cr Log function calls in changed lines
3311 for line_num, line in f.ChangedContents():
3312 if log_call_pattern.search(line):
3313 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3314
3315 # Per file checks
3316 if has_modified_logs:
3317 # Make sure the tag is using the "cr" prefix and is not too long
3318 match = log_decl_pattern.search(file_content)
3319 tag_name = match.group('name') if match else None
3320 if not tag_name:
3321 tag_decl_errors.append(f.LocalPath())
3322 elif len(tag_name) > 20:
3323 tag_length_errors.append(f.LocalPath())
3324 elif '.' in tag_name:
3325 tag_with_dot_errors.append(f.LocalPath())
3326
3327 results = []
3328 if tag_decl_errors:
3329 results.append(
3330 output_api.PresubmitPromptWarning(
3331 'Please define your tags using the suggested format: .\n'
3332 '"private static final String TAG = "<package tag>".\n'
3333 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3334 tag_decl_errors))
3335
3336 if tag_length_errors:
3337 results.append(
3338 output_api.PresubmitError(
3339 'The tag length is restricted by the system to be at most '
3340 '20 characters.\n' + REF_MSG, tag_length_errors))
3341
3342 if tag_errors:
3343 results.append(
3344 output_api.PresubmitPromptWarning(
3345 'Please use a variable named "TAG" for your log tags.\n' +
3346 REF_MSG, tag_errors))
3347
3348 if util_log_errors:
3349 results.append(
3350 output_api.PresubmitPromptWarning(
3351 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3352 util_log_errors))
3353
3354 if tag_with_dot_errors:
3355 results.append(
3356 output_api.PresubmitPromptWarning(
3357 'Dot in log tags cause them to be elided in crash reports.\n' +
3358 REF_MSG, tag_with_dot_errors))
3359
3360 return results
3361
3362
3363def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3364 """Checks that junit.framework.* is no longer used."""
3365 deprecated_junit_framework_pattern = input_api.re.compile(
3366 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3367 sources = lambda x: input_api.FilterSourceFile(
3368 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3369 errors = []
3370 for f in input_api.AffectedFiles(file_filter=sources):
3371 for line_num, line in f.ChangedContents():
3372 if deprecated_junit_framework_pattern.search(line):
3373 errors.append("%s:%d" % (f.LocalPath(), line_num))
3374
3375 results = []
3376 if errors:
3377 results.append(
3378 output_api.PresubmitError(
3379 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3380 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3381 ' if you have any question.', errors))
3382 return results
3383
3384
3385def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3386 """Checks that if new Java test classes have inheritance.
3387 Either the new test class is JUnit3 test or it is a JUnit4 test class
3388 with a base class, either case is undesirable.
3389 """
3390 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3391
3392 sources = lambda x: input_api.FilterSourceFile(
3393 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3394 errors = []
3395 for f in input_api.AffectedFiles(file_filter=sources):
3396 if not f.OldContents():
3397 class_declaration_start_flag = False
3398 for line_num, line in f.ChangedContents():
3399 if class_declaration_pattern.search(line):
3400 class_declaration_start_flag = True
3401 if class_declaration_start_flag and ' extends ' in line:
3402 errors.append('%s:%d' % (f.LocalPath(), line_num))
3403 if '{' in line:
3404 class_declaration_start_flag = False
3405
3406 results = []
3407 if errors:
3408 results.append(
3409 output_api.PresubmitPromptWarning(
3410 'The newly created files include Test classes that inherits from base'
3411 ' class. Please do not use inheritance in JUnit4 tests or add new'
3412 ' JUnit3 tests. Contact [email protected] if you have any'
3413 ' questions.', errors))
3414 return results
3415
3416
3417def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3418 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3419 deprecated_annotation_import_pattern = input_api.re.compile(
3420 r'^import android\.test\.suitebuilder\.annotation\..*;',
3421 input_api.re.MULTILINE)
3422 sources = lambda x: input_api.FilterSourceFile(
3423 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3424 errors = []
3425 for f in input_api.AffectedFiles(file_filter=sources):
3426 for line_num, line in f.ChangedContents():
3427 if deprecated_annotation_import_pattern.search(line):
3428 errors.append("%s:%d" % (f.LocalPath(), line_num))
3429
3430 results = []
3431 if errors:
3432 results.append(
3433 output_api.PresubmitError(
3434 'Annotations in android.test.suitebuilder.annotation have been'
3435 ' deprecated since API level 24. Please use android.support.test.filters'
3436 ' from //third_party/android_support_test_runner:runner_java instead.'
3437 ' Contact [email protected] if you have any questions.',
3438 errors))
3439 return results
3440
3441
3442def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3443 """Checks if MDPI assets are placed in a correct directory."""
3444 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3445 ('/res/drawable/' in f.LocalPath() or
3446 '/res/drawable-ldrtl/' in f.LocalPath()))
3447 errors = []
3448 for f in input_api.AffectedFiles(include_deletes=False,
3449 file_filter=file_filter):
3450 errors.append(' %s' % f.LocalPath())
3451
3452 results = []
3453 if errors:
3454 results.append(
3455 output_api.PresubmitError(
3456 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3457 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3458 '/res/drawable-ldrtl/.\n'
3459 'Contact [email protected] if you have questions.', errors))
3460 return results
3461
3462
3463def _CheckAndroidWebkitImports(input_api, output_api):
3464 """Checks that code uses org.chromium.base.Callback instead of
3465 android.webview.ValueCallback except in the WebView glue layer
3466 and WebLayer.
3467 """
3468 valuecallback_import_pattern = input_api.re.compile(
3469 r'^import android\.webkit\.ValueCallback;$')
3470
3471 errors = []
3472
3473 sources = lambda affected_file: input_api.FilterSourceFile(
3474 affected_file,
3475 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3476 DEFAULT_FILES_TO_SKIP + (
3477 r'^android_webview[\\/]glue[\\/].*',
3478 r'^weblayer[\\/].*',
3479 )),
3480 files_to_check=[r'.*\.java$'])
3481
3482 for f in input_api.AffectedSourceFiles(sources):
3483 for line_num, line in f.ChangedContents():
3484 if valuecallback_import_pattern.search(line):
3485 errors.append("%s:%d" % (f.LocalPath(), line_num))
3486
3487 results = []
3488
3489 if errors:
3490 results.append(
3491 output_api.PresubmitError(
3492 'android.webkit.ValueCallback usage is detected outside of the glue'
3493 ' layer. To stay compatible with the support library, android.webkit.*'
3494 ' classes should only be used inside the glue layer and'
3495 ' org.chromium.base.Callback should be used instead.', errors))
3496
3497 return results
3498
3499
3500def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3501 """Checks Android XML styles """
3502
3503 # Return early if no relevant files were modified.
3504 if not any(
3505 _IsXmlOrGrdFile(input_api, f.LocalPath())
3506 for f in input_api.AffectedFiles(include_deletes=False)):
3507 return []
3508
3509 import sys
3510 original_sys_path = sys.path
3511 try:
3512 sys.path = sys.path + [
3513 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3514 'android', 'checkxmlstyle')
3515 ]
3516 import checkxmlstyle
3517 finally:
3518 # Restore sys.path to what it was before.
3519 sys.path = original_sys_path
3520
3521 if is_check_on_upload:
3522 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3523 else:
3524 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3525
3526
3527def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3528 """Checks Android Infobar Deprecation """
3529
3530 import sys
3531 original_sys_path = sys.path
3532 try:
3533 sys.path = sys.path + [
3534 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3535 'android', 'infobar_deprecation')
3536 ]
3537 import infobar_deprecation
3538 finally:
3539 # Restore sys.path to what it was before.
3540 sys.path = original_sys_path
3541
3542 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3543
3544
3545class _PydepsCheckerResult:
3546 def __init__(self, cmd, pydeps_path, process, old_contents):
3547 self._cmd = cmd
3548 self._pydeps_path = pydeps_path
3549 self._process = process
3550 self._old_contents = old_contents
3551
3552 def GetError(self):
3553 """Returns an error message, or None."""
3554 import difflib
3555 if self._process.wait() != 0:
3556 # STDERR should already be printed.
3557 return 'Command failed: ' + self._cmd
3558 new_contents = self._process.stdout.read().splitlines()[2:]
3559 if self._old_contents != new_contents:
3560 diff = '\n'.join(
3561 difflib.context_diff(self._old_contents, new_contents))
3562 return ('File is stale: {}\n'
3563 'Diff (apply to fix):\n'
3564 '{}\n'
3565 'To regenerate, run:\n\n'
3566 ' {}').format(self._pydeps_path, diff, self._cmd)
3567 return None
3568
3569
3570class PydepsChecker:
3571 def __init__(self, input_api, pydeps_files):
3572 self._file_cache = {}
3573 self._input_api = input_api
3574 self._pydeps_files = pydeps_files
3575
3576 def _LoadFile(self, path):
3577 """Returns the list of paths within a .pydeps file relative to //."""
3578 if path not in self._file_cache:
3579 with open(path, encoding='utf-8') as f:
3580 self._file_cache[path] = f.read()
3581 return self._file_cache[path]
3582
3583 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3584 """Returns an interable of paths within the .pydep, relativized to //."""
3585 pydeps_data = self._LoadFile(pydeps_path)
3586 uses_gn_paths = '--gn-paths' in pydeps_data
3587 entries = (l for l in pydeps_data.splitlines()
3588 if not l.startswith('#'))
3589 if uses_gn_paths:
3590 # Paths look like: //foo/bar/baz
3591 return (e[2:] for e in entries)
3592 else:
3593 # Paths look like: path/relative/to/file.pydeps
3594 os_path = self._input_api.os_path
3595 pydeps_dir = os_path.dirname(pydeps_path)
3596 return (os_path.normpath(os_path.join(pydeps_dir, e))
3597 for e in entries)
3598
3599 def _CreateFilesToPydepsMap(self):
3600 """Returns a map of local_path -> list_of_pydeps."""
3601 ret = {}
3602 for pydep_local_path in self._pydeps_files:
3603 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3604 ret.setdefault(path, []).append(pydep_local_path)
3605 return ret
3606
3607 def ComputeAffectedPydeps(self):
3608 """Returns an iterable of .pydeps files that might need regenerating."""
3609 affected_pydeps = set()
3610 file_to_pydeps_map = None
3611 for f in self._input_api.AffectedFiles(include_deletes=True):
3612 local_path = f.LocalPath()
3613 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3614 # subrepositories. We can't figure out which files change, so re-check
3615 # all files.
3616 # Changes to print_python_deps.py affect all .pydeps.
3617 if local_path in ('DEPS', 'PRESUBMIT.py'
3618 ) or local_path.endswith('print_python_deps.py'):
3619 return self._pydeps_files
3620 elif local_path.endswith('.pydeps'):
3621 if local_path in self._pydeps_files:
3622 affected_pydeps.add(local_path)
3623 elif local_path.endswith('.py'):
3624 if file_to_pydeps_map is None:
3625 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3626 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3627 return affected_pydeps
3628
3629 def DetermineIfStaleAsync(self, pydeps_path):
3630 """Runs print_python_deps.py to see if the files is stale."""
3631 import os
3632
3633 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3634 if old_pydeps_data:
3635 cmd = old_pydeps_data[1][1:].strip()
3636 if '--output' not in cmd:
3637 cmd += ' --output ' + pydeps_path
3638 old_contents = old_pydeps_data[2:]
3639 else:
3640 # A default cmd that should work in most cases (as long as pydeps filename
3641 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3642 # file is empty/new.
3643 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3644 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3645 old_contents = []
3646 env = dict(os.environ)
3647 env['PYTHONDONTWRITEBYTECODE'] = '1'
3648 process = self._input_api.subprocess.Popen(
3649 cmd + ' --output ""',
3650 shell=True,
3651 env=env,
3652 stdout=self._input_api.subprocess.PIPE,
3653 encoding='utf-8')
3654 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:403655
3656
Tibor Goldschwendt360793f72019-06-25 18:23:493657def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:503658 args = {}
3659 with open('build/config/gclient_args.gni', 'r') as f:
3660 for line in f:
3661 line = line.strip()
3662 if not line or line.startswith('#'):
3663 continue
3664 attribute, value = line.split('=')
3665 args[attribute.strip()] = value.strip()
3666 return args
Tibor Goldschwendt360793f72019-06-25 18:23:493667
3668
Saagar Sanghavifceeaae2020-08-12 16:40:363669def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:503670 """Checks if a .pydeps file needs to be regenerated."""
3671 # This check is for Python dependency lists (.pydeps files), and involves
3672 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3673 # doesn't work on Windows and Mac, so skip it on other platforms.
3674 if not input_api.platform.startswith('linux'):
3675 return []
Erik Staabc734cd7a2021-11-23 03:11:523676
Sam Maiera6e76d72022-02-11 21:43:503677 results = []
3678 # First, check for new / deleted .pydeps.
3679 for f in input_api.AffectedFiles(include_deletes=True):
3680 # Check whether we are running the presubmit check for a file in src.
3681 # f.LocalPath is relative to repo (src, or internal repo).
3682 # os_path.exists is relative to src repo.
3683 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3684 # to src and we can conclude that the pydeps is in src.
3685 if f.LocalPath().endswith('.pydeps'):
3686 if input_api.os_path.exists(f.LocalPath()):
3687 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3688 results.append(
3689 output_api.PresubmitError(
3690 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3691 'remove %s' % f.LocalPath()))
3692 elif f.Action() != 'D' and f.LocalPath(
3693 ) not in _ALL_PYDEPS_FILES:
3694 results.append(
3695 output_api.PresubmitError(
3696 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3697 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403698
Sam Maiera6e76d72022-02-11 21:43:503699 if results:
3700 return results
3701
3702 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
3703 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3704 affected_pydeps = set(checker.ComputeAffectedPydeps())
3705 affected_android_pydeps = affected_pydeps.intersection(
3706 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3707 if affected_android_pydeps and not is_android:
3708 results.append(
3709 output_api.PresubmitPromptOrNotify(
3710 'You have changed python files that may affect pydeps for android\n'
3711 'specific scripts. However, the relevant presumbit check cannot be\n'
3712 'run because you are not using an Android checkout. To validate that\n'
3713 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3714 'use the android-internal-presubmit optional trybot.\n'
3715 'Possibly stale pydeps files:\n{}'.format(
3716 '\n'.join(affected_android_pydeps))))
3717
3718 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3719 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
3720 # Process these concurrently, as each one takes 1-2 seconds.
3721 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
3722 for result in pydep_results:
3723 error_msg = result.GetError()
3724 if error_msg:
3725 results.append(output_api.PresubmitError(error_msg))
3726
agrievef32bcc72016-04-04 14:57:403727 return results
3728
agrievef32bcc72016-04-04 14:57:403729
Saagar Sanghavifceeaae2020-08-12 16:40:363730def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503731 """Checks to make sure no header files have |Singleton<|."""
3732
3733 def FileFilter(affected_file):
3734 # It's ok for base/memory/singleton.h to have |Singleton<|.
3735 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
3736 (r"^base[\\/]memory[\\/]singleton\.h$",
3737 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
James Cook24a504192020-07-23 00:08:443738 r"quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:503739 return input_api.FilterSourceFile(affected_file,
3740 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433741
Sam Maiera6e76d72022-02-11 21:43:503742 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
3743 files = []
3744 for f in input_api.AffectedSourceFiles(FileFilter):
3745 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
3746 or f.LocalPath().endswith('.hpp')
3747 or f.LocalPath().endswith('.inl')):
3748 contents = input_api.ReadFile(f)
3749 for line in contents.splitlines(False):
3750 if (not line.lstrip().startswith('//')
3751 and # Strip C++ comment.
3752 pattern.search(line)):
3753 files.append(f)
3754 break
glidere61efad2015-02-18 17:39:433755
Sam Maiera6e76d72022-02-11 21:43:503756 if files:
3757 return [
3758 output_api.PresubmitError(
3759 'Found base::Singleton<T> in the following header files.\n' +
3760 'Please move them to an appropriate source file so that the ' +
3761 'template gets instantiated in a single compilation unit.',
3762 files)
3763 ]
3764 return []
glidere61efad2015-02-18 17:39:433765
3766
[email protected]fd20b902014-05-09 02:14:533767_DEPRECATED_CSS = [
3768 # Values
3769 ( "-webkit-box", "flex" ),
3770 ( "-webkit-inline-box", "inline-flex" ),
3771 ( "-webkit-flex", "flex" ),
3772 ( "-webkit-inline-flex", "inline-flex" ),
3773 ( "-webkit-min-content", "min-content" ),
3774 ( "-webkit-max-content", "max-content" ),
3775
3776 # Properties
3777 ( "-webkit-background-clip", "background-clip" ),
3778 ( "-webkit-background-origin", "background-origin" ),
3779 ( "-webkit-background-size", "background-size" ),
3780 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443781 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533782
3783 # Functions
3784 ( "-webkit-gradient", "gradient" ),
3785 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3786 ( "-webkit-linear-gradient", "linear-gradient" ),
3787 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3788 ( "-webkit-radial-gradient", "radial-gradient" ),
3789 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3790]
3791
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203792
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493793# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363794def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503795 """ Make sure that we don't use deprecated CSS
3796 properties, functions or values. Our external
3797 documentation and iOS CSS for dom distiller
3798 (reader mode) are ignored by the hooks as it
3799 needs to be consumed by WebKit. """
3800 results = []
3801 file_inclusion_pattern = [r".+\.css$"]
3802 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3803 input_api.DEFAULT_FILES_TO_SKIP +
3804 (r"^chrome/common/extensions/docs", r"^chrome/docs",
3805 r"^native_client_sdk"))
3806 file_filter = lambda f: input_api.FilterSourceFile(
3807 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3808 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3809 for line_num, line in fpath.ChangedContents():
3810 for (deprecated_value, value) in _DEPRECATED_CSS:
3811 if deprecated_value in line:
3812 results.append(
3813 output_api.PresubmitError(
3814 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3815 (fpath.LocalPath(), line_num, deprecated_value,
3816 value)))
3817 return results
[email protected]fd20b902014-05-09 02:14:533818
mohan.reddyf21db962014-10-16 12:26:473819
Saagar Sanghavifceeaae2020-08-12 16:40:363820def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503821 bad_files = {}
3822 for f in input_api.AffectedFiles(include_deletes=False):
3823 if (f.LocalPath().startswith('third_party')
3824 and not f.LocalPath().startswith('third_party/blink')
3825 and not f.LocalPath().startswith('third_party\\blink')):
3826 continue
rlanday6802cf632017-05-30 17:48:363827
Sam Maiera6e76d72022-02-11 21:43:503828 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3829 continue
rlanday6802cf632017-05-30 17:48:363830
Sam Maiera6e76d72022-02-11 21:43:503831 relative_includes = [
3832 line for _, line in f.ChangedContents()
3833 if "#include" in line and "../" in line
3834 ]
3835 if not relative_includes:
3836 continue
3837 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:363838
Sam Maiera6e76d72022-02-11 21:43:503839 if not bad_files:
3840 return []
rlanday6802cf632017-05-30 17:48:363841
Sam Maiera6e76d72022-02-11 21:43:503842 error_descriptions = []
3843 for file_path, bad_lines in bad_files.items():
3844 error_description = file_path
3845 for line in bad_lines:
3846 error_description += '\n ' + line
3847 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:363848
Sam Maiera6e76d72022-02-11 21:43:503849 results = []
3850 results.append(
3851 output_api.PresubmitError(
3852 'You added one or more relative #include paths (including "../").\n'
3853 'These shouldn\'t be used because they can be used to include headers\n'
3854 'from code that\'s not correctly specified as a dependency in the\n'
3855 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:363856
Sam Maiera6e76d72022-02-11 21:43:503857 return results
rlanday6802cf632017-05-30 17:48:363858
Takeshi Yoshinoe387aa32017-08-02 13:16:133859
Saagar Sanghavifceeaae2020-08-12 16:40:363860def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503861 """Check that nobody tries to include a cc file. It's a relatively
3862 common error which results in duplicate symbols in object
3863 files. This may not always break the build until someone later gets
3864 very confusing linking errors."""
3865 results = []
3866 for f in input_api.AffectedFiles(include_deletes=False):
3867 # We let third_party code do whatever it wants
3868 if (f.LocalPath().startswith('third_party')
3869 and not f.LocalPath().startswith('third_party/blink')
3870 and not f.LocalPath().startswith('third_party\\blink')):
3871 continue
Daniel Bratell65b033262019-04-23 08:17:063872
Sam Maiera6e76d72022-02-11 21:43:503873 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3874 continue
Daniel Bratell65b033262019-04-23 08:17:063875
Sam Maiera6e76d72022-02-11 21:43:503876 for _, line in f.ChangedContents():
3877 if line.startswith('#include "'):
3878 included_file = line.split('"')[1]
3879 if _IsCPlusPlusFile(input_api, included_file):
3880 # The most common naming for external files with C++ code,
3881 # apart from standard headers, is to call them foo.inc, but
3882 # Chromium sometimes uses foo-inc.cc so allow that as well.
3883 if not included_file.endswith(('.h', '-inc.cc')):
3884 results.append(
3885 output_api.PresubmitError(
3886 'Only header files or .inc files should be included in other\n'
3887 'C++ files. Compiling the contents of a cc file more than once\n'
3888 'will cause duplicate information in the build which may later\n'
3889 'result in strange link_errors.\n' +
3890 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:063891
Sam Maiera6e76d72022-02-11 21:43:503892 return results
Daniel Bratell65b033262019-04-23 08:17:063893
3894
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203895def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:503896 if not isinstance(key, ast.Str):
3897 return 'Key at line %d must be a string literal' % key.lineno
3898 if not isinstance(value, ast.Dict):
3899 return 'Value at line %d must be a dict' % value.lineno
3900 if len(value.keys) != 1:
3901 return 'Dict at line %d must have single entry' % value.lineno
3902 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3903 return (
3904 'Entry at line %d must have a string literal \'filepath\' as key' %
3905 value.lineno)
3906 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133907
Takeshi Yoshinoe387aa32017-08-02 13:16:133908
Sergey Ulanov4af16052018-11-08 02:41:463909def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:503910 if not isinstance(key, ast.Str):
3911 return 'Key at line %d must be a string literal' % key.lineno
3912 if not isinstance(value, ast.List):
3913 return 'Value at line %d must be a list' % value.lineno
3914 for element in value.elts:
3915 if not isinstance(element, ast.Str):
3916 return 'Watchlist elements on line %d is not a string' % key.lineno
3917 if not email_regex.match(element.s):
3918 return ('Watchlist element on line %d doesn\'t look like a valid '
3919 + 'email: %s') % (key.lineno, element.s)
3920 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133921
Takeshi Yoshinoe387aa32017-08-02 13:16:133922
Sergey Ulanov4af16052018-11-08 02:41:463923def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:503924 mismatch_template = (
3925 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3926 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133927
Sam Maiera6e76d72022-02-11 21:43:503928 email_regex = input_api.re.compile(
3929 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:463930
Sam Maiera6e76d72022-02-11 21:43:503931 ast = input_api.ast
3932 i = 0
3933 last_key = ''
3934 while True:
3935 if i >= len(wd_dict.keys):
3936 if i >= len(w_dict.keys):
3937 return None
3938 return mismatch_template % ('missing',
3939 'line %d' % w_dict.keys[i].lineno)
3940 elif i >= len(w_dict.keys):
3941 return (mismatch_template %
3942 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133943
Sam Maiera6e76d72022-02-11 21:43:503944 wd_key = wd_dict.keys[i]
3945 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133946
Sam Maiera6e76d72022-02-11 21:43:503947 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
3948 wd_dict.values[i], ast)
3949 if result is not None:
3950 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133951
Sam Maiera6e76d72022-02-11 21:43:503952 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
3953 email_regex)
3954 if result is not None:
3955 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203956
Sam Maiera6e76d72022-02-11 21:43:503957 if wd_key.s != w_key.s:
3958 return mismatch_template % ('%s at line %d' %
3959 (wd_key.s, wd_key.lineno),
3960 '%s at line %d' %
3961 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203962
Sam Maiera6e76d72022-02-11 21:43:503963 if wd_key.s < last_key:
3964 return (
3965 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
3966 % (wd_key.lineno, w_key.lineno))
3967 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203968
Sam Maiera6e76d72022-02-11 21:43:503969 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203970
3971
Sergey Ulanov4af16052018-11-08 02:41:463972def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:503973 ast = input_api.ast
3974 if not isinstance(expression, ast.Expression):
3975 return 'WATCHLISTS file must contain a valid expression'
3976 dictionary = expression.body
3977 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3978 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203979
Sam Maiera6e76d72022-02-11 21:43:503980 first_key = dictionary.keys[0]
3981 first_value = dictionary.values[0]
3982 second_key = dictionary.keys[1]
3983 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203984
Sam Maiera6e76d72022-02-11 21:43:503985 if (not isinstance(first_key, ast.Str)
3986 or first_key.s != 'WATCHLIST_DEFINITIONS'
3987 or not isinstance(first_value, ast.Dict)):
3988 return ('The first entry of the dict in WATCHLISTS file must be '
3989 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203990
Sam Maiera6e76d72022-02-11 21:43:503991 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
3992 or not isinstance(second_value, ast.Dict)):
3993 return ('The second entry of the dict in WATCHLISTS file must be '
3994 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203995
Sam Maiera6e76d72022-02-11 21:43:503996 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133997
3998
Saagar Sanghavifceeaae2020-08-12 16:40:363999def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504000 for f in input_api.AffectedFiles(include_deletes=False):
4001 if f.LocalPath() == 'WATCHLISTS':
4002 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134003
Sam Maiera6e76d72022-02-11 21:43:504004 try:
4005 # First, make sure that it can be evaluated.
4006 input_api.ast.literal_eval(contents)
4007 # Get an AST tree for it and scan the tree for detailed style checking.
4008 expression = input_api.ast.parse(contents,
4009 filename='WATCHLISTS',
4010 mode='eval')
4011 except ValueError as e:
4012 return [
4013 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4014 long_text=repr(e))
4015 ]
4016 except SyntaxError as e:
4017 return [
4018 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4019 long_text=repr(e))
4020 ]
4021 except TypeError as e:
4022 return [
4023 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4024 long_text=repr(e))
4025 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134026
Sam Maiera6e76d72022-02-11 21:43:504027 result = _CheckWATCHLISTSSyntax(expression, input_api)
4028 if result is not None:
4029 return [output_api.PresubmitError(result)]
4030 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134031
Sam Maiera6e76d72022-02-11 21:43:504032 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134033
4034
Andrew Grieve1b290e4a22020-11-24 20:07:014035def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504036 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014037
Sam Maiera6e76d72022-02-11 21:43:504038 As documented at //build/docs/writing_gn_templates.md
4039 """
Andrew Grieve1b290e4a22020-11-24 20:07:014040
Sam Maiera6e76d72022-02-11 21:43:504041 def gn_files(f):
4042 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014043
Sam Maiera6e76d72022-02-11 21:43:504044 problems = []
4045 for f in input_api.AffectedSourceFiles(gn_files):
4046 for line_num, line in f.ChangedContents():
4047 if 'forward_variables_from(invoker, "*")' in line:
4048 problems.append(
4049 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4050 (f.LocalPath(), line_num))
4051
4052 if problems:
4053 return [
4054 output_api.PresubmitPromptWarning(
4055 'forward_variables_from("*") without exclusions',
4056 items=sorted(problems),
4057 long_text=(
4058 'The variables "visibilty" and "test_only" should be '
4059 'explicitly listed in forward_variables_from(). For more '
4060 'details, see:\n'
4061 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4062 'build/docs/writing_gn_templates.md'
4063 '#Using-forward_variables_from'))
4064 ]
4065 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014066
4067
Saagar Sanghavifceeaae2020-08-12 16:40:364068def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504069 """Checks that newly added header files have corresponding GN changes.
4070 Note that this is only a heuristic. To be precise, run script:
4071 build/check_gn_headers.py.
4072 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194073
Sam Maiera6e76d72022-02-11 21:43:504074 def headers(f):
4075 return input_api.FilterSourceFile(
4076 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194077
Sam Maiera6e76d72022-02-11 21:43:504078 new_headers = []
4079 for f in input_api.AffectedSourceFiles(headers):
4080 if f.Action() != 'A':
4081 continue
4082 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194083
Sam Maiera6e76d72022-02-11 21:43:504084 def gn_files(f):
4085 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194086
Sam Maiera6e76d72022-02-11 21:43:504087 all_gn_changed_contents = ''
4088 for f in input_api.AffectedSourceFiles(gn_files):
4089 for _, line in f.ChangedContents():
4090 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194091
Sam Maiera6e76d72022-02-11 21:43:504092 problems = []
4093 for header in new_headers:
4094 basename = input_api.os_path.basename(header)
4095 if basename not in all_gn_changed_contents:
4096 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194097
Sam Maiera6e76d72022-02-11 21:43:504098 if problems:
4099 return [
4100 output_api.PresubmitPromptWarning(
4101 'Missing GN changes for new header files',
4102 items=sorted(problems),
4103 long_text=
4104 'Please double check whether newly added header files need '
4105 'corresponding changes in gn or gni files.\nThis checking is only a '
4106 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4107 'Read https://crbug.com/661774 for more info.')
4108 ]
4109 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194110
4111
Saagar Sanghavifceeaae2020-08-12 16:40:364112def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504113 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024114
Sam Maiera6e76d72022-02-11 21:43:504115 This assumes we won't intentionally reference one product from the other
4116 product.
4117 """
4118 all_problems = []
4119 test_cases = [{
4120 "filename_postfix": "google_chrome_strings.grd",
4121 "correct_name": "Chrome",
4122 "incorrect_name": "Chromium",
4123 }, {
4124 "filename_postfix": "chromium_strings.grd",
4125 "correct_name": "Chromium",
4126 "incorrect_name": "Chrome",
4127 }]
Michael Giuffridad3bc8672018-10-25 22:48:024128
Sam Maiera6e76d72022-02-11 21:43:504129 for test_case in test_cases:
4130 problems = []
4131 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4132 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024133
Sam Maiera6e76d72022-02-11 21:43:504134 # Check each new line. Can yield false positives in multiline comments, but
4135 # easier than trying to parse the XML because messages can have nested
4136 # children, and associating message elements with affected lines is hard.
4137 for f in input_api.AffectedSourceFiles(filename_filter):
4138 for line_num, line in f.ChangedContents():
4139 if "<message" in line or "<!--" in line or "-->" in line:
4140 continue
4141 if test_case["incorrect_name"] in line:
4142 problems.append("Incorrect product name in %s:%d" %
4143 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024144
Sam Maiera6e76d72022-02-11 21:43:504145 if problems:
4146 message = (
4147 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4148 % (test_case["correct_name"], test_case["correct_name"],
4149 test_case["incorrect_name"]))
4150 all_problems.append(
4151 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024152
Sam Maiera6e76d72022-02-11 21:43:504153 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024154
4155
Saagar Sanghavifceeaae2020-08-12 16:40:364156def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504157 """Avoid large files, especially binary files, in the repository since
4158 git doesn't scale well for those. They will be in everyone's repo
4159 clones forever, forever making Chromium slower to clone and work
4160 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364161
Sam Maiera6e76d72022-02-11 21:43:504162 # Uploading files to cloud storage is not trivial so we don't want
4163 # to set the limit too low, but the upper limit for "normal" large
4164 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4165 # anything over 20 MB is exceptional.
4166 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364167
Sam Maiera6e76d72022-02-11 21:43:504168 too_large_files = []
4169 for f in input_api.AffectedFiles():
4170 # Check both added and modified files (but not deleted files).
4171 if f.Action() in ('A', 'M'):
4172 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4173 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4174 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364175
Sam Maiera6e76d72022-02-11 21:43:504176 if too_large_files:
4177 message = (
4178 'Do not commit large files to git since git scales badly for those.\n'
4179 +
4180 'Instead put the large files in cloud storage and use DEPS to\n' +
4181 'fetch them.\n' + '\n'.join(too_large_files))
4182 return [
4183 output_api.PresubmitError('Too large files found in commit',
4184 long_text=message + '\n')
4185 ]
4186 else:
4187 return []
Daniel Bratell93eb6c62019-04-29 20:13:364188
Max Morozb47503b2019-08-08 21:03:274189
Saagar Sanghavifceeaae2020-08-12 16:40:364190def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504191 """Checks specific for fuzz target sources."""
4192 EXPORTED_SYMBOLS = [
4193 'LLVMFuzzerInitialize',
4194 'LLVMFuzzerCustomMutator',
4195 'LLVMFuzzerCustomCrossOver',
4196 'LLVMFuzzerMutate',
4197 ]
Max Morozb47503b2019-08-08 21:03:274198
Sam Maiera6e76d72022-02-11 21:43:504199 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274200
Sam Maiera6e76d72022-02-11 21:43:504201 def FilterFile(affected_file):
4202 """Ignore libFuzzer source code."""
4203 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4204 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274205
Sam Maiera6e76d72022-02-11 21:43:504206 return input_api.FilterSourceFile(affected_file,
4207 files_to_check=[files_to_check],
4208 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274209
Sam Maiera6e76d72022-02-11 21:43:504210 files_with_missing_header = []
4211 for f in input_api.AffectedSourceFiles(FilterFile):
4212 contents = input_api.ReadFile(f, 'r')
4213 if REQUIRED_HEADER in contents:
4214 continue
Max Morozb47503b2019-08-08 21:03:274215
Sam Maiera6e76d72022-02-11 21:43:504216 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4217 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274218
Sam Maiera6e76d72022-02-11 21:43:504219 if not files_with_missing_header:
4220 return []
Max Morozb47503b2019-08-08 21:03:274221
Sam Maiera6e76d72022-02-11 21:43:504222 long_text = (
4223 'If you define any of the libFuzzer optional functions (%s), it is '
4224 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4225 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4226 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4227 'to access command line arguments passed to the fuzzer. Instead, prefer '
4228 'static initialization and shared resources as documented in '
4229 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4230 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4231 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274232
Sam Maiera6e76d72022-02-11 21:43:504233 return [
4234 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4235 REQUIRED_HEADER,
4236 items=files_with_missing_header,
4237 long_text=long_text)
4238 ]
Max Morozb47503b2019-08-08 21:03:274239
4240
Mohamed Heikald048240a2019-11-12 16:57:374241def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504242 """
4243 Warns authors who add images into the repo to make sure their images are
4244 optimized before committing.
4245 """
4246 images_added = False
4247 image_paths = []
4248 errors = []
4249 filter_lambda = lambda x: input_api.FilterSourceFile(
4250 x,
4251 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4252 DEFAULT_FILES_TO_SKIP),
4253 files_to_check=[r'.*\/(drawable|mipmap)'])
4254 for f in input_api.AffectedFiles(include_deletes=False,
4255 file_filter=filter_lambda):
4256 local_path = f.LocalPath().lower()
4257 if any(
4258 local_path.endswith(extension)
4259 for extension in _IMAGE_EXTENSIONS):
4260 images_added = True
4261 image_paths.append(f)
4262 if images_added:
4263 errors.append(
4264 output_api.PresubmitPromptWarning(
4265 'It looks like you are trying to commit some images. If these are '
4266 'non-test-only images, please make sure to read and apply the tips in '
4267 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4268 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4269 'FYI only and will not block your CL on the CQ.', image_paths))
4270 return errors
Mohamed Heikald048240a2019-11-12 16:57:374271
4272
Saagar Sanghavifceeaae2020-08-12 16:40:364273def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504274 """Groups upload checks that target android code."""
4275 results = []
4276 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4277 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4278 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4279 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4280 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4281 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4282 input_api, output_api))
4283 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4284 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4285 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4286 results.extend(_CheckNewImagesWarning(input_api, output_api))
4287 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4288 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4289 return results
4290
Becky Zhou7c69b50992018-12-10 19:37:574291
Saagar Sanghavifceeaae2020-08-12 16:40:364292def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504293 """Groups commit checks that target android code."""
4294 results = []
4295 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4296 return results
dgnaa68d5e2015-06-10 10:08:224297
Chris Hall59f8d0c72020-05-01 07:31:194298# TODO(chrishall): could we additionally match on any path owned by
4299# ui/accessibility/OWNERS ?
4300_ACCESSIBILITY_PATHS = (
4301 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4302 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4303 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4304 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4305 r"^content[\\/]browser[\\/]accessibility[\\/]",
4306 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4307 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4308 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4309 r"^ui[\\/]accessibility[\\/]",
4310 r"^ui[\\/]views[\\/]accessibility[\\/]",
4311)
4312
Saagar Sanghavifceeaae2020-08-12 16:40:364313def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504314 """Checks that commits to accessibility code contain an AX-Relnotes field in
4315 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194316
Sam Maiera6e76d72022-02-11 21:43:504317 def FileFilter(affected_file):
4318 paths = _ACCESSIBILITY_PATHS
4319 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194320
Sam Maiera6e76d72022-02-11 21:43:504321 # Only consider changes affecting accessibility paths.
4322 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4323 return []
Akihiro Ota08108e542020-05-20 15:30:534324
Sam Maiera6e76d72022-02-11 21:43:504325 # AX-Relnotes can appear in either the description or the footer.
4326 # When searching the description, require 'AX-Relnotes:' to appear at the
4327 # beginning of a line.
4328 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4329 description_has_relnotes = any(
4330 ax_regex.match(line)
4331 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194332
Sam Maiera6e76d72022-02-11 21:43:504333 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4334 'AX-Relnotes', [])
4335 if description_has_relnotes or footer_relnotes:
4336 return []
Chris Hall59f8d0c72020-05-01 07:31:194337
Sam Maiera6e76d72022-02-11 21:43:504338 # TODO(chrishall): link to Relnotes documentation in message.
4339 message = (
4340 "Missing 'AX-Relnotes:' field required for accessibility changes"
4341 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4342 "user-facing changes"
4343 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4344 "user-facing effects"
4345 "\n if this is confusing or annoying then please contact members "
4346 "of ui/accessibility/OWNERS.")
4347
4348 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224349
Mark Schillacie5a0be22022-01-19 00:38:394350
4351_ACCESSIBILITY_EVENTS_TEST_PATH = (
4352 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]event[\\/].*\.html",
4353)
4354
4355_ACCESSIBILITY_TREE_TEST_PATH = (
4356 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]accname[\\/].*\.html",
4357 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]aria[\\/].*\.html",
4358 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]css[\\/].*\.html",
4359 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]html[\\/].*\.html",
4360)
4361
4362_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
4363 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4364)
4365
4366_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Mark Schillaci6f568a52022-02-17 18:41:444367 r"^.*[\\/]WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394368)
4369
4370def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504371 """Checks that commits that include a newly added, renamed/moved, or deleted
4372 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4373 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394374
Sam Maiera6e76d72022-02-11 21:43:504375 def FilePathFilter(affected_file):
4376 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4377 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394378
Sam Maiera6e76d72022-02-11 21:43:504379 def AndroidFilePathFilter(affected_file):
4380 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4381 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394382
Sam Maiera6e76d72022-02-11 21:43:504383 # Only consider changes in the events test data path with html type.
4384 if not any(
4385 input_api.AffectedFiles(include_deletes=True,
4386 file_filter=FilePathFilter)):
4387 return []
Mark Schillacie5a0be22022-01-19 00:38:394388
Sam Maiera6e76d72022-02-11 21:43:504389 # If the commit contains any change to the Android test file, ignore.
4390 if any(
4391 input_api.AffectedFiles(include_deletes=True,
4392 file_filter=AndroidFilePathFilter)):
4393 return []
Mark Schillacie5a0be22022-01-19 00:38:394394
Sam Maiera6e76d72022-02-11 21:43:504395 # Only consider changes that are adding/renaming or deleting a file
4396 message = []
4397 for f in input_api.AffectedFiles(include_deletes=True,
4398 file_filter=FilePathFilter):
4399 if f.Action() == 'A' or f.Action() == 'D':
4400 message = (
4401 "It appears that you are adding, renaming or deleting"
4402 "\na dump_accessibility_events* test, but have not included"
4403 "\na corresponding change for Android."
4404 "\nPlease include (or remove) the test from:"
4405 "\n content/public/android/javatests/src/org/chromium/"
4406 "content/browser/accessibility/"
4407 "WebContentsAccessibilityEventsTest.java"
4408 "\nIf this message is confusing or annoying, please contact"
4409 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394410
Sam Maiera6e76d72022-02-11 21:43:504411 # If no message was set, return empty.
4412 if not len(message):
4413 return []
4414
4415 return [output_api.PresubmitPromptWarning(message)]
4416
Mark Schillacie5a0be22022-01-19 00:38:394417
4418def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504419 """Checks that commits that include a newly added, renamed/moved, or deleted
4420 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4421 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394422
Sam Maiera6e76d72022-02-11 21:43:504423 def FilePathFilter(affected_file):
4424 paths = _ACCESSIBILITY_TREE_TEST_PATH
4425 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394426
Sam Maiera6e76d72022-02-11 21:43:504427 def AndroidFilePathFilter(affected_file):
4428 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4429 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394430
Sam Maiera6e76d72022-02-11 21:43:504431 # Only consider changes in the various tree test data paths with html type.
4432 if not any(
4433 input_api.AffectedFiles(include_deletes=True,
4434 file_filter=FilePathFilter)):
4435 return []
Mark Schillacie5a0be22022-01-19 00:38:394436
Sam Maiera6e76d72022-02-11 21:43:504437 # If the commit contains any change to the Android test file, ignore.
4438 if any(
4439 input_api.AffectedFiles(include_deletes=True,
4440 file_filter=AndroidFilePathFilter)):
4441 return []
Mark Schillacie5a0be22022-01-19 00:38:394442
Sam Maiera6e76d72022-02-11 21:43:504443 # Only consider changes that are adding/renaming or deleting a file
4444 message = []
4445 for f in input_api.AffectedFiles(include_deletes=True,
4446 file_filter=FilePathFilter):
4447 if f.Action() == 'A' or f.Action() == 'D':
4448 message = (
4449 "It appears that you are adding, renaming or deleting"
4450 "\na dump_accessibility_tree* test, but have not included"
4451 "\na corresponding change for Android."
4452 "\nPlease include (or remove) the test from:"
4453 "\n content/public/android/javatests/src/org/chromium/"
4454 "content/browser/accessibility/"
4455 "WebContentsAccessibilityTreeTest.java"
4456 "\nIf this message is confusing or annoying, please contact"
4457 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394458
Sam Maiera6e76d72022-02-11 21:43:504459 # If no message was set, return empty.
4460 if not len(message):
4461 return []
4462
4463 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394464
4465
seanmccullough4a9356252021-04-08 19:54:094466# string pattern, sequence of strings to show when pattern matches,
4467# error flag. True if match is a presubmit error, otherwise it's a warning.
4468_NON_INCLUSIVE_TERMS = (
4469 (
4470 # Note that \b pattern in python re is pretty particular. In this
4471 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4472 # ...' will not. This may require some tweaking to catch these cases
4473 # without triggering a lot of false positives. Leaving it naive and
4474 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324475 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094476 (
4477 'Please don\'t use blacklist, whitelist, ' # nocheck
4478 'or slave in your', # nocheck
4479 'code and make every effort to use other terms. Using "// nocheck"',
4480 '"# nocheck" or "<!-- nocheck -->"',
4481 'at the end of the offending line will bypass this PRESUBMIT error',
4482 'but avoid using this whenever possible. Reach out to',
4483 '[email protected] if you have questions'),
4484 True),)
4485
Saagar Sanghavifceeaae2020-08-12 16:40:364486def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504487 """Checks common to both upload and commit."""
4488 results = []
Eric Boren6fd2b932018-01-25 15:05:084489 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504490 input_api.canned_checks.PanProjectChecks(
4491 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084492
Sam Maiera6e76d72022-02-11 21:43:504493 author = input_api.change.author_email
4494 if author and author not in _KNOWN_ROBOTS:
4495 results.extend(
4496 input_api.canned_checks.CheckAuthorizedAuthor(
4497 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244498
Sam Maiera6e76d72022-02-11 21:43:504499 results.extend(
4500 input_api.canned_checks.CheckChangeHasNoTabs(
4501 input_api,
4502 output_api,
4503 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
4504 results.extend(
4505 input_api.RunTests(
4506 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:174507
Bruce Dawsonc8054482022-03-28 15:33:374508 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:504509 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:374510 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:504511 results.extend(
4512 input_api.RunTests(
4513 input_api.canned_checks.CheckDirMetadataFormat(
4514 input_api, output_api, dirmd_bin)))
4515 results.extend(
4516 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4517 input_api, output_api))
4518 results.extend(
4519 input_api.canned_checks.CheckNoNewMetadataInOwners(
4520 input_api, output_api))
4521 results.extend(
4522 input_api.canned_checks.CheckInclusiveLanguage(
4523 input_api,
4524 output_api,
4525 excluded_directories_relative_path=[
4526 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
4527 ],
4528 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:594529
Sam Maiera6e76d72022-02-11 21:43:504530 for f in input_api.AffectedFiles():
4531 path, name = input_api.os_path.split(f.LocalPath())
4532 if name == 'PRESUBMIT.py':
4533 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
4534 path)
4535 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4536 if f.Action() != 'D' and input_api.os_path.exists(test_file):
4537 # The PRESUBMIT.py file (and the directory containing it) might
4538 # have been affected by being moved or removed, so only try to
4539 # run the tests if they still exist.
4540 use_python3 = False
4541 with open(f.LocalPath()) as fp:
4542 use_python3 = any(
4543 line.startswith('USE_PYTHON3 = True')
4544 for line in fp.readlines())
4545
4546 results.extend(
4547 input_api.canned_checks.RunUnitTestsInDirectory(
4548 input_api,
4549 output_api,
4550 full_path,
4551 files_to_check=[r'^PRESUBMIT_test\.py$'],
4552 run_on_python2=not use_python3,
4553 run_on_python3=use_python3,
4554 skip_shebang_check=True))
4555 return results
[email protected]1f7b4172010-01-28 01:17:344556
[email protected]b337cb5b2011-01-23 21:24:054557
Saagar Sanghavifceeaae2020-08-12 16:40:364558def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504559 problems = [
4560 f.LocalPath() for f in input_api.AffectedFiles()
4561 if f.LocalPath().endswith(('.orig', '.rej'))
4562 ]
4563 # Cargo.toml.orig files are part of third-party crates downloaded from
4564 # crates.io and should be included.
4565 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
4566 if problems:
4567 return [
4568 output_api.PresubmitError("Don't commit .rej and .orig files.",
4569 problems)
4570 ]
4571 else:
4572 return []
[email protected]b8079ae4a2012-12-05 19:56:494573
4574
Saagar Sanghavifceeaae2020-08-12 16:40:364575def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504576 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4577 macro_re = input_api.re.compile(
4578 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
4579 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
4580 input_api.re.MULTILINE)
4581 extension_re = input_api.re.compile(r'\.[a-z]+$')
4582 errors = []
4583 for f in input_api.AffectedFiles(include_deletes=False):
4584 if not f.LocalPath().endswith(
4585 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4586 continue
4587 found_line_number = None
4588 found_macro = None
4589 all_lines = input_api.ReadFile(f, 'r').splitlines()
4590 for line_num, line in enumerate(all_lines):
4591 match = macro_re.search(line)
4592 if match:
4593 found_line_number = line_num
4594 found_macro = match.group(2)
4595 break
4596 if not found_line_number:
4597 continue
Kent Tamura5a8755d2017-06-29 23:37:074598
Sam Maiera6e76d72022-02-11 21:43:504599 found_include_line = -1
4600 for line_num, line in enumerate(all_lines):
4601 if include_re.search(line):
4602 found_include_line = line_num
4603 break
4604 if found_include_line >= 0 and found_include_line < found_line_number:
4605 continue
Kent Tamura5a8755d2017-06-29 23:37:074606
Sam Maiera6e76d72022-02-11 21:43:504607 if not f.LocalPath().endswith('.h'):
4608 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4609 try:
4610 content = input_api.ReadFile(primary_header_path, 'r')
4611 if include_re.search(content):
4612 continue
4613 except IOError:
4614 pass
4615 errors.append('%s:%d %s macro is used without first including build/'
4616 'build_config.h.' %
4617 (f.LocalPath(), found_line_number, found_macro))
4618 if errors:
4619 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4620 return []
Kent Tamura5a8755d2017-06-29 23:37:074621
4622
Lei Zhang1c12a22f2021-05-12 11:28:454623def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504624 stl_include_re = input_api.re.compile(r'^#include\s+<('
4625 r'algorithm|'
4626 r'array|'
4627 r'limits|'
4628 r'list|'
4629 r'map|'
4630 r'memory|'
4631 r'queue|'
4632 r'set|'
4633 r'string|'
4634 r'unordered_map|'
4635 r'unordered_set|'
4636 r'utility|'
4637 r'vector)>')
4638 std_namespace_re = input_api.re.compile(r'std::')
4639 errors = []
4640 for f in input_api.AffectedFiles():
4641 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4642 continue
Lei Zhang1c12a22f2021-05-12 11:28:454643
Sam Maiera6e76d72022-02-11 21:43:504644 uses_std_namespace = False
4645 has_stl_include = False
4646 for line in f.NewContents():
4647 if has_stl_include and uses_std_namespace:
4648 break
Lei Zhang1c12a22f2021-05-12 11:28:454649
Sam Maiera6e76d72022-02-11 21:43:504650 if not has_stl_include and stl_include_re.search(line):
4651 has_stl_include = True
4652 continue
Lei Zhang1c12a22f2021-05-12 11:28:454653
Bruce Dawson4a5579a2022-04-08 17:11:364654 if not uses_std_namespace and (std_namespace_re.search(line)
4655 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504656 uses_std_namespace = True
4657 continue
Lei Zhang1c12a22f2021-05-12 11:28:454658
Sam Maiera6e76d72022-02-11 21:43:504659 if has_stl_include and not uses_std_namespace:
4660 errors.append(
4661 '%s: Includes STL header(s) but does not reference std::' %
4662 f.LocalPath())
4663 if errors:
4664 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4665 return []
Lei Zhang1c12a22f2021-05-12 11:28:454666
4667
Xiaohan Wang42d96c22022-01-20 17:23:114668def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504669 """Check for sensible looking, totally invalid OS macros."""
4670 preprocessor_statement = input_api.re.compile(r'^\s*#')
4671 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
4672 results = []
4673 for lnum, line in f.ChangedContents():
4674 if preprocessor_statement.search(line):
4675 for match in os_macro.finditer(line):
4676 results.append(
4677 ' %s:%d: %s' %
4678 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
4679 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
4680 return results
[email protected]b00342e7f2013-03-26 16:21:544681
4682
Xiaohan Wang42d96c22022-01-20 17:23:114683def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504684 """Check all affected files for invalid OS macros."""
4685 bad_macros = []
4686 for f in input_api.AffectedSourceFiles(None):
4687 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
4688 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:544689
Sam Maiera6e76d72022-02-11 21:43:504690 if not bad_macros:
4691 return []
[email protected]b00342e7f2013-03-26 16:21:544692
Sam Maiera6e76d72022-02-11 21:43:504693 return [
4694 output_api.PresubmitError(
4695 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
4696 'defined in build_config.h):', bad_macros)
4697 ]
[email protected]b00342e7f2013-03-26 16:21:544698
lliabraa35bab3932014-10-01 12:16:444699
4700def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504701 """Check all affected files for invalid "if defined" macros."""
4702 ALWAYS_DEFINED_MACROS = (
4703 "TARGET_CPU_PPC",
4704 "TARGET_CPU_PPC64",
4705 "TARGET_CPU_68K",
4706 "TARGET_CPU_X86",
4707 "TARGET_CPU_ARM",
4708 "TARGET_CPU_MIPS",
4709 "TARGET_CPU_SPARC",
4710 "TARGET_CPU_ALPHA",
4711 "TARGET_IPHONE_SIMULATOR",
4712 "TARGET_OS_EMBEDDED",
4713 "TARGET_OS_IPHONE",
4714 "TARGET_OS_MAC",
4715 "TARGET_OS_UNIX",
4716 "TARGET_OS_WIN32",
4717 )
4718 ifdef_macro = input_api.re.compile(
4719 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4720 results = []
4721 for lnum, line in f.ChangedContents():
4722 for match in ifdef_macro.finditer(line):
4723 if match.group(1) in ALWAYS_DEFINED_MACROS:
4724 always_defined = ' %s is always defined. ' % match.group(1)
4725 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4726 results.append(
4727 ' %s:%d %s\n\t%s' %
4728 (f.LocalPath(), lnum, always_defined, did_you_mean))
4729 return results
lliabraa35bab3932014-10-01 12:16:444730
4731
Saagar Sanghavifceeaae2020-08-12 16:40:364732def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504733 """Check all affected files for invalid "if defined" macros."""
4734 bad_macros = []
4735 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
4736 for f in input_api.AffectedFiles():
4737 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
4738 continue
4739 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4740 bad_macros.extend(
4741 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:444742
Sam Maiera6e76d72022-02-11 21:43:504743 if not bad_macros:
4744 return []
lliabraa35bab3932014-10-01 12:16:444745
Sam Maiera6e76d72022-02-11 21:43:504746 return [
4747 output_api.PresubmitError(
4748 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4749 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4750 bad_macros)
4751 ]
lliabraa35bab3932014-10-01 12:16:444752
4753
Saagar Sanghavifceeaae2020-08-12 16:40:364754def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504755 """Check for same IPC rules described in
4756 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4757 """
4758 base_pattern = r'IPC_ENUM_TRAITS\('
4759 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4760 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:044761
Sam Maiera6e76d72022-02-11 21:43:504762 problems = []
4763 for f in input_api.AffectedSourceFiles(None):
4764 local_path = f.LocalPath()
4765 if not local_path.endswith('.h'):
4766 continue
4767 for line_number, line in f.ChangedContents():
4768 if inclusion_pattern.search(
4769 line) and not comment_pattern.search(line):
4770 problems.append('%s:%d\n %s' %
4771 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:044772
Sam Maiera6e76d72022-02-11 21:43:504773 if problems:
4774 return [
4775 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
4776 problems)
4777 ]
4778 else:
4779 return []
mlamouria82272622014-09-16 18:45:044780
[email protected]b00342e7f2013-03-26 16:21:544781
Saagar Sanghavifceeaae2020-08-12 16:40:364782def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504783 """Check to make sure no files being submitted have long paths.
4784 This causes issues on Windows.
4785 """
4786 problems = []
4787 for f in input_api.AffectedTestableFiles():
4788 local_path = f.LocalPath()
4789 # Windows has a path limit of 260 characters. Limit path length to 200 so
4790 # that we have some extra for the prefix on dev machines and the bots.
4791 if len(local_path) > 200:
4792 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:054793
Sam Maiera6e76d72022-02-11 21:43:504794 if problems:
4795 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4796 else:
4797 return []
Stephen Martinis97a394142018-06-07 23:06:054798
4799
Saagar Sanghavifceeaae2020-08-12 16:40:364800def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504801 """Check that header files have proper guards against multiple inclusion.
4802 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:364803 should include the string "no-include-guard-because-multiply-included" or
4804 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:504805 """
Daniel Bratell8ba52722018-03-02 16:06:144806
Sam Maiera6e76d72022-02-11 21:43:504807 def is_chromium_header_file(f):
4808 # We only check header files under the control of the Chromium
4809 # project. That is, those outside third_party apart from
4810 # third_party/blink.
4811 # We also exclude *_message_generator.h headers as they use
4812 # include guards in a special, non-typical way.
4813 file_with_path = input_api.os_path.normpath(f.LocalPath())
4814 return (file_with_path.endswith('.h')
4815 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:334816 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:504817 and (not file_with_path.startswith('third_party')
4818 or file_with_path.startswith(
4819 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144820
Sam Maiera6e76d72022-02-11 21:43:504821 def replace_special_with_underscore(string):
4822 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144823
Sam Maiera6e76d72022-02-11 21:43:504824 errors = []
Daniel Bratell8ba52722018-03-02 16:06:144825
Sam Maiera6e76d72022-02-11 21:43:504826 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
4827 guard_name = None
4828 guard_line_number = None
4829 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:144830
Sam Maiera6e76d72022-02-11 21:43:504831 file_with_path = input_api.os_path.normpath(f.LocalPath())
4832 base_file_name = input_api.os_path.splitext(
4833 input_api.os_path.basename(file_with_path))[0]
4834 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:144835
Sam Maiera6e76d72022-02-11 21:43:504836 expected_guard = replace_special_with_underscore(
4837 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144838
Sam Maiera6e76d72022-02-11 21:43:504839 # For "path/elem/file_name.h" we should really only accept
4840 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4841 # are too many (1000+) files with slight deviations from the
4842 # coding style. The most important part is that the include guard
4843 # is there, and that it's unique, not the name so this check is
4844 # forgiving for existing files.
4845 #
4846 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:144847
Sam Maiera6e76d72022-02-11 21:43:504848 guard_name_pattern_list = [
4849 # Anything with the right suffix (maybe with an extra _).
4850 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:144851
Sam Maiera6e76d72022-02-11 21:43:504852 # To cover include guards with old Blink style.
4853 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:144854
Sam Maiera6e76d72022-02-11 21:43:504855 # Anything including the uppercase name of the file.
4856 r'\w*' + input_api.re.escape(
4857 replace_special_with_underscore(upper_base_file_name)) +
4858 r'\w*',
4859 ]
4860 guard_name_pattern = '|'.join(guard_name_pattern_list)
4861 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
4862 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:144863
Sam Maiera6e76d72022-02-11 21:43:504864 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:364865 if ('no-include-guard-because-multiply-included' in line
4866 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504867 guard_name = 'DUMMY' # To not trigger check outside the loop.
4868 break
Daniel Bratell8ba52722018-03-02 16:06:144869
Sam Maiera6e76d72022-02-11 21:43:504870 if guard_name is None:
4871 match = guard_pattern.match(line)
4872 if match:
4873 guard_name = match.group(1)
4874 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:144875
Sam Maiera6e76d72022-02-11 21:43:504876 # We allow existing files to use include guards whose names
4877 # don't match the chromium style guide, but new files should
4878 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:494879 if guard_name != expected_guard:
4880 if not f.OldContents():
Sam Maiera6e76d72022-02-11 21:43:504881 errors.append(
4882 output_api.PresubmitPromptWarning(
4883 'Header using the wrong include guard name %s'
4884 % guard_name, [
4885 '%s:%d' %
4886 (f.LocalPath(), line_number + 1)
4887 ], 'Expected: %r\nFound: %r' %
4888 (expected_guard, guard_name)))
4889 else:
4890 # The line after #ifndef should have a #define of the same name.
4891 if line_number == guard_line_number + 1:
4892 expected_line = '#define %s' % guard_name
4893 if line != expected_line:
4894 errors.append(
4895 output_api.PresubmitPromptWarning(
4896 'Missing "%s" for include guard' %
4897 expected_line,
4898 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4899 'Expected: %r\nGot: %r' %
4900 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:144901
Sam Maiera6e76d72022-02-11 21:43:504902 if not seen_guard_end and line == '#endif // %s' % guard_name:
4903 seen_guard_end = True
4904 elif seen_guard_end:
4905 if line.strip() != '':
4906 errors.append(
4907 output_api.PresubmitPromptWarning(
4908 'Include guard %s not covering the whole file'
4909 % (guard_name), [f.LocalPath()]))
4910 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:144911
Sam Maiera6e76d72022-02-11 21:43:504912 if guard_name is None:
4913 errors.append(
4914 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:494915 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:504916 'Recommended name: %s\n'
4917 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:364918 '"no-include-guard-because-multiply-included" or\n'
4919 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:504920 % (f.LocalPath(), expected_guard)))
4921
4922 return errors
Daniel Bratell8ba52722018-03-02 16:06:144923
4924
Saagar Sanghavifceeaae2020-08-12 16:40:364925def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504926 """Check source code and known ascii text files for Windows style line
4927 endings.
4928 """
Bruce Dawson5efbdc652022-04-11 19:29:514929 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234930
Sam Maiera6e76d72022-02-11 21:43:504931 file_inclusion_pattern = (known_text_files,
4932 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4933 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:234934
Sam Maiera6e76d72022-02-11 21:43:504935 problems = []
4936 source_file_filter = lambda f: input_api.FilterSourceFile(
4937 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
4938 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:514939 # Ignore test files that contain crlf intentionally.
4940 if f.LocalPath().endswith('crlf.txt'):
4941 continue
Sam Maiera6e76d72022-02-11 21:43:504942 include_file = False
4943 for line in input_api.ReadFile(f, 'r').splitlines(True):
4944 if line.endswith('\r\n'):
4945 include_file = True
4946 if include_file:
4947 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234948
Sam Maiera6e76d72022-02-11 21:43:504949 if problems:
4950 return [
4951 output_api.PresubmitPromptWarning(
4952 'Are you sure that you want '
4953 'these files to contain Windows style line endings?\n' +
4954 '\n'.join(problems))
4955 ]
mostynbb639aca52015-01-07 20:31:234956
Sam Maiera6e76d72022-02-11 21:43:504957 return []
4958
mostynbb639aca52015-01-07 20:31:234959
Evan Stade6cfc964c12021-05-18 20:21:164960def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504961 """Check that .icon files (which are fragments of C++) have license headers.
4962 """
Evan Stade6cfc964c12021-05-18 20:21:164963
Sam Maiera6e76d72022-02-11 21:43:504964 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:164965
Sam Maiera6e76d72022-02-11 21:43:504966 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4967 return input_api.canned_checks.CheckLicense(input_api,
4968 output_api,
4969 source_file_filter=icons)
4970
Evan Stade6cfc964c12021-05-18 20:21:164971
Jose Magana2b456f22021-03-09 23:26:404972def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504973 """Check source code for use of Chrome App technologies being
4974 deprecated.
4975 """
Jose Magana2b456f22021-03-09 23:26:404976
Sam Maiera6e76d72022-02-11 21:43:504977 def _CheckForDeprecatedTech(input_api,
4978 output_api,
4979 detection_list,
4980 files_to_check=None,
4981 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:404982
Sam Maiera6e76d72022-02-11 21:43:504983 if (files_to_check or files_to_skip):
4984 source_file_filter = lambda f: input_api.FilterSourceFile(
4985 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
4986 else:
4987 source_file_filter = None
4988
4989 problems = []
4990
4991 for f in input_api.AffectedSourceFiles(source_file_filter):
4992 if f.Action() == 'D':
4993 continue
4994 for _, line in f.ChangedContents():
4995 if any(detect in line for detect in detection_list):
4996 problems.append(f.LocalPath())
4997
4998 return problems
4999
5000 # to avoid this presubmit script triggering warnings
5001 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405002
5003 problems = []
5004
Sam Maiera6e76d72022-02-11 21:43:505005 # NMF: any files with extensions .nmf or NMF
5006 _NMF_FILES = r'\.(nmf|NMF)$'
5007 problems += _CheckForDeprecatedTech(
5008 input_api,
5009 output_api,
5010 detection_list=[''], # any change to the file will trigger warning
5011 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405012
Sam Maiera6e76d72022-02-11 21:43:505013 # MANIFEST: any manifest.json that in its diff includes "app":
5014 _MANIFEST_FILES = r'(manifest\.json)$'
5015 problems += _CheckForDeprecatedTech(
5016 input_api,
5017 output_api,
5018 detection_list=['"app":'],
5019 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405020
Sam Maiera6e76d72022-02-11 21:43:505021 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5022 problems += _CheckForDeprecatedTech(
5023 input_api,
5024 output_api,
5025 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
5026 files_to_skip=files_to_skip + [r"^native_client_sdk[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405027
Sam Maiera6e76d72022-02-11 21:43:505028 # PPAPI: any C/C++ file that in its diff includes a ppappi library
5029 problems += _CheckForDeprecatedTech(
5030 input_api,
5031 output_api,
5032 detection_list=['#include "ppapi', '#include <ppapi'],
5033 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5034 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
5035 files_to_skip=[r"^ppapi[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405036
Sam Maiera6e76d72022-02-11 21:43:505037 if problems:
5038 return [
5039 output_api.PresubmitPromptWarning(
5040 'You are adding/modifying code'
5041 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5042 ' PNaCl, PPAPI). See this blog post for more details:\n'
5043 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5044 'and this documentation for options to replace these technologies:\n'
5045 'https://developer.chrome.com/docs/apps/migration/\n' +
5046 '\n'.join(problems))
5047 ]
Jose Magana2b456f22021-03-09 23:26:405048
Sam Maiera6e76d72022-02-11 21:43:505049 return []
Jose Magana2b456f22021-03-09 23:26:405050
mostynbb639aca52015-01-07 20:31:235051
Saagar Sanghavifceeaae2020-08-12 16:40:365052def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505053 """Checks that all source files use SYSLOG properly."""
5054 syslog_files = []
5055 for f in input_api.AffectedSourceFiles(src_file_filter):
5056 for line_number, line in f.ChangedContents():
5057 if 'SYSLOG' in line:
5058 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565059
Sam Maiera6e76d72022-02-11 21:43:505060 if syslog_files:
5061 return [
5062 output_api.PresubmitPromptWarning(
5063 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5064 ' calls.\nFiles to check:\n',
5065 items=syslog_files)
5066 ]
5067 return []
pastarmovj89f7ee12016-09-20 14:58:135068
5069
[email protected]1f7b4172010-01-28 01:17:345070def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505071 if input_api.version < [2, 0, 0]:
5072 return [
5073 output_api.PresubmitError(
5074 "Your depot_tools is out of date. "
5075 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5076 "but your version is %d.%d.%d" % tuple(input_api.version))
5077 ]
5078 results = []
5079 results.extend(
5080 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5081 return results
[email protected]ca8d1982009-02-19 16:33:125082
5083
5084def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505085 if input_api.version < [2, 0, 0]:
5086 return [
5087 output_api.PresubmitError(
5088 "Your depot_tools is out of date. "
5089 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5090 "but your version is %d.%d.%d" % tuple(input_api.version))
5091 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365092
Sam Maiera6e76d72022-02-11 21:43:505093 results = []
5094 # Make sure the tree is 'open'.
5095 results.extend(
5096 input_api.canned_checks.CheckTreeIsOpen(
5097 input_api,
5098 output_api,
5099 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275100
Sam Maiera6e76d72022-02-11 21:43:505101 results.extend(
5102 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5103 results.extend(
5104 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5105 results.extend(
5106 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5107 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505108 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145109
5110
Saagar Sanghavifceeaae2020-08-12 16:40:365111def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505112 """Check string ICU syntax validity and if translation screenshots exist."""
5113 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5114 # footer is set to true.
5115 git_footers = input_api.change.GitFootersFromDescription()
5116 skip_screenshot_check_footer = [
5117 footer.lower() for footer in git_footers.get(
5118 u'Skip-Translation-Screenshots-Check', [])
5119 ]
5120 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025121
Sam Maiera6e76d72022-02-11 21:43:505122 import os
5123 import re
5124 import sys
5125 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145126
Sam Maiera6e76d72022-02-11 21:43:505127 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5128 if (f.Action() == 'A' or f.Action() == 'M'))
5129 removed_paths = set(f.LocalPath()
5130 for f in input_api.AffectedFiles(include_deletes=True)
5131 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145132
Sam Maiera6e76d72022-02-11 21:43:505133 affected_grds = [
5134 f for f in input_api.AffectedFiles()
5135 if f.LocalPath().endswith(('.grd', '.grdp'))
5136 ]
5137 affected_grds = [
5138 f for f in affected_grds if not 'testdata' in f.LocalPath()
5139 ]
5140 if not affected_grds:
5141 return []
meacer8c0d3832019-12-26 21:46:165142
Sam Maiera6e76d72022-02-11 21:43:505143 affected_png_paths = [
5144 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5145 if (f.LocalPath().endswith('.png'))
5146 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145147
Sam Maiera6e76d72022-02-11 21:43:505148 # Check for screenshots. Developers can upload screenshots using
5149 # tools/translation/upload_screenshots.py which finds and uploads
5150 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5151 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5152 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5153 #
5154 # The logic here is as follows:
5155 #
5156 # - If the CL has a .png file under the screenshots directory for a grd
5157 # file, warn the developer. Actual images should never be checked into the
5158 # Chrome repo.
5159 #
5160 # - If the CL contains modified or new messages in grd files and doesn't
5161 # contain the corresponding .sha1 files, warn the developer to add images
5162 # and upload them via tools/translation/upload_screenshots.py.
5163 #
5164 # - If the CL contains modified or new messages in grd files and the
5165 # corresponding .sha1 files, everything looks good.
5166 #
5167 # - If the CL contains removed messages in grd files but the corresponding
5168 # .sha1 files aren't removed, warn the developer to remove them.
5169 unnecessary_screenshots = []
5170 missing_sha1 = []
5171 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145172
Sam Maiera6e76d72022-02-11 21:43:505173 # This checks verifies that the ICU syntax of messages this CL touched is
5174 # valid, and reports any found syntax errors.
5175 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5176 # without developers being aware of them. Later on, such ICU syntax errors
5177 # break message extraction for translation, hence would block Chromium
5178 # translations until they are fixed.
5179 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145180
Sam Maiera6e76d72022-02-11 21:43:505181 def _CheckScreenshotAdded(screenshots_dir, message_id):
5182 sha1_path = input_api.os_path.join(screenshots_dir,
5183 message_id + '.png.sha1')
5184 if sha1_path not in new_or_added_paths:
5185 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145186
Sam Maiera6e76d72022-02-11 21:43:505187 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5188 sha1_path = input_api.os_path.join(screenshots_dir,
5189 message_id + '.png.sha1')
5190 if input_api.os_path.exists(
5191 sha1_path) and sha1_path not in removed_paths:
5192 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145193
Sam Maiera6e76d72022-02-11 21:43:505194 def _ValidateIcuSyntax(text, level, signatures):
5195 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145196
Sam Maiera6e76d72022-02-11 21:43:505197 Check if text looks similar to ICU and checks for ICU syntax correctness
5198 in this case. Reports various issues with ICU syntax and values of
5199 variants. Supports checking of nested messages. Accumulate information of
5200 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265201
Sam Maiera6e76d72022-02-11 21:43:505202 Args:
5203 text: a string to check.
5204 level: a number of current nesting level.
5205 signatures: an accumulator, a list of tuple of (level, variable,
5206 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265207
Sam Maiera6e76d72022-02-11 21:43:505208 Returns:
5209 None if a string is not ICU or no issue detected.
5210 A tuple of (message, start index, end index) if an issue detected.
5211 """
5212 valid_types = {
5213 'plural': (frozenset(
5214 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5215 'other']), frozenset(['=1', 'other'])),
5216 'selectordinal': (frozenset(
5217 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5218 'other']), frozenset(['one', 'other'])),
5219 'select': (frozenset(), frozenset(['other'])),
5220 }
Rainhard Findlingfc31844c52020-05-15 09:58:265221
Sam Maiera6e76d72022-02-11 21:43:505222 # Check if the message looks like an attempt to use ICU
5223 # plural. If yes - check if its syntax strictly matches ICU format.
5224 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5225 text)
5226 if not like:
5227 signatures.append((level, None, None, None))
5228 return
Rainhard Findlingfc31844c52020-05-15 09:58:265229
Sam Maiera6e76d72022-02-11 21:43:505230 # Check for valid prefix and suffix
5231 m = re.match(
5232 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5233 r'(plural|selectordinal|select),\s*'
5234 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5235 if not m:
5236 return (('This message looks like an ICU plural, '
5237 'but does not follow ICU syntax.'), like.start(),
5238 like.end())
5239 starting, variable, kind, variant_pairs = m.groups()
5240 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5241 m.start(4))
5242 if depth:
5243 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5244 len(text))
5245 first = text[0]
5246 ending = text[last_pos:]
5247 if not starting:
5248 return ('Invalid ICU format. No initial opening bracket',
5249 last_pos - 1, last_pos)
5250 if not ending or '}' not in ending:
5251 return ('Invalid ICU format. No final closing bracket',
5252 last_pos - 1, last_pos)
5253 elif first != '{':
5254 return ((
5255 'Invalid ICU format. Extra characters at the start of a complex '
5256 'message (go/icu-message-migration): "%s"') % starting, 0,
5257 len(starting))
5258 elif ending != '}':
5259 return ((
5260 'Invalid ICU format. Extra characters at the end of a complex '
5261 'message (go/icu-message-migration): "%s"') % ending,
5262 last_pos - 1, len(text) - 1)
5263 if kind not in valid_types:
5264 return (('Unknown ICU message type %s. '
5265 'Valid types are: plural, select, selectordinal') % kind,
5266 0, 0)
5267 known, required = valid_types[kind]
5268 defined_variants = set()
5269 for variant, variant_range, value, value_range in variants:
5270 start, end = variant_range
5271 if variant in defined_variants:
5272 return ('Variant "%s" is defined more than once' % variant,
5273 start, end)
5274 elif known and variant not in known:
5275 return ('Variant "%s" is not valid for %s message' %
5276 (variant, kind), start, end)
5277 defined_variants.add(variant)
5278 # Check for nested structure
5279 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5280 if res:
5281 return (res[0], res[1] + value_range[0] + 1,
5282 res[2] + value_range[0] + 1)
5283 missing = required - defined_variants
5284 if missing:
5285 return ('Required variants missing: %s' % ', '.join(missing), 0,
5286 len(text))
5287 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265288
Sam Maiera6e76d72022-02-11 21:43:505289 def _ParseIcuVariants(text, offset=0):
5290 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265291
Sam Maiera6e76d72022-02-11 21:43:505292 Builds a tuple of variant names and values, as well as
5293 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265294
Sam Maiera6e76d72022-02-11 21:43:505295 Args:
5296 text: a string to parse
5297 offset: additional offset to add to positions in the text to get correct
5298 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265299
Sam Maiera6e76d72022-02-11 21:43:505300 Returns:
5301 List of tuples, each tuple consist of four fields: variant name,
5302 variant name span (tuple of two integers), variant value, value
5303 span (tuple of two integers).
5304 """
5305 depth, start, end = 0, -1, -1
5306 variants = []
5307 key = None
5308 for idx, char in enumerate(text):
5309 if char == '{':
5310 if not depth:
5311 start = idx
5312 chunk = text[end + 1:start]
5313 key = chunk.strip()
5314 pos = offset + end + 1 + chunk.find(key)
5315 span = (pos, pos + len(key))
5316 depth += 1
5317 elif char == '}':
5318 if not depth:
5319 return variants, depth, offset + idx
5320 depth -= 1
5321 if not depth:
5322 end = idx
5323 variants.append((key, span, text[start:end + 1],
5324 (offset + start, offset + end + 1)))
5325 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265326
Sam Maiera6e76d72022-02-11 21:43:505327 try:
5328 old_sys_path = sys.path
5329 sys.path = sys.path + [
5330 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5331 'translation')
5332 ]
5333 from helper import grd_helper
5334 finally:
5335 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265336
Sam Maiera6e76d72022-02-11 21:43:505337 for f in affected_grds:
5338 file_path = f.LocalPath()
5339 old_id_to_msg_map = {}
5340 new_id_to_msg_map = {}
5341 # Note that this code doesn't check if the file has been deleted. This is
5342 # OK because it only uses the old and new file contents and doesn't load
5343 # the file via its path.
5344 # It's also possible that a file's content refers to a renamed or deleted
5345 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5346 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5347 # .grdp files.
5348 if file_path.endswith('.grdp'):
5349 if f.OldContents():
5350 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5351 '\n'.join(f.OldContents()))
5352 if f.NewContents():
5353 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5354 '\n'.join(f.NewContents()))
5355 else:
5356 file_dir = input_api.os_path.dirname(file_path) or '.'
5357 if f.OldContents():
5358 old_id_to_msg_map = grd_helper.GetGrdMessages(
5359 StringIO('\n'.join(f.OldContents())), file_dir)
5360 if f.NewContents():
5361 new_id_to_msg_map = grd_helper.GetGrdMessages(
5362 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265363
Sam Maiera6e76d72022-02-11 21:43:505364 grd_name, ext = input_api.os_path.splitext(
5365 input_api.os_path.basename(file_path))
5366 screenshots_dir = input_api.os_path.join(
5367 input_api.os_path.dirname(file_path),
5368 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265369
Sam Maiera6e76d72022-02-11 21:43:505370 # Compute added, removed and modified message IDs.
5371 old_ids = set(old_id_to_msg_map)
5372 new_ids = set(new_id_to_msg_map)
5373 added_ids = new_ids - old_ids
5374 removed_ids = old_ids - new_ids
5375 modified_ids = set([])
5376 for key in old_ids.intersection(new_ids):
5377 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5378 new_id_to_msg_map[key].ContentsAsXml('', True)):
5379 # The message content itself changed. Require an updated screenshot.
5380 modified_ids.add(key)
5381 elif old_id_to_msg_map[key].attrs['meaning'] != \
5382 new_id_to_msg_map[key].attrs['meaning']:
5383 # The message meaning changed. Ensure there is a screenshot for it.
5384 sha1_path = input_api.os_path.join(screenshots_dir,
5385 key + '.png.sha1')
5386 if sha1_path not in new_or_added_paths and not \
5387 input_api.os_path.exists(sha1_path):
5388 # There is neither a previous screenshot nor is a new one added now.
5389 # Require a screenshot.
5390 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145391
Sam Maiera6e76d72022-02-11 21:43:505392 if run_screenshot_check:
5393 # Check the screenshot directory for .png files. Warn if there is any.
5394 for png_path in affected_png_paths:
5395 if png_path.startswith(screenshots_dir):
5396 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145397
Sam Maiera6e76d72022-02-11 21:43:505398 for added_id in added_ids:
5399 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095400
Sam Maiera6e76d72022-02-11 21:43:505401 for modified_id in modified_ids:
5402 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145403
Sam Maiera6e76d72022-02-11 21:43:505404 for removed_id in removed_ids:
5405 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5406
5407 # Check new and changed strings for ICU syntax errors.
5408 for key in added_ids.union(modified_ids):
5409 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5410 err = _ValidateIcuSyntax(msg, 0, [])
5411 if err is not None:
5412 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5413
5414 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265415 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505416 if unnecessary_screenshots:
5417 results.append(
5418 output_api.PresubmitError(
5419 'Do not include actual screenshots in the changelist. Run '
5420 'tools/translate/upload_screenshots.py to upload them instead:',
5421 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145422
Sam Maiera6e76d72022-02-11 21:43:505423 if missing_sha1:
5424 results.append(
5425 output_api.PresubmitError(
5426 'You are adding or modifying UI strings.\n'
5427 'To ensure the best translations, take screenshots of the relevant UI '
5428 '(https://g.co/chrome/translation) and add these files to your '
5429 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145430
Sam Maiera6e76d72022-02-11 21:43:505431 if unnecessary_sha1_files:
5432 results.append(
5433 output_api.PresubmitError(
5434 'You removed strings associated with these files. Remove:',
5435 sorted(unnecessary_sha1_files)))
5436 else:
5437 results.append(
5438 output_api.PresubmitPromptOrNotify('Skipping translation '
5439 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145440
Sam Maiera6e76d72022-02-11 21:43:505441 if icu_syntax_errors:
5442 results.append(
5443 output_api.PresubmitPromptWarning(
5444 'ICU syntax errors were found in the following strings (problems or '
5445 'feedback? Contact [email protected]):',
5446 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265447
Sam Maiera6e76d72022-02-11 21:43:505448 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125449
5450
Saagar Sanghavifceeaae2020-08-12 16:40:365451def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125452 repo_root=None,
5453 translation_expectations_path=None,
5454 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505455 import sys
5456 affected_grds = [
5457 f for f in input_api.AffectedFiles()
5458 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5459 ]
5460 if not affected_grds:
5461 return []
5462
5463 try:
5464 old_sys_path = sys.path
5465 sys.path = sys.path + [
5466 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5467 'translation')
5468 ]
5469 from helper import git_helper
5470 from helper import translation_helper
5471 finally:
5472 sys.path = old_sys_path
5473
5474 # Check that translation expectations can be parsed and we can get a list of
5475 # translatable grd files. |repo_root| and |translation_expectations_path| are
5476 # only passed by tests.
5477 if not repo_root:
5478 repo_root = input_api.PresubmitLocalPath()
5479 if not translation_expectations_path:
5480 translation_expectations_path = input_api.os_path.join(
5481 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5482 if not grd_files:
5483 grd_files = git_helper.list_grds_in_repository(repo_root)
5484
5485 # Ignore bogus grd files used only for testing
5486 # ui/webui/resoucres/tools/generate_grd.py.
5487 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
5488 'tests')
5489 grd_files = [p for p in grd_files if ignore_path not in p]
5490
5491 try:
5492 translation_helper.get_translatable_grds(
5493 repo_root, grd_files, translation_expectations_path)
5494 except Exception as e:
5495 return [
5496 output_api.PresubmitNotifyResult(
5497 'Failed to get a list of translatable grd files. This happens when:\n'
5498 ' - One of the modified grd or grdp files cannot be parsed or\n'
5499 ' - %s is not updated.\n'
5500 'Stack:\n%s' % (translation_expectations_path, str(e)))
5501 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:125502 return []
5503
Ken Rockotc31f4832020-05-29 18:58:515504
Saagar Sanghavifceeaae2020-08-12 16:40:365505def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505506 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5507 changed_mojoms = input_api.AffectedFiles(
5508 include_deletes=True,
5509 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525510
Sam Maiera6e76d72022-02-11 21:43:505511 if not changed_mojoms:
5512 return []
5513
5514 delta = []
5515 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:505516 delta.append({
5517 'filename': mojom.LocalPath(),
5518 'old': '\n'.join(mojom.OldContents()) or None,
5519 'new': '\n'.join(mojom.NewContents()) or None,
5520 })
5521
5522 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:215523 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:505524 input_api.os_path.join(
5525 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
5526 'check_stable_mojom_compatibility.py'), '--src-root',
5527 input_api.PresubmitLocalPath()
5528 ],
5529 stdin=input_api.subprocess.PIPE,
5530 stdout=input_api.subprocess.PIPE,
5531 stderr=input_api.subprocess.PIPE,
5532 universal_newlines=True)
5533 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5534 if process.returncode:
5535 return [
5536 output_api.PresubmitError(
5537 'One or more [Stable] mojom definitions appears to have been changed '
5538 'in a way that is not backward-compatible.',
5539 long_text=error)
5540 ]
Erik Staabc734cd7a2021-11-23 03:11:525541 return []
5542
Dominic Battre645d42342020-12-04 16:14:105543def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505544 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:105545
Sam Maiera6e76d72022-02-11 21:43:505546 def FilterFile(affected_file):
5547 """Accept only .cc files and the like."""
5548 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5549 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5550 input_api.DEFAULT_FILES_TO_SKIP)
5551 return input_api.FilterSourceFile(
5552 affected_file,
5553 files_to_check=file_inclusion_pattern,
5554 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:105555
Sam Maiera6e76d72022-02-11 21:43:505556 def ModifiedLines(affected_file):
5557 """Returns a list of tuples (line number, line text) of added and removed
5558 lines.
Dominic Battre645d42342020-12-04 16:14:105559
Sam Maiera6e76d72022-02-11 21:43:505560 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:105561
Sam Maiera6e76d72022-02-11 21:43:505562 This relies on the scm diff output describing each changed code section
5563 with a line of the form
Dominic Battre645d42342020-12-04 16:14:105564
Sam Maiera6e76d72022-02-11 21:43:505565 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5566 """
5567 line_num = 0
5568 modified_lines = []
5569 for line in affected_file.GenerateScmDiff().splitlines():
5570 # Extract <new line num> of the patch fragment (see format above).
5571 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
5572 line)
5573 if m:
5574 line_num = int(m.groups(1)[0])
5575 continue
5576 if ((line.startswith('+') and not line.startswith('++'))
5577 or (line.startswith('-') and not line.startswith('--'))):
5578 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:105579
Sam Maiera6e76d72022-02-11 21:43:505580 if not line.startswith('-'):
5581 line_num += 1
5582 return modified_lines
Dominic Battre645d42342020-12-04 16:14:105583
Sam Maiera6e76d72022-02-11 21:43:505584 def FindLineWith(lines, needle):
5585 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:105586
Sam Maiera6e76d72022-02-11 21:43:505587 If 0 or >1 lines contain `needle`, -1 is returned.
5588 """
5589 matching_line_numbers = [
5590 # + 1 for 1-based counting of line numbers.
5591 i + 1 for i, line in enumerate(lines) if needle in line
5592 ]
5593 return matching_line_numbers[0] if len(
5594 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:105595
Sam Maiera6e76d72022-02-11 21:43:505596 def ModifiedPrefMigration(affected_file):
5597 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5598 # Determine first and last lines of MigrateObsolete.*Pref functions.
5599 new_contents = affected_file.NewContents()
5600 range_1 = (FindLineWith(new_contents,
5601 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5602 FindLineWith(new_contents,
5603 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5604 range_2 = (FindLineWith(new_contents,
5605 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5606 FindLineWith(new_contents,
5607 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5608 if (-1 in range_1 + range_2):
5609 raise Exception(
5610 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
5611 )
Dominic Battre645d42342020-12-04 16:14:105612
Sam Maiera6e76d72022-02-11 21:43:505613 # Check whether any of the modified lines are part of the
5614 # MigrateObsolete.*Pref functions.
5615 for line_nr, line in ModifiedLines(affected_file):
5616 if (range_1[0] <= line_nr <= range_1[1]
5617 or range_2[0] <= line_nr <= range_2[1]):
5618 return True
5619 return False
Dominic Battre645d42342020-12-04 16:14:105620
Sam Maiera6e76d72022-02-11 21:43:505621 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5622 browser_prefs_file_pattern = input_api.re.compile(
5623 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:105624
Sam Maiera6e76d72022-02-11 21:43:505625 changes = input_api.AffectedFiles(include_deletes=True,
5626 file_filter=FilterFile)
5627 potential_problems = []
5628 for f in changes:
5629 for line in f.GenerateScmDiff().splitlines():
5630 # Check deleted lines for pref registrations.
5631 if (line.startswith('-') and not line.startswith('--')
5632 and register_pref_pattern.search(line)):
5633 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:105634
Sam Maiera6e76d72022-02-11 21:43:505635 if browser_prefs_file_pattern.search(f.LocalPath()):
5636 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5637 # assume that they knew that they have to deprecate preferences and don't
5638 # warn.
5639 try:
5640 if ModifiedPrefMigration(f):
5641 return []
5642 except Exception as e:
5643 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:105644
Sam Maiera6e76d72022-02-11 21:43:505645 if potential_problems:
5646 return [
5647 output_api.PresubmitPromptWarning(
5648 'Discovered possible removal of preference registrations.\n\n'
5649 'Please make sure to properly deprecate preferences by clearing their\n'
5650 'value for a couple of milestones before finally removing the code.\n'
5651 'Otherwise data may stay in the preferences files forever. See\n'
5652 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5653 'chrome/browser/prefs/README.md for examples.\n'
5654 'This may be a false positive warning (e.g. if you move preference\n'
5655 'registrations to a different place).\n', potential_problems)
5656 ]
5657 return []
5658
Matt Stark6ef08872021-07-29 01:21:465659
5660def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505661 """Changes to GRD files must be consistent for tools to read them."""
5662 changed_grds = input_api.AffectedFiles(
5663 include_deletes=False,
5664 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5665 errors = []
5666 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5667 for matcher, msg in _INVALID_GRD_FILE_LINE]
5668 for grd in changed_grds:
5669 for i, line in enumerate(grd.NewContents()):
5670 for matcher, msg in invalid_file_regexes:
5671 if matcher.search(line):
5672 errors.append(
5673 output_api.PresubmitError(
5674 'Problem on {grd}:{i} - {msg}'.format(
5675 grd=grd.LocalPath(), i=i + 1, msg=msg)))
5676 return errors
5677
Kevin McNee967dd2d22021-11-15 16:09:295678
5679def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505680 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5681 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5682 """
Kevin McNee967dd2d22021-11-15 16:09:295683
Ian Vollickdba956c2022-04-20 23:53:455684 # Only consider top-level directories that (1) can use content APIs or
5685 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
5686 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:505687 files_to_check = (
Ian Vollickdba956c2022-04-20 23:53:455688 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Kevin McNee967dd2d22021-11-15 16:09:295689 _IMPLEMENTATION_EXTENSIONS,
Ian Vollickdba956c2022-04-20 23:53:455690 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Sam Maiera6e76d72022-02-11 21:43:505691 _HEADER_EXTENSIONS,
5692 )
5693 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5694 input_api.DEFAULT_FILES_TO_SKIP)
5695 source_file_filter = lambda f: input_api.FilterSourceFile(
5696 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:295697
Sam Maiera6e76d72022-02-11 21:43:505698 # Note that since these are are just regular expressions and we don't have
5699 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5700 # could have a method named IsInMainFrame).
5701 concerning_class_pattern = input_api.re.compile(
5702 r'WebContentsObserver|WebContentsUserData')
5703 # A subset of WebContentsObserver overrides where there's particular risk for
5704 # confusing tab and page level operations and data (e.g. incorrectly
5705 # resetting page state in DidFinishNavigation).
5706 concerning_wco_methods = [
5707 'DidStartNavigation',
5708 'ReadyToCommitNavigation',
5709 'DidFinishNavigation',
5710 'RenderViewReady',
5711 'RenderViewDeleted',
5712 'RenderViewHostChanged',
5713 'PrimaryMainDocumentElementAvailable',
5714 'DocumentOnLoadCompletedInPrimaryMainFrame',
5715 'DOMContentLoaded',
5716 'DidFinishLoad',
5717 ]
5718 concerning_nav_handle_methods = [
5719 'IsInMainFrame',
5720 ]
5721 concerning_web_contents_methods = [
5722 'ForEachFrame',
5723 'GetAllFrames',
5724 'FromRenderFrameHost',
5725 'FromRenderViewHost',
5726 'GetMainFrame',
5727 'GetRenderViewHost',
5728 ]
5729 concerning_rfh_methods = [
5730 'GetParent',
5731 'GetMainFrame',
5732 'GetFrameTreeNodeId',
5733 ]
Ian Vollickc825b1f2022-04-19 14:30:155734 concerning_rfhi_methods = [
5735 'is_main_frame',
5736 ]
Ian Vollicka77a73ea2022-04-06 18:08:015737 concerning_ftn_methods = [
5738 'IsMainFrame',
5739 ]
Ian Vollickdba956c2022-04-20 23:53:455740 concerning_blink_frame_methods = [
5741 'IsCrossOriginToMainFrame',
5742 ]
Sam Maiera6e76d72022-02-11 21:43:505743 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5744 item for sublist in [
5745 concerning_wco_methods, concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:015746 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:155747 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:455748 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:505749 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:295750
Kevin McNee4eeec792022-02-14 20:02:045751 used_apis = set()
Sam Maiera6e76d72022-02-11 21:43:505752 for f in input_api.AffectedFiles(include_deletes=False,
5753 file_filter=source_file_filter):
5754 for line_num, line in f.ChangedContents():
Kevin McNee4eeec792022-02-14 20:02:045755 class_match = concerning_class_pattern.search(line)
5756 if class_match:
5757 used_apis.add(class_match[0])
5758 method_match = concerning_method_pattern.search(line)
5759 if method_match:
5760 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:505761
Kevin McNee4eeec792022-02-14 20:02:045762 if not used_apis:
5763 return []
Kevin McNee967dd2d22021-11-15 16:09:295764
Kevin McNee4eeec792022-02-14 20:02:045765 output_api.AppendCC('[email protected]')
5766 message = ('This change uses API(s) that are ambiguous in the presence of '
5767 'MPArch features such as bfcache, prerendering, and fenced '
5768 'frames.')
5769 explaination = (
5770 'Please double check whether new code assumes that a WebContents only '
5771 'contains a single page at a time. For example, it is discouraged to '
5772 'reset per-document state in response to the observation of a '
5773 'navigation. See this doc [1] and the comments on the individual APIs '
5774 'for guidance and this doc [2] for context. The MPArch review '
5775 'watchlist has been CC\'d on this change to help identify any issues.\n'
5776 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
5777 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
5778 )
5779 return [
5780 output_api.PresubmitNotifyResult(message,
5781 items=list(used_apis),
5782 long_text=explaination)
5783 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:365784
5785
5786def CheckAssertAshOnlyCode(input_api, output_api):
5787 """Errors if a BUILD.gn file in an ash/ directory doesn't include
5788 assert(is_chromeos_ash).
5789 """
5790
5791 def FileFilter(affected_file):
5792 """Includes directories known to be Ash only."""
5793 return input_api.FilterSourceFile(
5794 affected_file,
5795 files_to_check=(
5796 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
5797 r'.*/ash/.*BUILD\.gn'), # Any path component.
5798 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
5799
5800 errors = []
5801 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:565802 for f in input_api.AffectedFiles(include_deletes=False,
5803 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:365804 if (not pattern.search(input_api.ReadFile(f))):
5805 errors.append(
5806 output_api.PresubmitError(
5807 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
5808 'possible, please create and issue and add a comment such '
5809 'as:\n # TODO(https://crbug.com/XXX): add '
5810 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
5811 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:275812
5813
5814def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:505815 path = affected_file.LocalPath()
5816 if not _IsCPlusPlusFile(input_api, path):
5817 return False
5818
5819 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
5820 if "/renderer/" in path:
5821 return True
5822
5823 # Blink's public/web API is only used/included by Renderer-only code. Note
5824 # that public/platform API may be used in non-Renderer processes (e.g. there
5825 # are some includes in code used by Utility, PDF, or Plugin processes).
5826 if "/blink/public/web/" in path:
5827 return True
5828
5829 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:275830 return False
5831
Lukasz Anforowicz7016d05e2021-11-30 03:56:275832# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
5833# by the Chromium Clang Plugin (which will be preferable because it will
5834# 1) report errors earlier - at compile-time and 2) cover more rules).
5835def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505836 """Rough checks that raw_ptr<T> usage guidelines are followed."""
5837 errors = []
5838 # The regex below matches "raw_ptr<" following a word boundary, but not in a
5839 # C++ comment.
5840 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
5841 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
5842 for f, line_num, line in input_api.RightHandSideLines(file_filter):
5843 if raw_ptr_matcher.search(line):
5844 errors.append(
5845 output_api.PresubmitError(
5846 'Problem on {path}:{line} - '\
5847 'raw_ptr<T> should not be used in Renderer-only code '\
5848 '(as documented in the "Pointers to unprotected memory" '\
5849 'section in //base/memory/raw_ptr.md)'.format(
5850 path=f.LocalPath(), line=line_num)))
5851 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:565852
5853
5854def CheckPythonShebang(input_api, output_api):
5855 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
5856 system-wide python.
5857 """
5858 errors = []
5859 sources = lambda affected_file: input_api.FilterSourceFile(
5860 affected_file,
5861 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
5862 r'third_party/blink/web_tests/external/') + input_api.
5863 DEFAULT_FILES_TO_SKIP),
5864 files_to_check=[r'.*\.py$'])
5865 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:275866 for line_num, line in f.ChangedContents():
5867 if line_num == 1 and line.startswith('#!/usr/bin/python'):
5868 errors.append(f.LocalPath())
5869 break
Henrique Ferreirof9819f2e32021-11-30 13:31:565870
5871 result = []
5872 for file in errors:
5873 result.append(
5874 output_api.PresubmitError(
5875 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
5876 file))
5877 return result