blob: 971d9ef6b05138dcb77cd007e2aa4533a0a0f23f [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"""
Saagar Sanghavifceeaae2020-08-12 16:40:3610PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1211
Dirk Prankee3c9c62d2021-05-18 18:35:5912# This line is 'magic' in that git-cl looks for it to decide whether to
13# use Python3 instead of Python2 when running the code in this file.
14USE_PYTHON3 = True
15
[email protected]379e7dd2010-01-28 17:39:2116_EXCLUDED_PATHS = (
Mila Greene3aa7222021-09-07 16:34:0817 # File needs to write to stdout to emulate a tool it's replacing.
Mila Greend3fc6a42021-09-10 17:38:2318 r"chrome[\\/]updater[\\/]mac[\\/]keystone[\\/]ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4719 # Generated file.
20 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2621 r"client_variations.js"),
Mila Greene3aa7222021-09-07 16:34:0822 r"^native_client_sdksrc[\\/]build_tools[\\/]make_rules.py",
Egor Paskoce145c42018-09-28 19:31:0423 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
24 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
25 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
26 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4927 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0428 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4629 # sqlite is an imported third party dependency.
30 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0431 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5432 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5333 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1234 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0435 r".+[\\/]pnacl_shim\.c$",
36 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0437 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1438 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0439 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5440 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0441 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4042)
[email protected]ca8d1982009-02-19 16:33:1243
John Abd-El-Malek759fea62021-03-13 03:41:1444_EXCLUDED_SET_NO_PARENT_PATHS = (
45 # It's for historical reasons that blink isn't a top level directory, where
46 # it would be allowed to have "set noparent" to avoid top level owners
47 # accidentally +1ing changes.
48 'third_party/blink/OWNERS',
49)
50
wnwenbdc444e2016-05-25 13:44:1551
[email protected]06e6d0ff2012-12-11 01:36:4452# Fragment of a regular expression that matches C++ and Objective-C++
53# implementation files.
54_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
55
wnwenbdc444e2016-05-25 13:44:1556
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1957# Fragment of a regular expression that matches C++ and Objective-C++
58# header files.
59_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
60
61
[email protected]06e6d0ff2012-12-11 01:36:4462# Regular expression that matches code only used for test binaries
63# (best effort).
64_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0465 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4466 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1367 # Test suite files, like:
68 # foo_browsertest.cc
69 # bar_unittest_mac.cc (suffix)
70 # baz_unittests.cc (plural)
71 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1272 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1873 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2174 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0475 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4376 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0477 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4378 # Web test harness.
79 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4780 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0481 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0882 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0483 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4184 # EarlGrey app side code for tests.
85 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1786 # Views Examples code
87 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4188 # Chromium Codelab
89 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4490)
[email protected]ca8d1982009-02-19 16:33:1291
Daniel Bratell609102be2019-03-27 20:53:2192_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1593
[email protected]eea609a2011-11-18 13:10:1294_TEST_ONLY_WARNING = (
95 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5596 'production code. If you are doing this from inside another method\n'
97 'named as *ForTesting(), then consider exposing things to have tests\n'
98 'make that same call directly.\n'
99 'If that is not possible, you may put a comment on the same line with\n'
100 ' // IN-TEST \n'
101 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
102 'method and can be ignored. Do not do this inside production code.\n'
103 'The android-binary-size trybot will block if the method exists in the\n'
104 'release apk.')
[email protected]eea609a2011-11-18 13:10:12105
106
[email protected]cf9b78f2012-11-14 11:40:28107_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:40108 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:21109 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
110 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:28111
Michael Thiessen44457642020-02-06 00:24:15112# Format: Sequence of tuples containing:
113# * Full import path.
114# * Sequence of strings to show when the pattern matches.
115# * Sequence of path or filename exceptions to this rule
116_BANNED_JAVA_IMPORTS = (
117 (
Colin Blundell170d78c82020-03-12 13:56:04118 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15119 (
120 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
121 ),
122 (
123 'net/android/javatests/src/org/chromium/net/'
124 'AndroidProxySelectorTest.java',
125 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04126 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15127 ),
128 ),
Michael Thiessened631912020-08-07 19:01:31129 (
130 'android.support.test.rule.UiThreadTestRule;',
131 (
132 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43133 '@org.chromium.base.test.UiThreadTest on test methods that should run '
134 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31135 ),
136 (),
137 ),
138 (
139 'android.support.test.annotation.UiThreadTest;',
140 (
141 'Do not use android.support.test.annotation.UiThreadTest, use '
142 'org.chromium.base.test.UiThreadTest instead. See '
143 'https://crbug.com/1111893.',
144 ),
145 ()
Michael Thiessenfd6919b2020-12-08 20:44:01146 ),
147 (
148 'android.support.test.rule.ActivityTestRule;',
149 (
150 'Do not use ActivityTestRule, use '
151 'org.chromium.base.test.BaseActivityTestRule instead.',
152 ),
153 (
154 'components/cronet/',
155 )
Michael Thiessened631912020-08-07 19:01:31156 )
Michael Thiessen44457642020-02-06 00:24:15157)
wnwenbdc444e2016-05-25 13:44:15158
Daniel Bratell609102be2019-03-27 20:53:21159# Format: Sequence of tuples containing:
160# * String pattern or, if starting with a slash, a regular expression.
161# * Sequence of strings to show when the pattern matches.
162# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41163_BANNED_JAVA_FUNCTIONS = (
164 (
165 'StrictMode.allowThreadDiskReads()',
166 (
167 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
168 'directly.',
169 ),
170 False,
171 ),
172 (
173 'StrictMode.allowThreadDiskWrites()',
174 (
175 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
176 'directly.',
177 ),
178 False,
179 ),
Michael Thiessen0f2547e2020-07-27 21:55:36180 (
181 '.waitForIdleSync()',
182 (
183 'Do not use waitForIdleSync as it masks underlying issues. There is '
184 'almost always something else you should wait on instead.',
185 ),
186 False,
187 ),
Eric Stevensona9a980972017-09-23 00:04:41188)
189
Daniel Bratell609102be2019-03-27 20:53:21190# Format: Sequence of tuples containing:
191# * String pattern or, if starting with a slash, a regular expression.
192# * Sequence of strings to show when the pattern matches.
193# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59194_BANNED_OBJC_FUNCTIONS = (
195 (
196 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20197 (
198 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59199 'prohibited. Please use CrTrackingArea instead.',
200 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
201 ),
202 False,
203 ),
204 (
[email protected]eaae1972014-04-16 04:17:26205 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20206 (
207 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59208 'instead.',
209 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
210 ),
211 False,
212 ),
213 (
214 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20215 (
216 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59217 'Please use |convertPoint:(point) fromView:nil| instead.',
218 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
219 ),
220 True,
221 ),
222 (
223 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20224 (
225 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59226 'Please use |convertPoint:(point) toView:nil| instead.',
227 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
228 ),
229 True,
230 ),
231 (
232 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20233 (
234 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59235 'Please use |convertRect:(point) fromView:nil| instead.',
236 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
237 ),
238 True,
239 ),
240 (
241 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20242 (
243 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59244 'Please use |convertRect:(point) toView:nil| instead.',
245 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
246 ),
247 True,
248 ),
249 (
250 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20251 (
252 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59253 'Please use |convertSize:(point) fromView:nil| instead.',
254 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
255 ),
256 True,
257 ),
258 (
259 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20260 (
261 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59262 'Please use |convertSize:(point) toView:nil| instead.',
263 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
264 ),
265 True,
266 ),
jif65398702016-10-27 10:19:48267 (
268 r"/\s+UTF8String\s*]",
269 (
270 'The use of -[NSString UTF8String] is dangerous as it can return null',
271 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
272 'Please use |SysNSStringToUTF8| instead.',
273 ),
274 True,
275 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34276 (
277 r'__unsafe_unretained',
278 (
279 'The use of __unsafe_unretained is almost certainly wrong, unless',
280 'when interacting with NSFastEnumeration or NSInvocation.',
281 'Please use __weak in files build with ARC, nothing otherwise.',
282 ),
283 False,
284 ),
Avi Drissman7382afa02019-04-29 23:27:13285 (
286 'freeWhenDone:NO',
287 (
288 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
289 'Foundation types is prohibited.',
290 ),
291 True,
292 ),
[email protected]127f18ec2012-06-16 05:05:59293)
294
Daniel Bratell609102be2019-03-27 20:53:21295# Format: Sequence of tuples containing:
296# * String pattern or, if starting with a slash, a regular expression.
297# * Sequence of strings to show when the pattern matches.
298# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54299_BANNED_IOS_OBJC_FUNCTIONS = (
300 (
301 r'/\bTEST[(]',
302 (
303 'TEST() macro should not be used in Objective-C++ code as it does not ',
304 'drain the autorelease pool at the end of the test. Use TEST_F() ',
305 'macro instead with a fixture inheriting from PlatformTest (or a ',
306 'typedef).'
307 ),
308 True,
309 ),
310 (
311 r'/\btesting::Test\b',
312 (
313 'testing::Test should not be used in Objective-C++ code as it does ',
314 'not drain the autorelease pool at the end of the test. Use ',
315 'PlatformTest instead.'
316 ),
317 True,
318 ),
319)
320
Peter K. Lee6c03ccff2019-07-15 14:40:05321# Format: Sequence of tuples containing:
322# * String pattern or, if starting with a slash, a regular expression.
323# * Sequence of strings to show when the pattern matches.
324# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
325_BANNED_IOS_EGTEST_FUNCTIONS = (
326 (
327 r'/\bEXPECT_OCMOCK_VERIFY\b',
328 (
329 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
330 'it is meant for GTests. Use [mock verify] instead.'
331 ),
332 True,
333 ),
334)
335
Daniel Bratell609102be2019-03-27 20:53:21336# Format: Sequence of tuples containing:
337# * String pattern or, if starting with a slash, a regular expression.
338# * Sequence of strings to show when the pattern matches.
339# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
340# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59341_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20342 (
Peter Kasting94a56c42019-10-25 21:54:04343 r'/\busing namespace ',
344 (
345 'Using directives ("using namespace x") are banned by the Google Style',
346 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
347 'Explicitly qualify symbols or use using declarations ("using x::foo").',
348 ),
349 True,
350 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
351 ),
Antonio Gomes07300d02019-03-13 20:59:57352 # Make sure that gtest's FRIEND_TEST() macro is not used; the
353 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
354 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53355 (
[email protected]23e6cbc2012-06-16 18:51:20356 'FRIEND_TEST(',
357 (
[email protected]e3c945502012-06-26 20:01:49358 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20359 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
360 ),
361 False,
[email protected]7345da02012-11-27 14:31:49362 (),
[email protected]23e6cbc2012-06-16 18:51:20363 ),
364 (
tomhudsone2c14d552016-05-26 17:07:46365 'setMatrixClip',
366 (
367 'Overriding setMatrixClip() is prohibited; ',
368 'the base function is deprecated. ',
369 ),
370 True,
371 (),
372 ),
373 (
[email protected]52657f62013-05-20 05:30:31374 'SkRefPtr',
375 (
376 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22377 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31378 ),
379 True,
380 (),
381 ),
382 (
383 'SkAutoRef',
384 (
385 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22386 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31387 ),
388 True,
389 (),
390 ),
391 (
392 'SkAutoTUnref',
393 (
394 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22395 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31396 ),
397 True,
398 (),
399 ),
400 (
401 'SkAutoUnref',
402 (
403 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
404 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22405 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31406 ),
407 True,
408 (),
409 ),
[email protected]d89eec82013-12-03 14:10:59410 (
411 r'/HANDLE_EINTR\(.*close',
412 (
413 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
414 'descriptor will be closed, and it is incorrect to retry the close.',
415 'Either call close directly and ignore its return value, or wrap close',
416 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
417 ),
418 True,
419 (),
420 ),
421 (
422 r'/IGNORE_EINTR\((?!.*close)',
423 (
424 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
425 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
426 ),
427 True,
428 (
429 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04430 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
431 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59432 ),
433 ),
[email protected]ec5b3f02014-04-04 18:43:43434 (
435 r'/v8::Extension\(',
436 (
437 'Do not introduce new v8::Extensions into the code base, use',
438 'gin::Wrappable instead. See http://crbug.com/334679',
439 ),
440 True,
[email protected]f55c90ee62014-04-12 00:50:03441 (
Egor Paskoce145c42018-09-28 19:31:04442 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03443 ),
[email protected]ec5b3f02014-04-04 18:43:43444 ),
skyostilf9469f72015-04-20 10:38:52445 (
jame2d1a952016-04-02 00:27:10446 '#pragma comment(lib,',
447 (
448 'Specify libraries to link with in build files and not in the source.',
449 ),
450 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41451 (
tzik3f295992018-12-04 20:32:23452 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04453 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41454 ),
jame2d1a952016-04-02 00:27:10455 ),
fdorayc4ac18d2017-05-01 21:39:59456 (
Gabriel Charette7cc6c432018-04-25 20:52:02457 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59458 (
459 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
460 ),
461 False,
462 (),
463 ),
464 (
Gabriel Charette7cc6c432018-04-25 20:52:02465 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59466 (
467 'Consider using THREAD_CHECKER macros instead of the class directly.',
468 ),
469 False,
470 (),
471 ),
dbeamb6f4fde2017-06-15 04:03:06472 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06473 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
474 (
475 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
476 'deprecated (http://crbug.com/634507). Please avoid converting away',
477 'from the Time types in Chromium code, especially if any math is',
478 'being done on time values. For interfacing with platform/library',
479 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
480 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48481 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06482 'other use cases, please contact base/time/OWNERS.',
483 ),
484 False,
485 (),
486 ),
487 (
dbeamb6f4fde2017-06-15 04:03:06488 'CallJavascriptFunctionUnsafe',
489 (
490 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
491 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
492 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
493 ),
494 False,
495 (
Egor Paskoce145c42018-09-28 19:31:04496 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
497 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
498 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06499 ),
500 ),
dskiba1474c2bfd62017-07-20 02:19:24501 (
502 'leveldb::DB::Open',
503 (
504 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
505 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
506 "Chrome's tracing, making their memory usage visible.",
507 ),
508 True,
509 (
510 r'^third_party/leveldatabase/.*\.(cc|h)$',
511 ),
Gabriel Charette0592c3a2017-07-26 12:02:04512 ),
513 (
Chris Mumfordc38afb62017-10-09 17:55:08514 'leveldb::NewMemEnv',
515 (
516 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58517 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
518 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08519 ),
520 True,
521 (
522 r'^third_party/leveldatabase/.*\.(cc|h)$',
523 ),
524 ),
525 (
Gabriel Charetted9839bc2017-07-29 14:17:47526 'RunLoop::QuitCurrent',
527 (
Robert Liao64b7ab22017-08-04 23:03:43528 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
529 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47530 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41531 False,
Gabriel Charetted9839bc2017-07-29 14:17:47532 (),
Gabriel Charettea44975052017-08-21 23:14:04533 ),
534 (
535 'base::ScopedMockTimeMessageLoopTaskRunner',
536 (
Gabriel Charette87cc1af2018-04-25 20:52:51537 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11538 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51539 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
540 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
541 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04542 ),
Gabriel Charette87cc1af2018-04-25 20:52:51543 False,
Gabriel Charettea44975052017-08-21 23:14:04544 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57545 ),
546 (
Dave Tapuska98199b612019-07-10 13:30:44547 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57548 (
549 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02550 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57551 ),
552 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16553 # Abseil's benchmarks never linked into chrome.
554 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38555 ),
556 (
Peter Kasting991618a62019-06-17 22:00:09557 r'/\bstd::stoi\b',
558 (
559 'std::stoi uses exceptions to communicate results. ',
560 'Use base::StringToInt() instead.',
561 ),
562 True,
563 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
564 ),
565 (
566 r'/\bstd::stol\b',
567 (
568 'std::stol uses exceptions to communicate results. ',
569 'Use base::StringToInt() instead.',
570 ),
571 True,
572 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
573 ),
574 (
575 r'/\bstd::stoul\b',
576 (
577 'std::stoul uses exceptions to communicate results. ',
578 'Use base::StringToUint() instead.',
579 ),
580 True,
581 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
582 ),
583 (
584 r'/\bstd::stoll\b',
585 (
586 'std::stoll uses exceptions to communicate results. ',
587 'Use base::StringToInt64() instead.',
588 ),
589 True,
590 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
591 ),
592 (
593 r'/\bstd::stoull\b',
594 (
595 'std::stoull uses exceptions to communicate results. ',
596 'Use base::StringToUint64() instead.',
597 ),
598 True,
599 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
600 ),
601 (
602 r'/\bstd::stof\b',
603 (
604 'std::stof uses exceptions to communicate results. ',
605 'For locale-independent values, e.g. reading numbers from disk',
606 'profiles, use base::StringToDouble().',
607 'For user-visible values, parse using ICU.',
608 ),
609 True,
610 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
611 ),
612 (
613 r'/\bstd::stod\b',
614 (
615 'std::stod uses exceptions to communicate results. ',
616 'For locale-independent values, e.g. reading numbers from disk',
617 'profiles, use base::StringToDouble().',
618 'For user-visible values, parse using ICU.',
619 ),
620 True,
621 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
622 ),
623 (
624 r'/\bstd::stold\b',
625 (
626 'std::stold uses exceptions to communicate results. ',
627 'For locale-independent values, e.g. reading numbers from disk',
628 'profiles, use base::StringToDouble().',
629 'For user-visible values, parse using ICU.',
630 ),
631 True,
632 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
633 ),
634 (
Daniel Bratell69334cc2019-03-26 11:07:45635 r'/\bstd::to_string\b',
636 (
637 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09638 'For locale-independent strings, e.g. writing numbers to disk',
639 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45640 'For user-visible strings, use base::FormatNumber() and',
641 'the related functions in base/i18n/number_formatting.h.',
642 ),
Peter Kasting991618a62019-06-17 22:00:09643 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21644 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45645 ),
646 (
647 r'/\bstd::shared_ptr\b',
648 (
649 'std::shared_ptr should not be used. Use scoped_refptr instead.',
650 ),
651 True,
Ulan Degenbaev947043882021-02-10 14:02:31652 [
653 # Needed for interop with third-party library.
654 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57655 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58656 '^third_party/blink/renderer/bindings/core/v8/' +
657 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58658 '^gin/array_buffer\.(cc|h)',
659 '^chrome/services/sharing/nearby/',
Meilin Wang00efc7c2021-05-13 01:12:42660 # gRPC provides some C++ libraries that use std::shared_ptr<>.
661 '^chromeos/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59662 '^chromecast/cast_core/grpc',
663 '^chromecast/cast_core/runtime/browser',
Wez5f56be52021-05-04 09:30:58664 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
665 '.*fuchsia.*test\.(cc|h)',
Alex Chau9eb03cdd52020-07-13 21:04:57666 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21667 ),
668 (
Peter Kasting991618a62019-06-17 22:00:09669 r'/\bstd::weak_ptr\b',
670 (
671 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
672 ),
673 True,
674 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
675 ),
676 (
Daniel Bratell609102be2019-03-27 20:53:21677 r'/\blong long\b',
678 (
679 'long long is banned. Use stdint.h if you need a 64 bit number.',
680 ),
681 False, # Only a warning since it is already used.
682 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
683 ),
684 (
685 r'/\bstd::bind\b',
686 (
687 'std::bind is banned because of lifetime risks.',
688 'Use base::BindOnce or base::BindRepeating instead.',
689 ),
690 True,
691 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
692 ),
693 (
694 r'/\b#include <chrono>\b',
695 (
696 '<chrono> overlaps with Time APIs in base. Keep using',
697 'base classes.',
698 ),
699 True,
700 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
701 ),
702 (
703 r'/\b#include <exception>\b',
704 (
705 'Exceptions are banned and disabled in Chromium.',
706 ),
707 True,
708 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
709 ),
710 (
711 r'/\bstd::function\b',
712 (
Colin Blundellea615d422021-05-12 09:35:41713 'std::function is banned. Instead use base::OnceCallback or ',
714 'base::RepeatingCallback, which directly support Chromium\'s weak ',
715 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21716 ),
Peter Kasting991618a62019-06-17 22:00:09717 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21718 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
719 ),
720 (
721 r'/\b#include <random>\b',
722 (
723 'Do not use any random number engines from <random>. Instead',
724 'use base::RandomBitGenerator.',
725 ),
726 True,
727 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
728 ),
729 (
Tom Andersona95e12042020-09-09 23:08:00730 r'/\b#include <X11/',
731 (
732 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
733 ),
734 True,
735 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
736 ),
737 (
Daniel Bratell609102be2019-03-27 20:53:21738 r'/\bstd::ratio\b',
739 (
740 'std::ratio is banned by the Google Style Guide.',
741 ),
742 True,
743 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45744 ),
745 (
Gabriel Charetted90bcc92021-09-21 00:23:10746 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:38747 (
Gabriel Charetted90bcc92021-09-21 00:23:10748 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:38749 ),
Gabriel Charette04b138f2018-08-06 00:03:22750 False,
Francois Doray43670e32017-09-27 12:40:38751 (),
752 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38753 (
Michael Giuffrida7f93d6922019-04-19 14:39:58754 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19755 (
756 'RunMessageLoop is deprecated, use RunLoop instead.',
757 ),
758 False,
759 (),
760 ),
761 (
Dave Tapuska98199b612019-07-10 13:30:44762 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19763 (
764 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
765 ),
766 False,
767 (),
768 ),
769 (
Dave Tapuska98199b612019-07-10 13:30:44770 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19771 (
772 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
773 "if you're convinced you need this.",
774 ),
775 False,
776 (),
777 ),
778 (
Dave Tapuska98199b612019-07-10 13:30:44779 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19780 (
781 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04782 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19783 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
784 'async events instead of flushing threads.',
785 ),
786 False,
787 (),
788 ),
789 (
790 r'MessageLoopRunner',
791 (
792 'MessageLoopRunner is deprecated, use RunLoop instead.',
793 ),
794 False,
795 (),
796 ),
797 (
Dave Tapuska98199b612019-07-10 13:30:44798 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19799 (
800 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
801 "gab@ if you found a use case where this is the only solution.",
802 ),
803 False,
804 (),
805 ),
806 (
Victor Costane48a2e82019-03-15 22:02:34807 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16808 (
Victor Costane48a2e82019-03-15 22:02:34809 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16810 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
811 ),
812 True,
813 (
814 r'^sql/initialization\.(cc|h)$',
815 r'^third_party/sqlite/.*\.(c|cc|h)$',
816 ),
817 ),
Matt Menke7f520a82018-03-28 21:38:37818 (
Dave Tapuska98199b612019-07-10 13:30:44819 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47820 (
821 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
822 'base::RandomShuffle instead.'
823 ),
824 True,
825 (),
826 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24827 (
828 'ios/web/public/test/http_server',
829 (
830 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
831 ),
832 False,
833 (),
834 ),
Robert Liao764c9492019-01-24 18:46:28835 (
836 'GetAddressOf',
837 (
838 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53839 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11840 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53841 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28842 ),
843 True,
844 (),
845 ),
Antonio Gomes07300d02019-03-13 20:59:57846 (
Ben Lewisa9514602019-04-29 17:53:05847 'SHFileOperation',
848 (
849 'SHFileOperation was deprecated in Windows Vista, and there are less ',
850 'complex functions to achieve the same goals. Use IFileOperation for ',
851 'any esoteric actions instead.'
852 ),
853 True,
854 (),
855 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18856 (
Cliff Smolinsky81951642019-04-30 21:39:51857 'StringFromGUID2',
858 (
859 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24860 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51861 ),
862 True,
863 (
864 r'/base/win/win_util_unittest.cc'
865 ),
866 ),
867 (
868 'StringFromCLSID',
869 (
870 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24871 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51872 ),
873 True,
874 (
875 r'/base/win/win_util_unittest.cc'
876 ),
877 ),
878 (
Avi Drissman7382afa02019-04-29 23:27:13879 'kCFAllocatorNull',
880 (
881 'The use of kCFAllocatorNull with the NoCopy creation of ',
882 'CoreFoundation types is prohibited.',
883 ),
884 True,
885 (),
886 ),
Oksana Zhuravlovafd247772019-05-16 16:57:29887 (
888 'mojo::ConvertTo',
889 (
890 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
891 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
892 'StringTraits if you would like to convert between custom types and',
893 'the wire format of mojom types.'
894 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22895 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29896 (
Wezf89dec092019-09-11 19:38:33897 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
898 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29899 r'^third_party/blink/.*\.(cc|h)$',
900 r'^content/renderer/.*\.(cc|h)$',
901 ),
902 ),
Robert Liao1d78df52019-11-11 20:02:01903 (
Oksana Zhuravlovac8222d22019-12-19 19:21:16904 'GetInterfaceProvider',
905 (
906 'InterfaceProvider is deprecated.',
907 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
908 'or Platform::GetBrowserInterfaceBroker.'
909 ),
910 False,
911 (),
912 ),
913 (
Robert Liao1d78df52019-11-11 20:02:01914 'CComPtr',
915 (
916 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
917 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
918 'details.'
919 ),
920 False,
921 (),
922 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:20923 (
924 r'/\b(IFACE|STD)METHOD_?\(',
925 (
926 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
927 'Instead, always use IFACEMETHODIMP in the declaration.'
928 ),
929 False,
930 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
931 ),
Allen Bauer53b43fb12020-03-12 17:21:47932 (
933 'set_owned_by_client',
934 (
935 'set_owned_by_client is deprecated.',
936 'views::View already owns the child views by default. This introduces ',
937 'a competing ownership model which makes the code difficult to reason ',
938 'about. See http://crbug.com/1044687 for more details.'
939 ),
940 False,
941 (),
942 ),
Eric Secklerbe6f48d2020-05-06 18:09:12943 (
Peter Boström7ff41522021-07-29 03:43:27944 'RemoveAllChildViewsWithoutDeleting',
945 (
946 'RemoveAllChildViewsWithoutDeleting is deprecated.',
947 'This method is deemed dangerous as, unless raw pointers are re-added,',
948 'calls to this method introduce memory leaks.'
949 ),
950 False,
951 (),
952 ),
953 (
Eric Secklerbe6f48d2020-05-06 18:09:12954 r'/\bTRACE_EVENT_ASYNC_',
955 (
956 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
957 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
958 ),
959 False,
960 (
961 r'^base/trace_event/.*',
962 r'^base/tracing/.*',
963 ),
964 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:26965 (
Robert Liao22f66a52021-04-10 00:57:52966 'RoInitialize',
967 (
Robert Liao48018922021-04-16 23:03:02968 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:52969 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
970 'instead. See http://crbug.com/1197722 for more information.'
971 ),
972 True,
Robert Liao48018922021-04-16 23:03:02973 (
974 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$'
975 ),
Robert Liao22f66a52021-04-10 00:57:52976 ),
[email protected]127f18ec2012-06-16 05:05:59977)
978
Mario Sanchez Prada2472cab2019-09-18 10:58:31979# Format: Sequence of tuples containing:
980# * String pattern or, if starting with a slash, a regular expression.
981# * Sequence of strings to show when the pattern matches.
982_DEPRECATED_MOJO_TYPES = (
983 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31984 r'/\bmojo::AssociatedInterfacePtrInfo\b',
985 (
986 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
987 'Use mojo::PendingAssociatedRemote<Interface> instead.',
988 ),
989 ),
990 (
991 r'/\bmojo::AssociatedInterfaceRequest\b',
992 (
993 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
994 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
995 ),
996 ),
997 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31998 r'/\bmojo::InterfacePtr\b',
999 (
1000 'mojo::InterfacePtr<Interface> is deprecated.',
1001 'Use mojo::Remote<Interface> instead.',
1002 ),
1003 ),
1004 (
1005 r'/\bmojo::InterfacePtrInfo\b',
1006 (
1007 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1008 'Use mojo::PendingRemote<Interface> instead.',
1009 ),
1010 ),
1011 (
1012 r'/\bmojo::InterfaceRequest\b',
1013 (
1014 'mojo::InterfaceRequest<Interface> is deprecated.',
1015 'Use mojo::PendingReceiver<Interface> instead.',
1016 ),
1017 ),
1018 (
1019 r'/\bmojo::MakeRequest\b',
1020 (
1021 'mojo::MakeRequest is deprecated.',
1022 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1023 ),
1024 ),
Mario Sanchez Prada2472cab2019-09-18 10:58:311025)
wnwenbdc444e2016-05-25 13:44:151026
mlamouria82272622014-09-16 18:45:041027_IPC_ENUM_TRAITS_DEPRECATED = (
1028 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501029 'See http://www.chromium.org/Home/chromium-security/education/'
1030 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041031
Stephen Martinis97a394142018-06-07 23:06:051032_LONG_PATH_ERROR = (
1033 'Some files included in this CL have file names that are too long (> 200'
1034 ' characters). If committed, these files will cause issues on Windows. See'
1035 ' https://crbug.com/612667 for more details.'
1036)
1037
Shenghua Zhangbfaa38b82017-11-16 21:58:021038_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041039 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041040 r".*[\\/]BuildHooksAndroidImpl\.java",
1041 r".*[\\/]LicenseContentProvider\.java",
1042 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281043 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021044]
[email protected]127f18ec2012-06-16 05:05:591045
Mohamed Heikald048240a2019-11-12 16:57:371046# List of image extensions that are used as resources in chromium.
1047_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1048
Sean Kau46e29bc2017-08-28 16:31:161049# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401050_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041051 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401052 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041053 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1054 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041055 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431056 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161057]
1058
1059
[email protected]b00342e7f2013-03-26 16:21:541060_VALID_OS_MACROS = (
1061 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081062 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541063 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441064 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121065 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541066 'OS_BSD',
1067 'OS_CAT', # For testing.
1068 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041069 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541070 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371071 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541072 'OS_IOS',
1073 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441074 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541075 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211076 'OS_NACL_NONSFI',
1077 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121078 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541079 'OS_OPENBSD',
1080 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371081 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541082 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541083 'OS_WIN',
1084)
1085
1086
Andrew Grieveb773bad2020-06-05 18:00:381087# These are not checked on the public chromium-presubmit trybot.
1088# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041089# checkouts.
agrievef32bcc72016-04-04 14:57:401090_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381091 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381092]
1093
1094
1095_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041096 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361097 'base/android/jni_generator/jni_generator.pydeps',
1098 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361099 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041100 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361101 'build/android/gyp/aar.pydeps',
1102 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271103 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361104 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381105 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361106 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021107 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221108 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111109 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361110 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361111 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361112 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111113 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041114 'build/android/gyp/create_app_bundle_apks.pydeps',
1115 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361116 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121117 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091118 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221119 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001120 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361121 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421122 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041123 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361124 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361125 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211126 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361127 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361128 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361129 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581130 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361131 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141132 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261133 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471134 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011135 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041136 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361137 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361138 'build/android/gyp/merge_manifest.pydeps',
1139 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221140 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361141 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461142 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301143 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241144 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361145 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461146 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561147 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361148 'build/android/incremental_install/generate_android_manifest.pydeps',
1149 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041150 'build/android/resource_sizes.pydeps',
1151 'build/android/test_runner.pydeps',
1152 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361153 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361154 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321155 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271156 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1157 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041158 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001159 'components/cronet/tools/generate_javadoc.pydeps',
1160 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381161 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001162 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381163 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041164 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181165 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041166 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421167 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1168 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131169 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501170 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061171 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221172 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401173]
1174
wnwenbdc444e2016-05-25 13:44:151175
agrievef32bcc72016-04-04 14:57:401176_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1177
1178
Eric Boren6fd2b932018-01-25 15:05:081179# Bypass the AUTHORS check for these accounts.
1180_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591181 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451182 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591183 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521184 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231185 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471186 'lacros-version-skew-roller', 'skylab-test-cros-roller',
1187 'infra-try-recipes-tester')
Eric Boren835d71f2018-09-07 21:09:041188 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271189 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041190 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161191 for s in ('chromium-internal-autoroll',)
1192 ) | set('%[email protected]' % s
1193 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081194
Matt Stark6ef08872021-07-29 01:21:461195_INVALID_GRD_FILE_LINE = [
1196 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1197]
Eric Boren6fd2b932018-01-25 15:05:081198
Daniel Bratell65b033262019-04-23 08:17:061199def _IsCPlusPlusFile(input_api, file_path):
1200 """Returns True if this file contains C++-like code (and not Python,
1201 Go, Java, MarkDown, ...)"""
1202
1203 ext = input_api.os_path.splitext(file_path)[1]
1204 # This list is compatible with CppChecker.IsCppFile but we should
1205 # consider adding ".c" to it. If we do that we can use this function
1206 # at more places in the code.
1207 return ext in (
1208 '.h',
1209 '.cc',
1210 '.cpp',
1211 '.m',
1212 '.mm',
1213 )
1214
1215def _IsCPlusPlusHeaderFile(input_api, file_path):
1216 return input_api.os_path.splitext(file_path)[1] == ".h"
1217
1218
1219def _IsJavaFile(input_api, file_path):
1220 return input_api.os_path.splitext(file_path)[1] == ".java"
1221
1222
1223def _IsProtoFile(input_api, file_path):
1224 return input_api.os_path.splitext(file_path)[1] == ".proto"
1225
Mohamed Heikal5e5b7922020-10-29 18:57:591226
Erik Staabc734cd7a2021-11-23 03:11:521227def _IsXmlOrGrdFile(input_api, file_path):
1228 ext = input_api.os_path.splitext(file_path)[1]
1229 return ext in ('.grd', '.xml')
1230
1231
Mohamed Heikal5e5b7922020-10-29 18:57:591232def CheckNoUpstreamDepsOnClank(input_api, output_api):
1233 """Prevent additions of dependencies from the upstream repo on //clank."""
1234 # clank can depend on clank
1235 if input_api.change.RepositoryRoot().endswith('clank'):
1236 return []
1237 build_file_patterns = [
1238 r'(.+/)?BUILD\.gn',
1239 r'.+\.gni',
1240 ]
1241 excluded_files = [
1242 r'build[/\\]config[/\\]android[/\\]config\.gni'
1243 ]
1244 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1245
1246 error_message = 'Disallowed import on //clank in an upstream build file:'
1247
1248 def FilterFile(affected_file):
1249 return input_api.FilterSourceFile(
1250 affected_file,
1251 files_to_check=build_file_patterns,
1252 files_to_skip=excluded_files)
1253
1254 problems = []
1255 for f in input_api.AffectedSourceFiles(FilterFile):
1256 local_path = f.LocalPath()
1257 for line_number, line in f.ChangedContents():
1258 if (bad_pattern.search(line)):
1259 problems.append(
1260 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1261 if problems:
1262 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1263 else:
1264 return []
1265
1266
Saagar Sanghavifceeaae2020-08-12 16:40:361267def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191268 """Attempts to prevent use of functions intended only for testing in
1269 non-testing code. For now this is just a best-effort implementation
1270 that ignores header files and may have some false positives. A
1271 better implementation would probably need a proper C++ parser.
1272 """
1273 # We only scan .cc files and the like, as the declaration of
1274 # for-testing functions in header files are hard to distinguish from
1275 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491276 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191277
jochenc0d4808c2015-07-27 09:25:421278 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191279 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091280 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131281 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191282 exclusion_pattern = input_api.re.compile(
1283 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1284 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131285 # Avoid a false positive in this case, where the method name, the ::, and
1286 # the closing { are all on different lines due to line wrapping.
1287 # HelperClassForTesting::
1288 # HelperClassForTesting(
1289 # args)
1290 # : member(0) {}
1291 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191292
1293 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441294 files_to_skip = (_EXCLUDED_PATHS +
1295 _TEST_CODE_EXCLUDED_PATHS +
1296 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191297 return input_api.FilterSourceFile(
1298 affected_file,
James Cook24a504192020-07-23 00:08:441299 files_to_check=file_inclusion_pattern,
1300 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191301
1302 problems = []
1303 for f in input_api.AffectedSourceFiles(FilterFile):
1304 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131305 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241306 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031307 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461308 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131309 not exclusion_pattern.search(line) and
1310 not allowlist_pattern.search(line) and
1311 not in_method_defn):
[email protected]55459852011-08-10 15:17:191312 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031313 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131314 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191315
1316 if problems:
[email protected]f7051d52013-04-02 18:31:421317 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031318 else:
1319 return []
[email protected]55459852011-08-10 15:17:191320
1321
Saagar Sanghavifceeaae2020-08-12 16:40:361322def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231323 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591324 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231325 """
1326 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1327 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1328 name_pattern = r'ForTest(s|ing)?'
1329 # Describes an occurrence of "ForTest*" inside a // comment.
1330 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501331 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551332 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231333 # Catch calls.
1334 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1335 # Ignore definitions. (Comments are ignored separately.)
1336 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1337
1338 problems = []
1339 sources = lambda x: input_api.FilterSourceFile(
1340 x,
James Cook24a504192020-07-23 00:08:441341 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1342 + input_api.DEFAULT_FILES_TO_SKIP),
1343 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231344 )
1345 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1346 local_path = f.LocalPath()
1347 is_inside_javadoc = False
1348 for line_number, line in f.ChangedContents():
1349 if is_inside_javadoc and javadoc_end_re.search(line):
1350 is_inside_javadoc = False
1351 if not is_inside_javadoc and javadoc_start_re.search(line):
1352 is_inside_javadoc = True
1353 if is_inside_javadoc:
1354 continue
1355 if (inclusion_re.search(line) and
1356 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501357 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231358 not exclusion_re.search(line)):
1359 problems.append(
1360 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1361
1362 if problems:
1363 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1364 else:
1365 return []
1366
1367
Saagar Sanghavifceeaae2020-08-12 16:40:361368def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541369 """Checks to make sure no .h files include <iostream>."""
1370 files = []
1371 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1372 input_api.re.MULTILINE)
1373 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1374 if not f.LocalPath().endswith('.h'):
1375 continue
1376 contents = input_api.ReadFile(f)
1377 if pattern.search(contents):
1378 files.append(f)
1379
1380 if len(files):
yolandyandaabc6d2016-04-18 18:29:391381 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061382 'Do not #include <iostream> in header files, since it inserts static '
1383 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541384 '#include <ostream>. See http://crbug.com/94794',
1385 files) ]
1386 return []
1387
Danil Chapovalov3518f362018-08-11 16:13:431388def _CheckNoStrCatRedefines(input_api, output_api):
1389 """Checks no windows headers with StrCat redefined are included directly."""
1390 files = []
1391 pattern_deny = input_api.re.compile(
1392 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1393 input_api.re.MULTILINE)
1394 pattern_allow = input_api.re.compile(
1395 r'^#include\s"base/win/windows_defines.inc"',
1396 input_api.re.MULTILINE)
1397 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1398 contents = input_api.ReadFile(f)
1399 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1400 files.append(f.LocalPath())
1401
1402 if len(files):
1403 return [output_api.PresubmitError(
1404 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1405 'directly since they pollute code with StrCat macro. Instead, '
1406 'include matching header from base/win. See http://crbug.com/856536',
1407 files) ]
1408 return []
1409
[email protected]10689ca2011-09-02 02:31:541410
Saagar Sanghavifceeaae2020-08-12 16:40:361411def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521412 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181413 problems = []
1414 for f in input_api.AffectedFiles():
1415 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1416 continue
1417
1418 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041419 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181420 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1421
1422 if not problems:
1423 return []
1424 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1425 '\n'.join(problems))]
1426
Saagar Sanghavifceeaae2020-08-12 16:40:361427def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341428 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1429
1430 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1431 instead of DISABLED_. To filter false positives, reports are only generated
1432 if a corresponding MAYBE_ line exists.
1433 """
1434 problems = []
1435
1436 # The following two patterns are looked for in tandem - is a test labeled
1437 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1438 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1439 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1440
1441 # This is for the case that a test is disabled on all platforms.
1442 full_disable_pattern = input_api.re.compile(
1443 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1444 input_api.re.MULTILINE)
1445
Katie Df13948e2018-09-25 07:33:441446 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341447 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1448 continue
1449
1450 # Search for MABYE_, DISABLE_ pairs.
1451 disable_lines = {} # Maps of test name to line number.
1452 maybe_lines = {}
1453 for line_num, line in f.ChangedContents():
1454 disable_match = disable_pattern.search(line)
1455 if disable_match:
1456 disable_lines[disable_match.group(1)] = line_num
1457 maybe_match = maybe_pattern.search(line)
1458 if maybe_match:
1459 maybe_lines[maybe_match.group(1)] = line_num
1460
1461 # Search for DISABLE_ occurrences within a TEST() macro.
1462 disable_tests = set(disable_lines.keys())
1463 maybe_tests = set(maybe_lines.keys())
1464 for test in disable_tests.intersection(maybe_tests):
1465 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1466
1467 contents = input_api.ReadFile(f)
1468 full_disable_match = full_disable_pattern.search(contents)
1469 if full_disable_match:
1470 problems.append(' %s' % f.LocalPath())
1471
1472 if not problems:
1473 return []
1474 return [
1475 output_api.PresubmitPromptWarning(
1476 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1477 '\n'.join(problems))
1478 ]
1479
Nina Satragnof7660532021-09-20 18:03:351480def CheckForgettingMAYBEInTests(input_api, output_api):
1481 """Checks to make sure tests disabled conditionally are not missing a
1482 corresponding MAYBE_ prefix.
1483 """
1484 # Expect at least a lowercase character in the test name. This helps rule out
1485 # false positives with macros wrapping the actual tests name.
1486 define_maybe_pattern = input_api.re.compile(
1487 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
1488 test_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*\w+,\s*MAYBE_{test_name}\)'
1489 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1490 warnings = []
1491
1492 # Read the entire files. We can't just read the affected lines, forgetting to
1493 # add MAYBE_ on a change would not show up otherwise.
1494 for f in input_api.AffectedFiles(False):
1495 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1496 continue
1497 contents = input_api.ReadFile(f)
1498 lines = contents.splitlines(True)
1499 current_position = 0
1500 warning_test_names = set()
1501 for line_num, line in enumerate(lines, start=1):
1502 current_position += len(line)
1503 maybe_match = define_maybe_pattern.search(line)
1504 if maybe_match:
1505 test_name = maybe_match.group('test_name')
1506 # Do not warn twice for the same test.
1507 if (test_name in warning_test_names):
1508 continue
1509 warning_test_names.add(test_name)
1510
1511 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1512 # the current position.
1513 test_match = input_api.re.compile(
1514 test_maybe_pattern.format(test_name=test_name),
1515 input_api.re.MULTILINE).search(contents, current_position)
1516 suite_match = input_api.re.compile(
1517 suite_maybe_pattern.format(test_name=test_name),
1518 input_api.re.MULTILINE).search(contents, current_position)
1519 if not test_match and not suite_match:
1520 warnings.append(
1521 output_api.PresubmitPromptWarning(
1522 '%s:%d found MAYBE_ defined without corresponding test %s' %
1523 (f.LocalPath(), line_num, test_name)))
1524 return warnings
[email protected]72df4e782012-06-21 16:28:181525
Saagar Sanghavifceeaae2020-08-12 16:40:361526def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571527 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521528 errors = []
Hans Wennborg944479f2020-06-25 21:39:251529 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521530 input_api.re.MULTILINE)
1531 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1532 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1533 continue
1534 for lnum, line in f.ChangedContents():
1535 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171536 errors.append(output_api.PresubmitError(
1537 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571538 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171539 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521540 return errors
1541
1542
Weilun Shia487fad2020-10-28 00:10:341543# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1544# more reliable way. See
1545# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191546
wnwenbdc444e2016-05-25 13:44:151547
Saagar Sanghavifceeaae2020-08-12 16:40:361548def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391549 """Check that FlakyTest annotation is our own instead of the android one"""
1550 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1551 files = []
1552 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1553 if f.LocalPath().endswith('Test.java'):
1554 if pattern.search(input_api.ReadFile(f)):
1555 files.append(f)
1556 if len(files):
1557 return [output_api.PresubmitError(
1558 'Use org.chromium.base.test.util.FlakyTest instead of '
1559 'android.test.FlakyTest',
1560 files)]
1561 return []
mcasasb7440c282015-02-04 14:52:191562
wnwenbdc444e2016-05-25 13:44:151563
Saagar Sanghavifceeaae2020-08-12 16:40:361564def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441565 """Make sure .DEPS.git is never modified manually."""
1566 if any(f.LocalPath().endswith('.DEPS.git') for f in
1567 input_api.AffectedFiles()):
1568 return [output_api.PresubmitError(
1569 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1570 'automated system based on what\'s in DEPS and your changes will be\n'
1571 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501572 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1573 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441574 'for more information')]
1575 return []
1576
1577
Saagar Sanghavifceeaae2020-08-12 16:40:361578def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471579 """Checks that DEPS file deps are from allowed_hosts."""
1580 # Run only if DEPS file has been modified to annoy fewer bystanders.
1581 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1582 return []
1583 # Outsource work to gclient verify
1584 try:
John Budorickf20c0042019-04-25 23:23:401585 gclient_path = input_api.os_path.join(
1586 input_api.PresubmitLocalPath(),
1587 'third_party', 'depot_tools', 'gclient.py')
1588 input_api.subprocess.check_output(
1589 [input_api.python_executable, gclient_path, 'verify'],
1590 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471591 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201592 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471593 return [output_api.PresubmitError(
1594 'DEPS file must have only git dependencies.',
1595 long_text=error.output)]
1596
1597
Mario Sanchez Prada2472cab2019-09-18 10:58:311598def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1599 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591600 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311601
1602 Returns an string composed of the name of the file, the line number where the
1603 match has been found and the additional text passed as |message| in case the
1604 target type name matches the text inside the line passed as parameter.
1605 """
Peng Huang9c5949a02020-06-11 19:20:541606 result = []
1607
danakjd18e8892020-12-17 17:42:011608 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1609 return result
1610 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541611 return result
1612
Mario Sanchez Prada2472cab2019-09-18 10:58:311613 matched = False
1614 if type_name[0:1] == '/':
1615 regex = type_name[1:]
1616 if input_api.re.search(regex, line):
1617 matched = True
1618 elif type_name in line:
1619 matched = True
1620
Mario Sanchez Prada2472cab2019-09-18 10:58:311621 if matched:
1622 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1623 for message_line in message:
1624 result.append(' %s' % message_line)
1625
1626 return result
1627
1628
Saagar Sanghavifceeaae2020-08-12 16:40:361629def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591630 """Make sure that banned functions are not used."""
1631 warnings = []
1632 errors = []
1633
James Cook24a504192020-07-23 00:08:441634 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151635 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441636 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151637 if input_api.re.match(item, local_path):
1638 return True
1639 return False
1640
Peter K. Lee6c03ccff2019-07-15 14:40:051641 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541642 local_path = affected_file.LocalPath()
1643 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1644 return False
1645 basename = input_api.os_path.basename(local_path)
1646 if 'ios' in basename.split('_'):
1647 return True
1648 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1649 if sep and 'ios' in local_path.split(sep):
1650 return True
1651 return False
1652
wnwenbdc444e2016-05-25 13:44:151653 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311654 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1655 func_name, message)
1656 if problems:
wnwenbdc444e2016-05-25 13:44:151657 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311658 errors.extend(problems)
1659 else:
1660 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151661
Eric Stevensona9a980972017-09-23 00:04:411662 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1663 for f in input_api.AffectedFiles(file_filter=file_filter):
1664 for line_num, line in f.ChangedContents():
1665 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1666 CheckForMatch(f, line_num, line, func_name, message, error)
1667
[email protected]127f18ec2012-06-16 05:05:591668 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1669 for f in input_api.AffectedFiles(file_filter=file_filter):
1670 for line_num, line in f.ChangedContents():
1671 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151672 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591673
Peter K. Lee6c03ccff2019-07-15 14:40:051674 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541675 for line_num, line in f.ChangedContents():
1676 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1677 CheckForMatch(f, line_num, line, func_name, message, error)
1678
Peter K. Lee6c03ccff2019-07-15 14:40:051679 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1680 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1681 for line_num, line in f.ChangedContents():
1682 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1683 CheckForMatch(f, line_num, line, func_name, message, error)
1684
[email protected]127f18ec2012-06-16 05:05:591685 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1686 for f in input_api.AffectedFiles(file_filter=file_filter):
1687 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491688 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441689 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491690 continue
wnwenbdc444e2016-05-25 13:44:151691 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591692
1693 result = []
1694 if (warnings):
1695 result.append(output_api.PresubmitPromptWarning(
1696 'Banned functions were used.\n' + '\n'.join(warnings)))
1697 if (errors):
1698 result.append(output_api.PresubmitError(
1699 'Banned functions were used.\n' + '\n'.join(errors)))
1700 return result
1701
1702
Michael Thiessen44457642020-02-06 00:24:151703def _CheckAndroidNoBannedImports(input_api, output_api):
1704 """Make sure that banned java imports are not used."""
1705 errors = []
1706
1707 def IsException(path, exceptions):
1708 for exception in exceptions:
1709 if (path.startswith(exception)):
1710 return True
1711 return False
1712
1713 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1714 for f in input_api.AffectedFiles(file_filter=file_filter):
1715 for line_num, line in f.ChangedContents():
1716 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1717 if IsException(f.LocalPath(), exceptions):
1718 continue;
1719 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1720 'import ' + import_name, message)
1721 if problems:
1722 errors.extend(problems)
1723 result = []
1724 if (errors):
1725 result.append(output_api.PresubmitError(
1726 'Banned imports were used.\n' + '\n'.join(errors)))
1727 return result
1728
1729
Saagar Sanghavifceeaae2020-08-12 16:40:361730def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311731 """Make sure that old Mojo types are not used."""
1732 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571733 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311734
Mario Sanchez Pradaaab91382019-12-19 08:57:091735 # For any path that is not an "ok" or an "error" path, a warning will be
1736 # raised if deprecated mojo types are found.
1737 ok_paths = ['components/arc']
1738 error_paths = ['third_party/blink', 'content']
1739
Mario Sanchez Prada2472cab2019-09-18 10:58:311740 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1741 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571742 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091743 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311744 continue
1745
1746 for line_num, line in f.ChangedContents():
1747 for func_name, message in _DEPRECATED_MOJO_TYPES:
1748 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1749 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571750
Mario Sanchez Prada2472cab2019-09-18 10:58:311751 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091752 # Raise errors inside |error_paths| and warnings everywhere else.
1753 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571754 errors.extend(problems)
1755 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311756 warnings.extend(problems)
1757
1758 result = []
1759 if (warnings):
1760 result.append(output_api.PresubmitPromptWarning(
1761 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571762 if (errors):
1763 result.append(output_api.PresubmitError(
1764 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311765 return result
1766
1767
Saagar Sanghavifceeaae2020-08-12 16:40:361768def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061769 """Make sure that banned functions are not used."""
1770 files = []
1771 pattern = input_api.re.compile(r'^#pragma\s+once',
1772 input_api.re.MULTILINE)
1773 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1774 if not f.LocalPath().endswith('.h'):
1775 continue
1776 contents = input_api.ReadFile(f)
1777 if pattern.search(contents):
1778 files.append(f)
1779
1780 if files:
1781 return [output_api.PresubmitError(
1782 'Do not use #pragma once in header files.\n'
1783 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1784 files)]
1785 return []
1786
[email protected]127f18ec2012-06-16 05:05:591787
Saagar Sanghavifceeaae2020-08-12 16:40:361788def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121789 """Checks to make sure we don't introduce use of foo ? true : false."""
1790 problems = []
1791 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1792 for f in input_api.AffectedFiles():
1793 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1794 continue
1795
1796 for line_num, line in f.ChangedContents():
1797 if pattern.match(line):
1798 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1799
1800 if not problems:
1801 return []
1802 return [output_api.PresubmitPromptWarning(
1803 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1804 '\n'.join(problems))]
1805
1806
Saagar Sanghavifceeaae2020-08-12 16:40:361807def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281808 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181809 change. Breaking - rules is an error, breaking ! rules is a
1810 warning.
1811 """
Erik Staabc734cd7a2021-11-23 03:11:521812 # Return early if no relevant file types were modified.
1813 for f in input_api.AffectedFiles():
1814 path = f.LocalPath()
1815 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path) or
1816 _IsJavaFile(input_api, path)):
1817 break
1818 else:
1819 return []
1820
mohan.reddyf21db962014-10-16 12:26:471821 import sys
[email protected]55f9f382012-07-31 11:02:181822 # We need to wait until we have an input_api object and use this
1823 # roundabout construct to import checkdeps because this file is
1824 # eval-ed and thus doesn't have __file__.
1825 original_sys_path = sys.path
1826 try:
1827 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471828 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181829 import checkdeps
[email protected]55f9f382012-07-31 11:02:181830 from rules import Rule
1831 finally:
1832 # Restore sys.path to what it was before.
1833 sys.path = original_sys_path
1834
1835 added_includes = []
rhalavati08acd232017-04-03 07:23:281836 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241837 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181838 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061839 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501840 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081841 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061842 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501843 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081844 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061845 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501846 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081847 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181848
[email protected]26385172013-05-09 23:11:351849 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181850
1851 error_descriptions = []
1852 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281853 error_subjects = set()
1854 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361855
[email protected]55f9f382012-07-31 11:02:181856 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1857 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081858 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181859 description_with_path = '%s\n %s' % (path, rule_description)
1860 if rule_type == Rule.DISALLOW:
1861 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281862 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181863 else:
1864 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281865 warning_subjects.add("#includes")
1866
1867 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1868 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081869 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281870 description_with_path = '%s\n %s' % (path, rule_description)
1871 if rule_type == Rule.DISALLOW:
1872 error_descriptions.append(description_with_path)
1873 error_subjects.add("imports")
1874 else:
1875 warning_descriptions.append(description_with_path)
1876 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181877
Jinsuk Kim5a092672017-10-24 22:42:241878 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021879 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081880 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241881 description_with_path = '%s\n %s' % (path, rule_description)
1882 if rule_type == Rule.DISALLOW:
1883 error_descriptions.append(description_with_path)
1884 error_subjects.add("imports")
1885 else:
1886 warning_descriptions.append(description_with_path)
1887 warning_subjects.add("imports")
1888
[email protected]55f9f382012-07-31 11:02:181889 results = []
1890 if error_descriptions:
1891 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281892 'You added one or more %s that violate checkdeps rules.'
1893 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181894 error_descriptions))
1895 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421896 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281897 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181898 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281899 '%s? See relevant DEPS file(s) for details and contacts.' %
1900 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181901 warning_descriptions))
1902 return results
1903
1904
Saagar Sanghavifceeaae2020-08-12 16:40:361905def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:221906 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151907 if input_api.platform == 'win32':
1908 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291909 checkperms_tool = input_api.os_path.join(
1910 input_api.PresubmitLocalPath(),
1911 'tools', 'checkperms', 'checkperms.py')
1912 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471913 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391914 with input_api.CreateTemporaryFile() as file_list:
1915 for f in input_api.AffectedFiles():
1916 # checkperms.py file/directory arguments must be relative to the
1917 # repository.
Dirk Prankee3c9c62d2021-05-18 18:35:591918 file_list.write((f.LocalPath() + '\n').encode('utf8'))
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391919 file_list.close()
1920 args += ['--file-list', file_list.name]
1921 try:
1922 input_api.subprocess.check_output(args)
1923 return []
1924 except input_api.subprocess.CalledProcessError as error:
1925 return [output_api.PresubmitError(
1926 'checkperms.py failed:',
Ari Chivukula45f58dd52021-06-18 04:23:041927 long_text=error.output.decode('utf-8', 'ignore'))]
[email protected]fbcafe5a2012-08-08 15:31:221928
1929
Saagar Sanghavifceeaae2020-08-12 16:40:361930def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:491931 """Makes sure we don't include ui/aura/window_property.h
1932 in header files.
1933 """
1934 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1935 errors = []
1936 for f in input_api.AffectedFiles():
1937 if not f.LocalPath().endswith('.h'):
1938 continue
1939 for line_num, line in f.ChangedContents():
1940 if pattern.match(line):
1941 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1942
1943 results = []
1944 if errors:
1945 results.append(output_api.PresubmitError(
1946 'Header files should not include ui/aura/window_property.h', errors))
1947 return results
1948
1949
Omer Katzcc77ea92021-04-26 10:23:281950def CheckNoInternalHeapIncludes(input_api, output_api):
1951 """Makes sure we don't include any headers from
1952 third_party/blink/renderer/platform/heap/impl or
1953 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1954 third_party/blink/renderer/platform/heap
1955 """
1956 impl_pattern = input_api.re.compile(
1957 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1958 v8_wrapper_pattern = input_api.re.compile(
1959 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"')
1960 file_filter = lambda f: not input_api.re.match(
1961 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1962 f.LocalPath())
1963 errors = []
1964
1965 for f in input_api.AffectedFiles(file_filter=file_filter):
1966 for line_num, line in f.ChangedContents():
1967 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1968 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1969
1970 results = []
1971 if errors:
1972 results.append(output_api.PresubmitError(
1973 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1974 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1975 'relevant counterparts from third_party/blink/renderer/platform/heap',
1976 errors))
1977 return results
1978
1979
[email protected]70ca77752012-11-20 03:45:031980def _CheckForVersionControlConflictsInFile(input_api, f):
1981 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1982 errors = []
1983 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161984 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231985 # First-level headers in markdown look a lot like version control
1986 # conflict markers. http://daringfireball.net/projects/markdown/basics
1987 continue
[email protected]70ca77752012-11-20 03:45:031988 if pattern.match(line):
1989 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1990 return errors
1991
1992
Saagar Sanghavifceeaae2020-08-12 16:40:361993def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:031994 """Usually this is not intentional and will cause a compile failure."""
1995 errors = []
1996 for f in input_api.AffectedFiles():
1997 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1998
1999 results = []
2000 if errors:
2001 results.append(output_api.PresubmitError(
2002 'Version control conflict markers found, please resolve.', errors))
2003 return results
2004
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202005
Saagar Sanghavifceeaae2020-08-12 16:40:362006def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162007 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2008 errors = []
2009 for f in input_api.AffectedFiles():
2010 for line_num, line in f.ChangedContents():
2011 if pattern.search(line):
2012 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2013
2014 results = []
2015 if errors:
2016 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502017 'Found Google support URL addressed by answer number. Please replace '
2018 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162019 return results
2020
[email protected]70ca77752012-11-20 03:45:032021
Saagar Sanghavifceeaae2020-08-12 16:40:362022def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442023 def FilterFile(affected_file):
2024 """Filter function for use with input_api.AffectedSourceFiles,
2025 below. This filters out everything except non-test files from
2026 top-level directories that generally speaking should not hard-code
2027 service URLs (e.g. src/android_webview/, src/content/ and others).
2028 """
2029 return input_api.FilterSourceFile(
2030 affected_file,
James Cook24a504192020-07-23 00:08:442031 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2032 files_to_skip=(_EXCLUDED_PATHS +
2033 _TEST_CODE_EXCLUDED_PATHS +
2034 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442035
reillyi38965732015-11-16 18:27:332036 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2037 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462038 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2039 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442040 problems = [] # items are (filename, line_number, line)
2041 for f in input_api.AffectedSourceFiles(FilterFile):
2042 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462043 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442044 problems.append((f.LocalPath(), line_num, line))
2045
2046 if problems:
[email protected]f7051d52013-04-02 18:31:422047 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442048 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582049 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442050 [' %s:%d: %s' % (
2051 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032052 else:
2053 return []
[email protected]06e6d0ff2012-12-11 01:36:442054
2055
Saagar Sanghavifceeaae2020-08-12 16:40:362056def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292057 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2058 def FileFilter(affected_file):
2059 """Includes directories known to be Chrome OS only."""
2060 return input_api.FilterSourceFile(
2061 affected_file,
James Cook24a504192020-07-23 00:08:442062 files_to_check=('^ash/',
2063 '^chromeos/', # Top-level src/chromeos.
Henrique Ferreiro2e1aa1092021-11-29 22:22:122064 '.*/chromeos/', # Any path component.
James Cook24a504192020-07-23 00:08:442065 '^components/arc',
2066 '^components/exo'),
2067 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292068
2069 prefs = []
2070 priority_prefs = []
2071 for f in input_api.AffectedFiles(file_filter=FileFilter):
2072 for line_num, line in f.ChangedContents():
2073 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2074 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2075 prefs.append(' %s' % line)
2076 if input_api.re.search(
2077 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2078 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2079 priority_prefs.append(' %s' % line)
2080
2081 results = []
2082 if (prefs):
2083 results.append(output_api.PresubmitPromptWarning(
2084 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2085 'by browser sync settings. If these prefs should be controlled by OS '
2086 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2087 if (priority_prefs):
2088 results.append(output_api.PresubmitPromptWarning(
2089 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2090 'controlled by browser sync settings. If these prefs should be '
2091 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2092 'instead.\n' + '\n'.join(prefs)))
2093 return results
2094
2095
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492096# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362097def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272098 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312099 The native_client_sdk directory is excluded because it has auto-generated PNG
2100 files for documentation.
[email protected]d2530012013-01-25 16:39:272101 """
[email protected]d2530012013-01-25 16:39:272102 errors = []
James Cook24a504192020-07-23 00:08:442103 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2104 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312105 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442106 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312107 for f in input_api.AffectedFiles(include_deletes=False,
2108 file_filter=file_filter):
2109 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272110
2111 results = []
2112 if errors:
2113 results.append(output_api.PresubmitError(
2114 'The name of PNG files should not have abbreviations. \n'
2115 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2116 'Contact [email protected] if you have questions.', errors))
2117 return results
2118
2119
Daniel Cheng4dcdb6b2017-04-13 08:30:172120def _ExtractAddRulesFromParsedDeps(parsed_deps):
2121 """Extract the rules that add dependencies from a parsed DEPS file.
2122
2123 Args:
2124 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2125 add_rules = set()
2126 add_rules.update([
2127 rule[1:] for rule in parsed_deps.get('include_rules', [])
2128 if rule.startswith('+') or rule.startswith('!')
2129 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502130 for _, rules in parsed_deps.get('specific_include_rules',
Dirk Prankee3c9c62d2021-05-18 18:35:592131 {}).items():
Daniel Cheng4dcdb6b2017-04-13 08:30:172132 add_rules.update([
2133 rule[1:] for rule in rules
2134 if rule.startswith('+') or rule.startswith('!')
2135 ])
2136 return add_rules
2137
2138
2139def _ParseDeps(contents):
2140 """Simple helper for parsing DEPS files."""
2141 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172142 class _VarImpl:
2143
2144 def __init__(self, local_scope):
2145 self._local_scope = local_scope
2146
2147 def Lookup(self, var_name):
2148 """Implements the Var syntax."""
2149 try:
2150 return self._local_scope['vars'][var_name]
2151 except KeyError:
2152 raise Exception('Var is not defined: %s' % var_name)
2153
2154 local_scope = {}
2155 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172156 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592157 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172158 }
Dirk Pranke1b9e06382021-05-14 01:16:222159
Dirk Prankee3c9c62d2021-05-18 18:35:592160 exec(contents, global_scope, local_scope)
Daniel Cheng4dcdb6b2017-04-13 08:30:172161 return local_scope
2162
2163
2164def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592165 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412166 a set of DEPS entries that we should look up.
2167
2168 For a directory (rather than a specific filename) we fake a path to
2169 a specific filename by adding /DEPS. This is chosen as a file that
2170 will seldom or never be subject to per-file include_rules.
2171 """
[email protected]2b438d62013-11-14 17:54:142172 # We ignore deps entries on auto-generated directories.
2173 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082174
Daniel Cheng4dcdb6b2017-04-13 08:30:172175 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2176 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2177
2178 added_deps = new_deps.difference(old_deps)
2179
[email protected]2b438d62013-11-14 17:54:142180 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172181 for added_dep in added_deps:
2182 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2183 continue
2184 # Assume that a rule that ends in .h is a rule for a specific file.
2185 if added_dep.endswith('.h'):
2186 results.add(added_dep)
2187 else:
2188 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082189 return results
2190
2191
Saagar Sanghavifceeaae2020-08-12 16:40:362192def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552193 """When a dependency prefixed with + is added to a DEPS file, we
2194 want to make sure that the change is reviewed by an OWNER of the
2195 target file or directory, to avoid layering violations from being
2196 introduced. This check verifies that this happens.
2197 """
Joey Mou57048132021-02-26 22:17:552198 # We rely on Gerrit's code-owners to check approvals.
2199 # input_api.gerrit is always set for Chromium, but other projects
2200 # might not use Gerrit.
2201 if not input_api.gerrit:
2202 return []
Edward Lesmes44feb2332021-03-19 01:27:522203 if (input_api.change.issue and
2204 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232205 # Skip OWNERS check when Owners-Override label is approved. This is intended
2206 # for global owners, trusted bots, and on-call sheriffs. Review is still
2207 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522208 return []
Edward Lesmes6fba51082021-01-20 04:20:232209
Daniel Cheng4dcdb6b2017-04-13 08:30:172210 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242211
2212 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492213 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242214 for f in input_api.AffectedFiles(include_deletes=False,
2215 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552216 filename = input_api.os_path.basename(f.LocalPath())
2217 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172218 virtual_depended_on_files.update(_CalculateAddedDeps(
2219 input_api.os_path,
2220 '\n'.join(f.OldContents()),
2221 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552222
[email protected]e871964c2013-05-13 14:14:552223 if not virtual_depended_on_files:
2224 return []
2225
2226 if input_api.is_committing:
2227 if input_api.tbr:
2228 return [output_api.PresubmitNotifyResult(
2229 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272230 if input_api.dry_run:
2231 return [output_api.PresubmitNotifyResult(
2232 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552233 if not input_api.change.issue:
2234 return [output_api.PresubmitError(
2235 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402236 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552237 output = output_api.PresubmitError
2238 else:
2239 output = output_api.PresubmitNotifyResult
2240
tandriied3b7e12016-05-12 14:38:502241 owner_email, reviewers = (
2242 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2243 input_api,
Edward Lesmesa3846442021-02-08 20:20:032244 None,
tandriied3b7e12016-05-12 14:38:502245 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552246
2247 owner_email = owner_email or input_api.change.author_email
2248
Edward Lesmesa3846442021-02-08 20:20:032249 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2250 virtual_depended_on_files, reviewers.union([owner_email]), [])
2251 missing_files = [
2252 f for f in virtual_depended_on_files
2253 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412254
2255 # We strip the /DEPS part that was added by
2256 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2257 # directory.
2258 def StripDeps(path):
2259 start_deps = path.rfind('/DEPS')
2260 if start_deps != -1:
2261 return path[:start_deps]
2262 else:
2263 return path
2264 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552265 for path in missing_files]
2266
2267 if unapproved_dependencies:
2268 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152269 output('You need LGTM from owners of depends-on paths in DEPS that were '
2270 'modified in this CL:\n %s' %
2271 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032272 suggested_owners = input_api.owners_client.SuggestOwners(
2273 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152274 output_list.append(output(
2275 'Suggested missing target path OWNERS:\n %s' %
2276 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552277 return output_list
2278
2279 return []
2280
2281
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492282# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362283def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492284 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442285 files_to_skip = (_EXCLUDED_PATHS +
2286 _TEST_CODE_EXCLUDED_PATHS +
2287 input_api.DEFAULT_FILES_TO_SKIP +
2288 (r"^base[\\/]logging\.h$",
2289 r"^base[\\/]logging\.cc$",
2290 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2291 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2292 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2293 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2294 r"startup_browser_creator\.cc$",
2295 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2296 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2297 r"diagnostics_writer\.cc$",
2298 r"^chrome[\\/]chrome_cleaner[\\/].*",
2299 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2300 r"dll_hash_main\.cc$",
2301 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2302 r"^chromecast[\\/]",
2303 r"^cloud_print[\\/]",
2304 r"^components[\\/]browser_watcher[\\/]"
2305 r"dump_stability_report_main_win.cc$",
2306 r"^components[\\/]media_control[\\/]renderer[\\/]"
2307 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352308 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2309 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442310 r"^components[\\/]zucchini[\\/].*",
2311 # TODO(peter): Remove exception. https://crbug.com/534537
2312 r"^content[\\/]browser[\\/]notifications[\\/]"
2313 r"notification_event_dispatcher_impl\.cc$",
2314 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2315 r"gl_helper_benchmark\.cc$",
2316 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2317 r"^courgette[\\/]courgette_tool\.cc$",
2318 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
David Dorwinfa9aef42021-08-17 06:46:202319 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
James Cook24a504192020-07-23 00:08:442320 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Sergey Ulanov6db14b4d62021-05-10 07:59:482321 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
James Cook24a504192020-07-23 00:08:442322 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2323 r"^ipc[\\/]ipc_logging\.cc$",
2324 r"^native_client_sdk[\\/]",
2325 r"^remoting[\\/]base[\\/]logging\.h$",
2326 r"^remoting[\\/]host[\\/].*",
2327 r"^sandbox[\\/]linux[\\/].*",
2328 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2329 r"dump_file_system.cc$",
2330 r"^tools[\\/]",
2331 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2332 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2333 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2334 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2335 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402336 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442337 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402338
thomasanderson625d3932017-03-29 07:16:582339 log_info = set([])
2340 printf = set([])
[email protected]85218562013-11-22 07:41:402341
2342 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582343 for _, line in f.ChangedContents():
2344 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2345 log_info.add(f.LocalPath())
2346 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2347 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372348
thomasanderson625d3932017-03-29 07:16:582349 if input_api.re.search(r"\bprintf\(", line):
2350 printf.add(f.LocalPath())
2351 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2352 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402353
2354 if log_info:
2355 return [output_api.PresubmitError(
2356 'These files spam the console log with LOG(INFO):',
2357 items=log_info)]
2358 if printf:
2359 return [output_api.PresubmitError(
2360 'These files spam the console log with printf/fprintf:',
2361 items=printf)]
2362 return []
2363
2364
Saagar Sanghavifceeaae2020-08-12 16:40:362365def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162366 """These types are all expected to hold locks while in scope and
2367 so should never be anonymous (which causes them to be immediately
2368 destroyed)."""
2369 they_who_must_be_named = [
2370 'base::AutoLock',
2371 'base::AutoReset',
2372 'base::AutoUnlock',
2373 'SkAutoAlphaRestore',
2374 'SkAutoBitmapShaderInstall',
2375 'SkAutoBlitterChoose',
2376 'SkAutoBounderCommit',
2377 'SkAutoCallProc',
2378 'SkAutoCanvasRestore',
2379 'SkAutoCommentBlock',
2380 'SkAutoDescriptor',
2381 'SkAutoDisableDirectionCheck',
2382 'SkAutoDisableOvalCheck',
2383 'SkAutoFree',
2384 'SkAutoGlyphCache',
2385 'SkAutoHDC',
2386 'SkAutoLockColors',
2387 'SkAutoLockPixels',
2388 'SkAutoMalloc',
2389 'SkAutoMaskFreeImage',
2390 'SkAutoMutexAcquire',
2391 'SkAutoPathBoundsUpdate',
2392 'SkAutoPDFRelease',
2393 'SkAutoRasterClipValidate',
2394 'SkAutoRef',
2395 'SkAutoTime',
2396 'SkAutoTrace',
2397 'SkAutoUnref',
2398 ]
2399 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2400 # bad: base::AutoLock(lock.get());
2401 # not bad: base::AutoLock lock(lock.get());
2402 bad_pattern = input_api.re.compile(anonymous)
2403 # good: new base::AutoLock(lock.get())
2404 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2405 errors = []
2406
2407 for f in input_api.AffectedFiles():
2408 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2409 continue
2410 for linenum, line in f.ChangedContents():
2411 if bad_pattern.search(line) and not good_pattern.search(line):
2412 errors.append('%s:%d' % (f.LocalPath(), linenum))
2413
2414 if errors:
2415 return [output_api.PresubmitError(
2416 'These lines create anonymous variables that need to be named:',
2417 items=errors)]
2418 return []
2419
2420
Saagar Sanghavifceeaae2020-08-12 16:40:362421def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532422 # Returns whether |template_str| is of the form <T, U...> for some types T
2423 # and U. Assumes that |template_str| is already in the form <...>.
2424 def HasMoreThanOneArg(template_str):
2425 # Level of <...> nesting.
2426 nesting = 0
2427 for c in template_str:
2428 if c == '<':
2429 nesting += 1
2430 elif c == '>':
2431 nesting -= 1
2432 elif c == ',' and nesting == 1:
2433 return True
2434 return False
2435
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492436 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102437 sources = lambda affected_file: input_api.FilterSourceFile(
2438 affected_file,
James Cook24a504192020-07-23 00:08:442439 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2440 input_api.DEFAULT_FILES_TO_SKIP),
2441 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552442
2443 # Pattern to capture a single "<...>" block of template arguments. It can
2444 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2445 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2446 # latter would likely require counting that < and > match, which is not
2447 # expressible in regular languages. Should the need arise, one can introduce
2448 # limited counting (matching up to a total number of nesting depth), which
2449 # should cover all practical cases for already a low nesting limit.
2450 template_arg_pattern = (
2451 r'<[^>]*' # Opening block of <.
2452 r'>([^<]*>)?') # Closing block of >.
2453 # Prefix expressing that whatever follows is not already inside a <...>
2454 # block.
2455 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102456 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552457 not_inside_template_arg_pattern
2458 + r'\bstd::unique_ptr'
2459 + template_arg_pattern
2460 + r'\(\)')
2461
2462 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2463 template_arg_no_array_pattern = (
2464 r'<[^>]*[^]]' # Opening block of <.
2465 r'>([^(<]*[^]]>)?') # Closing block of >.
2466 # Prefix saying that what follows is the start of an expression.
2467 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2468 # Suffix saying that what follows are call parentheses with a non-empty list
2469 # of arguments.
2470 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532471 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552472 return_construct_pattern = input_api.re.compile(
2473 start_of_expr_pattern
2474 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532475 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552476 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532477 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552478 + nonempty_arg_list_pattern)
2479
Vaclav Brozek851d9602018-04-04 16:13:052480 problems_constructor = []
2481 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102482 for f in input_api.AffectedSourceFiles(sources):
2483 for line_number, line in f.ChangedContents():
2484 # Disallow:
2485 # return std::unique_ptr<T>(foo);
2486 # bar = std::unique_ptr<T>(foo);
2487 # But allow:
2488 # return std::unique_ptr<T[]>(foo);
2489 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532490 # And also allow cases when the second template argument is present. Those
2491 # cases cannot be handled by std::make_unique:
2492 # return std::unique_ptr<T, U>(foo);
2493 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052494 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532495 return_construct_result = return_construct_pattern.search(line)
2496 if return_construct_result and not HasMoreThanOneArg(
2497 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052498 problems_constructor.append(
2499 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102500 # Disallow:
2501 # std::unique_ptr<T>()
2502 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052503 problems_nullptr.append(
2504 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2505
2506 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162507 if problems_nullptr:
Daniel Cheng2dbf9c42021-10-06 21:26:112508 errors.append(output_api.PresubmitPromptWarning(
Vaclav Brozek851d9602018-04-04 16:13:052509 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162510 problems_nullptr))
2511 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052512 errors.append(output_api.PresubmitError(
Yao Li7f5a705d2021-11-23 22:30:562513 'The following files use explicit std::unique_ptr constructor. '
2514 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2515 'std::make_unique is not an option.',
Vaclav Brozekc2fecf42018-04-06 16:40:162516 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102517 return errors
2518
2519
Saagar Sanghavifceeaae2020-08-12 16:40:362520def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082521 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522522 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082523 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522524 # If actions.xml is already included in the changelist, the PRESUBMIT
2525 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082526 return []
2527
Alexei Svitkine64505a92021-03-11 22:00:542528 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2529 files_to_skip = (_EXCLUDED_PATHS +
2530 _TEST_CODE_EXCLUDED_PATHS +
2531 input_api.DEFAULT_FILES_TO_SKIP )
2532 file_filter = lambda f: input_api.FilterSourceFile(
2533 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2534
[email protected]999261d2014-03-03 20:08:082535 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522536 current_actions = None
[email protected]999261d2014-03-03 20:08:082537 for f in input_api.AffectedFiles(file_filter=file_filter):
2538 for line_num, line in f.ChangedContents():
2539 match = input_api.re.search(action_re, line)
2540 if match:
[email protected]2f92dec2014-03-07 19:21:522541 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2542 # loaded only once.
2543 if not current_actions:
2544 with open('tools/metrics/actions/actions.xml') as actions_f:
2545 current_actions = actions_f.read()
2546 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082547 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522548 action = 'name="{0}"'.format(action_name)
2549 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082550 return [output_api.PresubmitPromptWarning(
2551 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522552 'tools/metrics/actions/actions.xml. Please run '
2553 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082554 % (f.LocalPath(), line_num, action_name))]
2555 return []
2556
2557
Daniel Cheng13ca61a882017-08-25 15:11:252558def _ImportJSONCommentEater(input_api):
2559 import sys
2560 sys.path = sys.path + [input_api.os_path.join(
2561 input_api.PresubmitLocalPath(),
2562 'tools', 'json_comment_eater')]
2563 import json_comment_eater
2564 return json_comment_eater
2565
2566
[email protected]99171a92014-06-03 08:44:472567def _GetJSONParseError(input_api, filename, eat_comments=True):
2568 try:
2569 contents = input_api.ReadFile(filename)
2570 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252571 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132572 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472573
2574 input_api.json.loads(contents)
2575 except ValueError as e:
2576 return e
2577 return None
2578
2579
2580def _GetIDLParseError(input_api, filename):
2581 try:
2582 contents = input_api.ReadFile(filename)
2583 idl_schema = input_api.os_path.join(
2584 input_api.PresubmitLocalPath(),
2585 'tools', 'json_schema_compiler', 'idl_schema.py')
2586 process = input_api.subprocess.Popen(
2587 [input_api.python_executable, idl_schema],
2588 stdin=input_api.subprocess.PIPE,
2589 stdout=input_api.subprocess.PIPE,
2590 stderr=input_api.subprocess.PIPE,
2591 universal_newlines=True)
2592 (_, error) = process.communicate(input=contents)
2593 return error or None
2594 except ValueError as e:
2595 return e
2596
2597
Saagar Sanghavifceeaae2020-08-12 16:40:362598def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472599 """Check that IDL and JSON files do not contain syntax errors."""
2600 actions = {
2601 '.idl': _GetIDLParseError,
2602 '.json': _GetJSONParseError,
2603 }
[email protected]99171a92014-06-03 08:44:472604 # Most JSON files are preprocessed and support comments, but these do not.
2605 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042606 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472607 ]
2608 # Only run IDL checker on files in these directories.
2609 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042610 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2611 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472612 ]
2613
2614 def get_action(affected_file):
2615 filename = affected_file.LocalPath()
2616 return actions.get(input_api.os_path.splitext(filename)[1])
2617
[email protected]99171a92014-06-03 08:44:472618 def FilterFile(affected_file):
2619 action = get_action(affected_file)
2620 if not action:
2621 return False
2622 path = affected_file.LocalPath()
2623
Erik Staab2dd72b12020-04-16 15:03:402624 if _MatchesFile(input_api,
2625 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2626 path):
[email protected]99171a92014-06-03 08:44:472627 return False
2628
2629 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162630 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472631 return False
2632 return True
2633
2634 results = []
2635 for affected_file in input_api.AffectedFiles(
2636 file_filter=FilterFile, include_deletes=False):
2637 action = get_action(affected_file)
2638 kwargs = {}
2639 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162640 _MatchesFile(input_api, json_no_comments_patterns,
2641 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472642 kwargs['eat_comments'] = False
2643 parse_error = action(input_api,
2644 affected_file.AbsoluteLocalPath(),
2645 **kwargs)
2646 if parse_error:
2647 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2648 (affected_file.LocalPath(), parse_error)))
2649 return results
2650
2651
Saagar Sanghavifceeaae2020-08-12 16:40:362652def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492653 """Runs checkstyle on changed java files and returns errors if any exist."""
Erik Staabc734cd7a2021-11-23 03:11:522654
2655 # Return early if no java files were modified.
2656 if not any(_IsJavaFile(input_api, f.LocalPath()) for f in
2657 input_api.AffectedFiles()):
2658 return []
2659
mohan.reddyf21db962014-10-16 12:26:472660 import sys
[email protected]760deea2013-12-10 19:33:492661 original_sys_path = sys.path
2662 try:
2663 sys.path = sys.path + [input_api.os_path.join(
2664 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2665 import checkstyle
2666 finally:
2667 # Restore sys.path to what it was before.
2668 sys.path = original_sys_path
2669
2670 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092671 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442672 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492673
2674
Saagar Sanghavifceeaae2020-08-12 16:40:362675def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002676 """Checks to make sure devil is initialized correctly in python scripts."""
2677 script_common_initialize_pattern = input_api.re.compile(
2678 r'script_common\.InitializeEnvironment\(')
2679 devil_env_config_initialize = input_api.re.compile(
2680 r'devil_env\.config\.Initialize\(')
2681
2682 errors = []
2683
2684 sources = lambda affected_file: input_api.FilterSourceFile(
2685 affected_file,
James Cook24a504192020-07-23 00:08:442686 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2687 (r'^build[\\/]android[\\/]devil_chromium\.py',
2688 r'^third_party[\\/].*',)),
2689 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002690
2691 for f in input_api.AffectedSourceFiles(sources):
2692 for line_num, line in f.ChangedContents():
2693 if (script_common_initialize_pattern.search(line) or
2694 devil_env_config_initialize.search(line)):
2695 errors.append("%s:%d" % (f.LocalPath(), line_num))
2696
2697 results = []
2698
2699 if errors:
2700 results.append(output_api.PresubmitError(
2701 'Devil initialization should always be done using '
2702 'devil_chromium.Initialize() in the chromium project, to use better '
2703 'defaults for dependencies (ex. up-to-date version of adb).',
2704 errors))
2705
2706 return results
2707
2708
Sean Kau46e29bc2017-08-28 16:31:162709def _MatchesFile(input_api, patterns, path):
2710 for pattern in patterns:
2711 if input_api.re.search(pattern, path):
2712 return True
2713 return False
2714
2715
Daniel Cheng7052cdf2017-11-21 19:23:292716def _GetOwnersFilesToCheckForIpcOwners(input_api):
2717 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172718
Daniel Cheng7052cdf2017-11-21 19:23:292719 Returns:
2720 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2721 contain to cover IPC-related files with noparent reviewer rules.
2722 """
2723 # Whether or not a file affects IPC is (mostly) determined by a simple list
2724 # of filename patterns.
dchenge07de812016-06-20 19:27:172725 file_patterns = [
palmerb19a0932017-01-24 04:00:312726 # Legacy IPC:
dchenge07de812016-06-20 19:27:172727 '*_messages.cc',
2728 '*_messages*.h',
2729 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312730 # Mojo IPC:
dchenge07de812016-06-20 19:27:172731 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472732 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172733 '*_struct_traits*.*',
2734 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312735 '*.typemap',
2736 # Android native IPC:
2737 '*.aidl',
2738 # Blink uses a different file naming convention:
2739 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472740 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172741 '*StructTraits*.*',
2742 '*TypeConverter*.*',
2743 ]
2744
scottmg7a6ed5ba2016-11-04 18:22:042745 # These third_party directories do not contain IPCs, but contain files
2746 # matching the above patterns, which trigger false positives.
2747 exclude_paths = [
2748 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162749 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232750 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292751 'third_party/win_build_output/*',
Scott Violet9f82d362019-11-06 21:42:162752 # These files are just used to communicate between class loaders running
2753 # in the same process.
2754 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572755 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2756
scottmg7a6ed5ba2016-11-04 18:22:042757 ]
2758
dchenge07de812016-06-20 19:27:172759 # Dictionary mapping an OWNERS file path to Patterns.
2760 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2761 # rules ) to a PatternEntry.
2762 # PatternEntry is a dictionary with two keys:
2763 # - 'files': the files that are matched by this pattern
2764 # - 'rules': the per-file rules needed for this pattern
2765 # For example, if we expect OWNERS file to contain rules for *.mojom and
2766 # *_struct_traits*.*, Patterns might look like this:
2767 # {
2768 # '*.mojom': {
2769 # 'files': ...,
2770 # 'rules': [
2771 # 'per-file *.mojom=set noparent',
2772 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2773 # ],
2774 # },
2775 # '*_struct_traits*.*': {
2776 # 'files': ...,
2777 # 'rules': [
2778 # 'per-file *_struct_traits*.*=set noparent',
2779 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2780 # ],
2781 # },
2782 # }
2783 to_check = {}
2784
Daniel Cheng13ca61a882017-08-25 15:11:252785 def AddPatternToCheck(input_file, pattern):
2786 owners_file = input_api.os_path.join(
2787 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2788 if owners_file not in to_check:
2789 to_check[owners_file] = {}
2790 if pattern not in to_check[owners_file]:
2791 to_check[owners_file][pattern] = {
2792 'files': [],
2793 'rules': [
2794 'per-file %s=set noparent' % pattern,
2795 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2796 ]
2797 }
Vaclav Brozekd5de76a2018-03-17 07:57:502798 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252799
dchenge07de812016-06-20 19:27:172800 # Iterate through the affected files to see what we actually need to check
2801 # for. We should only nag patch authors about per-file rules if a file in that
2802 # directory would match that pattern. If a directory only contains *.mojom
2803 # files and no *_messages*.h files, we should only nag about rules for
2804 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252805 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262806 # Manifest files don't have a strong naming convention. Instead, try to find
2807 # affected .cc and .h files which look like they contain a manifest
2808 # definition.
2809 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2810 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2811 if (manifest_pattern.search(f.LocalPath()) and not
2812 test_manifest_pattern.search(f.LocalPath())):
2813 # We expect all actual service manifest files to contain at least one
2814 # qualified reference to service_manager::Manifest.
2815 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252816 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172817 for pattern in file_patterns:
2818 if input_api.fnmatch.fnmatch(
2819 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042820 skip = False
2821 for exclude in exclude_paths:
2822 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2823 skip = True
2824 break
2825 if skip:
2826 continue
Daniel Cheng13ca61a882017-08-25 15:11:252827 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172828 break
2829
Daniel Cheng7052cdf2017-11-21 19:23:292830 return to_check
2831
2832
Wez17c66962020-04-29 15:26:032833def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2834 """Adds OWNERS files to check for correct Fuchsia security owners."""
2835
2836 file_patterns = [
2837 # Component specifications.
2838 '*.cml', # Component Framework v2.
2839 '*.cmx', # Component Framework v1.
2840
2841 # Fuchsia IDL protocol specifications.
2842 '*.fidl',
2843 ]
2844
Joshua Peraza1ca6d392020-12-08 00:14:092845 # Don't check for owners files for changes in these directories.
2846 exclude_paths = [
2847 'third_party/crashpad/*',
2848 ]
2849
Wez17c66962020-04-29 15:26:032850 def AddPatternToCheck(input_file, pattern):
2851 owners_file = input_api.os_path.join(
2852 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2853 if owners_file not in to_check:
2854 to_check[owners_file] = {}
2855 if pattern not in to_check[owners_file]:
2856 to_check[owners_file][pattern] = {
2857 'files': [],
2858 'rules': [
2859 'per-file %s=set noparent' % pattern,
2860 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2861 ]
2862 }
2863 to_check[owners_file][pattern]['files'].append(input_file)
2864
2865 # Iterate through the affected files to see what we actually need to check
2866 # for. We should only nag patch authors about per-file rules if a file in that
2867 # directory would match that pattern.
2868 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092869 skip = False
2870 for exclude in exclude_paths:
2871 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2872 skip = True
2873 if skip:
2874 continue
2875
Wez17c66962020-04-29 15:26:032876 for pattern in file_patterns:
2877 if input_api.fnmatch.fnmatch(
2878 input_api.os_path.basename(f.LocalPath()), pattern):
2879 AddPatternToCheck(f, pattern)
2880 break
2881
2882 return to_check
2883
2884
Saagar Sanghavifceeaae2020-08-12 16:40:362885def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292886 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2887 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032888 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292889
2890 if to_check:
2891 # If there are any OWNERS files to check, there are IPC-related changes in
2892 # this CL. Auto-CC the review list.
2893 output_api.AppendCC('[email protected]')
2894
2895 # Go through the OWNERS files to check, filtering out rules that are already
2896 # present in that OWNERS file.
Dirk Prankee3c9c62d2021-05-18 18:35:592897 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172898 try:
Dirk Prankee3c9c62d2021-05-18 18:35:592899 with open(owners_file) as f:
dchenge07de812016-06-20 19:27:172900 lines = set(f.read().splitlines())
Jeffrey Youngf3a5c8c42021-05-14 21:56:102901 for entry in patterns.values():
dchenge07de812016-06-20 19:27:172902 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2903 ]
2904 except IOError:
2905 # No OWNERS file, so all the rules are definitely missing.
2906 continue
2907
2908 # All the remaining lines weren't found in OWNERS files, so emit an error.
2909 errors = []
Dirk Prankee3c9c62d2021-05-18 18:35:592910 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172911 missing_lines = []
2912 files = []
Dirk Prankee3c9c62d2021-05-18 18:35:592913 for _, entry in patterns.items():
dchenge07de812016-06-20 19:27:172914 missing_lines.extend(entry['rules'])
2915 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2916 if missing_lines:
2917 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052918 'Because of the presence of files:\n%s\n\n'
2919 '%s needs the following %d lines added:\n\n%s' %
2920 ('\n'.join(files), owners_file, len(missing_lines),
2921 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172922
2923 results = []
2924 if errors:
vabrf5ce3bf92016-07-11 14:52:412925 if input_api.is_committing:
2926 output = output_api.PresubmitError
2927 else:
2928 output = output_api.PresubmitPromptWarning
2929 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592930 'Found OWNERS files that need to be updated for IPC security ' +
2931 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172932 long_text='\n\n'.join(errors)))
2933
2934 return results
2935
2936
Robert Sesek2c905332020-05-06 23:17:132937def _GetFilesUsingSecurityCriticalFunctions(input_api):
2938 """Checks affected files for changes to security-critical calls. This
2939 function checks the full change diff, to catch both additions/changes
2940 and removals.
2941
2942 Returns a dict keyed by file name, and the value is a set of detected
2943 functions.
2944 """
2945 # Map of function pretty name (displayed in an error) to the pattern to
2946 # match it with.
2947 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:372948 'content::GetServiceSandboxType<>()':
2949 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:132950 }
2951 _PATTERNS_TO_CHECK = {
2952 k: input_api.re.compile(v)
2953 for k, v in _PATTERNS_TO_CHECK.items()
2954 }
2955
2956 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2957 files_to_functions = {}
2958 for f in input_api.AffectedFiles():
2959 diff = f.GenerateScmDiff()
2960 for line in diff.split('\n'):
2961 # Not using just RightHandSideLines() because removing a
2962 # call to a security-critical function can be just as important
2963 # as adding or changing the arguments.
2964 if line.startswith('-') or (line.startswith('+') and
2965 not line.startswith('++')):
2966 for name, pattern in _PATTERNS_TO_CHECK.items():
2967 if pattern.search(line):
2968 path = f.LocalPath()
2969 if not path in files_to_functions:
2970 files_to_functions[path] = set()
2971 files_to_functions[path].add(name)
2972 return files_to_functions
2973
2974
Saagar Sanghavifceeaae2020-08-12 16:40:362975def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:132976 """Checks that changes involving security-critical functions are reviewed
2977 by the security team.
2978 """
2979 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:122980 if not len(files_to_functions):
2981 return []
Robert Sesek2c905332020-05-06 23:17:132982
Edward Lesmes1e9fade2021-02-08 20:31:122983 owner_email, reviewers = (
2984 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2985 input_api,
2986 None,
2987 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:132988
Edward Lesmes1e9fade2021-02-08 20:31:122989 # Load the OWNERS file for security changes.
2990 owners_file = 'ipc/SECURITY_OWNERS'
2991 security_owners = input_api.owners_client.ListOwners(owners_file)
2992 has_security_owner = any([owner in reviewers for owner in security_owners])
2993 if has_security_owner:
2994 return []
Robert Sesek2c905332020-05-06 23:17:132995
Edward Lesmes1e9fade2021-02-08 20:31:122996 msg = 'The following files change calls to security-sensive functions\n' \
2997 'that need to be reviewed by {}.\n'.format(owners_file)
2998 for path, names in files_to_functions.items():
2999 msg += ' {}\n'.format(path)
3000 for name in names:
3001 msg += ' {}\n'.format(name)
3002 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133003
Edward Lesmes1e9fade2021-02-08 20:31:123004 if input_api.is_committing:
3005 output = output_api.PresubmitError
3006 else:
3007 output = output_api.PresubmitNotifyResult
3008 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133009
3010
Saagar Sanghavifceeaae2020-08-12 16:40:363011def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263012 """Checks that set noparent is only used together with an OWNERS file in
3013 //build/OWNERS.setnoparent (see also
3014 //docs/code_reviews.md#owners-files-details)
3015 """
Erik Staabc734cd7a2021-11-23 03:11:523016 # Return early if no OWNERS files were modified.
3017 if not any(f.LocalPath().endswith('OWNERS') for f in
3018 input_api.AffectedFiles(include_deletes=False)):
3019 return []
3020
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263021 errors = []
3022
3023 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3024 allowed_owners_files = set()
3025 with open(allowed_owners_files_file, 'r') as f:
3026 for line in f:
3027 line = line.strip()
3028 if not line or line.startswith('#'):
3029 continue
3030 allowed_owners_files.add(line)
3031
3032 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3033
3034 for f in input_api.AffectedFiles(include_deletes=False):
3035 if not f.LocalPath().endswith('OWNERS'):
3036 continue
3037
3038 found_owners_files = set()
3039 found_set_noparent_lines = dict()
3040
3041 # Parse the OWNERS file.
3042 for lineno, line in enumerate(f.NewContents(), 1):
3043 line = line.strip()
3044 if line.startswith('set noparent'):
3045 found_set_noparent_lines[''] = lineno
3046 if line.startswith('file://'):
3047 if line in allowed_owners_files:
3048 found_owners_files.add('')
3049 if line.startswith('per-file'):
3050 match = per_file_pattern.match(line)
3051 if match:
3052 glob = match.group(1).strip()
3053 directive = match.group(2).strip()
3054 if directive == 'set noparent':
3055 found_set_noparent_lines[glob] = lineno
3056 if directive.startswith('file://'):
3057 if directive in allowed_owners_files:
3058 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153059
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263060 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403061 # listed in build/OWNERS.setnoparent. An exception is made for top level
3062 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143063 if (f.LocalPath().count('/') != 1 and
3064 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403065 for set_noparent_line in found_set_noparent_lines:
3066 if set_noparent_line in found_owners_files:
3067 continue
3068 errors.append(' %s:%d' % (f.LocalPath(),
3069 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263070
3071 results = []
3072 if errors:
3073 if input_api.is_committing:
3074 output = output_api.PresubmitError
3075 else:
3076 output = output_api.PresubmitPromptWarning
3077 results.append(output(
3078 'Found the following "set noparent" restrictions in OWNERS files that '
3079 'do not include owners from build/OWNERS.setnoparent:',
3080 long_text='\n\n'.join(errors)))
3081 return results
3082
3083
Saagar Sanghavifceeaae2020-08-12 16:40:363084def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313085 """Checks that added or removed lines in non third party affected
3086 header files do not lead to new useless class or struct forward
3087 declaration.
jbriance9e12f162016-11-25 07:57:503088 """
3089 results = []
3090 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3091 input_api.re.MULTILINE)
3092 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3093 input_api.re.MULTILINE)
3094 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313095 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193096 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493097 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313098 continue
3099
jbriance9e12f162016-11-25 07:57:503100 if not f.LocalPath().endswith('.h'):
3101 continue
3102
3103 contents = input_api.ReadFile(f)
3104 fwd_decls = input_api.re.findall(class_pattern, contents)
3105 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3106
3107 useless_fwd_decls = []
3108 for decl in fwd_decls:
3109 count = sum(1 for _ in input_api.re.finditer(
3110 r'\b%s\b' % input_api.re.escape(decl), contents))
3111 if count == 1:
3112 useless_fwd_decls.append(decl)
3113
3114 if not useless_fwd_decls:
3115 continue
3116
3117 for line in f.GenerateScmDiff().splitlines():
3118 if (line.startswith('-') and not line.startswith('--') or
3119 line.startswith('+') and not line.startswith('++')):
3120 for decl in useless_fwd_decls:
3121 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3122 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243123 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503124 (f.LocalPath(), decl)))
3125 useless_fwd_decls.remove(decl)
3126
3127 return results
3128
Jinsong Fan91ebbbd2019-04-16 14:57:173129def _CheckAndroidDebuggableBuild(input_api, output_api):
3130 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3131 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3132 this is a debuggable build of Android.
3133 """
3134 build_type_check_pattern = input_api.re.compile(
3135 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3136
3137 errors = []
3138
3139 sources = lambda affected_file: input_api.FilterSourceFile(
3140 affected_file,
James Cook24a504192020-07-23 00:08:443141 files_to_skip=(_EXCLUDED_PATHS +
3142 _TEST_CODE_EXCLUDED_PATHS +
3143 input_api.DEFAULT_FILES_TO_SKIP +
3144 (r"^android_webview[\\/]support_library[\\/]"
3145 "boundary_interfaces[\\/]",
3146 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3147 r'^third_party[\\/].*',
3148 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3149 r"webview[\\/]chromium[\\/]License.*",)),
3150 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173151
3152 for f in input_api.AffectedSourceFiles(sources):
3153 for line_num, line in f.ChangedContents():
3154 if build_type_check_pattern.search(line):
3155 errors.append("%s:%d" % (f.LocalPath(), line_num))
3156
3157 results = []
3158
3159 if errors:
3160 results.append(output_api.PresubmitPromptWarning(
3161 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3162 ' Please use BuildInfo.isDebugAndroid() instead.',
3163 errors))
3164
3165 return results
jbriance9e12f162016-11-25 07:57:503166
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493167# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293168def _CheckAndroidToastUsage(input_api, output_api):
3169 """Checks that code uses org.chromium.ui.widget.Toast instead of
3170 android.widget.Toast (Chromium Toast doesn't force hardware
3171 acceleration on low-end devices, saving memory).
3172 """
3173 toast_import_pattern = input_api.re.compile(
3174 r'^import android\.widget\.Toast;$')
3175
3176 errors = []
3177
3178 sources = lambda affected_file: input_api.FilterSourceFile(
3179 affected_file,
James Cook24a504192020-07-23 00:08:443180 files_to_skip=(_EXCLUDED_PATHS +
3181 _TEST_CODE_EXCLUDED_PATHS +
3182 input_api.DEFAULT_FILES_TO_SKIP +
3183 (r'^chromecast[\\/].*',
3184 r'^remoting[\\/].*')),
3185 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293186
3187 for f in input_api.AffectedSourceFiles(sources):
3188 for line_num, line in f.ChangedContents():
3189 if toast_import_pattern.search(line):
3190 errors.append("%s:%d" % (f.LocalPath(), line_num))
3191
3192 results = []
3193
3194 if errors:
3195 results.append(output_api.PresubmitError(
3196 'android.widget.Toast usage is detected. Android toasts use hardware'
3197 ' acceleration, and can be\ncostly on low-end devices. Please use'
3198 ' org.chromium.ui.widget.Toast instead.\n'
3199 'Contact [email protected] if you have any questions.',
3200 errors))
3201
3202 return results
3203
3204
dgnaa68d5e2015-06-10 10:08:223205def _CheckAndroidCrLogUsage(input_api, output_api):
3206 """Checks that new logs using org.chromium.base.Log:
3207 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513208 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223209 """
pkotwicza1dd0b002016-05-16 14:41:043210
torne89540622017-03-24 19:41:303211 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043212 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303213 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043214 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303215 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043216 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3217 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093218 # The customtabs_benchmark is a small app that does not depend on Chromium
3219 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043220 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043221 ]
3222
dgnaa68d5e2015-06-10 10:08:223223 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123224 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3225 class_in_base_pattern = input_api.re.compile(
3226 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3227 has_some_log_import_pattern = input_api.re.compile(
3228 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223229 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553230 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223231 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463232 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553233 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223234
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463235 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443236 sources = lambda x: input_api.FilterSourceFile(x,
3237 files_to_check=[r'.*\.java$'],
3238 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123239
dgnaa68d5e2015-06-10 10:08:223240 tag_decl_errors = []
3241 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123242 tag_errors = []
dgn38736db2015-09-18 19:20:513243 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123244 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223245
3246 for f in input_api.AffectedSourceFiles(sources):
3247 file_content = input_api.ReadFile(f)
3248 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223249 # Per line checks
dgn87d9fb62015-06-12 09:15:123250 if (cr_log_import_pattern.search(file_content) or
3251 (class_in_base_pattern.search(file_content) and
3252 not has_some_log_import_pattern.search(file_content))):
3253 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223254 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553255 if rough_log_decl_pattern.search(line):
3256 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223257
3258 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123259 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223260 if match:
3261 has_modified_logs = True
3262
3263 # Make sure it uses "TAG"
3264 if not match.group('tag') == 'TAG':
3265 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123266 else:
3267 # Report non cr Log function calls in changed lines
3268 for line_num, line in f.ChangedContents():
3269 if log_call_pattern.search(line):
3270 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223271
3272 # Per file checks
3273 if has_modified_logs:
3274 # Make sure the tag is using the "cr" prefix and is not too long
3275 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513276 tag_name = match.group('name') if match else None
3277 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223278 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513279 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223280 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513281 elif '.' in tag_name:
3282 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223283
3284 results = []
3285 if tag_decl_errors:
3286 results.append(output_api.PresubmitPromptWarning(
3287 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513288 '"private static final String TAG = "<package tag>".\n'
3289 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223290 tag_decl_errors))
3291
3292 if tag_length_errors:
3293 results.append(output_api.PresubmitError(
3294 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513295 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223296 tag_length_errors))
3297
3298 if tag_errors:
3299 results.append(output_api.PresubmitPromptWarning(
3300 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3301 tag_errors))
3302
dgn87d9fb62015-06-12 09:15:123303 if util_log_errors:
dgn4401aa52015-04-29 16:26:173304 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123305 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3306 util_log_errors))
3307
dgn38736db2015-09-18 19:20:513308 if tag_with_dot_errors:
3309 results.append(output_api.PresubmitPromptWarning(
3310 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3311 tag_with_dot_errors))
3312
dgn4401aa52015-04-29 16:26:173313 return results
3314
3315
Yoland Yanb92fa522017-08-28 17:37:063316def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3317 """Checks that junit.framework.* is no longer used."""
3318 deprecated_junit_framework_pattern = input_api.re.compile(
3319 r'^import junit\.framework\..*;',
3320 input_api.re.MULTILINE)
3321 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443322 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063323 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133324 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063325 for line_num, line in f.ChangedContents():
3326 if deprecated_junit_framework_pattern.search(line):
3327 errors.append("%s:%d" % (f.LocalPath(), line_num))
3328
3329 results = []
3330 if errors:
3331 results.append(output_api.PresubmitError(
3332 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3333 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3334 ' if you have any question.', errors))
3335 return results
3336
3337
3338def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3339 """Checks that if new Java test classes have inheritance.
3340 Either the new test class is JUnit3 test or it is a JUnit4 test class
3341 with a base class, either case is undesirable.
3342 """
3343 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3344
3345 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443346 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063347 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133348 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063349 if not f.OldContents():
3350 class_declaration_start_flag = False
3351 for line_num, line in f.ChangedContents():
3352 if class_declaration_pattern.search(line):
3353 class_declaration_start_flag = True
3354 if class_declaration_start_flag and ' extends ' in line:
3355 errors.append('%s:%d' % (f.LocalPath(), line_num))
3356 if '{' in line:
3357 class_declaration_start_flag = False
3358
3359 results = []
3360 if errors:
3361 results.append(output_api.PresubmitPromptWarning(
3362 'The newly created files include Test classes that inherits from base'
3363 ' class. Please do not use inheritance in JUnit4 tests or add new'
3364 ' JUnit3 tests. Contact [email protected] if you have any'
3365 ' questions.', errors))
3366 return results
3367
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203368
yolandyan45001472016-12-21 21:12:423369def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3370 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3371 deprecated_annotation_import_pattern = input_api.re.compile(
3372 r'^import android\.test\.suitebuilder\.annotation\..*;',
3373 input_api.re.MULTILINE)
3374 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443375 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423376 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133377 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423378 for line_num, line in f.ChangedContents():
3379 if deprecated_annotation_import_pattern.search(line):
3380 errors.append("%s:%d" % (f.LocalPath(), line_num))
3381
3382 results = []
3383 if errors:
3384 results.append(output_api.PresubmitError(
3385 'Annotations in android.test.suitebuilder.annotation have been'
3386 ' deprecated since API level 24. Please use android.support.test.filters'
3387 ' from //third_party/android_support_test_runner:runner_java instead.'
3388 ' Contact [email protected] if you have any questions.', errors))
3389 return results
3390
3391
agrieve7b6479d82015-10-07 14:24:223392def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3393 """Checks if MDPI assets are placed in a correct directory."""
3394 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3395 ('/res/drawable/' in f.LocalPath() or
3396 '/res/drawable-ldrtl/' in f.LocalPath()))
3397 errors = []
3398 for f in input_api.AffectedFiles(include_deletes=False,
3399 file_filter=file_filter):
3400 errors.append(' %s' % f.LocalPath())
3401
3402 results = []
3403 if errors:
3404 results.append(output_api.PresubmitError(
3405 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3406 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3407 '/res/drawable-ldrtl/.\n'
3408 'Contact [email protected] if you have questions.', errors))
3409 return results
3410
3411
Nate Fischer535972b2017-09-16 01:06:183412def _CheckAndroidWebkitImports(input_api, output_api):
3413 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353414 android.webview.ValueCallback except in the WebView glue layer
3415 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183416 """
3417 valuecallback_import_pattern = input_api.re.compile(
3418 r'^import android\.webkit\.ValueCallback;$')
3419
3420 errors = []
3421
3422 sources = lambda affected_file: input_api.FilterSourceFile(
3423 affected_file,
James Cook24a504192020-07-23 00:08:443424 files_to_skip=(_EXCLUDED_PATHS +
3425 _TEST_CODE_EXCLUDED_PATHS +
3426 input_api.DEFAULT_FILES_TO_SKIP +
3427 (r'^android_webview[\\/]glue[\\/].*',
3428 r'^weblayer[\\/].*',)),
3429 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183430
3431 for f in input_api.AffectedSourceFiles(sources):
3432 for line_num, line in f.ChangedContents():
3433 if valuecallback_import_pattern.search(line):
3434 errors.append("%s:%d" % (f.LocalPath(), line_num))
3435
3436 results = []
3437
3438 if errors:
3439 results.append(output_api.PresubmitError(
3440 'android.webkit.ValueCallback usage is detected outside of the glue'
3441 ' layer. To stay compatible with the support library, android.webkit.*'
3442 ' classes should only be used inside the glue layer and'
3443 ' org.chromium.base.Callback should be used instead.',
3444 errors))
3445
3446 return results
3447
3448
Becky Zhou7c69b50992018-12-10 19:37:573449def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3450 """Checks Android XML styles """
Erik Staabc734cd7a2021-11-23 03:11:523451
3452 # Return early if no relevant files were modified.
3453 if not any(_IsXmlOrGrdFile(input_api, f.LocalPath()) for f in
3454 input_api.AffectedFiles(include_deletes=False)):
3455 return []
3456
Becky Zhou7c69b50992018-12-10 19:37:573457 import sys
3458 original_sys_path = sys.path
3459 try:
3460 sys.path = sys.path + [input_api.os_path.join(
3461 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3462 import checkxmlstyle
3463 finally:
3464 # Restore sys.path to what it was before.
3465 sys.path = original_sys_path
3466
3467 if is_check_on_upload:
3468 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3469 else:
3470 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3471
Lijin Shen260f0852021-12-16 17:20:333472def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3473 """Checks Android Infobar Deprecation """
3474
3475 import sys
3476 original_sys_path = sys.path
3477 try:
3478 sys.path = sys.path + [input_api.os_path.join(
3479 input_api.PresubmitLocalPath(), 'tools', 'android',
3480 'infobar_deprecation')]
3481 import infobar_deprecation
3482 finally:
3483 # Restore sys.path to what it was before.
3484 sys.path = original_sys_path
3485
3486 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3487
Becky Zhou7c69b50992018-12-10 19:37:573488
agrievef32bcc72016-04-04 14:57:403489class PydepsChecker(object):
3490 def __init__(self, input_api, pydeps_files):
3491 self._file_cache = {}
3492 self._input_api = input_api
3493 self._pydeps_files = pydeps_files
3494
3495 def _LoadFile(self, path):
3496 """Returns the list of paths within a .pydeps file relative to //."""
3497 if path not in self._file_cache:
Mohamed Heikal112874d2021-11-15 14:42:203498 with open(path, encoding='utf-8') as f:
agrievef32bcc72016-04-04 14:57:403499 self._file_cache[path] = f.read()
3500 return self._file_cache[path]
3501
3502 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3503 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393504 pydeps_data = self._LoadFile(pydeps_path)
3505 uses_gn_paths = '--gn-paths' in pydeps_data
3506 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3507 if uses_gn_paths:
3508 # Paths look like: //foo/bar/baz
3509 return (e[2:] for e in entries)
3510 else:
3511 # Paths look like: path/relative/to/file.pydeps
3512 os_path = self._input_api.os_path
3513 pydeps_dir = os_path.dirname(pydeps_path)
3514 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403515
3516 def _CreateFilesToPydepsMap(self):
3517 """Returns a map of local_path -> list_of_pydeps."""
3518 ret = {}
3519 for pydep_local_path in self._pydeps_files:
3520 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3521 ret.setdefault(path, []).append(pydep_local_path)
3522 return ret
3523
3524 def ComputeAffectedPydeps(self):
3525 """Returns an iterable of .pydeps files that might need regenerating."""
3526 affected_pydeps = set()
3527 file_to_pydeps_map = None
3528 for f in self._input_api.AffectedFiles(include_deletes=True):
3529 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463530 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3531 # subrepositories. We can't figure out which files change, so re-check
3532 # all files.
3533 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383534 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3535 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403536 return self._pydeps_files
3537 elif local_path.endswith('.pydeps'):
3538 if local_path in self._pydeps_files:
3539 affected_pydeps.add(local_path)
3540 elif local_path.endswith('.py'):
3541 if file_to_pydeps_map is None:
3542 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3543 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3544 return affected_pydeps
3545
3546 def DetermineIfStale(self, pydeps_path):
3547 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413548 import difflib
John Budorick47ca3fe2018-02-10 00:53:103549 import os
3550
agrievef32bcc72016-04-04 14:57:403551 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033552 if old_pydeps_data:
3553 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393554 if '--output' not in cmd:
3555 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033556 old_contents = old_pydeps_data[2:]
3557 else:
3558 # A default cmd that should work in most cases (as long as pydeps filename
3559 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3560 # file is empty/new.
3561 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3562 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3563 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103564 env = dict(os.environ)
3565 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403566 new_pydeps_data = self._input_api.subprocess.check_output(
Mohamed Heikal112874d2021-11-15 14:42:203567 cmd + ' --output ""', shell=True, env=env, encoding='utf-8')
phajdan.jr0d9878552016-11-04 10:49:413568 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033569 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413570 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403571
3572
Tibor Goldschwendt360793f72019-06-25 18:23:493573def _ParseGclientArgs():
3574 args = {}
3575 with open('build/config/gclient_args.gni', 'r') as f:
3576 for line in f:
3577 line = line.strip()
3578 if not line or line.startswith('#'):
3579 continue
3580 attribute, value = line.split('=')
3581 args[attribute.strip()] = value.strip()
3582 return args
3583
3584
Saagar Sanghavifceeaae2020-08-12 16:40:363585def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403586 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403587 # This check is for Python dependency lists (.pydeps files), and involves
3588 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
Erik Staabc734cd7a2021-11-23 03:11:523589 # doesn't work on Windows and Mac, so skip it on other platforms and skip if
3590 # no pydeps files are affected.
Mohamed Heikal112874d2021-11-15 14:42:203591 if not input_api.platform.startswith('linux'):
agrievebb9c5b472016-04-22 15:13:003592 return []
Erik Staabc734cd7a2021-11-23 03:11:523593 if not any(f.LocalPath().endswith('.pydeps') for f in input_api.AffectedFiles(
3594 include_deletes=True)):
3595 return []
3596
Tibor Goldschwendt360793f72019-06-25 18:23:493597 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403598 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403599 results = []
3600 # First, check for new / deleted .pydeps.
3601 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033602 # Check whether we are running the presubmit check for a file in src.
3603 # f.LocalPath is relative to repo (src, or internal repo).
3604 # os_path.exists is relative to src repo.
3605 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3606 # to src and we can conclude that the pydeps is in src.
3607 if input_api.os_path.exists(f.LocalPath()):
3608 if f.LocalPath().endswith('.pydeps'):
3609 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3610 results.append(output_api.PresubmitError(
3611 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3612 'remove %s' % f.LocalPath()))
3613 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3614 results.append(output_api.PresubmitError(
3615 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3616 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403617
3618 if results:
3619 return results
3620
Mohamed Heikal7cd4d8312020-06-16 16:49:403621 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3622 affected_pydeps = set(checker.ComputeAffectedPydeps())
3623 affected_android_pydeps = affected_pydeps.intersection(
3624 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3625 if affected_android_pydeps and not is_android:
3626 results.append(output_api.PresubmitPromptOrNotify(
3627 'You have changed python files that may affect pydeps for android\n'
3628 'specific scripts. However, the relevant presumbit check cannot be\n'
3629 'run because you are not using an Android checkout. To validate that\n'
3630 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3631 'use the android-internal-presubmit optional trybot.\n'
3632 'Possibly stale pydeps files:\n{}'.format(
3633 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403634
Mohamed Heikal7cd4d8312020-06-16 16:49:403635 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3636 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403637 try:
phajdan.jr0d9878552016-11-04 10:49:413638 result = checker.DetermineIfStale(pydep_path)
3639 if result:
3640 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403641 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413642 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3643 'To regenerate, run:\n\n %s' %
3644 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403645 except input_api.subprocess.CalledProcessError as error:
3646 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3647 long_text=error.output)]
3648
3649 return results
3650
3651
Saagar Sanghavifceeaae2020-08-12 16:40:363652def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433653 """Checks to make sure no header files have |Singleton<|."""
3654 def FileFilter(affected_file):
3655 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443656 files_to_skip = (_EXCLUDED_PATHS +
3657 input_api.DEFAULT_FILES_TO_SKIP +
3658 (r"^base[\\/]memory[\\/]singleton\.h$",
3659 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3660 r"quic_singleton_impl\.h$"))
3661 return input_api.FilterSourceFile(affected_file,
3662 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433663
sergeyu34d21222015-09-16 00:11:443664 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433665 files = []
3666 for f in input_api.AffectedSourceFiles(FileFilter):
3667 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3668 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3669 contents = input_api.ReadFile(f)
3670 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243671 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433672 pattern.search(line)):
3673 files.append(f)
3674 break
3675
3676 if files:
yolandyandaabc6d2016-04-18 18:29:393677 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443678 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433679 'Please move them to an appropriate source file so that the ' +
3680 'template gets instantiated in a single compilation unit.',
3681 files) ]
3682 return []
3683
3684
[email protected]fd20b902014-05-09 02:14:533685_DEPRECATED_CSS = [
3686 # Values
3687 ( "-webkit-box", "flex" ),
3688 ( "-webkit-inline-box", "inline-flex" ),
3689 ( "-webkit-flex", "flex" ),
3690 ( "-webkit-inline-flex", "inline-flex" ),
3691 ( "-webkit-min-content", "min-content" ),
3692 ( "-webkit-max-content", "max-content" ),
3693
3694 # Properties
3695 ( "-webkit-background-clip", "background-clip" ),
3696 ( "-webkit-background-origin", "background-origin" ),
3697 ( "-webkit-background-size", "background-size" ),
3698 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443699 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533700
3701 # Functions
3702 ( "-webkit-gradient", "gradient" ),
3703 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3704 ( "-webkit-linear-gradient", "linear-gradient" ),
3705 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3706 ( "-webkit-radial-gradient", "radial-gradient" ),
3707 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3708]
3709
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203710
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493711# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363712def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533713 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253714 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343715 documentation and iOS CSS for dom distiller
3716 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253717 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533718 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493719 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443720 files_to_skip = (_EXCLUDED_PATHS +
3721 _TEST_CODE_EXCLUDED_PATHS +
3722 input_api.DEFAULT_FILES_TO_SKIP +
3723 (r"^chrome/common/extensions/docs",
3724 r"^chrome/docs",
James Cook24a504192020-07-23 00:08:443725 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253726 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443727 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533728 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3729 for line_num, line in fpath.ChangedContents():
3730 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023731 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533732 results.append(output_api.PresubmitError(
3733 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3734 (fpath.LocalPath(), line_num, deprecated_value, value)))
3735 return results
3736
mohan.reddyf21db962014-10-16 12:26:473737
Saagar Sanghavifceeaae2020-08-12 16:40:363738def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363739 bad_files = {}
3740 for f in input_api.AffectedFiles(include_deletes=False):
3741 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493742 not f.LocalPath().startswith('third_party/blink') and
3743 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363744 continue
3745
Daniel Bratell65b033262019-04-23 08:17:063746 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363747 continue
3748
Vaclav Brozekd5de76a2018-03-17 07:57:503749 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363750 if "#include" in line and "../" in line]
3751 if not relative_includes:
3752 continue
3753 bad_files[f.LocalPath()] = relative_includes
3754
3755 if not bad_files:
3756 return []
3757
3758 error_descriptions = []
Dirk Prankee3c9c62d2021-05-18 18:35:593759 for file_path, bad_lines in bad_files.items():
rlanday6802cf632017-05-30 17:48:363760 error_description = file_path
3761 for line in bad_lines:
3762 error_description += '\n ' + line
3763 error_descriptions.append(error_description)
3764
3765 results = []
3766 results.append(output_api.PresubmitError(
3767 'You added one or more relative #include paths (including "../").\n'
3768 'These shouldn\'t be used because they can be used to include headers\n'
3769 'from code that\'s not correctly specified as a dependency in the\n'
3770 'relevant BUILD.gn file(s).',
3771 error_descriptions))
3772
3773 return results
3774
Takeshi Yoshinoe387aa32017-08-02 13:16:133775
Saagar Sanghavifceeaae2020-08-12 16:40:363776def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063777 """Check that nobody tries to include a cc file. It's a relatively
3778 common error which results in duplicate symbols in object
3779 files. This may not always break the build until someone later gets
3780 very confusing linking errors."""
3781 results = []
3782 for f in input_api.AffectedFiles(include_deletes=False):
3783 # We let third_party code do whatever it wants
3784 if (f.LocalPath().startswith('third_party') and
3785 not f.LocalPath().startswith('third_party/blink') and
3786 not f.LocalPath().startswith('third_party\\blink')):
3787 continue
3788
3789 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3790 continue
3791
3792 for _, line in f.ChangedContents():
3793 if line.startswith('#include "'):
3794 included_file = line.split('"')[1]
3795 if _IsCPlusPlusFile(input_api, included_file):
3796 # The most common naming for external files with C++ code,
3797 # apart from standard headers, is to call them foo.inc, but
3798 # Chromium sometimes uses foo-inc.cc so allow that as well.
3799 if not included_file.endswith(('.h', '-inc.cc')):
3800 results.append(output_api.PresubmitError(
3801 'Only header files or .inc files should be included in other\n'
3802 'C++ files. Compiling the contents of a cc file more than once\n'
3803 'will cause duplicate information in the build which may later\n'
3804 'result in strange link_errors.\n' +
3805 f.LocalPath() + ':\n ' +
3806 line))
3807
3808 return results
3809
3810
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203811def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3812 if not isinstance(key, ast.Str):
3813 return 'Key at line %d must be a string literal' % key.lineno
3814 if not isinstance(value, ast.Dict):
3815 return 'Value at line %d must be a dict' % value.lineno
3816 if len(value.keys) != 1:
3817 return 'Dict at line %d must have single entry' % value.lineno
3818 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3819 return (
3820 'Entry at line %d must have a string literal \'filepath\' as key' %
3821 value.lineno)
3822 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133823
Takeshi Yoshinoe387aa32017-08-02 13:16:133824
Sergey Ulanov4af16052018-11-08 02:41:463825def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203826 if not isinstance(key, ast.Str):
3827 return 'Key at line %d must be a string literal' % key.lineno
3828 if not isinstance(value, ast.List):
3829 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463830 for element in value.elts:
3831 if not isinstance(element, ast.Str):
3832 return 'Watchlist elements on line %d is not a string' % key.lineno
3833 if not email_regex.match(element.s):
3834 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3835 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203836 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133837
Takeshi Yoshinoe387aa32017-08-02 13:16:133838
Sergey Ulanov4af16052018-11-08 02:41:463839def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203840 mismatch_template = (
3841 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3842 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133843
Sergey Ulanov4af16052018-11-08 02:41:463844 email_regex = input_api.re.compile(
3845 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3846
3847 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203848 i = 0
3849 last_key = ''
3850 while True:
3851 if i >= len(wd_dict.keys):
3852 if i >= len(w_dict.keys):
3853 return None
3854 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3855 elif i >= len(w_dict.keys):
3856 return (
3857 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133858
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203859 wd_key = wd_dict.keys[i]
3860 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133861
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203862 result = _CheckWatchlistDefinitionsEntrySyntax(
3863 wd_key, wd_dict.values[i], ast)
3864 if result is not None:
3865 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133866
Sergey Ulanov4af16052018-11-08 02:41:463867 result = _CheckWatchlistsEntrySyntax(
3868 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203869 if result is not None:
3870 return 'Bad entry in WATCHLISTS dict: %s' % result
3871
3872 if wd_key.s != w_key.s:
3873 return mismatch_template % (
3874 '%s at line %d' % (wd_key.s, wd_key.lineno),
3875 '%s at line %d' % (w_key.s, w_key.lineno))
3876
3877 if wd_key.s < last_key:
3878 return (
3879 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3880 (wd_key.lineno, w_key.lineno))
3881 last_key = wd_key.s
3882
3883 i = i + 1
3884
3885
Sergey Ulanov4af16052018-11-08 02:41:463886def _CheckWATCHLISTSSyntax(expression, input_api):
3887 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203888 if not isinstance(expression, ast.Expression):
3889 return 'WATCHLISTS file must contain a valid expression'
3890 dictionary = expression.body
3891 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3892 return 'WATCHLISTS file must have single dict with exactly two entries'
3893
3894 first_key = dictionary.keys[0]
3895 first_value = dictionary.values[0]
3896 second_key = dictionary.keys[1]
3897 second_value = dictionary.values[1]
3898
3899 if (not isinstance(first_key, ast.Str) or
3900 first_key.s != 'WATCHLIST_DEFINITIONS' or
3901 not isinstance(first_value, ast.Dict)):
3902 return (
3903 'The first entry of the dict in WATCHLISTS file must be '
3904 'WATCHLIST_DEFINITIONS dict')
3905
3906 if (not isinstance(second_key, ast.Str) or
3907 second_key.s != 'WATCHLISTS' or
3908 not isinstance(second_value, ast.Dict)):
3909 return (
3910 'The second entry of the dict in WATCHLISTS file must be '
3911 'WATCHLISTS dict')
3912
Sergey Ulanov4af16052018-11-08 02:41:463913 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133914
3915
Saagar Sanghavifceeaae2020-08-12 16:40:363916def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133917 for f in input_api.AffectedFiles(include_deletes=False):
3918 if f.LocalPath() == 'WATCHLISTS':
3919 contents = input_api.ReadFile(f, 'r')
3920
3921 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203922 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133923 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203924 # Get an AST tree for it and scan the tree for detailed style checking.
3925 expression = input_api.ast.parse(
3926 contents, filename='WATCHLISTS', mode='eval')
3927 except ValueError as e:
3928 return [output_api.PresubmitError(
3929 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3930 except SyntaxError as e:
3931 return [output_api.PresubmitError(
3932 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3933 except TypeError as e:
3934 return [output_api.PresubmitError(
3935 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133936
Sergey Ulanov4af16052018-11-08 02:41:463937 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203938 if result is not None:
3939 return [output_api.PresubmitError(result)]
3940 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133941
3942 return []
3943
3944
Andrew Grieve1b290e4a22020-11-24 20:07:013945def CheckGnGlobForward(input_api, output_api):
3946 """Checks that forward_variables_from(invoker, "*") follows best practices.
3947
3948 As documented at //build/docs/writing_gn_templates.md
3949 """
3950 def gn_files(f):
3951 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3952
3953 problems = []
3954 for f in input_api.AffectedSourceFiles(gn_files):
3955 for line_num, line in f.ChangedContents():
3956 if 'forward_variables_from(invoker, "*")' in line:
3957 problems.append(
3958 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3959 f.LocalPath(), line_num))
3960
3961 if problems:
3962 return [output_api.PresubmitPromptWarning(
3963 'forward_variables_from("*") without exclusions',
3964 items=sorted(problems),
3965 long_text=('The variables "visibilty" and "test_only" should be '
3966 'explicitly listed in forward_variables_from(). For more '
3967 'details, see:\n'
3968 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
3969 'build/docs/writing_gn_templates.md'
3970 '#Using-forward_variables_from'))]
3971 return []
3972
3973
Saagar Sanghavifceeaae2020-08-12 16:40:363974def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193975 """Checks that newly added header files have corresponding GN changes.
3976 Note that this is only a heuristic. To be precise, run script:
3977 build/check_gn_headers.py.
3978 """
3979
3980 def headers(f):
3981 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443982 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193983
3984 new_headers = []
3985 for f in input_api.AffectedSourceFiles(headers):
3986 if f.Action() != 'A':
3987 continue
3988 new_headers.append(f.LocalPath())
3989
3990 def gn_files(f):
James Cook24a504192020-07-23 00:08:443991 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193992
3993 all_gn_changed_contents = ''
3994 for f in input_api.AffectedSourceFiles(gn_files):
3995 for _, line in f.ChangedContents():
3996 all_gn_changed_contents += line
3997
3998 problems = []
3999 for header in new_headers:
4000 basename = input_api.os_path.basename(header)
4001 if basename not in all_gn_changed_contents:
4002 problems.append(header)
4003
4004 if problems:
4005 return [output_api.PresubmitPromptWarning(
4006 'Missing GN changes for new header files', items=sorted(problems),
4007 long_text='Please double check whether newly added header files need '
4008 'corresponding changes in gn or gni files.\nThis checking is only a '
4009 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4010 'Read https://crbug.com/661774 for more info.')]
4011 return []
4012
4013
Saagar Sanghavifceeaae2020-08-12 16:40:364014def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024015 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4016
4017 This assumes we won't intentionally reference one product from the other
4018 product.
4019 """
4020 all_problems = []
4021 test_cases = [{
4022 "filename_postfix": "google_chrome_strings.grd",
4023 "correct_name": "Chrome",
4024 "incorrect_name": "Chromium",
4025 }, {
4026 "filename_postfix": "chromium_strings.grd",
4027 "correct_name": "Chromium",
4028 "incorrect_name": "Chrome",
4029 }]
4030
4031 for test_case in test_cases:
4032 problems = []
4033 filename_filter = lambda x: x.LocalPath().endswith(
4034 test_case["filename_postfix"])
4035
4036 # Check each new line. Can yield false positives in multiline comments, but
4037 # easier than trying to parse the XML because messages can have nested
4038 # children, and associating message elements with affected lines is hard.
4039 for f in input_api.AffectedSourceFiles(filename_filter):
4040 for line_num, line in f.ChangedContents():
4041 if "<message" in line or "<!--" in line or "-->" in line:
4042 continue
4043 if test_case["incorrect_name"] in line:
4044 problems.append(
4045 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4046
4047 if problems:
4048 message = (
4049 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4050 % (test_case["correct_name"], test_case["correct_name"],
4051 test_case["incorrect_name"]))
4052 all_problems.append(
4053 output_api.PresubmitPromptWarning(message, items=problems))
4054
4055 return all_problems
4056
4057
Saagar Sanghavifceeaae2020-08-12 16:40:364058def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364059 """Avoid large files, especially binary files, in the repository since
4060 git doesn't scale well for those. They will be in everyone's repo
4061 clones forever, forever making Chromium slower to clone and work
4062 with."""
4063
4064 # Uploading files to cloud storage is not trivial so we don't want
4065 # to set the limit too low, but the upper limit for "normal" large
4066 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4067 # anything over 20 MB is exceptional.
4068 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4069
4070 too_large_files = []
4071 for f in input_api.AffectedFiles():
4072 # Check both added and modified files (but not deleted files).
4073 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384074 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364075 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4076 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4077
4078 if too_large_files:
4079 message = (
4080 'Do not commit large files to git since git scales badly for those.\n' +
4081 'Instead put the large files in cloud storage and use DEPS to\n' +
4082 'fetch them.\n' + '\n'.join(too_large_files)
4083 )
4084 return [output_api.PresubmitError(
4085 'Too large files found in commit', long_text=message + '\n')]
4086 else:
4087 return []
4088
Max Morozb47503b2019-08-08 21:03:274089
Saagar Sanghavifceeaae2020-08-12 16:40:364090def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274091 """Checks specific for fuzz target sources."""
4092 EXPORTED_SYMBOLS = [
4093 'LLVMFuzzerInitialize',
4094 'LLVMFuzzerCustomMutator',
4095 'LLVMFuzzerCustomCrossOver',
4096 'LLVMFuzzerMutate',
4097 ]
4098
4099 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4100
4101 def FilterFile(affected_file):
4102 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444103 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4104 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274105
4106 return input_api.FilterSourceFile(
4107 affected_file,
James Cook24a504192020-07-23 00:08:444108 files_to_check=[files_to_check],
4109 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274110
4111 files_with_missing_header = []
4112 for f in input_api.AffectedSourceFiles(FilterFile):
4113 contents = input_api.ReadFile(f, 'r')
4114 if REQUIRED_HEADER in contents:
4115 continue
4116
4117 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4118 files_with_missing_header.append(f.LocalPath())
4119
4120 if not files_with_missing_header:
4121 return []
4122
4123 long_text = (
4124 'If you define any of the libFuzzer optional functions (%s), it is '
4125 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4126 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4127 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4128 'to access command line arguments passed to the fuzzer. Instead, prefer '
4129 'static initialization and shared resources as documented in '
John Palmer0e0f72bf2021-06-07 09:10:204130 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
Max Morozb47503b2019-08-08 21:03:274131 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4132 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4133 )
4134
4135 return [output_api.PresubmitPromptWarning(
4136 message="Missing '%s' in:" % REQUIRED_HEADER,
4137 items=files_with_missing_header,
4138 long_text=long_text)]
4139
4140
Mohamed Heikald048240a2019-11-12 16:57:374141def _CheckNewImagesWarning(input_api, output_api):
4142 """
4143 Warns authors who add images into the repo to make sure their images are
4144 optimized before committing.
4145 """
4146 images_added = False
4147 image_paths = []
4148 errors = []
4149 filter_lambda = lambda x: input_api.FilterSourceFile(
4150 x,
James Cook24a504192020-07-23 00:08:444151 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4152 + input_api.DEFAULT_FILES_TO_SKIP),
4153 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374154 )
4155 for f in input_api.AffectedFiles(
4156 include_deletes=False, file_filter=filter_lambda):
4157 local_path = f.LocalPath().lower()
4158 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4159 images_added = True
4160 image_paths.append(f)
4161 if images_added:
4162 errors.append(output_api.PresubmitPromptWarning(
4163 'It looks like you are trying to commit some images. If these are '
4164 'non-test-only images, please make sure to read and apply the tips in '
4165 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4166 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4167 'FYI only and will not block your CL on the CQ.', image_paths))
4168 return errors
4169
4170
Saagar Sanghavifceeaae2020-08-12 16:40:364171def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574172 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224173 results = []
dgnaa68d5e2015-06-10 10:08:224174 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174175 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224176 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294177 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064178 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4179 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424180 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184181 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574182 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374183 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154184 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Lijin Shen260f0852021-12-16 17:20:334185 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574186 return results
4187
Saagar Sanghavifceeaae2020-08-12 16:40:364188def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574189 """Groups commit checks that target android code."""
4190 results = []
4191 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224192 return results
4193
Chris Hall59f8d0c72020-05-01 07:31:194194# TODO(chrishall): could we additionally match on any path owned by
4195# ui/accessibility/OWNERS ?
4196_ACCESSIBILITY_PATHS = (
4197 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4198 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4199 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4200 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4201 r"^content[\\/]browser[\\/]accessibility[\\/]",
4202 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4203 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4204 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4205 r"^ui[\\/]accessibility[\\/]",
4206 r"^ui[\\/]views[\\/]accessibility[\\/]",
4207)
4208
Saagar Sanghavifceeaae2020-08-12 16:40:364209def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194210 """Checks that commits to accessibility code contain an AX-Relnotes field in
4211 their commit message."""
4212 def FileFilter(affected_file):
4213 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444214 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194215
4216 # Only consider changes affecting accessibility paths.
4217 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4218 return []
4219
Akihiro Ota08108e542020-05-20 15:30:534220 # AX-Relnotes can appear in either the description or the footer.
4221 # When searching the description, require 'AX-Relnotes:' to appear at the
4222 # beginning of a line.
4223 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4224 description_has_relnotes = any(ax_regex.match(line)
4225 for line in input_api.change.DescriptionText().lower().splitlines())
4226
4227 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4228 'AX-Relnotes', [])
4229 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194230 return []
4231
4232 # TODO(chrishall): link to Relnotes documentation in message.
4233 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4234 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4235 "user-facing changes"
4236 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4237 "user-facing effects"
4238 "\n if this is confusing or annoying then please contact members "
4239 "of ui/accessibility/OWNERS.")
4240
4241 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224242
seanmccullough4a9356252021-04-08 19:54:094243# string pattern, sequence of strings to show when pattern matches,
4244# error flag. True if match is a presubmit error, otherwise it's a warning.
4245_NON_INCLUSIVE_TERMS = (
4246 (
4247 # Note that \b pattern in python re is pretty particular. In this
4248 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4249 # ...' will not. This may require some tweaking to catch these cases
4250 # without triggering a lot of false positives. Leaving it naive and
4251 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324252 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094253 (
4254 'Please don\'t use blacklist, whitelist, ' # nocheck
4255 'or slave in your', # nocheck
4256 'code and make every effort to use other terms. Using "// nocheck"',
4257 '"# nocheck" or "<!-- nocheck -->"',
4258 'at the end of the offending line will bypass this PRESUBMIT error',
4259 'but avoid using this whenever possible. Reach out to',
4260 '[email protected] if you have questions'),
4261 True),)
4262
Saagar Sanghavifceeaae2020-08-12 16:40:364263def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394264 """Checks common to both upload and commit."""
4265 results = []
4266 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384267 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544268 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084269
4270 author = input_api.change.author_email
4271 if author and author not in _KNOWN_ROBOTS:
4272 results.extend(
4273 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4274
[email protected]9f919cc2013-07-31 03:04:044275 results.extend(
4276 input_api.canned_checks.CheckChangeHasNoTabs(
4277 input_api,
4278 output_api,
4279 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434280 results.extend(input_api.RunTests(
4281 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244282
Edward Lesmesce51df52020-08-04 22:10:174283 dirmd_bin = input_api.os_path.join(
4284 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4285 results.extend(input_api.RunTests(
4286 input_api.canned_checks.CheckDirMetadataFormat(
4287 input_api, output_api, dirmd_bin)))
4288 results.extend(
4289 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4290 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554291 results.extend(
4292 input_api.canned_checks.CheckNoNewMetadataInOwners(
4293 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094294 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4295 input_api, output_api,
4296 excluded_directories_relative_path = [
4297 'infra',
4298 'inclusive_language_presubmit_exempt_dirs.txt'
4299 ],
4300 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174301
Vaclav Brozekcdc7defb2018-03-20 09:54:354302 for f in input_api.AffectedFiles():
4303 path, name = input_api.os_path.split(f.LocalPath())
4304 if name == 'PRESUBMIT.py':
4305 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004306 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4307 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074308 # The PRESUBMIT.py file (and the directory containing it) might
4309 # have been affected by being moved or removed, so only try to
4310 # run the tests if they still exist.
Dirk Prankee3c9c62d2021-05-18 18:35:594311 use_python3 = False
4312 with open(f.LocalPath()) as fp:
Daniel Chengab582892021-09-30 20:53:194313 use_python3 = any(line.startswith('USE_PYTHON3 = True')
4314 for line in fp.readlines())
Dirk Prankee3c9c62d2021-05-18 18:35:594315
Dirk Pranke38557312018-04-18 00:53:074316 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4317 input_api, output_api, full_path,
Dirk Prankee3c9c62d2021-05-18 18:35:594318 files_to_check=[r'^PRESUBMIT_test\.py$'],
4319 run_on_python2=not use_python3,
Jonathan Njeunjee45f2bd2021-10-12 16:21:584320 run_on_python3=use_python3,
4321 skip_shebang_check=True))
[email protected]22c9bd72011-03-27 16:47:394322 return results
[email protected]1f7b4172010-01-28 01:17:344323
[email protected]b337cb5b2011-01-23 21:24:054324
Saagar Sanghavifceeaae2020-08-12 16:40:364325def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494326 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4327 if f.LocalPath().endswith(('.orig', '.rej'))]
danakj30f05352021-11-03 18:58:414328 # Cargo.toml.orig files are part of third-party crates downloaded from
4329 # crates.io and should be included.
4330 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
[email protected]b8079ae4a2012-12-05 19:56:494331 if problems:
4332 return [output_api.PresubmitError(
4333 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034334 else:
4335 return []
[email protected]b8079ae4a2012-12-05 19:56:494336
4337
Saagar Sanghavifceeaae2020-08-12 16:40:364338def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214339 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4340 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4341 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074342 include_re = input_api.re.compile(
4343 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4344 extension_re = input_api.re.compile(r'\.[a-z]+$')
4345 errors = []
Bruce Dawsonaae5e652021-06-24 15:05:394346 for f in input_api.AffectedFiles(include_deletes=False):
Kent Tamura5a8755d2017-06-29 23:37:074347 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4348 continue
4349 found_line_number = None
4350 found_macro = None
Bruce Dawsonaae5e652021-06-24 15:05:394351 all_lines = input_api.ReadFile(f, 'r').splitlines()
4352 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074353 match = macro_re.search(line)
4354 if match:
4355 found_line_number = line_num
4356 found_macro = match.group(2)
4357 break
4358 if not found_line_number:
4359 continue
4360
Bruce Dawsonaae5e652021-06-24 15:05:394361 found_include_line = -1
4362 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074363 if include_re.search(line):
Bruce Dawsonaae5e652021-06-24 15:05:394364 found_include_line = line_num
Kent Tamura5a8755d2017-06-29 23:37:074365 break
Bruce Dawsonaae5e652021-06-24 15:05:394366 if found_include_line >= 0 and found_include_line < found_line_number:
Kent Tamura5a8755d2017-06-29 23:37:074367 continue
4368
4369 if not f.LocalPath().endswith('.h'):
4370 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4371 try:
4372 content = input_api.ReadFile(primary_header_path, 'r')
4373 if include_re.search(content):
4374 continue
4375 except IOError:
4376 pass
Bruce Dawsonaae5e652021-06-24 15:05:394377 errors.append('%s:%d %s macro is used without first including build/'
Kent Tamura5a8755d2017-06-29 23:37:074378 'build_config.h.'
4379 % (f.LocalPath(), found_line_number, found_macro))
4380 if errors:
4381 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4382 return []
4383
4384
Lei Zhang1c12a22f2021-05-12 11:28:454385def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
4386 stl_include_re = input_api.re.compile(
Lei Zhang0643e342021-05-12 18:02:124387 r'^#include\s+<('
Lei Zhang1c12a22f2021-05-12 11:28:454388 r'algorithm|'
4389 r'array|'
4390 r'limits|'
4391 r'list|'
4392 r'map|'
4393 r'memory|'
4394 r'queue|'
4395 r'set|'
4396 r'string|'
4397 r'unordered_map|'
4398 r'unordered_set|'
4399 r'utility|'
Lei Zhang0643e342021-05-12 18:02:124400 r'vector)>')
Lei Zhang1c12a22f2021-05-12 11:28:454401 std_namespace_re = input_api.re.compile(r'std::')
4402 errors = []
4403 for f in input_api.AffectedFiles():
4404 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4405 continue
4406
4407 uses_std_namespace = False
4408 has_stl_include = False
4409 for line in f.NewContents():
4410 if has_stl_include and uses_std_namespace:
4411 break
4412
4413 if not has_stl_include and stl_include_re.search(line):
4414 has_stl_include = True
4415 continue
4416
4417 if not uses_std_namespace and std_namespace_re.search(line):
4418 uses_std_namespace = True
4419 continue
4420
4421 if has_stl_include and not uses_std_namespace:
4422 errors.append('%s: Includes STL header(s) but does not reference std::'
4423 % f.LocalPath())
4424 if errors:
4425 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4426 return []
4427
4428
[email protected]b00342e7f2013-03-26 16:21:544429def _DidYouMeanOSMacro(bad_macro):
4430 try:
4431 return {'A': 'OS_ANDROID',
4432 'B': 'OS_BSD',
4433 'C': 'OS_CHROMEOS',
4434 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444435 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544436 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444437 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544438 'N': 'OS_NACL',
4439 'O': 'OS_OPENBSD',
4440 'P': 'OS_POSIX',
4441 'S': 'OS_SOLARIS',
4442 'W': 'OS_WIN'}[bad_macro[3].upper()]
4443 except KeyError:
4444 return ''
4445
4446
4447def _CheckForInvalidOSMacrosInFile(input_api, f):
4448 """Check for sensible looking, totally invalid OS macros."""
4449 preprocessor_statement = input_api.re.compile(r'^\s*#')
4450 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4451 results = []
4452 for lnum, line in f.ChangedContents():
4453 if preprocessor_statement.search(line):
4454 for match in os_macro.finditer(line):
4455 if not match.group(1) in _VALID_OS_MACROS:
4456 good = _DidYouMeanOSMacro(match.group(1))
4457 did_you_mean = ' (did you mean %s?)' % good if good else ''
4458 results.append(' %s:%d %s%s' % (f.LocalPath(),
4459 lnum,
4460 match.group(1),
4461 did_you_mean))
4462 return results
4463
4464
Saagar Sanghavifceeaae2020-08-12 16:40:364465def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544466 """Check all affected files for invalid OS macros."""
4467 bad_macros = []
tzik3f295992018-12-04 20:32:234468 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474469 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544470 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4471
4472 if not bad_macros:
4473 return []
4474
4475 return [output_api.PresubmitError(
4476 'Possibly invalid OS macro[s] found. Please fix your code\n'
4477 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4478
lliabraa35bab3932014-10-01 12:16:444479
4480def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4481 """Check all affected files for invalid "if defined" macros."""
4482 ALWAYS_DEFINED_MACROS = (
4483 "TARGET_CPU_PPC",
4484 "TARGET_CPU_PPC64",
4485 "TARGET_CPU_68K",
4486 "TARGET_CPU_X86",
4487 "TARGET_CPU_ARM",
4488 "TARGET_CPU_MIPS",
4489 "TARGET_CPU_SPARC",
4490 "TARGET_CPU_ALPHA",
4491 "TARGET_IPHONE_SIMULATOR",
4492 "TARGET_OS_EMBEDDED",
4493 "TARGET_OS_IPHONE",
4494 "TARGET_OS_MAC",
4495 "TARGET_OS_UNIX",
4496 "TARGET_OS_WIN32",
4497 )
4498 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4499 results = []
4500 for lnum, line in f.ChangedContents():
4501 for match in ifdef_macro.finditer(line):
4502 if match.group(1) in ALWAYS_DEFINED_MACROS:
4503 always_defined = ' %s is always defined. ' % match.group(1)
4504 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4505 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4506 lnum,
4507 always_defined,
4508 did_you_mean))
4509 return results
4510
4511
Saagar Sanghavifceeaae2020-08-12 16:40:364512def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444513 """Check all affected files for invalid "if defined" macros."""
4514 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054515 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444516 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054517 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214518 continue
lliabraa35bab3932014-10-01 12:16:444519 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4520 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4521
4522 if not bad_macros:
4523 return []
4524
4525 return [output_api.PresubmitError(
4526 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4527 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4528 bad_macros)]
4529
4530
Saagar Sanghavifceeaae2020-08-12 16:40:364531def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044532 """Check for same IPC rules described in
4533 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4534 """
4535 base_pattern = r'IPC_ENUM_TRAITS\('
4536 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4537 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4538
4539 problems = []
4540 for f in input_api.AffectedSourceFiles(None):
4541 local_path = f.LocalPath()
4542 if not local_path.endswith('.h'):
4543 continue
4544 for line_number, line in f.ChangedContents():
4545 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4546 problems.append(
4547 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4548
4549 if problems:
4550 return [output_api.PresubmitPromptWarning(
4551 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4552 else:
4553 return []
4554
[email protected]b00342e7f2013-03-26 16:21:544555
Saagar Sanghavifceeaae2020-08-12 16:40:364556def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054557 """Check to make sure no files being submitted have long paths.
4558 This causes issues on Windows.
4559 """
4560 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194561 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054562 local_path = f.LocalPath()
4563 # Windows has a path limit of 260 characters. Limit path length to 200 so
4564 # that we have some extra for the prefix on dev machines and the bots.
4565 if len(local_path) > 200:
4566 problems.append(local_path)
4567
4568 if problems:
4569 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4570 else:
4571 return []
4572
4573
Saagar Sanghavifceeaae2020-08-12 16:40:364574def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144575 """Check that header files have proper guards against multiple inclusion.
4576 If a file should not have such guards (and it probably should) then it
4577 should include the string "no-include-guard-because-multiply-included".
4578 """
Daniel Bratell6a75baef62018-06-04 10:04:454579 def is_chromium_header_file(f):
4580 # We only check header files under the control of the Chromium
4581 # project. That is, those outside third_party apart from
4582 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324583 # We also exclude *_message_generator.h headers as they use
4584 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454585 file_with_path = input_api.os_path.normpath(f.LocalPath())
4586 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324587 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454588 (not file_with_path.startswith('third_party') or
4589 file_with_path.startswith(
4590 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144591
4592 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344593 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144594
4595 errors = []
4596
Daniel Bratell6a75baef62018-06-04 10:04:454597 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144598 guard_name = None
4599 guard_line_number = None
4600 seen_guard_end = False
4601
4602 file_with_path = input_api.os_path.normpath(f.LocalPath())
4603 base_file_name = input_api.os_path.splitext(
4604 input_api.os_path.basename(file_with_path))[0]
4605 upper_base_file_name = base_file_name.upper()
4606
4607 expected_guard = replace_special_with_underscore(
4608 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144609
4610 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574611 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4612 # are too many (1000+) files with slight deviations from the
4613 # coding style. The most important part is that the include guard
4614 # is there, and that it's unique, not the name so this check is
4615 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144616 #
4617 # As code becomes more uniform, this could be made stricter.
4618
4619 guard_name_pattern_list = [
4620 # Anything with the right suffix (maybe with an extra _).
4621 r'\w+_H__?',
4622
Daniel Bratell39b5b062018-05-16 18:09:574623 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144624 r'\w+_h',
4625
4626 # Anything including the uppercase name of the file.
4627 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4628 upper_base_file_name)) + r'\w*',
4629 ]
4630 guard_name_pattern = '|'.join(guard_name_pattern_list)
4631 guard_pattern = input_api.re.compile(
4632 r'#ifndef\s+(' + guard_name_pattern + ')')
4633
4634 for line_number, line in enumerate(f.NewContents()):
4635 if 'no-include-guard-because-multiply-included' in line:
4636 guard_name = 'DUMMY' # To not trigger check outside the loop.
4637 break
4638
4639 if guard_name is None:
4640 match = guard_pattern.match(line)
4641 if match:
4642 guard_name = match.group(1)
4643 guard_line_number = line_number
4644
Daniel Bratell39b5b062018-05-16 18:09:574645 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454646 # don't match the chromium style guide, but new files should
4647 # get it right.
4648 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574649 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144650 errors.append(output_api.PresubmitPromptWarning(
4651 'Header using the wrong include guard name %s' % guard_name,
4652 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574653 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144654 else:
4655 # The line after #ifndef should have a #define of the same name.
4656 if line_number == guard_line_number + 1:
4657 expected_line = '#define %s' % guard_name
4658 if line != expected_line:
4659 errors.append(output_api.PresubmitPromptWarning(
4660 'Missing "%s" for include guard' % expected_line,
4661 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4662 'Expected: %r\nGot: %r' % (expected_line, line)))
4663
4664 if not seen_guard_end and line == '#endif // %s' % guard_name:
4665 seen_guard_end = True
4666 elif seen_guard_end:
4667 if line.strip() != '':
4668 errors.append(output_api.PresubmitPromptWarning(
4669 'Include guard %s not covering the whole file' % (
4670 guard_name), [f.LocalPath()]))
4671 break # Nothing else to check and enough to warn once.
4672
4673 if guard_name is None:
4674 errors.append(output_api.PresubmitPromptWarning(
4675 'Missing include guard %s' % expected_guard,
4676 [f.LocalPath()],
4677 'Missing include guard in %s\n'
4678 'Recommended name: %s\n'
4679 'This check can be disabled by having the string\n'
4680 'no-include-guard-because-multiply-included in the header.' %
4681 (f.LocalPath(), expected_guard)))
4682
4683 return errors
4684
4685
Saagar Sanghavifceeaae2020-08-12 16:40:364686def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234687 """Check source code and known ascii text files for Windows style line
4688 endings.
4689 """
Evan Stade6cfc964c12021-05-18 20:21:164690 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234691
4692 file_inclusion_pattern = (
4693 known_text_files,
Bruce Dawson6141d4a2021-06-08 15:56:114694 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4695 r'.+%s' % _HEADER_EXTENSIONS
mostynbb639aca52015-01-07 20:31:234696 )
4697
mostynbb639aca52015-01-07 20:31:234698 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534699 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444700 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534701 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504702 include_file = False
Bruce Dawsonb2cfdfe2021-06-10 19:01:204703 for line in input_api.ReadFile(f, 'r').splitlines(True):
mostynbb639aca52015-01-07 20:31:234704 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504705 include_file = True
4706 if include_file:
4707 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234708
4709 if problems:
4710 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4711 'these files to contain Windows style line endings?\n' +
4712 '\n'.join(problems))]
4713
4714 return []
4715
Evan Stade6cfc964c12021-05-18 20:21:164716def CheckIconFilesForLicenseHeaders(input_api, output_api):
4717 """Check that .icon files (which are fragments of C++) have license headers.
4718 """
4719
4720 icon_files = (r'.*\.icon$',)
4721
4722 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4723 return input_api.canned_checks.CheckLicense(
4724 input_api, output_api, source_file_filter=icons)
4725
Jose Magana2b456f22021-03-09 23:26:404726def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4727 """Check source code for use of Chrome App technologies being
4728 deprecated.
4729 """
4730
4731 def _CheckForDeprecatedTech(input_api, output_api,
4732 detection_list, files_to_check = None, files_to_skip = None):
4733
4734 if (files_to_check or files_to_skip):
4735 source_file_filter = lambda f: input_api.FilterSourceFile(
4736 f, files_to_check=files_to_check,
4737 files_to_skip=files_to_skip)
4738 else:
4739 source_file_filter = None
4740
4741 problems = []
4742
4743 for f in input_api.AffectedSourceFiles(source_file_filter):
4744 if f.Action() == 'D':
4745 continue
4746 for _, line in f.ChangedContents():
4747 if any( detect in line for detect in detection_list ):
4748 problems.append(f.LocalPath())
4749
4750 return problems
4751
4752 # to avoid this presubmit script triggering warnings
4753 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4754
4755 problems =[]
4756
4757 # NMF: any files with extensions .nmf or NMF
4758 _NMF_FILES = r'\.(nmf|NMF)$'
4759 problems += _CheckForDeprecatedTech(input_api, output_api,
4760 detection_list = [''], # any change to the file will trigger warning
4761 files_to_check = [ r'.+%s' % _NMF_FILES ])
4762
4763 # MANIFEST: any manifest.json that in its diff includes "app":
4764 _MANIFEST_FILES = r'(manifest\.json)$'
4765 problems += _CheckForDeprecatedTech(input_api, output_api,
4766 detection_list = ['"app":'],
4767 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4768
4769 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4770 problems += _CheckForDeprecatedTech(input_api, output_api,
4771 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4772 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4773
4774 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4775 problems += _CheckForDeprecatedTech(input_api, output_api,
4776 detection_list = ['#include "ppapi','#include <ppapi'],
4777 files_to_check = (
4778 r'.+%s' % _HEADER_EXTENSIONS,
4779 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4780 files_to_skip = [r"^ppapi[\\/]"] )
4781
Jose Magana2b456f22021-03-09 23:26:404782 if problems:
4783 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4784 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4785 ' PNaCl, PPAPI). See this blog post for more details:\n'
4786 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4787 'and this documentation for options to replace these technologies:\n'
4788 'https://developer.chrome.com/docs/apps/migration/\n'+
4789 '\n'.join(problems))]
4790
4791 return []
4792
mostynbb639aca52015-01-07 20:31:234793
Saagar Sanghavifceeaae2020-08-12 16:40:364794def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134795 """Checks that all source files use SYSLOG properly."""
4796 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364797 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564798 for line_number, line in f.ChangedContents():
4799 if 'SYSLOG' in line:
4800 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4801
pastarmovj89f7ee12016-09-20 14:58:134802 if syslog_files:
4803 return [output_api.PresubmitPromptWarning(
4804 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4805 ' calls.\nFiles to check:\n', items=syslog_files)]
4806 return []
4807
4808
[email protected]1f7b4172010-01-28 01:17:344809def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364810 if input_api.version < [2, 0, 0]:
4811 return [output_api.PresubmitError("Your depot_tools is out of date. "
4812 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4813 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344814 results = []
scottmg39b29952014-12-08 18:31:284815 results.extend(
jam93a6ee792017-02-08 23:59:224816 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544817 return results
[email protected]ca8d1982009-02-19 16:33:124818
4819
4820def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364821 if input_api.version < [2, 0, 0]:
4822 return [output_api.PresubmitError("Your depot_tools is out of date. "
4823 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4824 "but your version is %d.%d.%d" % tuple(input_api.version))]
4825
[email protected]fe5f57c52009-06-05 14:25:544826 results = []
[email protected]fe5f57c52009-06-05 14:25:544827 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274828 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344829 input_api,
4830 output_api,
[email protected]2fdd1f362013-01-16 03:56:034831 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274832
jam93a6ee792017-02-08 23:59:224833 results.extend(
4834 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544835 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4836 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384837 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4838 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414839 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4840 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544841 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144842
4843
Saagar Sanghavifceeaae2020-08-12 16:40:364844def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264845 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024846 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4847 # footer is set to true.
4848 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264849 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024850 footer.lower()
4851 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264852 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024853
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144854 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264855 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144856 import sys
4857 from io import StringIO
4858
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144859 new_or_added_paths = set(f.LocalPath()
4860 for f in input_api.AffectedFiles()
4861 if (f.Action() == 'A' or f.Action() == 'M'))
4862 removed_paths = set(f.LocalPath()
4863 for f in input_api.AffectedFiles(include_deletes=True)
4864 if f.Action() == 'D')
4865
Andrew Grieve0e8790c2020-09-03 17:27:324866 affected_grds = [
4867 f for f in input_api.AffectedFiles()
4868 if f.LocalPath().endswith(('.grd', '.grdp'))
4869 ]
4870 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164871 if not affected_grds:
4872 return []
4873
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144874 affected_png_paths = [f.AbsoluteLocalPath()
4875 for f in input_api.AffectedFiles()
4876 if (f.LocalPath().endswith('.png'))]
4877
4878 # Check for screenshots. Developers can upload screenshots using
4879 # tools/translation/upload_screenshots.py which finds and uploads
4880 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4881 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4882 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4883 #
4884 # The logic here is as follows:
4885 #
4886 # - If the CL has a .png file under the screenshots directory for a grd
4887 # file, warn the developer. Actual images should never be checked into the
4888 # Chrome repo.
4889 #
4890 # - If the CL contains modified or new messages in grd files and doesn't
4891 # contain the corresponding .sha1 files, warn the developer to add images
4892 # and upload them via tools/translation/upload_screenshots.py.
4893 #
4894 # - If the CL contains modified or new messages in grd files and the
4895 # corresponding .sha1 files, everything looks good.
4896 #
4897 # - If the CL contains removed messages in grd files but the corresponding
4898 # .sha1 files aren't removed, warn the developer to remove them.
4899 unnecessary_screenshots = []
4900 missing_sha1 = []
4901 unnecessary_sha1_files = []
4902
Rainhard Findlingfc31844c52020-05-15 09:58:264903 # This checks verifies that the ICU syntax of messages this CL touched is
4904 # valid, and reports any found syntax errors.
4905 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4906 # without developers being aware of them. Later on, such ICU syntax errors
4907 # break message extraction for translation, hence would block Chromium
4908 # translations until they are fixed.
4909 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144910
4911 def _CheckScreenshotAdded(screenshots_dir, message_id):
4912 sha1_path = input_api.os_path.join(
4913 screenshots_dir, message_id + '.png.sha1')
4914 if sha1_path not in new_or_added_paths:
4915 missing_sha1.append(sha1_path)
4916
4917
4918 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4919 sha1_path = input_api.os_path.join(
4920 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034921 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144922 unnecessary_sha1_files.append(sha1_path)
4923
Rainhard Findlingfc31844c52020-05-15 09:58:264924
4925 def _ValidateIcuSyntax(text, level, signatures):
Daniel Chengab582892021-09-30 20:53:194926 """Validates ICU syntax of a text string.
Rainhard Findlingfc31844c52020-05-15 09:58:264927
4928 Check if text looks similar to ICU and checks for ICU syntax correctness
4929 in this case. Reports various issues with ICU syntax and values of
4930 variants. Supports checking of nested messages. Accumulate information of
4931 each ICU messages found in the text for further checking.
4932
4933 Args:
4934 text: a string to check.
4935 level: a number of current nesting level.
4936 signatures: an accumulator, a list of tuple of (level, variable,
4937 kind, variants).
4938
4939 Returns:
4940 None if a string is not ICU or no issue detected.
4941 A tuple of (message, start index, end index) if an issue detected.
4942 """
Daniel Chengab582892021-09-30 20:53:194943 valid_types = {
4944 'plural': (frozenset(
4945 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4946 frozenset(['=1', 'other'])),
4947 'selectordinal': (frozenset(
4948 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4949 frozenset(['one', 'other'])),
4950 'select': (frozenset(), frozenset(['other'])),
4951 }
Rainhard Findlingfc31844c52020-05-15 09:58:264952
Daniel Chengab582892021-09-30 20:53:194953 # Check if the message looks like an attempt to use ICU
4954 # plural. If yes - check if its syntax strictly matches ICU format.
4955 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4956 if not like:
4957 signatures.append((level, None, None, None))
4958 return
Rainhard Findlingfc31844c52020-05-15 09:58:264959
Daniel Chengab582892021-09-30 20:53:194960 # Check for valid prefix and suffix
4961 m = re.match(
4962 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4963 r'(plural|selectordinal|select),\s*'
4964 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4965 if not m:
4966 return (('This message looks like an ICU plural, '
4967 'but does not follow ICU syntax.'), like.start(), like.end())
4968 starting, variable, kind, variant_pairs = m.groups()
4969 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4970 if depth:
4971 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4972 len(text))
4973 first = text[0]
4974 ending = text[last_pos:]
4975 if not starting:
4976 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4977 last_pos)
4978 if not ending or '}' not in ending:
4979 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4980 last_pos)
4981 elif first != '{':
4982 return (
4983 ('Invalid ICU format. Extra characters at the start of a complex '
4984 'message (go/icu-message-migration): "%s"') %
4985 starting, 0, len(starting))
4986 elif ending != '}':
4987 return (('Invalid ICU format. Extra characters at the end of a complex '
4988 'message (go/icu-message-migration): "%s"')
4989 % ending, last_pos - 1, len(text) - 1)
4990 if kind not in valid_types:
4991 return (('Unknown ICU message type %s. '
4992 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4993 known, required = valid_types[kind]
4994 defined_variants = set()
4995 for variant, variant_range, value, value_range in variants:
4996 start, end = variant_range
4997 if variant in defined_variants:
4998 return ('Variant "%s" is defined more than once' % variant,
4999 start, end)
5000 elif known and variant not in known:
5001 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5002 start, end)
5003 defined_variants.add(variant)
5004 # Check for nested structure
5005 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5006 if res:
5007 return (res[0], res[1] + value_range[0] + 1,
5008 res[2] + value_range[0] + 1)
5009 missing = required - defined_variants
5010 if missing:
5011 return ('Required variants missing: %s' % ', '.join(missing), 0,
5012 len(text))
5013 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265014
5015
5016 def _ParseIcuVariants(text, offset=0):
5017 """Parse variants part of ICU complex message.
5018
5019 Builds a tuple of variant names and values, as well as
5020 their offsets in the input string.
5021
5022 Args:
5023 text: a string to parse
5024 offset: additional offset to add to positions in the text to get correct
5025 position in the complete ICU string.
5026
5027 Returns:
5028 List of tuples, each tuple consist of four fields: variant name,
5029 variant name span (tuple of two integers), variant value, value
5030 span (tuple of two integers).
5031 """
5032 depth, start, end = 0, -1, -1
5033 variants = []
5034 key = None
5035 for idx, char in enumerate(text):
5036 if char == '{':
5037 if not depth:
5038 start = idx
5039 chunk = text[end + 1:start]
5040 key = chunk.strip()
5041 pos = offset + end + 1 + chunk.find(key)
5042 span = (pos, pos + len(key))
5043 depth += 1
5044 elif char == '}':
5045 if not depth:
5046 return variants, depth, offset + idx
5047 depth -= 1
5048 if not depth:
5049 end = idx
5050 variants.append((key, span, text[start:end + 1], (offset + start,
5051 offset + end + 1)))
5052 return variants, depth, offset + end + 1
5053
meacer8c0d3832019-12-26 21:46:165054 try:
5055 old_sys_path = sys.path
5056 sys.path = sys.path + [input_api.os_path.join(
5057 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5058 from helper import grd_helper
5059 finally:
5060 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145061
5062 for f in affected_grds:
5063 file_path = f.LocalPath()
5064 old_id_to_msg_map = {}
5065 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385066 # Note that this code doesn't check if the file has been deleted. This is
5067 # OK because it only uses the old and new file contents and doesn't load
5068 # the file via its path.
5069 # It's also possible that a file's content refers to a renamed or deleted
5070 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5071 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5072 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145073 if file_path.endswith('.grdp'):
5074 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585075 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595076 '\n'.join(f.OldContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145077 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585078 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595079 '\n'.join(f.NewContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145080 else:
meacerff8a9b62019-12-10 19:43:585081 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145082 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585083 old_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595084 StringIO('\n'.join(f.OldContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145085 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585086 new_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595087 StringIO('\n'.join(f.NewContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145088
Rainhard Findlingd8d04372020-08-13 13:30:095089 grd_name, ext = input_api.os_path.splitext(
5090 input_api.os_path.basename(file_path))
5091 screenshots_dir = input_api.os_path.join(
5092 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5093
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145094 # Compute added, removed and modified message IDs.
5095 old_ids = set(old_id_to_msg_map)
5096 new_ids = set(new_id_to_msg_map)
5097 added_ids = new_ids - old_ids
5098 removed_ids = old_ids - new_ids
5099 modified_ids = set([])
5100 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355101 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095102 != new_id_to_msg_map[key].ContentsAsXml('', True)):
Daniel Chengab582892021-09-30 20:53:195103 # The message content itself changed. Require an updated screenshot.
5104 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355105 elif old_id_to_msg_map[key].attrs['meaning'] != \
5106 new_id_to_msg_map[key].attrs['meaning']:
5107 # The message meaning changed. Ensure there is a screenshot for it.
5108 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5109 if sha1_path not in new_or_added_paths and not \
5110 input_api.os_path.exists(sha1_path):
5111 # There is neither a previous screenshot nor is a new one added now.
5112 # Require a screenshot.
5113 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145114
Rainhard Findlingfc31844c52020-05-15 09:58:265115 if run_screenshot_check:
5116 # Check the screenshot directory for .png files. Warn if there is any.
5117 for png_path in affected_png_paths:
5118 if png_path.startswith(screenshots_dir):
5119 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145120
Rainhard Findlingfc31844c52020-05-15 09:58:265121 for added_id in added_ids:
5122 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145123
Rainhard Findlingfc31844c52020-05-15 09:58:265124 for modified_id in modified_ids:
5125 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145126
Rainhard Findlingfc31844c52020-05-15 09:58:265127 for removed_id in removed_ids:
5128 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5129
5130 # Check new and changed strings for ICU syntax errors.
5131 for key in added_ids.union(modified_ids):
5132 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5133 err = _ValidateIcuSyntax(msg, 0, [])
5134 if err is not None:
5135 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145136
5137 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265138 if run_screenshot_check:
5139 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005140 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265141 'Do not include actual screenshots in the changelist. Run '
5142 'tools/translate/upload_screenshots.py to upload them instead:',
5143 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145144
Rainhard Findlingfc31844c52020-05-15 09:58:265145 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005146 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265147 'You are adding or modifying UI strings.\n'
5148 'To ensure the best translations, take screenshots of the relevant UI '
5149 '(https://g.co/chrome/translation) and add these files to your '
5150 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145151
Rainhard Findlingfc31844c52020-05-15 09:58:265152 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005153 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265154 'You removed strings associated with these files. Remove:',
5155 sorted(unnecessary_sha1_files)))
5156 else:
5157 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5158 'screenshots check.'))
5159
5160 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075161 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265162 'ICU syntax errors were found in the following strings (problems or '
5163 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145164
5165 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125166
5167
Saagar Sanghavifceeaae2020-08-12 16:40:365168def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125169 repo_root=None,
5170 translation_expectations_path=None,
5171 grd_files=None):
5172 import sys
5173 affected_grds = [f for f in input_api.AffectedFiles()
5174 if (f.LocalPath().endswith('.grd') or
5175 f.LocalPath().endswith('.grdp'))]
5176 if not affected_grds:
5177 return []
5178
5179 try:
5180 old_sys_path = sys.path
5181 sys.path = sys.path + [
5182 input_api.os_path.join(
5183 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5184 from helper import git_helper
5185 from helper import translation_helper
5186 finally:
5187 sys.path = old_sys_path
5188
5189 # Check that translation expectations can be parsed and we can get a list of
5190 # translatable grd files. |repo_root| and |translation_expectations_path| are
5191 # only passed by tests.
5192 if not repo_root:
5193 repo_root = input_api.PresubmitLocalPath()
5194 if not translation_expectations_path:
5195 translation_expectations_path = input_api.os_path.join(
5196 repo_root, 'tools', 'gritsettings',
5197 'translation_expectations.pyl')
5198 if not grd_files:
5199 grd_files = git_helper.list_grds_in_repository(repo_root)
5200
dpapad8e21b472020-10-23 17:15:035201 # Ignore bogus grd files used only for testing
5202 # ui/webui/resoucres/tools/generate_grd.py.
5203 ignore_path = input_api.os_path.join(
5204 'ui', 'webui', 'resources', 'tools', 'tests')
Dirk Prankee3c9c62d2021-05-18 18:35:595205 grd_files = [p for p in grd_files if ignore_path not in p]
dpapad8e21b472020-10-23 17:15:035206
Mustafa Emre Acer51f2f742020-03-09 19:41:125207 try:
5208 translation_helper.get_translatable_grds(repo_root, grd_files,
5209 translation_expectations_path)
5210 except Exception as e:
5211 return [output_api.PresubmitNotifyResult(
5212 'Failed to get a list of translatable grd files. This happens when:\n'
5213 ' - One of the modified grd or grdp files cannot be parsed or\n'
5214 ' - %s is not updated.\n'
5215 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5216 return []
Ken Rockotc31f4832020-05-29 18:58:515217
5218
Saagar Sanghavifceeaae2020-08-12 16:40:365219def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515220 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095221 changed_mojoms = input_api.AffectedFiles(
5222 include_deletes=True,
5223 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525224
5225 if not changed_mojoms:
5226 return []
5227
Ken Rockotc31f4832020-05-29 18:58:515228 delta = []
5229 for mojom in changed_mojoms:
5230 old_contents = ''.join(mojom.OldContents()) or None
5231 new_contents = ''.join(mojom.NewContents()) or None
5232 delta.append({
5233 'filename': mojom.LocalPath(),
5234 'old': '\n'.join(mojom.OldContents()) or None,
5235 'new': '\n'.join(mojom.NewContents()) or None,
5236 })
5237
5238 process = input_api.subprocess.Popen(
5239 [input_api.python_executable,
5240 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5241 'public', 'tools', 'mojom',
5242 'check_stable_mojom_compatibility.py'),
5243 '--src-root', input_api.PresubmitLocalPath()],
5244 stdin=input_api.subprocess.PIPE,
5245 stdout=input_api.subprocess.PIPE,
5246 stderr=input_api.subprocess.PIPE,
5247 universal_newlines=True)
5248 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5249 if process.returncode:
5250 return [output_api.PresubmitError(
5251 'One or more [Stable] mojom definitions appears to have been changed '
5252 'in a way that is not backward-compatible.',
5253 long_text=error)]
5254 return []
Dominic Battre645d42342020-12-04 16:14:105255
5256def CheckDeprecationOfPreferences(input_api, output_api):
5257 """Removing a preference should come with a deprecation."""
5258
5259 def FilterFile(affected_file):
5260 """Accept only .cc files and the like."""
5261 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5262 files_to_skip = (_EXCLUDED_PATHS +
5263 _TEST_CODE_EXCLUDED_PATHS +
5264 input_api.DEFAULT_FILES_TO_SKIP)
5265 return input_api.FilterSourceFile(
5266 affected_file,
5267 files_to_check=file_inclusion_pattern,
5268 files_to_skip=files_to_skip)
5269
5270 def ModifiedLines(affected_file):
5271 """Returns a list of tuples (line number, line text) of added and removed
5272 lines.
5273
5274 Deleted lines share the same line number as the previous line.
5275
5276 This relies on the scm diff output describing each changed code section
5277 with a line of the form
5278
5279 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5280 """
5281 line_num = 0
5282 modified_lines = []
5283 for line in affected_file.GenerateScmDiff().splitlines():
5284 # Extract <new line num> of the patch fragment (see format above).
5285 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5286 if m:
5287 line_num = int(m.groups(1)[0])
5288 continue
5289 if ((line.startswith('+') and not line.startswith('++')) or
5290 (line.startswith('-') and not line.startswith('--'))):
5291 modified_lines.append((line_num, line))
5292
5293 if not line.startswith('-'):
5294 line_num += 1
5295 return modified_lines
5296
5297 def FindLineWith(lines, needle):
5298 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5299
5300 If 0 or >1 lines contain `needle`, -1 is returned.
5301 """
5302 matching_line_numbers = [
5303 # + 1 for 1-based counting of line numbers.
5304 i + 1 for i, line
5305 in enumerate(lines)
5306 if needle in line]
5307 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5308
5309 def ModifiedPrefMigration(affected_file):
5310 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5311 # Determine first and last lines of MigrateObsolete.*Pref functions.
5312 new_contents = affected_file.NewContents();
5313 range_1 = (
5314 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5315 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5316 range_2 = (
5317 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5318 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5319 if (-1 in range_1 + range_2):
5320 raise Exception(
5321 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5322
5323 # Check whether any of the modified lines are part of the
5324 # MigrateObsolete.*Pref functions.
5325 for line_nr, line in ModifiedLines(affected_file):
5326 if (range_1[0] <= line_nr <= range_1[1] or
5327 range_2[0] <= line_nr <= range_2[1]):
5328 return True
5329 return False
5330
5331 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5332 browser_prefs_file_pattern = input_api.re.compile(
5333 r'chrome/browser/prefs/browser_prefs.cc')
5334
5335 changes = input_api.AffectedFiles(include_deletes=True,
5336 file_filter=FilterFile)
5337 potential_problems = []
5338 for f in changes:
5339 for line in f.GenerateScmDiff().splitlines():
5340 # Check deleted lines for pref registrations.
5341 if (line.startswith('-') and not line.startswith('--') and
5342 register_pref_pattern.search(line)):
5343 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5344
5345 if browser_prefs_file_pattern.search(f.LocalPath()):
5346 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5347 # assume that they knew that they have to deprecate preferences and don't
5348 # warn.
5349 try:
5350 if ModifiedPrefMigration(f):
5351 return []
5352 except Exception as e:
5353 return [output_api.PresubmitError(str(e))]
5354
5355 if potential_problems:
5356 return [output_api.PresubmitPromptWarning(
5357 'Discovered possible removal of preference registrations.\n\n'
5358 'Please make sure to properly deprecate preferences by clearing their\n'
5359 'value for a couple of milestones before finally removing the code.\n'
5360 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195361 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5362 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105363 'This may be a false positive warning (e.g. if you move preference\n'
5364 'registrations to a different place).\n',
5365 potential_problems
5366 )]
5367 return []
Matt Stark6ef08872021-07-29 01:21:465368
5369def CheckConsistentGrdChanges(input_api, output_api):
5370 """Changes to GRD files must be consistent for tools to read them."""
5371 changed_grds = input_api.AffectedFiles(
5372 include_deletes=False,
5373 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5374 errors = []
Daniel Chengab582892021-09-30 20:53:195375 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5376 for matcher, msg in _INVALID_GRD_FILE_LINE]
Matt Stark6ef08872021-07-29 01:21:465377 for grd in changed_grds:
5378 for i, line in enumerate(grd.NewContents()):
5379 for matcher, msg in invalid_file_regexes:
5380 if matcher.search(line):
Daniel Chengab582892021-09-30 20:53:195381 errors.append(
5382 output_api.PresubmitError('Problem on {grd}:{i} - {msg}'.format(
5383 grd=grd.LocalPath(), i=i + 1, msg=msg)))
Matt Stark6ef08872021-07-29 01:21:465384 return errors
Kevin McNee967dd2d22021-11-15 16:09:295385
5386def CheckMPArchApiUsage(input_api, output_api):
5387 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5388 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5389 """
5390
5391 # Only consider top-level directories that (1) can use content APIs, (2)
5392 # apply to desktop or android chrome, and (3) are known to have a significant
5393 # number of uses of the APIs of concern.
5394 files_to_check = (
5395 r'^(chrome|components|content|extensions)[\\/].+%s' %
5396 _IMPLEMENTATION_EXTENSIONS,
5397 r'^(chrome|components|content|extensions)[\\/].+%s' % _HEADER_EXTENSIONS,
5398 )
5399 files_to_skip=(_EXCLUDED_PATHS +
5400 _TEST_CODE_EXCLUDED_PATHS +
5401 input_api.DEFAULT_FILES_TO_SKIP)
5402 source_file_filter = lambda f: input_api.FilterSourceFile(
5403 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5404
5405 # Note that since these are are just regular expressions and we don't have
5406 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5407 # could have a method named IsInMainFrame).
5408 concerning_class_pattern = input_api.re.compile(
5409 r'WebContentsObserver|WebContentsUserData')
5410 # A subset of WebContentsObserver overrides where there's particular risk for
5411 # confusing tab and page level operations and data (e.g. incorrectly
5412 # resetting page state in DidFinishNavigation).
5413 concerning_wco_methods = [
5414 'DidStartNavigation',
5415 'ReadyToCommitNavigation',
5416 'DidFinishNavigation',
5417 'RenderViewReady',
5418 'RenderViewDeleted',
5419 'RenderViewHostChanged',
5420 'DocumentAvailableInMainFrame',
Sreeja Kamishetty81347582022-01-06 12:46:335421 'DocumentOnLoadCompletedInPrimaryMainFrame',
Kevin McNee967dd2d22021-11-15 16:09:295422 'DOMContentLoaded',
5423 'DidFinishLoad',
5424 ]
5425 concerning_nav_handle_methods = [
5426 'IsInMainFrame',
5427 ]
5428 concerning_web_contents_methods = [
5429 'ForEachFrame',
5430 'GetAllFrames',
5431 'FromRenderFrameHost',
5432 'FromRenderViewHost',
5433 'GetMainFrame',
5434 'GetRenderViewHost',
5435 ]
5436 concerning_rfh_methods = [
5437 'GetParent',
5438 'GetMainFrame',
5439 'GetFrameTreeNodeId',
5440 ]
5441 concerning_method_pattern = input_api.re.compile(
5442 r'(' +
5443 r'|'.join(
5444 item
5445 for sublist in [concerning_wco_methods,
5446 concerning_nav_handle_methods,
5447 concerning_web_contents_methods,
5448 concerning_rfh_methods]
5449 for item in sublist) +
5450 r')\(')
5451
5452 uses_concerning_api = False
5453 for f in input_api.AffectedFiles(include_deletes=False,
5454 file_filter=source_file_filter):
5455 for line_num, line in f.ChangedContents():
5456 if (concerning_class_pattern.search(line) or
5457 concerning_method_pattern.search(line)):
5458 uses_concerning_api = True
5459 break
5460 if uses_concerning_api:
5461 break
5462
5463 if uses_concerning_api:
5464 output_api.AppendCC('[email protected]')
5465
5466 return []
Henrique Ferreiro2a4b55942021-11-29 23:45:365467
5468
5469def CheckAssertAshOnlyCode(input_api, output_api):
5470 """Errors if a BUILD.gn file in an ash/ directory doesn't include
5471 assert(is_chromeos_ash).
5472 """
5473
5474 def FileFilter(affected_file):
5475 """Includes directories known to be Ash only."""
5476 return input_api.FilterSourceFile(
5477 affected_file,
5478 files_to_check=(
5479 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
5480 r'.*/ash/.*BUILD\.gn'), # Any path component.
5481 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
5482
5483 errors = []
5484 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:565485 for f in input_api.AffectedFiles(include_deletes=False,
5486 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:365487 if (not pattern.search(input_api.ReadFile(f))):
5488 errors.append(
5489 output_api.PresubmitError(
5490 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
5491 'possible, please create and issue and add a comment such '
5492 'as:\n # TODO(https://crbug.com/XXX): add '
5493 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
5494 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:275495
5496
5497def _IsRendererOnlyCppFile(input_api, affected_file):
5498 path = affected_file.LocalPath()
5499 if not _IsCPlusPlusFile(input_api, path):
5500 return False
5501
5502 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
5503 if "/renderer/" in path:
5504 return True
5505
5506 # Blink's public/web API is only used/included by Renderer-only code. Note
5507 # that public/platform API may be used in non-Renderer processes (e.g. there
5508 # are some includes in code used by Utility, PDF, or Plugin processes).
5509 if "/blink/public/web/" in path:
5510 return True
5511
5512 # We assume that everything else may be used outside of Renderer processes.
5513 return False
5514
5515# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
5516# by the Chromium Clang Plugin (which will be preferable because it will
5517# 1) report errors earlier - at compile-time and 2) cover more rules).
5518def CheckRawPtrUsage(input_api, output_api):
5519 """Rough checks that raw_ptr<T> usage guidelines are followed."""
5520 errors = []
5521 # The regex below matches "raw_ptr<" following a word boundary, but not in a
5522 # C++ comment.
5523 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
5524 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
5525 for f, line_num, line in input_api.RightHandSideLines(file_filter):
5526 if raw_ptr_matcher.search(line):
5527 errors.append(
5528 output_api.PresubmitError(
5529 'Problem on {path}:{line} - '\
5530 'raw_ptr<T> should not be used in Renderer-only code '\
5531 '(as documented in the "Pointers to unprotected memory" '\
5532 'section in //base/memory/raw_ptr.md)'.format(
5533 path=f.LocalPath(), line=line_num)))
5534 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:565535
5536
5537def CheckPythonShebang(input_api, output_api):
5538 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
5539 system-wide python.
5540 """
5541 errors = []
5542 sources = lambda affected_file: input_api.FilterSourceFile(
5543 affected_file,
5544 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
5545 r'third_party/blink/web_tests/external/') + input_api.
5546 DEFAULT_FILES_TO_SKIP),
5547 files_to_check=[r'.*\.py$'])
5548 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:275549 for line_num, line in f.ChangedContents():
5550 if line_num == 1 and line.startswith('#!/usr/bin/python'):
5551 errors.append(f.LocalPath())
5552 break
Henrique Ferreirof9819f2e32021-11-30 13:31:565553
5554 result = []
5555 for file in errors:
5556 result.append(
5557 output_api.PresubmitError(
5558 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
5559 file))
5560 return result