blob: 553ca4461695762ec8806b1defccd6198002619d [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/',
Wez5f56be52021-05-04 09:30:58662 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
663 '.*fuchsia.*test\.(cc|h)',
Alex Chau9eb03cdd52020-07-13 21:04:57664 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21665 ),
666 (
Peter Kasting991618a62019-06-17 22:00:09667 r'/\bstd::weak_ptr\b',
668 (
669 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
670 ),
671 True,
672 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
673 ),
674 (
Daniel Bratell609102be2019-03-27 20:53:21675 r'/\blong long\b',
676 (
677 'long long is banned. Use stdint.h if you need a 64 bit number.',
678 ),
679 False, # Only a warning since it is already used.
680 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
681 ),
682 (
683 r'/\bstd::bind\b',
684 (
685 'std::bind is banned because of lifetime risks.',
686 'Use base::BindOnce or base::BindRepeating instead.',
687 ),
688 True,
689 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
690 ),
691 (
692 r'/\b#include <chrono>\b',
693 (
694 '<chrono> overlaps with Time APIs in base. Keep using',
695 'base classes.',
696 ),
697 True,
698 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
699 ),
700 (
701 r'/\b#include <exception>\b',
702 (
703 'Exceptions are banned and disabled in Chromium.',
704 ),
705 True,
706 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
707 ),
708 (
709 r'/\bstd::function\b',
710 (
Colin Blundellea615d422021-05-12 09:35:41711 'std::function is banned. Instead use base::OnceCallback or ',
712 'base::RepeatingCallback, which directly support Chromium\'s weak ',
713 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21714 ),
Peter Kasting991618a62019-06-17 22:00:09715 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21716 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
717 ),
718 (
719 r'/\b#include <random>\b',
720 (
721 'Do not use any random number engines from <random>. Instead',
722 'use base::RandomBitGenerator.',
723 ),
724 True,
725 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
726 ),
727 (
Tom Andersona95e12042020-09-09 23:08:00728 r'/\b#include <X11/',
729 (
730 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
731 ),
732 True,
733 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
734 ),
735 (
Daniel Bratell609102be2019-03-27 20:53:21736 r'/\bstd::ratio\b',
737 (
738 'std::ratio is banned by the Google Style Guide.',
739 ),
740 True,
741 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45742 ),
743 (
Gabriel Charetted90bcc92021-09-21 00:23:10744 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:38745 (
Gabriel Charetted90bcc92021-09-21 00:23:10746 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:38747 ),
Gabriel Charette04b138f2018-08-06 00:03:22748 False,
Francois Doray43670e32017-09-27 12:40:38749 (),
750 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38751 (
Michael Giuffrida7f93d6922019-04-19 14:39:58752 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19753 (
754 'RunMessageLoop is deprecated, use RunLoop instead.',
755 ),
756 False,
757 (),
758 ),
759 (
Dave Tapuska98199b612019-07-10 13:30:44760 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19761 (
762 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
763 ),
764 False,
765 (),
766 ),
767 (
Dave Tapuska98199b612019-07-10 13:30:44768 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19769 (
770 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
771 "if you're convinced you need this.",
772 ),
773 False,
774 (),
775 ),
776 (
Dave Tapuska98199b612019-07-10 13:30:44777 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19778 (
779 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04780 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19781 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
782 'async events instead of flushing threads.',
783 ),
784 False,
785 (),
786 ),
787 (
788 r'MessageLoopRunner',
789 (
790 'MessageLoopRunner is deprecated, use RunLoop instead.',
791 ),
792 False,
793 (),
794 ),
795 (
Dave Tapuska98199b612019-07-10 13:30:44796 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19797 (
798 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
799 "gab@ if you found a use case where this is the only solution.",
800 ),
801 False,
802 (),
803 ),
804 (
Victor Costane48a2e82019-03-15 22:02:34805 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16806 (
Victor Costane48a2e82019-03-15 22:02:34807 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16808 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
809 ),
810 True,
811 (
812 r'^sql/initialization\.(cc|h)$',
813 r'^third_party/sqlite/.*\.(c|cc|h)$',
814 ),
815 ),
Matt Menke7f520a82018-03-28 21:38:37816 (
Dave Tapuska98199b612019-07-10 13:30:44817 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47818 (
819 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
820 'base::RandomShuffle instead.'
821 ),
822 True,
823 (),
824 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24825 (
826 'ios/web/public/test/http_server',
827 (
828 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
829 ),
830 False,
831 (),
832 ),
Robert Liao764c9492019-01-24 18:46:28833 (
834 'GetAddressOf',
835 (
836 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53837 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11838 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53839 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28840 ),
841 True,
842 (),
843 ),
Antonio Gomes07300d02019-03-13 20:59:57844 (
Ben Lewisa9514602019-04-29 17:53:05845 'SHFileOperation',
846 (
847 'SHFileOperation was deprecated in Windows Vista, and there are less ',
848 'complex functions to achieve the same goals. Use IFileOperation for ',
849 'any esoteric actions instead.'
850 ),
851 True,
852 (),
853 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18854 (
Cliff Smolinsky81951642019-04-30 21:39:51855 'StringFromGUID2',
856 (
857 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24858 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51859 ),
860 True,
861 (
862 r'/base/win/win_util_unittest.cc'
863 ),
864 ),
865 (
866 'StringFromCLSID',
867 (
868 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24869 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51870 ),
871 True,
872 (
873 r'/base/win/win_util_unittest.cc'
874 ),
875 ),
876 (
Avi Drissman7382afa02019-04-29 23:27:13877 'kCFAllocatorNull',
878 (
879 'The use of kCFAllocatorNull with the NoCopy creation of ',
880 'CoreFoundation types is prohibited.',
881 ),
882 True,
883 (),
884 ),
Oksana Zhuravlovafd247772019-05-16 16:57:29885 (
886 'mojo::ConvertTo',
887 (
888 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
889 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
890 'StringTraits if you would like to convert between custom types and',
891 'the wire format of mojom types.'
892 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22893 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29894 (
Wezf89dec092019-09-11 19:38:33895 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
896 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29897 r'^third_party/blink/.*\.(cc|h)$',
898 r'^content/renderer/.*\.(cc|h)$',
899 ),
900 ),
Robert Liao1d78df52019-11-11 20:02:01901 (
Oksana Zhuravlovac8222d22019-12-19 19:21:16902 'GetInterfaceProvider',
903 (
904 'InterfaceProvider is deprecated.',
905 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
906 'or Platform::GetBrowserInterfaceBroker.'
907 ),
908 False,
909 (),
910 ),
911 (
Robert Liao1d78df52019-11-11 20:02:01912 'CComPtr',
913 (
914 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
915 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
916 'details.'
917 ),
918 False,
919 (),
920 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:20921 (
922 r'/\b(IFACE|STD)METHOD_?\(',
923 (
924 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
925 'Instead, always use IFACEMETHODIMP in the declaration.'
926 ),
927 False,
928 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
929 ),
Allen Bauer53b43fb12020-03-12 17:21:47930 (
931 'set_owned_by_client',
932 (
933 'set_owned_by_client is deprecated.',
934 'views::View already owns the child views by default. This introduces ',
935 'a competing ownership model which makes the code difficult to reason ',
936 'about. See http://crbug.com/1044687 for more details.'
937 ),
938 False,
939 (),
940 ),
Eric Secklerbe6f48d2020-05-06 18:09:12941 (
Peter Boström7ff41522021-07-29 03:43:27942 'RemoveAllChildViewsWithoutDeleting',
943 (
944 'RemoveAllChildViewsWithoutDeleting is deprecated.',
945 'This method is deemed dangerous as, unless raw pointers are re-added,',
946 'calls to this method introduce memory leaks.'
947 ),
948 False,
949 (),
950 ),
951 (
Eric Secklerbe6f48d2020-05-06 18:09:12952 r'/\bTRACE_EVENT_ASYNC_',
953 (
954 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
955 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
956 ),
957 False,
958 (
959 r'^base/trace_event/.*',
960 r'^base/tracing/.*',
961 ),
962 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:26963 (
Robert Liao22f66a52021-04-10 00:57:52964 'RoInitialize',
965 (
Robert Liao48018922021-04-16 23:03:02966 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:52967 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
968 'instead. See http://crbug.com/1197722 for more information.'
969 ),
970 True,
Robert Liao48018922021-04-16 23:03:02971 (
972 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$'
973 ),
Robert Liao22f66a52021-04-10 00:57:52974 ),
[email protected]127f18ec2012-06-16 05:05:59975)
976
Mario Sanchez Prada2472cab2019-09-18 10:58:31977# Format: Sequence of tuples containing:
978# * String pattern or, if starting with a slash, a regular expression.
979# * Sequence of strings to show when the pattern matches.
980_DEPRECATED_MOJO_TYPES = (
981 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31982 r'/\bmojo::AssociatedInterfacePtrInfo\b',
983 (
984 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
985 'Use mojo::PendingAssociatedRemote<Interface> instead.',
986 ),
987 ),
988 (
989 r'/\bmojo::AssociatedInterfaceRequest\b',
990 (
991 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
992 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
993 ),
994 ),
995 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31996 r'/\bmojo::InterfacePtr\b',
997 (
998 'mojo::InterfacePtr<Interface> is deprecated.',
999 'Use mojo::Remote<Interface> instead.',
1000 ),
1001 ),
1002 (
1003 r'/\bmojo::InterfacePtrInfo\b',
1004 (
1005 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1006 'Use mojo::PendingRemote<Interface> instead.',
1007 ),
1008 ),
1009 (
1010 r'/\bmojo::InterfaceRequest\b',
1011 (
1012 'mojo::InterfaceRequest<Interface> is deprecated.',
1013 'Use mojo::PendingReceiver<Interface> instead.',
1014 ),
1015 ),
1016 (
1017 r'/\bmojo::MakeRequest\b',
1018 (
1019 'mojo::MakeRequest is deprecated.',
1020 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1021 ),
1022 ),
Mario Sanchez Prada2472cab2019-09-18 10:58:311023)
wnwenbdc444e2016-05-25 13:44:151024
mlamouria82272622014-09-16 18:45:041025_IPC_ENUM_TRAITS_DEPRECATED = (
1026 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501027 'See http://www.chromium.org/Home/chromium-security/education/'
1028 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041029
Stephen Martinis97a394142018-06-07 23:06:051030_LONG_PATH_ERROR = (
1031 'Some files included in this CL have file names that are too long (> 200'
1032 ' characters). If committed, these files will cause issues on Windows. See'
1033 ' https://crbug.com/612667 for more details.'
1034)
1035
Shenghua Zhangbfaa38b82017-11-16 21:58:021036_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041037 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041038 r".*[\\/]BuildHooksAndroidImpl\.java",
1039 r".*[\\/]LicenseContentProvider\.java",
1040 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281041 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021042]
[email protected]127f18ec2012-06-16 05:05:591043
Mohamed Heikald048240a2019-11-12 16:57:371044# List of image extensions that are used as resources in chromium.
1045_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1046
Sean Kau46e29bc2017-08-28 16:31:161047# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401048_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041049 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401050 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041051 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1052 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041053 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431054 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161055]
1056
1057
[email protected]b00342e7f2013-03-26 16:21:541058_VALID_OS_MACROS = (
1059 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081060 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541061 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441062 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121063 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541064 'OS_BSD',
1065 'OS_CAT', # For testing.
1066 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041067 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541068 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371069 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541070 'OS_IOS',
1071 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441072 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541073 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211074 'OS_NACL_NONSFI',
1075 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121076 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541077 'OS_OPENBSD',
1078 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371079 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541080 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541081 'OS_WIN',
1082)
1083
1084
Andrew Grieveb773bad2020-06-05 18:00:381085# These are not checked on the public chromium-presubmit trybot.
1086# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041087# checkouts.
agrievef32bcc72016-04-04 14:57:401088_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381089 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381090]
1091
1092
1093_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041094 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361095 'base/android/jni_generator/jni_generator.pydeps',
1096 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361097 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041098 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361099 'build/android/gyp/aar.pydeps',
1100 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271101 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361102 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381103 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361104 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021105 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221106 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111107 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361108 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361109 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361110 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111111 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041112 'build/android/gyp/create_app_bundle_apks.pydeps',
1113 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361114 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121115 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091116 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221117 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001118 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361119 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421120 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041121 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361122 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361123 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211124 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361125 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361126 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361127 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581128 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361129 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141130 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261131 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471132 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011133 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041134 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361135 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361136 'build/android/gyp/merge_manifest.pydeps',
1137 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221138 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361139 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461140 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301141 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241142 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361143 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461144 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561145 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361146 'build/android/incremental_install/generate_android_manifest.pydeps',
1147 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041148 'build/android/resource_sizes.pydeps',
1149 'build/android/test_runner.pydeps',
1150 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361151 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361152 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321153 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271154 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1155 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041156 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001157 'components/cronet/tools/generate_javadoc.pydeps',
1158 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381159 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001160 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381161 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041162 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181163 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041164 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421165 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1166 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131167 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501168 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061169 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221170 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401171]
1172
wnwenbdc444e2016-05-25 13:44:151173
agrievef32bcc72016-04-04 14:57:401174_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1175
1176
Eric Boren6fd2b932018-01-25 15:05:081177# Bypass the AUTHORS check for these accounts.
1178_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591179 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451180 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591181 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521182 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231183 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471184 'lacros-version-skew-roller', 'skylab-test-cros-roller',
1185 'infra-try-recipes-tester')
Eric Boren835d71f2018-09-07 21:09:041186 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271187 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041188 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161189 for s in ('chromium-internal-autoroll',)
1190 ) | set('%[email protected]' % s
1191 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081192
Matt Stark6ef08872021-07-29 01:21:461193_INVALID_GRD_FILE_LINE = [
1194 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1195]
Eric Boren6fd2b932018-01-25 15:05:081196
Daniel Bratell65b033262019-04-23 08:17:061197def _IsCPlusPlusFile(input_api, file_path):
1198 """Returns True if this file contains C++-like code (and not Python,
1199 Go, Java, MarkDown, ...)"""
1200
1201 ext = input_api.os_path.splitext(file_path)[1]
1202 # This list is compatible with CppChecker.IsCppFile but we should
1203 # consider adding ".c" to it. If we do that we can use this function
1204 # at more places in the code.
1205 return ext in (
1206 '.h',
1207 '.cc',
1208 '.cpp',
1209 '.m',
1210 '.mm',
1211 )
1212
1213def _IsCPlusPlusHeaderFile(input_api, file_path):
1214 return input_api.os_path.splitext(file_path)[1] == ".h"
1215
1216
1217def _IsJavaFile(input_api, file_path):
1218 return input_api.os_path.splitext(file_path)[1] == ".java"
1219
1220
1221def _IsProtoFile(input_api, file_path):
1222 return input_api.os_path.splitext(file_path)[1] == ".proto"
1223
Mohamed Heikal5e5b7922020-10-29 18:57:591224
Erik Staabc734cd7a2021-11-23 03:11:521225def _IsXmlOrGrdFile(input_api, file_path):
1226 ext = input_api.os_path.splitext(file_path)[1]
1227 return ext in ('.grd', '.xml')
1228
1229
Mohamed Heikal5e5b7922020-10-29 18:57:591230def CheckNoUpstreamDepsOnClank(input_api, output_api):
1231 """Prevent additions of dependencies from the upstream repo on //clank."""
1232 # clank can depend on clank
1233 if input_api.change.RepositoryRoot().endswith('clank'):
1234 return []
1235 build_file_patterns = [
1236 r'(.+/)?BUILD\.gn',
1237 r'.+\.gni',
1238 ]
1239 excluded_files = [
1240 r'build[/\\]config[/\\]android[/\\]config\.gni'
1241 ]
1242 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1243
1244 error_message = 'Disallowed import on //clank in an upstream build file:'
1245
1246 def FilterFile(affected_file):
1247 return input_api.FilterSourceFile(
1248 affected_file,
1249 files_to_check=build_file_patterns,
1250 files_to_skip=excluded_files)
1251
1252 problems = []
1253 for f in input_api.AffectedSourceFiles(FilterFile):
1254 local_path = f.LocalPath()
1255 for line_number, line in f.ChangedContents():
1256 if (bad_pattern.search(line)):
1257 problems.append(
1258 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1259 if problems:
1260 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1261 else:
1262 return []
1263
1264
Saagar Sanghavifceeaae2020-08-12 16:40:361265def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191266 """Attempts to prevent use of functions intended only for testing in
1267 non-testing code. For now this is just a best-effort implementation
1268 that ignores header files and may have some false positives. A
1269 better implementation would probably need a proper C++ parser.
1270 """
1271 # We only scan .cc files and the like, as the declaration of
1272 # for-testing functions in header files are hard to distinguish from
1273 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491274 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191275
jochenc0d4808c2015-07-27 09:25:421276 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191277 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091278 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131279 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191280 exclusion_pattern = input_api.re.compile(
1281 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1282 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131283 # Avoid a false positive in this case, where the method name, the ::, and
1284 # the closing { are all on different lines due to line wrapping.
1285 # HelperClassForTesting::
1286 # HelperClassForTesting(
1287 # args)
1288 # : member(0) {}
1289 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191290
1291 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441292 files_to_skip = (_EXCLUDED_PATHS +
1293 _TEST_CODE_EXCLUDED_PATHS +
1294 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191295 return input_api.FilterSourceFile(
1296 affected_file,
James Cook24a504192020-07-23 00:08:441297 files_to_check=file_inclusion_pattern,
1298 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191299
1300 problems = []
1301 for f in input_api.AffectedSourceFiles(FilterFile):
1302 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131303 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241304 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031305 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461306 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131307 not exclusion_pattern.search(line) and
1308 not allowlist_pattern.search(line) and
1309 not in_method_defn):
[email protected]55459852011-08-10 15:17:191310 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031311 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131312 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191313
1314 if problems:
[email protected]f7051d52013-04-02 18:31:421315 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031316 else:
1317 return []
[email protected]55459852011-08-10 15:17:191318
1319
Saagar Sanghavifceeaae2020-08-12 16:40:361320def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231321 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591322 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231323 """
1324 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1325 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1326 name_pattern = r'ForTest(s|ing)?'
1327 # Describes an occurrence of "ForTest*" inside a // comment.
1328 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501329 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551330 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231331 # Catch calls.
1332 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1333 # Ignore definitions. (Comments are ignored separately.)
1334 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1335
1336 problems = []
1337 sources = lambda x: input_api.FilterSourceFile(
1338 x,
James Cook24a504192020-07-23 00:08:441339 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1340 + input_api.DEFAULT_FILES_TO_SKIP),
1341 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231342 )
1343 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1344 local_path = f.LocalPath()
1345 is_inside_javadoc = False
1346 for line_number, line in f.ChangedContents():
1347 if is_inside_javadoc and javadoc_end_re.search(line):
1348 is_inside_javadoc = False
1349 if not is_inside_javadoc and javadoc_start_re.search(line):
1350 is_inside_javadoc = True
1351 if is_inside_javadoc:
1352 continue
1353 if (inclusion_re.search(line) and
1354 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501355 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231356 not exclusion_re.search(line)):
1357 problems.append(
1358 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1359
1360 if problems:
1361 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1362 else:
1363 return []
1364
1365
Saagar Sanghavifceeaae2020-08-12 16:40:361366def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541367 """Checks to make sure no .h files include <iostream>."""
1368 files = []
1369 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1370 input_api.re.MULTILINE)
1371 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1372 if not f.LocalPath().endswith('.h'):
1373 continue
1374 contents = input_api.ReadFile(f)
1375 if pattern.search(contents):
1376 files.append(f)
1377
1378 if len(files):
yolandyandaabc6d2016-04-18 18:29:391379 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061380 'Do not #include <iostream> in header files, since it inserts static '
1381 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541382 '#include <ostream>. See http://crbug.com/94794',
1383 files) ]
1384 return []
1385
Danil Chapovalov3518f362018-08-11 16:13:431386def _CheckNoStrCatRedefines(input_api, output_api):
1387 """Checks no windows headers with StrCat redefined are included directly."""
1388 files = []
1389 pattern_deny = input_api.re.compile(
1390 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1391 input_api.re.MULTILINE)
1392 pattern_allow = input_api.re.compile(
1393 r'^#include\s"base/win/windows_defines.inc"',
1394 input_api.re.MULTILINE)
1395 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1396 contents = input_api.ReadFile(f)
1397 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1398 files.append(f.LocalPath())
1399
1400 if len(files):
1401 return [output_api.PresubmitError(
1402 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1403 'directly since they pollute code with StrCat macro. Instead, '
1404 'include matching header from base/win. See http://crbug.com/856536',
1405 files) ]
1406 return []
1407
[email protected]10689ca2011-09-02 02:31:541408
Saagar Sanghavifceeaae2020-08-12 16:40:361409def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521410 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181411 problems = []
1412 for f in input_api.AffectedFiles():
1413 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1414 continue
1415
1416 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041417 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181418 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1419
1420 if not problems:
1421 return []
1422 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1423 '\n'.join(problems))]
1424
Saagar Sanghavifceeaae2020-08-12 16:40:361425def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341426 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1427
1428 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1429 instead of DISABLED_. To filter false positives, reports are only generated
1430 if a corresponding MAYBE_ line exists.
1431 """
1432 problems = []
1433
1434 # The following two patterns are looked for in tandem - is a test labeled
1435 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1436 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1437 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1438
1439 # This is for the case that a test is disabled on all platforms.
1440 full_disable_pattern = input_api.re.compile(
1441 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1442 input_api.re.MULTILINE)
1443
Katie Df13948e2018-09-25 07:33:441444 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341445 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1446 continue
1447
1448 # Search for MABYE_, DISABLE_ pairs.
1449 disable_lines = {} # Maps of test name to line number.
1450 maybe_lines = {}
1451 for line_num, line in f.ChangedContents():
1452 disable_match = disable_pattern.search(line)
1453 if disable_match:
1454 disable_lines[disable_match.group(1)] = line_num
1455 maybe_match = maybe_pattern.search(line)
1456 if maybe_match:
1457 maybe_lines[maybe_match.group(1)] = line_num
1458
1459 # Search for DISABLE_ occurrences within a TEST() macro.
1460 disable_tests = set(disable_lines.keys())
1461 maybe_tests = set(maybe_lines.keys())
1462 for test in disable_tests.intersection(maybe_tests):
1463 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1464
1465 contents = input_api.ReadFile(f)
1466 full_disable_match = full_disable_pattern.search(contents)
1467 if full_disable_match:
1468 problems.append(' %s' % f.LocalPath())
1469
1470 if not problems:
1471 return []
1472 return [
1473 output_api.PresubmitPromptWarning(
1474 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1475 '\n'.join(problems))
1476 ]
1477
Nina Satragnof7660532021-09-20 18:03:351478def CheckForgettingMAYBEInTests(input_api, output_api):
1479 """Checks to make sure tests disabled conditionally are not missing a
1480 corresponding MAYBE_ prefix.
1481 """
1482 # Expect at least a lowercase character in the test name. This helps rule out
1483 # false positives with macros wrapping the actual tests name.
1484 define_maybe_pattern = input_api.re.compile(
1485 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
1486 test_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*\w+,\s*MAYBE_{test_name}\)'
1487 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1488 warnings = []
1489
1490 # Read the entire files. We can't just read the affected lines, forgetting to
1491 # add MAYBE_ on a change would not show up otherwise.
1492 for f in input_api.AffectedFiles(False):
1493 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1494 continue
1495 contents = input_api.ReadFile(f)
1496 lines = contents.splitlines(True)
1497 current_position = 0
1498 warning_test_names = set()
1499 for line_num, line in enumerate(lines, start=1):
1500 current_position += len(line)
1501 maybe_match = define_maybe_pattern.search(line)
1502 if maybe_match:
1503 test_name = maybe_match.group('test_name')
1504 # Do not warn twice for the same test.
1505 if (test_name in warning_test_names):
1506 continue
1507 warning_test_names.add(test_name)
1508
1509 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1510 # the current position.
1511 test_match = input_api.re.compile(
1512 test_maybe_pattern.format(test_name=test_name),
1513 input_api.re.MULTILINE).search(contents, current_position)
1514 suite_match = input_api.re.compile(
1515 suite_maybe_pattern.format(test_name=test_name),
1516 input_api.re.MULTILINE).search(contents, current_position)
1517 if not test_match and not suite_match:
1518 warnings.append(
1519 output_api.PresubmitPromptWarning(
1520 '%s:%d found MAYBE_ defined without corresponding test %s' %
1521 (f.LocalPath(), line_num, test_name)))
1522 return warnings
[email protected]72df4e782012-06-21 16:28:181523
Saagar Sanghavifceeaae2020-08-12 16:40:361524def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571525 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521526 errors = []
Hans Wennborg944479f2020-06-25 21:39:251527 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521528 input_api.re.MULTILINE)
1529 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1530 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1531 continue
1532 for lnum, line in f.ChangedContents():
1533 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171534 errors.append(output_api.PresubmitError(
1535 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571536 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171537 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521538 return errors
1539
1540
Weilun Shia487fad2020-10-28 00:10:341541# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1542# more reliable way. See
1543# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191544
wnwenbdc444e2016-05-25 13:44:151545
Saagar Sanghavifceeaae2020-08-12 16:40:361546def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391547 """Check that FlakyTest annotation is our own instead of the android one"""
1548 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1549 files = []
1550 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1551 if f.LocalPath().endswith('Test.java'):
1552 if pattern.search(input_api.ReadFile(f)):
1553 files.append(f)
1554 if len(files):
1555 return [output_api.PresubmitError(
1556 'Use org.chromium.base.test.util.FlakyTest instead of '
1557 'android.test.FlakyTest',
1558 files)]
1559 return []
mcasasb7440c282015-02-04 14:52:191560
wnwenbdc444e2016-05-25 13:44:151561
Saagar Sanghavifceeaae2020-08-12 16:40:361562def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441563 """Make sure .DEPS.git is never modified manually."""
1564 if any(f.LocalPath().endswith('.DEPS.git') for f in
1565 input_api.AffectedFiles()):
1566 return [output_api.PresubmitError(
1567 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1568 'automated system based on what\'s in DEPS and your changes will be\n'
1569 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501570 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1571 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441572 'for more information')]
1573 return []
1574
1575
Saagar Sanghavifceeaae2020-08-12 16:40:361576def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471577 """Checks that DEPS file deps are from allowed_hosts."""
1578 # Run only if DEPS file has been modified to annoy fewer bystanders.
1579 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1580 return []
1581 # Outsource work to gclient verify
1582 try:
John Budorickf20c0042019-04-25 23:23:401583 gclient_path = input_api.os_path.join(
1584 input_api.PresubmitLocalPath(),
1585 'third_party', 'depot_tools', 'gclient.py')
1586 input_api.subprocess.check_output(
1587 [input_api.python_executable, gclient_path, 'verify'],
1588 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471589 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201590 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471591 return [output_api.PresubmitError(
1592 'DEPS file must have only git dependencies.',
1593 long_text=error.output)]
1594
1595
Mario Sanchez Prada2472cab2019-09-18 10:58:311596def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1597 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591598 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311599
1600 Returns an string composed of the name of the file, the line number where the
1601 match has been found and the additional text passed as |message| in case the
1602 target type name matches the text inside the line passed as parameter.
1603 """
Peng Huang9c5949a02020-06-11 19:20:541604 result = []
1605
danakjd18e8892020-12-17 17:42:011606 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1607 return result
1608 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541609 return result
1610
Mario Sanchez Prada2472cab2019-09-18 10:58:311611 matched = False
1612 if type_name[0:1] == '/':
1613 regex = type_name[1:]
1614 if input_api.re.search(regex, line):
1615 matched = True
1616 elif type_name in line:
1617 matched = True
1618
Mario Sanchez Prada2472cab2019-09-18 10:58:311619 if matched:
1620 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1621 for message_line in message:
1622 result.append(' %s' % message_line)
1623
1624 return result
1625
1626
Saagar Sanghavifceeaae2020-08-12 16:40:361627def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591628 """Make sure that banned functions are not used."""
1629 warnings = []
1630 errors = []
1631
James Cook24a504192020-07-23 00:08:441632 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151633 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441634 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151635 if input_api.re.match(item, local_path):
1636 return True
1637 return False
1638
Peter K. Lee6c03ccff2019-07-15 14:40:051639 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541640 local_path = affected_file.LocalPath()
1641 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1642 return False
1643 basename = input_api.os_path.basename(local_path)
1644 if 'ios' in basename.split('_'):
1645 return True
1646 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1647 if sep and 'ios' in local_path.split(sep):
1648 return True
1649 return False
1650
wnwenbdc444e2016-05-25 13:44:151651 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311652 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1653 func_name, message)
1654 if problems:
wnwenbdc444e2016-05-25 13:44:151655 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311656 errors.extend(problems)
1657 else:
1658 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151659
Eric Stevensona9a980972017-09-23 00:04:411660 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1661 for f in input_api.AffectedFiles(file_filter=file_filter):
1662 for line_num, line in f.ChangedContents():
1663 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1664 CheckForMatch(f, line_num, line, func_name, message, error)
1665
[email protected]127f18ec2012-06-16 05:05:591666 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1667 for f in input_api.AffectedFiles(file_filter=file_filter):
1668 for line_num, line in f.ChangedContents():
1669 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151670 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591671
Peter K. Lee6c03ccff2019-07-15 14:40:051672 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541673 for line_num, line in f.ChangedContents():
1674 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1675 CheckForMatch(f, line_num, line, func_name, message, error)
1676
Peter K. Lee6c03ccff2019-07-15 14:40:051677 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1678 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1679 for line_num, line in f.ChangedContents():
1680 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1681 CheckForMatch(f, line_num, line, func_name, message, error)
1682
[email protected]127f18ec2012-06-16 05:05:591683 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1684 for f in input_api.AffectedFiles(file_filter=file_filter):
1685 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491686 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441687 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491688 continue
wnwenbdc444e2016-05-25 13:44:151689 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591690
1691 result = []
1692 if (warnings):
1693 result.append(output_api.PresubmitPromptWarning(
1694 'Banned functions were used.\n' + '\n'.join(warnings)))
1695 if (errors):
1696 result.append(output_api.PresubmitError(
1697 'Banned functions were used.\n' + '\n'.join(errors)))
1698 return result
1699
1700
Michael Thiessen44457642020-02-06 00:24:151701def _CheckAndroidNoBannedImports(input_api, output_api):
1702 """Make sure that banned java imports are not used."""
1703 errors = []
1704
1705 def IsException(path, exceptions):
1706 for exception in exceptions:
1707 if (path.startswith(exception)):
1708 return True
1709 return False
1710
1711 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1712 for f in input_api.AffectedFiles(file_filter=file_filter):
1713 for line_num, line in f.ChangedContents():
1714 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1715 if IsException(f.LocalPath(), exceptions):
1716 continue;
1717 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1718 'import ' + import_name, message)
1719 if problems:
1720 errors.extend(problems)
1721 result = []
1722 if (errors):
1723 result.append(output_api.PresubmitError(
1724 'Banned imports were used.\n' + '\n'.join(errors)))
1725 return result
1726
1727
Saagar Sanghavifceeaae2020-08-12 16:40:361728def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311729 """Make sure that old Mojo types are not used."""
1730 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571731 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311732
Mario Sanchez Pradaaab91382019-12-19 08:57:091733 # For any path that is not an "ok" or an "error" path, a warning will be
1734 # raised if deprecated mojo types are found.
1735 ok_paths = ['components/arc']
1736 error_paths = ['third_party/blink', 'content']
1737
Mario Sanchez Prada2472cab2019-09-18 10:58:311738 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1739 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571740 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091741 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311742 continue
1743
1744 for line_num, line in f.ChangedContents():
1745 for func_name, message in _DEPRECATED_MOJO_TYPES:
1746 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1747 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571748
Mario Sanchez Prada2472cab2019-09-18 10:58:311749 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091750 # Raise errors inside |error_paths| and warnings everywhere else.
1751 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571752 errors.extend(problems)
1753 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311754 warnings.extend(problems)
1755
1756 result = []
1757 if (warnings):
1758 result.append(output_api.PresubmitPromptWarning(
1759 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571760 if (errors):
1761 result.append(output_api.PresubmitError(
1762 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311763 return result
1764
1765
Saagar Sanghavifceeaae2020-08-12 16:40:361766def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061767 """Make sure that banned functions are not used."""
1768 files = []
1769 pattern = input_api.re.compile(r'^#pragma\s+once',
1770 input_api.re.MULTILINE)
1771 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1772 if not f.LocalPath().endswith('.h'):
1773 continue
1774 contents = input_api.ReadFile(f)
1775 if pattern.search(contents):
1776 files.append(f)
1777
1778 if files:
1779 return [output_api.PresubmitError(
1780 'Do not use #pragma once in header files.\n'
1781 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1782 files)]
1783 return []
1784
[email protected]127f18ec2012-06-16 05:05:591785
Saagar Sanghavifceeaae2020-08-12 16:40:361786def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121787 """Checks to make sure we don't introduce use of foo ? true : false."""
1788 problems = []
1789 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1790 for f in input_api.AffectedFiles():
1791 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1792 continue
1793
1794 for line_num, line in f.ChangedContents():
1795 if pattern.match(line):
1796 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1797
1798 if not problems:
1799 return []
1800 return [output_api.PresubmitPromptWarning(
1801 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1802 '\n'.join(problems))]
1803
1804
Saagar Sanghavifceeaae2020-08-12 16:40:361805def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281806 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181807 change. Breaking - rules is an error, breaking ! rules is a
1808 warning.
1809 """
Erik Staabc734cd7a2021-11-23 03:11:521810 # Return early if no relevant file types were modified.
1811 for f in input_api.AffectedFiles():
1812 path = f.LocalPath()
1813 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path) or
1814 _IsJavaFile(input_api, path)):
1815 break
1816 else:
1817 return []
1818
mohan.reddyf21db962014-10-16 12:26:471819 import sys
[email protected]55f9f382012-07-31 11:02:181820 # We need to wait until we have an input_api object and use this
1821 # roundabout construct to import checkdeps because this file is
1822 # eval-ed and thus doesn't have __file__.
1823 original_sys_path = sys.path
1824 try:
1825 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471826 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181827 import checkdeps
[email protected]55f9f382012-07-31 11:02:181828 from rules import Rule
1829 finally:
1830 # Restore sys.path to what it was before.
1831 sys.path = original_sys_path
1832
1833 added_includes = []
rhalavati08acd232017-04-03 07:23:281834 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241835 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181836 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061837 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501838 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081839 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061840 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501841 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081842 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061843 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501844 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081845 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181846
[email protected]26385172013-05-09 23:11:351847 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181848
1849 error_descriptions = []
1850 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281851 error_subjects = set()
1852 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361853
[email protected]55f9f382012-07-31 11:02:181854 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1855 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081856 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181857 description_with_path = '%s\n %s' % (path, rule_description)
1858 if rule_type == Rule.DISALLOW:
1859 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281860 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181861 else:
1862 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281863 warning_subjects.add("#includes")
1864
1865 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1866 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081867 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281868 description_with_path = '%s\n %s' % (path, rule_description)
1869 if rule_type == Rule.DISALLOW:
1870 error_descriptions.append(description_with_path)
1871 error_subjects.add("imports")
1872 else:
1873 warning_descriptions.append(description_with_path)
1874 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181875
Jinsuk Kim5a092672017-10-24 22:42:241876 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021877 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081878 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241879 description_with_path = '%s\n %s' % (path, rule_description)
1880 if rule_type == Rule.DISALLOW:
1881 error_descriptions.append(description_with_path)
1882 error_subjects.add("imports")
1883 else:
1884 warning_descriptions.append(description_with_path)
1885 warning_subjects.add("imports")
1886
[email protected]55f9f382012-07-31 11:02:181887 results = []
1888 if error_descriptions:
1889 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281890 'You added one or more %s that violate checkdeps rules.'
1891 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181892 error_descriptions))
1893 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421894 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281895 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181896 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281897 '%s? See relevant DEPS file(s) for details and contacts.' %
1898 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181899 warning_descriptions))
1900 return results
1901
1902
Saagar Sanghavifceeaae2020-08-12 16:40:361903def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:221904 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151905 if input_api.platform == 'win32':
1906 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291907 checkperms_tool = input_api.os_path.join(
1908 input_api.PresubmitLocalPath(),
1909 'tools', 'checkperms', 'checkperms.py')
1910 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471911 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391912 with input_api.CreateTemporaryFile() as file_list:
1913 for f in input_api.AffectedFiles():
1914 # checkperms.py file/directory arguments must be relative to the
1915 # repository.
Dirk Prankee3c9c62d2021-05-18 18:35:591916 file_list.write((f.LocalPath() + '\n').encode('utf8'))
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391917 file_list.close()
1918 args += ['--file-list', file_list.name]
1919 try:
1920 input_api.subprocess.check_output(args)
1921 return []
1922 except input_api.subprocess.CalledProcessError as error:
1923 return [output_api.PresubmitError(
1924 'checkperms.py failed:',
Ari Chivukula45f58dd52021-06-18 04:23:041925 long_text=error.output.decode('utf-8', 'ignore'))]
[email protected]fbcafe5a2012-08-08 15:31:221926
1927
Saagar Sanghavifceeaae2020-08-12 16:40:361928def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:491929 """Makes sure we don't include ui/aura/window_property.h
1930 in header files.
1931 """
1932 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1933 errors = []
1934 for f in input_api.AffectedFiles():
1935 if not f.LocalPath().endswith('.h'):
1936 continue
1937 for line_num, line in f.ChangedContents():
1938 if pattern.match(line):
1939 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1940
1941 results = []
1942 if errors:
1943 results.append(output_api.PresubmitError(
1944 'Header files should not include ui/aura/window_property.h', errors))
1945 return results
1946
1947
Omer Katzcc77ea92021-04-26 10:23:281948def CheckNoInternalHeapIncludes(input_api, output_api):
1949 """Makes sure we don't include any headers from
1950 third_party/blink/renderer/platform/heap/impl or
1951 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1952 third_party/blink/renderer/platform/heap
1953 """
1954 impl_pattern = input_api.re.compile(
1955 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1956 v8_wrapper_pattern = input_api.re.compile(
1957 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"')
1958 file_filter = lambda f: not input_api.re.match(
1959 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1960 f.LocalPath())
1961 errors = []
1962
1963 for f in input_api.AffectedFiles(file_filter=file_filter):
1964 for line_num, line in f.ChangedContents():
1965 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1966 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1967
1968 results = []
1969 if errors:
1970 results.append(output_api.PresubmitError(
1971 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1972 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1973 'relevant counterparts from third_party/blink/renderer/platform/heap',
1974 errors))
1975 return results
1976
1977
[email protected]70ca77752012-11-20 03:45:031978def _CheckForVersionControlConflictsInFile(input_api, f):
1979 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1980 errors = []
1981 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161982 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231983 # First-level headers in markdown look a lot like version control
1984 # conflict markers. http://daringfireball.net/projects/markdown/basics
1985 continue
[email protected]70ca77752012-11-20 03:45:031986 if pattern.match(line):
1987 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1988 return errors
1989
1990
Saagar Sanghavifceeaae2020-08-12 16:40:361991def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:031992 """Usually this is not intentional and will cause a compile failure."""
1993 errors = []
1994 for f in input_api.AffectedFiles():
1995 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1996
1997 results = []
1998 if errors:
1999 results.append(output_api.PresubmitError(
2000 'Version control conflict markers found, please resolve.', errors))
2001 return results
2002
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202003
Saagar Sanghavifceeaae2020-08-12 16:40:362004def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162005 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2006 errors = []
2007 for f in input_api.AffectedFiles():
2008 for line_num, line in f.ChangedContents():
2009 if pattern.search(line):
2010 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2011
2012 results = []
2013 if errors:
2014 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502015 'Found Google support URL addressed by answer number. Please replace '
2016 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162017 return results
2018
[email protected]70ca77752012-11-20 03:45:032019
Saagar Sanghavifceeaae2020-08-12 16:40:362020def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442021 def FilterFile(affected_file):
2022 """Filter function for use with input_api.AffectedSourceFiles,
2023 below. This filters out everything except non-test files from
2024 top-level directories that generally speaking should not hard-code
2025 service URLs (e.g. src/android_webview/, src/content/ and others).
2026 """
2027 return input_api.FilterSourceFile(
2028 affected_file,
James Cook24a504192020-07-23 00:08:442029 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2030 files_to_skip=(_EXCLUDED_PATHS +
2031 _TEST_CODE_EXCLUDED_PATHS +
2032 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442033
reillyi38965732015-11-16 18:27:332034 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2035 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462036 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2037 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442038 problems = [] # items are (filename, line_number, line)
2039 for f in input_api.AffectedSourceFiles(FilterFile):
2040 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462041 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442042 problems.append((f.LocalPath(), line_num, line))
2043
2044 if problems:
[email protected]f7051d52013-04-02 18:31:422045 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442046 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582047 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442048 [' %s:%d: %s' % (
2049 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032050 else:
2051 return []
[email protected]06e6d0ff2012-12-11 01:36:442052
2053
Saagar Sanghavifceeaae2020-08-12 16:40:362054def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292055 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2056 def FileFilter(affected_file):
2057 """Includes directories known to be Chrome OS only."""
2058 return input_api.FilterSourceFile(
2059 affected_file,
James Cook24a504192020-07-23 00:08:442060 files_to_check=('^ash/',
2061 '^chromeos/', # Top-level src/chromeos.
Henrique Ferreiro2e1aa1092021-11-29 22:22:122062 '.*/chromeos/', # Any path component.
James Cook24a504192020-07-23 00:08:442063 '^components/arc',
2064 '^components/exo'),
2065 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292066
2067 prefs = []
2068 priority_prefs = []
2069 for f in input_api.AffectedFiles(file_filter=FileFilter):
2070 for line_num, line in f.ChangedContents():
2071 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2072 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2073 prefs.append(' %s' % line)
2074 if input_api.re.search(
2075 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2076 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2077 priority_prefs.append(' %s' % line)
2078
2079 results = []
2080 if (prefs):
2081 results.append(output_api.PresubmitPromptWarning(
2082 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2083 'by browser sync settings. If these prefs should be controlled by OS '
2084 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2085 if (priority_prefs):
2086 results.append(output_api.PresubmitPromptWarning(
2087 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2088 'controlled by browser sync settings. If these prefs should be '
2089 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2090 'instead.\n' + '\n'.join(prefs)))
2091 return results
2092
2093
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492094# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362095def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272096 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312097 The native_client_sdk directory is excluded because it has auto-generated PNG
2098 files for documentation.
[email protected]d2530012013-01-25 16:39:272099 """
[email protected]d2530012013-01-25 16:39:272100 errors = []
James Cook24a504192020-07-23 00:08:442101 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2102 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312103 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442104 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312105 for f in input_api.AffectedFiles(include_deletes=False,
2106 file_filter=file_filter):
2107 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272108
2109 results = []
2110 if errors:
2111 results.append(output_api.PresubmitError(
2112 'The name of PNG files should not have abbreviations. \n'
2113 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2114 'Contact [email protected] if you have questions.', errors))
2115 return results
2116
2117
Daniel Cheng4dcdb6b2017-04-13 08:30:172118def _ExtractAddRulesFromParsedDeps(parsed_deps):
2119 """Extract the rules that add dependencies from a parsed DEPS file.
2120
2121 Args:
2122 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2123 add_rules = set()
2124 add_rules.update([
2125 rule[1:] for rule in parsed_deps.get('include_rules', [])
2126 if rule.startswith('+') or rule.startswith('!')
2127 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502128 for _, rules in parsed_deps.get('specific_include_rules',
Dirk Prankee3c9c62d2021-05-18 18:35:592129 {}).items():
Daniel Cheng4dcdb6b2017-04-13 08:30:172130 add_rules.update([
2131 rule[1:] for rule in rules
2132 if rule.startswith('+') or rule.startswith('!')
2133 ])
2134 return add_rules
2135
2136
2137def _ParseDeps(contents):
2138 """Simple helper for parsing DEPS files."""
2139 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172140 class _VarImpl:
2141
2142 def __init__(self, local_scope):
2143 self._local_scope = local_scope
2144
2145 def Lookup(self, var_name):
2146 """Implements the Var syntax."""
2147 try:
2148 return self._local_scope['vars'][var_name]
2149 except KeyError:
2150 raise Exception('Var is not defined: %s' % var_name)
2151
2152 local_scope = {}
2153 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172154 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592155 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172156 }
Dirk Pranke1b9e06382021-05-14 01:16:222157
Dirk Prankee3c9c62d2021-05-18 18:35:592158 exec(contents, global_scope, local_scope)
Daniel Cheng4dcdb6b2017-04-13 08:30:172159 return local_scope
2160
2161
2162def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592163 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412164 a set of DEPS entries that we should look up.
2165
2166 For a directory (rather than a specific filename) we fake a path to
2167 a specific filename by adding /DEPS. This is chosen as a file that
2168 will seldom or never be subject to per-file include_rules.
2169 """
[email protected]2b438d62013-11-14 17:54:142170 # We ignore deps entries on auto-generated directories.
2171 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082172
Daniel Cheng4dcdb6b2017-04-13 08:30:172173 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2174 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2175
2176 added_deps = new_deps.difference(old_deps)
2177
[email protected]2b438d62013-11-14 17:54:142178 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172179 for added_dep in added_deps:
2180 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2181 continue
2182 # Assume that a rule that ends in .h is a rule for a specific file.
2183 if added_dep.endswith('.h'):
2184 results.add(added_dep)
2185 else:
2186 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082187 return results
2188
2189
Saagar Sanghavifceeaae2020-08-12 16:40:362190def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552191 """When a dependency prefixed with + is added to a DEPS file, we
2192 want to make sure that the change is reviewed by an OWNER of the
2193 target file or directory, to avoid layering violations from being
2194 introduced. This check verifies that this happens.
2195 """
Joey Mou57048132021-02-26 22:17:552196 # We rely on Gerrit's code-owners to check approvals.
2197 # input_api.gerrit is always set for Chromium, but other projects
2198 # might not use Gerrit.
2199 if not input_api.gerrit:
2200 return []
Edward Lesmes44feb2332021-03-19 01:27:522201 if (input_api.change.issue and
2202 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232203 # Skip OWNERS check when Owners-Override label is approved. This is intended
2204 # for global owners, trusted bots, and on-call sheriffs. Review is still
2205 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522206 return []
Edward Lesmes6fba51082021-01-20 04:20:232207
Daniel Cheng4dcdb6b2017-04-13 08:30:172208 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242209
2210 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492211 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242212 for f in input_api.AffectedFiles(include_deletes=False,
2213 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552214 filename = input_api.os_path.basename(f.LocalPath())
2215 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172216 virtual_depended_on_files.update(_CalculateAddedDeps(
2217 input_api.os_path,
2218 '\n'.join(f.OldContents()),
2219 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552220
[email protected]e871964c2013-05-13 14:14:552221 if not virtual_depended_on_files:
2222 return []
2223
2224 if input_api.is_committing:
2225 if input_api.tbr:
2226 return [output_api.PresubmitNotifyResult(
2227 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272228 if input_api.dry_run:
2229 return [output_api.PresubmitNotifyResult(
2230 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552231 if not input_api.change.issue:
2232 return [output_api.PresubmitError(
2233 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402234 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552235 output = output_api.PresubmitError
2236 else:
2237 output = output_api.PresubmitNotifyResult
2238
tandriied3b7e12016-05-12 14:38:502239 owner_email, reviewers = (
2240 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2241 input_api,
Edward Lesmesa3846442021-02-08 20:20:032242 None,
tandriied3b7e12016-05-12 14:38:502243 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552244
2245 owner_email = owner_email or input_api.change.author_email
2246
Edward Lesmesa3846442021-02-08 20:20:032247 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2248 virtual_depended_on_files, reviewers.union([owner_email]), [])
2249 missing_files = [
2250 f for f in virtual_depended_on_files
2251 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412252
2253 # We strip the /DEPS part that was added by
2254 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2255 # directory.
2256 def StripDeps(path):
2257 start_deps = path.rfind('/DEPS')
2258 if start_deps != -1:
2259 return path[:start_deps]
2260 else:
2261 return path
2262 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552263 for path in missing_files]
2264
2265 if unapproved_dependencies:
2266 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152267 output('You need LGTM from owners of depends-on paths in DEPS that were '
2268 'modified in this CL:\n %s' %
2269 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032270 suggested_owners = input_api.owners_client.SuggestOwners(
2271 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152272 output_list.append(output(
2273 'Suggested missing target path OWNERS:\n %s' %
2274 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552275 return output_list
2276
2277 return []
2278
2279
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492280# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362281def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492282 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442283 files_to_skip = (_EXCLUDED_PATHS +
2284 _TEST_CODE_EXCLUDED_PATHS +
2285 input_api.DEFAULT_FILES_TO_SKIP +
2286 (r"^base[\\/]logging\.h$",
2287 r"^base[\\/]logging\.cc$",
2288 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2289 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2290 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2291 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2292 r"startup_browser_creator\.cc$",
2293 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2294 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2295 r"diagnostics_writer\.cc$",
2296 r"^chrome[\\/]chrome_cleaner[\\/].*",
2297 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2298 r"dll_hash_main\.cc$",
2299 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2300 r"^chromecast[\\/]",
2301 r"^cloud_print[\\/]",
2302 r"^components[\\/]browser_watcher[\\/]"
2303 r"dump_stability_report_main_win.cc$",
2304 r"^components[\\/]media_control[\\/]renderer[\\/]"
2305 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352306 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2307 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442308 r"^components[\\/]zucchini[\\/].*",
2309 # TODO(peter): Remove exception. https://crbug.com/534537
2310 r"^content[\\/]browser[\\/]notifications[\\/]"
2311 r"notification_event_dispatcher_impl\.cc$",
2312 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2313 r"gl_helper_benchmark\.cc$",
2314 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2315 r"^courgette[\\/]courgette_tool\.cc$",
2316 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
David Dorwinfa9aef42021-08-17 06:46:202317 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
James Cook24a504192020-07-23 00:08:442318 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Sergey Ulanov6db14b4d62021-05-10 07:59:482319 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
James Cook24a504192020-07-23 00:08:442320 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2321 r"^ipc[\\/]ipc_logging\.cc$",
2322 r"^native_client_sdk[\\/]",
2323 r"^remoting[\\/]base[\\/]logging\.h$",
2324 r"^remoting[\\/]host[\\/].*",
2325 r"^sandbox[\\/]linux[\\/].*",
2326 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2327 r"dump_file_system.cc$",
2328 r"^tools[\\/]",
2329 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2330 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2331 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2332 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2333 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402334 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442335 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402336
thomasanderson625d3932017-03-29 07:16:582337 log_info = set([])
2338 printf = set([])
[email protected]85218562013-11-22 07:41:402339
2340 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582341 for _, line in f.ChangedContents():
2342 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2343 log_info.add(f.LocalPath())
2344 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2345 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372346
thomasanderson625d3932017-03-29 07:16:582347 if input_api.re.search(r"\bprintf\(", line):
2348 printf.add(f.LocalPath())
2349 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2350 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402351
2352 if log_info:
2353 return [output_api.PresubmitError(
2354 'These files spam the console log with LOG(INFO):',
2355 items=log_info)]
2356 if printf:
2357 return [output_api.PresubmitError(
2358 'These files spam the console log with printf/fprintf:',
2359 items=printf)]
2360 return []
2361
2362
Saagar Sanghavifceeaae2020-08-12 16:40:362363def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162364 """These types are all expected to hold locks while in scope and
2365 so should never be anonymous (which causes them to be immediately
2366 destroyed)."""
2367 they_who_must_be_named = [
2368 'base::AutoLock',
2369 'base::AutoReset',
2370 'base::AutoUnlock',
2371 'SkAutoAlphaRestore',
2372 'SkAutoBitmapShaderInstall',
2373 'SkAutoBlitterChoose',
2374 'SkAutoBounderCommit',
2375 'SkAutoCallProc',
2376 'SkAutoCanvasRestore',
2377 'SkAutoCommentBlock',
2378 'SkAutoDescriptor',
2379 'SkAutoDisableDirectionCheck',
2380 'SkAutoDisableOvalCheck',
2381 'SkAutoFree',
2382 'SkAutoGlyphCache',
2383 'SkAutoHDC',
2384 'SkAutoLockColors',
2385 'SkAutoLockPixels',
2386 'SkAutoMalloc',
2387 'SkAutoMaskFreeImage',
2388 'SkAutoMutexAcquire',
2389 'SkAutoPathBoundsUpdate',
2390 'SkAutoPDFRelease',
2391 'SkAutoRasterClipValidate',
2392 'SkAutoRef',
2393 'SkAutoTime',
2394 'SkAutoTrace',
2395 'SkAutoUnref',
2396 ]
2397 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2398 # bad: base::AutoLock(lock.get());
2399 # not bad: base::AutoLock lock(lock.get());
2400 bad_pattern = input_api.re.compile(anonymous)
2401 # good: new base::AutoLock(lock.get())
2402 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2403 errors = []
2404
2405 for f in input_api.AffectedFiles():
2406 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2407 continue
2408 for linenum, line in f.ChangedContents():
2409 if bad_pattern.search(line) and not good_pattern.search(line):
2410 errors.append('%s:%d' % (f.LocalPath(), linenum))
2411
2412 if errors:
2413 return [output_api.PresubmitError(
2414 'These lines create anonymous variables that need to be named:',
2415 items=errors)]
2416 return []
2417
2418
Saagar Sanghavifceeaae2020-08-12 16:40:362419def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532420 # Returns whether |template_str| is of the form <T, U...> for some types T
2421 # and U. Assumes that |template_str| is already in the form <...>.
2422 def HasMoreThanOneArg(template_str):
2423 # Level of <...> nesting.
2424 nesting = 0
2425 for c in template_str:
2426 if c == '<':
2427 nesting += 1
2428 elif c == '>':
2429 nesting -= 1
2430 elif c == ',' and nesting == 1:
2431 return True
2432 return False
2433
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492434 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102435 sources = lambda affected_file: input_api.FilterSourceFile(
2436 affected_file,
James Cook24a504192020-07-23 00:08:442437 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2438 input_api.DEFAULT_FILES_TO_SKIP),
2439 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552440
2441 # Pattern to capture a single "<...>" block of template arguments. It can
2442 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2443 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2444 # latter would likely require counting that < and > match, which is not
2445 # expressible in regular languages. Should the need arise, one can introduce
2446 # limited counting (matching up to a total number of nesting depth), which
2447 # should cover all practical cases for already a low nesting limit.
2448 template_arg_pattern = (
2449 r'<[^>]*' # Opening block of <.
2450 r'>([^<]*>)?') # Closing block of >.
2451 # Prefix expressing that whatever follows is not already inside a <...>
2452 # block.
2453 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102454 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552455 not_inside_template_arg_pattern
2456 + r'\bstd::unique_ptr'
2457 + template_arg_pattern
2458 + r'\(\)')
2459
2460 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2461 template_arg_no_array_pattern = (
2462 r'<[^>]*[^]]' # Opening block of <.
2463 r'>([^(<]*[^]]>)?') # Closing block of >.
2464 # Prefix saying that what follows is the start of an expression.
2465 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2466 # Suffix saying that what follows are call parentheses with a non-empty list
2467 # of arguments.
2468 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532469 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552470 return_construct_pattern = input_api.re.compile(
2471 start_of_expr_pattern
2472 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532473 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552474 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532475 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552476 + nonempty_arg_list_pattern)
2477
Vaclav Brozek851d9602018-04-04 16:13:052478 problems_constructor = []
2479 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102480 for f in input_api.AffectedSourceFiles(sources):
2481 for line_number, line in f.ChangedContents():
2482 # Disallow:
2483 # return std::unique_ptr<T>(foo);
2484 # bar = std::unique_ptr<T>(foo);
2485 # But allow:
2486 # return std::unique_ptr<T[]>(foo);
2487 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532488 # And also allow cases when the second template argument is present. Those
2489 # cases cannot be handled by std::make_unique:
2490 # return std::unique_ptr<T, U>(foo);
2491 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052492 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532493 return_construct_result = return_construct_pattern.search(line)
2494 if return_construct_result and not HasMoreThanOneArg(
2495 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052496 problems_constructor.append(
2497 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102498 # Disallow:
2499 # std::unique_ptr<T>()
2500 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052501 problems_nullptr.append(
2502 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2503
2504 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162505 if problems_nullptr:
Daniel Cheng2dbf9c42021-10-06 21:26:112506 errors.append(output_api.PresubmitPromptWarning(
Vaclav Brozek851d9602018-04-04 16:13:052507 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162508 problems_nullptr))
2509 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052510 errors.append(output_api.PresubmitError(
Yao Li7f5a705d2021-11-23 22:30:562511 'The following files use explicit std::unique_ptr constructor. '
2512 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2513 'std::make_unique is not an option.',
Vaclav Brozekc2fecf42018-04-06 16:40:162514 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102515 return errors
2516
2517
Saagar Sanghavifceeaae2020-08-12 16:40:362518def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082519 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522520 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082521 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522522 # If actions.xml is already included in the changelist, the PRESUBMIT
2523 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082524 return []
2525
Alexei Svitkine64505a92021-03-11 22:00:542526 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2527 files_to_skip = (_EXCLUDED_PATHS +
2528 _TEST_CODE_EXCLUDED_PATHS +
2529 input_api.DEFAULT_FILES_TO_SKIP )
2530 file_filter = lambda f: input_api.FilterSourceFile(
2531 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2532
[email protected]999261d2014-03-03 20:08:082533 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522534 current_actions = None
[email protected]999261d2014-03-03 20:08:082535 for f in input_api.AffectedFiles(file_filter=file_filter):
2536 for line_num, line in f.ChangedContents():
2537 match = input_api.re.search(action_re, line)
2538 if match:
[email protected]2f92dec2014-03-07 19:21:522539 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2540 # loaded only once.
2541 if not current_actions:
2542 with open('tools/metrics/actions/actions.xml') as actions_f:
2543 current_actions = actions_f.read()
2544 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082545 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522546 action = 'name="{0}"'.format(action_name)
2547 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082548 return [output_api.PresubmitPromptWarning(
2549 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522550 'tools/metrics/actions/actions.xml. Please run '
2551 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082552 % (f.LocalPath(), line_num, action_name))]
2553 return []
2554
2555
Daniel Cheng13ca61a882017-08-25 15:11:252556def _ImportJSONCommentEater(input_api):
2557 import sys
2558 sys.path = sys.path + [input_api.os_path.join(
2559 input_api.PresubmitLocalPath(),
2560 'tools', 'json_comment_eater')]
2561 import json_comment_eater
2562 return json_comment_eater
2563
2564
[email protected]99171a92014-06-03 08:44:472565def _GetJSONParseError(input_api, filename, eat_comments=True):
2566 try:
2567 contents = input_api.ReadFile(filename)
2568 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252569 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132570 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472571
2572 input_api.json.loads(contents)
2573 except ValueError as e:
2574 return e
2575 return None
2576
2577
2578def _GetIDLParseError(input_api, filename):
2579 try:
2580 contents = input_api.ReadFile(filename)
2581 idl_schema = input_api.os_path.join(
2582 input_api.PresubmitLocalPath(),
2583 'tools', 'json_schema_compiler', 'idl_schema.py')
2584 process = input_api.subprocess.Popen(
2585 [input_api.python_executable, idl_schema],
2586 stdin=input_api.subprocess.PIPE,
2587 stdout=input_api.subprocess.PIPE,
2588 stderr=input_api.subprocess.PIPE,
2589 universal_newlines=True)
2590 (_, error) = process.communicate(input=contents)
2591 return error or None
2592 except ValueError as e:
2593 return e
2594
2595
Saagar Sanghavifceeaae2020-08-12 16:40:362596def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472597 """Check that IDL and JSON files do not contain syntax errors."""
2598 actions = {
2599 '.idl': _GetIDLParseError,
2600 '.json': _GetJSONParseError,
2601 }
[email protected]99171a92014-06-03 08:44:472602 # Most JSON files are preprocessed and support comments, but these do not.
2603 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042604 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472605 ]
2606 # Only run IDL checker on files in these directories.
2607 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042608 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2609 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472610 ]
2611
2612 def get_action(affected_file):
2613 filename = affected_file.LocalPath()
2614 return actions.get(input_api.os_path.splitext(filename)[1])
2615
[email protected]99171a92014-06-03 08:44:472616 def FilterFile(affected_file):
2617 action = get_action(affected_file)
2618 if not action:
2619 return False
2620 path = affected_file.LocalPath()
2621
Erik Staab2dd72b12020-04-16 15:03:402622 if _MatchesFile(input_api,
2623 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2624 path):
[email protected]99171a92014-06-03 08:44:472625 return False
2626
2627 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162628 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472629 return False
2630 return True
2631
2632 results = []
2633 for affected_file in input_api.AffectedFiles(
2634 file_filter=FilterFile, include_deletes=False):
2635 action = get_action(affected_file)
2636 kwargs = {}
2637 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162638 _MatchesFile(input_api, json_no_comments_patterns,
2639 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472640 kwargs['eat_comments'] = False
2641 parse_error = action(input_api,
2642 affected_file.AbsoluteLocalPath(),
2643 **kwargs)
2644 if parse_error:
2645 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2646 (affected_file.LocalPath(), parse_error)))
2647 return results
2648
2649
Saagar Sanghavifceeaae2020-08-12 16:40:362650def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492651 """Runs checkstyle on changed java files and returns errors if any exist."""
Erik Staabc734cd7a2021-11-23 03:11:522652
2653 # Return early if no java files were modified.
2654 if not any(_IsJavaFile(input_api, f.LocalPath()) for f in
2655 input_api.AffectedFiles()):
2656 return []
2657
mohan.reddyf21db962014-10-16 12:26:472658 import sys
[email protected]760deea2013-12-10 19:33:492659 original_sys_path = sys.path
2660 try:
2661 sys.path = sys.path + [input_api.os_path.join(
2662 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2663 import checkstyle
2664 finally:
2665 # Restore sys.path to what it was before.
2666 sys.path = original_sys_path
2667
2668 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092669 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442670 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492671
2672
Saagar Sanghavifceeaae2020-08-12 16:40:362673def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002674 """Checks to make sure devil is initialized correctly in python scripts."""
2675 script_common_initialize_pattern = input_api.re.compile(
2676 r'script_common\.InitializeEnvironment\(')
2677 devil_env_config_initialize = input_api.re.compile(
2678 r'devil_env\.config\.Initialize\(')
2679
2680 errors = []
2681
2682 sources = lambda affected_file: input_api.FilterSourceFile(
2683 affected_file,
James Cook24a504192020-07-23 00:08:442684 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2685 (r'^build[\\/]android[\\/]devil_chromium\.py',
2686 r'^third_party[\\/].*',)),
2687 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002688
2689 for f in input_api.AffectedSourceFiles(sources):
2690 for line_num, line in f.ChangedContents():
2691 if (script_common_initialize_pattern.search(line) or
2692 devil_env_config_initialize.search(line)):
2693 errors.append("%s:%d" % (f.LocalPath(), line_num))
2694
2695 results = []
2696
2697 if errors:
2698 results.append(output_api.PresubmitError(
2699 'Devil initialization should always be done using '
2700 'devil_chromium.Initialize() in the chromium project, to use better '
2701 'defaults for dependencies (ex. up-to-date version of adb).',
2702 errors))
2703
2704 return results
2705
2706
Sean Kau46e29bc2017-08-28 16:31:162707def _MatchesFile(input_api, patterns, path):
2708 for pattern in patterns:
2709 if input_api.re.search(pattern, path):
2710 return True
2711 return False
2712
2713
Daniel Cheng7052cdf2017-11-21 19:23:292714def _GetOwnersFilesToCheckForIpcOwners(input_api):
2715 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172716
Daniel Cheng7052cdf2017-11-21 19:23:292717 Returns:
2718 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2719 contain to cover IPC-related files with noparent reviewer rules.
2720 """
2721 # Whether or not a file affects IPC is (mostly) determined by a simple list
2722 # of filename patterns.
dchenge07de812016-06-20 19:27:172723 file_patterns = [
palmerb19a0932017-01-24 04:00:312724 # Legacy IPC:
dchenge07de812016-06-20 19:27:172725 '*_messages.cc',
2726 '*_messages*.h',
2727 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312728 # Mojo IPC:
dchenge07de812016-06-20 19:27:172729 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472730 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172731 '*_struct_traits*.*',
2732 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312733 '*.typemap',
2734 # Android native IPC:
2735 '*.aidl',
2736 # Blink uses a different file naming convention:
2737 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472738 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172739 '*StructTraits*.*',
2740 '*TypeConverter*.*',
2741 ]
2742
scottmg7a6ed5ba2016-11-04 18:22:042743 # These third_party directories do not contain IPCs, but contain files
2744 # matching the above patterns, which trigger false positives.
2745 exclude_paths = [
2746 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162747 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232748 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292749 'third_party/win_build_output/*',
Scott Violet9f82d362019-11-06 21:42:162750 # These files are just used to communicate between class loaders running
2751 # in the same process.
2752 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572753 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2754
scottmg7a6ed5ba2016-11-04 18:22:042755 ]
2756
dchenge07de812016-06-20 19:27:172757 # Dictionary mapping an OWNERS file path to Patterns.
2758 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2759 # rules ) to a PatternEntry.
2760 # PatternEntry is a dictionary with two keys:
2761 # - 'files': the files that are matched by this pattern
2762 # - 'rules': the per-file rules needed for this pattern
2763 # For example, if we expect OWNERS file to contain rules for *.mojom and
2764 # *_struct_traits*.*, Patterns might look like this:
2765 # {
2766 # '*.mojom': {
2767 # 'files': ...,
2768 # 'rules': [
2769 # 'per-file *.mojom=set noparent',
2770 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2771 # ],
2772 # },
2773 # '*_struct_traits*.*': {
2774 # 'files': ...,
2775 # 'rules': [
2776 # 'per-file *_struct_traits*.*=set noparent',
2777 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2778 # ],
2779 # },
2780 # }
2781 to_check = {}
2782
Daniel Cheng13ca61a882017-08-25 15:11:252783 def AddPatternToCheck(input_file, pattern):
2784 owners_file = input_api.os_path.join(
2785 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2786 if owners_file not in to_check:
2787 to_check[owners_file] = {}
2788 if pattern not in to_check[owners_file]:
2789 to_check[owners_file][pattern] = {
2790 'files': [],
2791 'rules': [
2792 'per-file %s=set noparent' % pattern,
2793 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2794 ]
2795 }
Vaclav Brozekd5de76a2018-03-17 07:57:502796 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252797
dchenge07de812016-06-20 19:27:172798 # Iterate through the affected files to see what we actually need to check
2799 # for. We should only nag patch authors about per-file rules if a file in that
2800 # directory would match that pattern. If a directory only contains *.mojom
2801 # files and no *_messages*.h files, we should only nag about rules for
2802 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252803 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262804 # Manifest files don't have a strong naming convention. Instead, try to find
2805 # affected .cc and .h files which look like they contain a manifest
2806 # definition.
2807 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2808 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2809 if (manifest_pattern.search(f.LocalPath()) and not
2810 test_manifest_pattern.search(f.LocalPath())):
2811 # We expect all actual service manifest files to contain at least one
2812 # qualified reference to service_manager::Manifest.
2813 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252814 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172815 for pattern in file_patterns:
2816 if input_api.fnmatch.fnmatch(
2817 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042818 skip = False
2819 for exclude in exclude_paths:
2820 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2821 skip = True
2822 break
2823 if skip:
2824 continue
Daniel Cheng13ca61a882017-08-25 15:11:252825 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172826 break
2827
Daniel Cheng7052cdf2017-11-21 19:23:292828 return to_check
2829
2830
Wez17c66962020-04-29 15:26:032831def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2832 """Adds OWNERS files to check for correct Fuchsia security owners."""
2833
2834 file_patterns = [
2835 # Component specifications.
2836 '*.cml', # Component Framework v2.
2837 '*.cmx', # Component Framework v1.
2838
2839 # Fuchsia IDL protocol specifications.
2840 '*.fidl',
2841 ]
2842
Joshua Peraza1ca6d392020-12-08 00:14:092843 # Don't check for owners files for changes in these directories.
2844 exclude_paths = [
2845 'third_party/crashpad/*',
2846 ]
2847
Wez17c66962020-04-29 15:26:032848 def AddPatternToCheck(input_file, pattern):
2849 owners_file = input_api.os_path.join(
2850 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2851 if owners_file not in to_check:
2852 to_check[owners_file] = {}
2853 if pattern not in to_check[owners_file]:
2854 to_check[owners_file][pattern] = {
2855 'files': [],
2856 'rules': [
2857 'per-file %s=set noparent' % pattern,
2858 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2859 ]
2860 }
2861 to_check[owners_file][pattern]['files'].append(input_file)
2862
2863 # Iterate through the affected files to see what we actually need to check
2864 # for. We should only nag patch authors about per-file rules if a file in that
2865 # directory would match that pattern.
2866 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092867 skip = False
2868 for exclude in exclude_paths:
2869 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2870 skip = True
2871 if skip:
2872 continue
2873
Wez17c66962020-04-29 15:26:032874 for pattern in file_patterns:
2875 if input_api.fnmatch.fnmatch(
2876 input_api.os_path.basename(f.LocalPath()), pattern):
2877 AddPatternToCheck(f, pattern)
2878 break
2879
2880 return to_check
2881
2882
Saagar Sanghavifceeaae2020-08-12 16:40:362883def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292884 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2885 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032886 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292887
2888 if to_check:
2889 # If there are any OWNERS files to check, there are IPC-related changes in
2890 # this CL. Auto-CC the review list.
2891 output_api.AppendCC('[email protected]')
2892
2893 # Go through the OWNERS files to check, filtering out rules that are already
2894 # present in that OWNERS file.
Dirk Prankee3c9c62d2021-05-18 18:35:592895 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172896 try:
Dirk Prankee3c9c62d2021-05-18 18:35:592897 with open(owners_file) as f:
dchenge07de812016-06-20 19:27:172898 lines = set(f.read().splitlines())
Jeffrey Youngf3a5c8c42021-05-14 21:56:102899 for entry in patterns.values():
dchenge07de812016-06-20 19:27:172900 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2901 ]
2902 except IOError:
2903 # No OWNERS file, so all the rules are definitely missing.
2904 continue
2905
2906 # All the remaining lines weren't found in OWNERS files, so emit an error.
2907 errors = []
Dirk Prankee3c9c62d2021-05-18 18:35:592908 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172909 missing_lines = []
2910 files = []
Dirk Prankee3c9c62d2021-05-18 18:35:592911 for _, entry in patterns.items():
dchenge07de812016-06-20 19:27:172912 missing_lines.extend(entry['rules'])
2913 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2914 if missing_lines:
2915 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052916 'Because of the presence of files:\n%s\n\n'
2917 '%s needs the following %d lines added:\n\n%s' %
2918 ('\n'.join(files), owners_file, len(missing_lines),
2919 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172920
2921 results = []
2922 if errors:
vabrf5ce3bf92016-07-11 14:52:412923 if input_api.is_committing:
2924 output = output_api.PresubmitError
2925 else:
2926 output = output_api.PresubmitPromptWarning
2927 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592928 'Found OWNERS files that need to be updated for IPC security ' +
2929 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172930 long_text='\n\n'.join(errors)))
2931
2932 return results
2933
2934
Robert Sesek2c905332020-05-06 23:17:132935def _GetFilesUsingSecurityCriticalFunctions(input_api):
2936 """Checks affected files for changes to security-critical calls. This
2937 function checks the full change diff, to catch both additions/changes
2938 and removals.
2939
2940 Returns a dict keyed by file name, and the value is a set of detected
2941 functions.
2942 """
2943 # Map of function pretty name (displayed in an error) to the pattern to
2944 # match it with.
2945 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:372946 'content::GetServiceSandboxType<>()':
2947 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:132948 }
2949 _PATTERNS_TO_CHECK = {
2950 k: input_api.re.compile(v)
2951 for k, v in _PATTERNS_TO_CHECK.items()
2952 }
2953
2954 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2955 files_to_functions = {}
2956 for f in input_api.AffectedFiles():
2957 diff = f.GenerateScmDiff()
2958 for line in diff.split('\n'):
2959 # Not using just RightHandSideLines() because removing a
2960 # call to a security-critical function can be just as important
2961 # as adding or changing the arguments.
2962 if line.startswith('-') or (line.startswith('+') and
2963 not line.startswith('++')):
2964 for name, pattern in _PATTERNS_TO_CHECK.items():
2965 if pattern.search(line):
2966 path = f.LocalPath()
2967 if not path in files_to_functions:
2968 files_to_functions[path] = set()
2969 files_to_functions[path].add(name)
2970 return files_to_functions
2971
2972
Saagar Sanghavifceeaae2020-08-12 16:40:362973def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:132974 """Checks that changes involving security-critical functions are reviewed
2975 by the security team.
2976 """
2977 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:122978 if not len(files_to_functions):
2979 return []
Robert Sesek2c905332020-05-06 23:17:132980
Edward Lesmes1e9fade2021-02-08 20:31:122981 owner_email, reviewers = (
2982 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2983 input_api,
2984 None,
2985 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:132986
Edward Lesmes1e9fade2021-02-08 20:31:122987 # Load the OWNERS file for security changes.
2988 owners_file = 'ipc/SECURITY_OWNERS'
2989 security_owners = input_api.owners_client.ListOwners(owners_file)
2990 has_security_owner = any([owner in reviewers for owner in security_owners])
2991 if has_security_owner:
2992 return []
Robert Sesek2c905332020-05-06 23:17:132993
Edward Lesmes1e9fade2021-02-08 20:31:122994 msg = 'The following files change calls to security-sensive functions\n' \
2995 'that need to be reviewed by {}.\n'.format(owners_file)
2996 for path, names in files_to_functions.items():
2997 msg += ' {}\n'.format(path)
2998 for name in names:
2999 msg += ' {}\n'.format(name)
3000 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133001
Edward Lesmes1e9fade2021-02-08 20:31:123002 if input_api.is_committing:
3003 output = output_api.PresubmitError
3004 else:
3005 output = output_api.PresubmitNotifyResult
3006 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133007
3008
Saagar Sanghavifceeaae2020-08-12 16:40:363009def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263010 """Checks that set noparent is only used together with an OWNERS file in
3011 //build/OWNERS.setnoparent (see also
3012 //docs/code_reviews.md#owners-files-details)
3013 """
Erik Staabc734cd7a2021-11-23 03:11:523014 # Return early if no OWNERS files were modified.
3015 if not any(f.LocalPath().endswith('OWNERS') for f in
3016 input_api.AffectedFiles(include_deletes=False)):
3017 return []
3018
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263019 errors = []
3020
3021 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3022 allowed_owners_files = set()
3023 with open(allowed_owners_files_file, 'r') as f:
3024 for line in f:
3025 line = line.strip()
3026 if not line or line.startswith('#'):
3027 continue
3028 allowed_owners_files.add(line)
3029
3030 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3031
3032 for f in input_api.AffectedFiles(include_deletes=False):
3033 if not f.LocalPath().endswith('OWNERS'):
3034 continue
3035
3036 found_owners_files = set()
3037 found_set_noparent_lines = dict()
3038
3039 # Parse the OWNERS file.
3040 for lineno, line in enumerate(f.NewContents(), 1):
3041 line = line.strip()
3042 if line.startswith('set noparent'):
3043 found_set_noparent_lines[''] = lineno
3044 if line.startswith('file://'):
3045 if line in allowed_owners_files:
3046 found_owners_files.add('')
3047 if line.startswith('per-file'):
3048 match = per_file_pattern.match(line)
3049 if match:
3050 glob = match.group(1).strip()
3051 directive = match.group(2).strip()
3052 if directive == 'set noparent':
3053 found_set_noparent_lines[glob] = lineno
3054 if directive.startswith('file://'):
3055 if directive in allowed_owners_files:
3056 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153057
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263058 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403059 # listed in build/OWNERS.setnoparent. An exception is made for top level
3060 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143061 if (f.LocalPath().count('/') != 1 and
3062 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403063 for set_noparent_line in found_set_noparent_lines:
3064 if set_noparent_line in found_owners_files:
3065 continue
3066 errors.append(' %s:%d' % (f.LocalPath(),
3067 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263068
3069 results = []
3070 if errors:
3071 if input_api.is_committing:
3072 output = output_api.PresubmitError
3073 else:
3074 output = output_api.PresubmitPromptWarning
3075 results.append(output(
3076 'Found the following "set noparent" restrictions in OWNERS files that '
3077 'do not include owners from build/OWNERS.setnoparent:',
3078 long_text='\n\n'.join(errors)))
3079 return results
3080
3081
Saagar Sanghavifceeaae2020-08-12 16:40:363082def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313083 """Checks that added or removed lines in non third party affected
3084 header files do not lead to new useless class or struct forward
3085 declaration.
jbriance9e12f162016-11-25 07:57:503086 """
3087 results = []
3088 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3089 input_api.re.MULTILINE)
3090 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3091 input_api.re.MULTILINE)
3092 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313093 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193094 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493095 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313096 continue
3097
jbriance9e12f162016-11-25 07:57:503098 if not f.LocalPath().endswith('.h'):
3099 continue
3100
3101 contents = input_api.ReadFile(f)
3102 fwd_decls = input_api.re.findall(class_pattern, contents)
3103 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3104
3105 useless_fwd_decls = []
3106 for decl in fwd_decls:
3107 count = sum(1 for _ in input_api.re.finditer(
3108 r'\b%s\b' % input_api.re.escape(decl), contents))
3109 if count == 1:
3110 useless_fwd_decls.append(decl)
3111
3112 if not useless_fwd_decls:
3113 continue
3114
3115 for line in f.GenerateScmDiff().splitlines():
3116 if (line.startswith('-') and not line.startswith('--') or
3117 line.startswith('+') and not line.startswith('++')):
3118 for decl in useless_fwd_decls:
3119 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3120 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243121 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503122 (f.LocalPath(), decl)))
3123 useless_fwd_decls.remove(decl)
3124
3125 return results
3126
Jinsong Fan91ebbbd2019-04-16 14:57:173127def _CheckAndroidDebuggableBuild(input_api, output_api):
3128 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3129 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3130 this is a debuggable build of Android.
3131 """
3132 build_type_check_pattern = input_api.re.compile(
3133 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3134
3135 errors = []
3136
3137 sources = lambda affected_file: input_api.FilterSourceFile(
3138 affected_file,
James Cook24a504192020-07-23 00:08:443139 files_to_skip=(_EXCLUDED_PATHS +
3140 _TEST_CODE_EXCLUDED_PATHS +
3141 input_api.DEFAULT_FILES_TO_SKIP +
3142 (r"^android_webview[\\/]support_library[\\/]"
3143 "boundary_interfaces[\\/]",
3144 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3145 r'^third_party[\\/].*',
3146 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3147 r"webview[\\/]chromium[\\/]License.*",)),
3148 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173149
3150 for f in input_api.AffectedSourceFiles(sources):
3151 for line_num, line in f.ChangedContents():
3152 if build_type_check_pattern.search(line):
3153 errors.append("%s:%d" % (f.LocalPath(), line_num))
3154
3155 results = []
3156
3157 if errors:
3158 results.append(output_api.PresubmitPromptWarning(
3159 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3160 ' Please use BuildInfo.isDebugAndroid() instead.',
3161 errors))
3162
3163 return results
jbriance9e12f162016-11-25 07:57:503164
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493165# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293166def _CheckAndroidToastUsage(input_api, output_api):
3167 """Checks that code uses org.chromium.ui.widget.Toast instead of
3168 android.widget.Toast (Chromium Toast doesn't force hardware
3169 acceleration on low-end devices, saving memory).
3170 """
3171 toast_import_pattern = input_api.re.compile(
3172 r'^import android\.widget\.Toast;$')
3173
3174 errors = []
3175
3176 sources = lambda affected_file: input_api.FilterSourceFile(
3177 affected_file,
James Cook24a504192020-07-23 00:08:443178 files_to_skip=(_EXCLUDED_PATHS +
3179 _TEST_CODE_EXCLUDED_PATHS +
3180 input_api.DEFAULT_FILES_TO_SKIP +
3181 (r'^chromecast[\\/].*',
3182 r'^remoting[\\/].*')),
3183 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293184
3185 for f in input_api.AffectedSourceFiles(sources):
3186 for line_num, line in f.ChangedContents():
3187 if toast_import_pattern.search(line):
3188 errors.append("%s:%d" % (f.LocalPath(), line_num))
3189
3190 results = []
3191
3192 if errors:
3193 results.append(output_api.PresubmitError(
3194 'android.widget.Toast usage is detected. Android toasts use hardware'
3195 ' acceleration, and can be\ncostly on low-end devices. Please use'
3196 ' org.chromium.ui.widget.Toast instead.\n'
3197 'Contact [email protected] if you have any questions.',
3198 errors))
3199
3200 return results
3201
3202
dgnaa68d5e2015-06-10 10:08:223203def _CheckAndroidCrLogUsage(input_api, output_api):
3204 """Checks that new logs using org.chromium.base.Log:
3205 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513206 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223207 """
pkotwicza1dd0b002016-05-16 14:41:043208
torne89540622017-03-24 19:41:303209 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043210 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303211 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043212 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303213 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043214 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3215 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093216 # The customtabs_benchmark is a small app that does not depend on Chromium
3217 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043218 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043219 ]
3220
dgnaa68d5e2015-06-10 10:08:223221 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123222 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3223 class_in_base_pattern = input_api.re.compile(
3224 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3225 has_some_log_import_pattern = input_api.re.compile(
3226 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223227 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553228 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223229 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463230 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553231 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223232
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463233 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443234 sources = lambda x: input_api.FilterSourceFile(x,
3235 files_to_check=[r'.*\.java$'],
3236 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123237
dgnaa68d5e2015-06-10 10:08:223238 tag_decl_errors = []
3239 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123240 tag_errors = []
dgn38736db2015-09-18 19:20:513241 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123242 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223243
3244 for f in input_api.AffectedSourceFiles(sources):
3245 file_content = input_api.ReadFile(f)
3246 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223247 # Per line checks
dgn87d9fb62015-06-12 09:15:123248 if (cr_log_import_pattern.search(file_content) or
3249 (class_in_base_pattern.search(file_content) and
3250 not has_some_log_import_pattern.search(file_content))):
3251 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223252 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553253 if rough_log_decl_pattern.search(line):
3254 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223255
3256 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123257 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223258 if match:
3259 has_modified_logs = True
3260
3261 # Make sure it uses "TAG"
3262 if not match.group('tag') == 'TAG':
3263 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123264 else:
3265 # Report non cr Log function calls in changed lines
3266 for line_num, line in f.ChangedContents():
3267 if log_call_pattern.search(line):
3268 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223269
3270 # Per file checks
3271 if has_modified_logs:
3272 # Make sure the tag is using the "cr" prefix and is not too long
3273 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513274 tag_name = match.group('name') if match else None
3275 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223276 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513277 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223278 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513279 elif '.' in tag_name:
3280 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223281
3282 results = []
3283 if tag_decl_errors:
3284 results.append(output_api.PresubmitPromptWarning(
3285 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513286 '"private static final String TAG = "<package tag>".\n'
3287 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223288 tag_decl_errors))
3289
3290 if tag_length_errors:
3291 results.append(output_api.PresubmitError(
3292 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513293 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223294 tag_length_errors))
3295
3296 if tag_errors:
3297 results.append(output_api.PresubmitPromptWarning(
3298 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3299 tag_errors))
3300
dgn87d9fb62015-06-12 09:15:123301 if util_log_errors:
dgn4401aa52015-04-29 16:26:173302 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123303 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3304 util_log_errors))
3305
dgn38736db2015-09-18 19:20:513306 if tag_with_dot_errors:
3307 results.append(output_api.PresubmitPromptWarning(
3308 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3309 tag_with_dot_errors))
3310
dgn4401aa52015-04-29 16:26:173311 return results
3312
3313
Yoland Yanb92fa522017-08-28 17:37:063314def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3315 """Checks that junit.framework.* is no longer used."""
3316 deprecated_junit_framework_pattern = input_api.re.compile(
3317 r'^import junit\.framework\..*;',
3318 input_api.re.MULTILINE)
3319 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443320 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063321 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133322 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063323 for line_num, line in f.ChangedContents():
3324 if deprecated_junit_framework_pattern.search(line):
3325 errors.append("%s:%d" % (f.LocalPath(), line_num))
3326
3327 results = []
3328 if errors:
3329 results.append(output_api.PresubmitError(
3330 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3331 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3332 ' if you have any question.', errors))
3333 return results
3334
3335
3336def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3337 """Checks that if new Java test classes have inheritance.
3338 Either the new test class is JUnit3 test or it is a JUnit4 test class
3339 with a base class, either case is undesirable.
3340 """
3341 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3342
3343 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443344 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063345 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133346 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063347 if not f.OldContents():
3348 class_declaration_start_flag = False
3349 for line_num, line in f.ChangedContents():
3350 if class_declaration_pattern.search(line):
3351 class_declaration_start_flag = True
3352 if class_declaration_start_flag and ' extends ' in line:
3353 errors.append('%s:%d' % (f.LocalPath(), line_num))
3354 if '{' in line:
3355 class_declaration_start_flag = False
3356
3357 results = []
3358 if errors:
3359 results.append(output_api.PresubmitPromptWarning(
3360 'The newly created files include Test classes that inherits from base'
3361 ' class. Please do not use inheritance in JUnit4 tests or add new'
3362 ' JUnit3 tests. Contact [email protected] if you have any'
3363 ' questions.', errors))
3364 return results
3365
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203366
yolandyan45001472016-12-21 21:12:423367def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3368 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3369 deprecated_annotation_import_pattern = input_api.re.compile(
3370 r'^import android\.test\.suitebuilder\.annotation\..*;',
3371 input_api.re.MULTILINE)
3372 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443373 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423374 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133375 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423376 for line_num, line in f.ChangedContents():
3377 if deprecated_annotation_import_pattern.search(line):
3378 errors.append("%s:%d" % (f.LocalPath(), line_num))
3379
3380 results = []
3381 if errors:
3382 results.append(output_api.PresubmitError(
3383 'Annotations in android.test.suitebuilder.annotation have been'
3384 ' deprecated since API level 24. Please use android.support.test.filters'
3385 ' from //third_party/android_support_test_runner:runner_java instead.'
3386 ' Contact [email protected] if you have any questions.', errors))
3387 return results
3388
3389
agrieve7b6479d82015-10-07 14:24:223390def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3391 """Checks if MDPI assets are placed in a correct directory."""
3392 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3393 ('/res/drawable/' in f.LocalPath() or
3394 '/res/drawable-ldrtl/' in f.LocalPath()))
3395 errors = []
3396 for f in input_api.AffectedFiles(include_deletes=False,
3397 file_filter=file_filter):
3398 errors.append(' %s' % f.LocalPath())
3399
3400 results = []
3401 if errors:
3402 results.append(output_api.PresubmitError(
3403 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3404 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3405 '/res/drawable-ldrtl/.\n'
3406 'Contact [email protected] if you have questions.', errors))
3407 return results
3408
3409
Nate Fischer535972b2017-09-16 01:06:183410def _CheckAndroidWebkitImports(input_api, output_api):
3411 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353412 android.webview.ValueCallback except in the WebView glue layer
3413 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183414 """
3415 valuecallback_import_pattern = input_api.re.compile(
3416 r'^import android\.webkit\.ValueCallback;$')
3417
3418 errors = []
3419
3420 sources = lambda affected_file: input_api.FilterSourceFile(
3421 affected_file,
James Cook24a504192020-07-23 00:08:443422 files_to_skip=(_EXCLUDED_PATHS +
3423 _TEST_CODE_EXCLUDED_PATHS +
3424 input_api.DEFAULT_FILES_TO_SKIP +
3425 (r'^android_webview[\\/]glue[\\/].*',
3426 r'^weblayer[\\/].*',)),
3427 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183428
3429 for f in input_api.AffectedSourceFiles(sources):
3430 for line_num, line in f.ChangedContents():
3431 if valuecallback_import_pattern.search(line):
3432 errors.append("%s:%d" % (f.LocalPath(), line_num))
3433
3434 results = []
3435
3436 if errors:
3437 results.append(output_api.PresubmitError(
3438 'android.webkit.ValueCallback usage is detected outside of the glue'
3439 ' layer. To stay compatible with the support library, android.webkit.*'
3440 ' classes should only be used inside the glue layer and'
3441 ' org.chromium.base.Callback should be used instead.',
3442 errors))
3443
3444 return results
3445
3446
Becky Zhou7c69b50992018-12-10 19:37:573447def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3448 """Checks Android XML styles """
Erik Staabc734cd7a2021-11-23 03:11:523449
3450 # Return early if no relevant files were modified.
3451 if not any(_IsXmlOrGrdFile(input_api, f.LocalPath()) for f in
3452 input_api.AffectedFiles(include_deletes=False)):
3453 return []
3454
Becky Zhou7c69b50992018-12-10 19:37:573455 import sys
3456 original_sys_path = sys.path
3457 try:
3458 sys.path = sys.path + [input_api.os_path.join(
3459 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3460 import checkxmlstyle
3461 finally:
3462 # Restore sys.path to what it was before.
3463 sys.path = original_sys_path
3464
3465 if is_check_on_upload:
3466 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3467 else:
3468 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3469
3470
agrievef32bcc72016-04-04 14:57:403471class PydepsChecker(object):
3472 def __init__(self, input_api, pydeps_files):
3473 self._file_cache = {}
3474 self._input_api = input_api
3475 self._pydeps_files = pydeps_files
3476
3477 def _LoadFile(self, path):
3478 """Returns the list of paths within a .pydeps file relative to //."""
3479 if path not in self._file_cache:
Mohamed Heikal112874d2021-11-15 14:42:203480 with open(path, encoding='utf-8') as f:
agrievef32bcc72016-04-04 14:57:403481 self._file_cache[path] = f.read()
3482 return self._file_cache[path]
3483
3484 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3485 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393486 pydeps_data = self._LoadFile(pydeps_path)
3487 uses_gn_paths = '--gn-paths' in pydeps_data
3488 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3489 if uses_gn_paths:
3490 # Paths look like: //foo/bar/baz
3491 return (e[2:] for e in entries)
3492 else:
3493 # Paths look like: path/relative/to/file.pydeps
3494 os_path = self._input_api.os_path
3495 pydeps_dir = os_path.dirname(pydeps_path)
3496 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403497
3498 def _CreateFilesToPydepsMap(self):
3499 """Returns a map of local_path -> list_of_pydeps."""
3500 ret = {}
3501 for pydep_local_path in self._pydeps_files:
3502 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3503 ret.setdefault(path, []).append(pydep_local_path)
3504 return ret
3505
3506 def ComputeAffectedPydeps(self):
3507 """Returns an iterable of .pydeps files that might need regenerating."""
3508 affected_pydeps = set()
3509 file_to_pydeps_map = None
3510 for f in self._input_api.AffectedFiles(include_deletes=True):
3511 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463512 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3513 # subrepositories. We can't figure out which files change, so re-check
3514 # all files.
3515 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383516 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3517 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403518 return self._pydeps_files
3519 elif local_path.endswith('.pydeps'):
3520 if local_path in self._pydeps_files:
3521 affected_pydeps.add(local_path)
3522 elif local_path.endswith('.py'):
3523 if file_to_pydeps_map is None:
3524 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3525 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3526 return affected_pydeps
3527
3528 def DetermineIfStale(self, pydeps_path):
3529 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413530 import difflib
John Budorick47ca3fe2018-02-10 00:53:103531 import os
3532
agrievef32bcc72016-04-04 14:57:403533 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033534 if old_pydeps_data:
3535 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393536 if '--output' not in cmd:
3537 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033538 old_contents = old_pydeps_data[2:]
3539 else:
3540 # A default cmd that should work in most cases (as long as pydeps filename
3541 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3542 # file is empty/new.
3543 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3544 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3545 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103546 env = dict(os.environ)
3547 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403548 new_pydeps_data = self._input_api.subprocess.check_output(
Mohamed Heikal112874d2021-11-15 14:42:203549 cmd + ' --output ""', shell=True, env=env, encoding='utf-8')
phajdan.jr0d9878552016-11-04 10:49:413550 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033551 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413552 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403553
3554
Tibor Goldschwendt360793f72019-06-25 18:23:493555def _ParseGclientArgs():
3556 args = {}
3557 with open('build/config/gclient_args.gni', 'r') as f:
3558 for line in f:
3559 line = line.strip()
3560 if not line or line.startswith('#'):
3561 continue
3562 attribute, value = line.split('=')
3563 args[attribute.strip()] = value.strip()
3564 return args
3565
3566
Saagar Sanghavifceeaae2020-08-12 16:40:363567def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403568 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403569 # This check is for Python dependency lists (.pydeps files), and involves
3570 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
Erik Staabc734cd7a2021-11-23 03:11:523571 # doesn't work on Windows and Mac, so skip it on other platforms and skip if
3572 # no pydeps files are affected.
Mohamed Heikal112874d2021-11-15 14:42:203573 if not input_api.platform.startswith('linux'):
agrievebb9c5b472016-04-22 15:13:003574 return []
Erik Staabc734cd7a2021-11-23 03:11:523575 if not any(f.LocalPath().endswith('.pydeps') for f in input_api.AffectedFiles(
3576 include_deletes=True)):
3577 return []
3578
Tibor Goldschwendt360793f72019-06-25 18:23:493579 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403580 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403581 results = []
3582 # First, check for new / deleted .pydeps.
3583 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033584 # Check whether we are running the presubmit check for a file in src.
3585 # f.LocalPath is relative to repo (src, or internal repo).
3586 # os_path.exists is relative to src repo.
3587 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3588 # to src and we can conclude that the pydeps is in src.
3589 if input_api.os_path.exists(f.LocalPath()):
3590 if f.LocalPath().endswith('.pydeps'):
3591 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3592 results.append(output_api.PresubmitError(
3593 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3594 'remove %s' % f.LocalPath()))
3595 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3596 results.append(output_api.PresubmitError(
3597 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3598 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403599
3600 if results:
3601 return results
3602
Mohamed Heikal7cd4d8312020-06-16 16:49:403603 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3604 affected_pydeps = set(checker.ComputeAffectedPydeps())
3605 affected_android_pydeps = affected_pydeps.intersection(
3606 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3607 if affected_android_pydeps and not is_android:
3608 results.append(output_api.PresubmitPromptOrNotify(
3609 'You have changed python files that may affect pydeps for android\n'
3610 'specific scripts. However, the relevant presumbit check cannot be\n'
3611 'run because you are not using an Android checkout. To validate that\n'
3612 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3613 'use the android-internal-presubmit optional trybot.\n'
3614 'Possibly stale pydeps files:\n{}'.format(
3615 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403616
Mohamed Heikal7cd4d8312020-06-16 16:49:403617 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3618 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403619 try:
phajdan.jr0d9878552016-11-04 10:49:413620 result = checker.DetermineIfStale(pydep_path)
3621 if result:
3622 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403623 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413624 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3625 'To regenerate, run:\n\n %s' %
3626 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403627 except input_api.subprocess.CalledProcessError as error:
3628 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3629 long_text=error.output)]
3630
3631 return results
3632
3633
Saagar Sanghavifceeaae2020-08-12 16:40:363634def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433635 """Checks to make sure no header files have |Singleton<|."""
3636 def FileFilter(affected_file):
3637 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443638 files_to_skip = (_EXCLUDED_PATHS +
3639 input_api.DEFAULT_FILES_TO_SKIP +
3640 (r"^base[\\/]memory[\\/]singleton\.h$",
3641 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3642 r"quic_singleton_impl\.h$"))
3643 return input_api.FilterSourceFile(affected_file,
3644 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433645
sergeyu34d21222015-09-16 00:11:443646 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433647 files = []
3648 for f in input_api.AffectedSourceFiles(FileFilter):
3649 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3650 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3651 contents = input_api.ReadFile(f)
3652 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243653 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433654 pattern.search(line)):
3655 files.append(f)
3656 break
3657
3658 if files:
yolandyandaabc6d2016-04-18 18:29:393659 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443660 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433661 'Please move them to an appropriate source file so that the ' +
3662 'template gets instantiated in a single compilation unit.',
3663 files) ]
3664 return []
3665
3666
[email protected]fd20b902014-05-09 02:14:533667_DEPRECATED_CSS = [
3668 # Values
3669 ( "-webkit-box", "flex" ),
3670 ( "-webkit-inline-box", "inline-flex" ),
3671 ( "-webkit-flex", "flex" ),
3672 ( "-webkit-inline-flex", "inline-flex" ),
3673 ( "-webkit-min-content", "min-content" ),
3674 ( "-webkit-max-content", "max-content" ),
3675
3676 # Properties
3677 ( "-webkit-background-clip", "background-clip" ),
3678 ( "-webkit-background-origin", "background-origin" ),
3679 ( "-webkit-background-size", "background-size" ),
3680 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443681 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533682
3683 # Functions
3684 ( "-webkit-gradient", "gradient" ),
3685 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3686 ( "-webkit-linear-gradient", "linear-gradient" ),
3687 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3688 ( "-webkit-radial-gradient", "radial-gradient" ),
3689 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3690]
3691
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203692
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493693# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363694def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533695 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253696 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343697 documentation and iOS CSS for dom distiller
3698 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253699 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533700 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493701 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443702 files_to_skip = (_EXCLUDED_PATHS +
3703 _TEST_CODE_EXCLUDED_PATHS +
3704 input_api.DEFAULT_FILES_TO_SKIP +
3705 (r"^chrome/common/extensions/docs",
3706 r"^chrome/docs",
3707 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3708 r"^components/neterror/resources/neterror.css",
3709 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253710 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443711 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533712 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3713 for line_num, line in fpath.ChangedContents():
3714 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023715 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533716 results.append(output_api.PresubmitError(
3717 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3718 (fpath.LocalPath(), line_num, deprecated_value, value)))
3719 return results
3720
mohan.reddyf21db962014-10-16 12:26:473721
Saagar Sanghavifceeaae2020-08-12 16:40:363722def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363723 bad_files = {}
3724 for f in input_api.AffectedFiles(include_deletes=False):
3725 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493726 not f.LocalPath().startswith('third_party/blink') and
3727 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363728 continue
3729
Daniel Bratell65b033262019-04-23 08:17:063730 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363731 continue
3732
Vaclav Brozekd5de76a2018-03-17 07:57:503733 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363734 if "#include" in line and "../" in line]
3735 if not relative_includes:
3736 continue
3737 bad_files[f.LocalPath()] = relative_includes
3738
3739 if not bad_files:
3740 return []
3741
3742 error_descriptions = []
Dirk Prankee3c9c62d2021-05-18 18:35:593743 for file_path, bad_lines in bad_files.items():
rlanday6802cf632017-05-30 17:48:363744 error_description = file_path
3745 for line in bad_lines:
3746 error_description += '\n ' + line
3747 error_descriptions.append(error_description)
3748
3749 results = []
3750 results.append(output_api.PresubmitError(
3751 'You added one or more relative #include paths (including "../").\n'
3752 'These shouldn\'t be used because they can be used to include headers\n'
3753 'from code that\'s not correctly specified as a dependency in the\n'
3754 'relevant BUILD.gn file(s).',
3755 error_descriptions))
3756
3757 return results
3758
Takeshi Yoshinoe387aa32017-08-02 13:16:133759
Saagar Sanghavifceeaae2020-08-12 16:40:363760def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063761 """Check that nobody tries to include a cc file. It's a relatively
3762 common error which results in duplicate symbols in object
3763 files. This may not always break the build until someone later gets
3764 very confusing linking errors."""
3765 results = []
3766 for f in input_api.AffectedFiles(include_deletes=False):
3767 # We let third_party code do whatever it wants
3768 if (f.LocalPath().startswith('third_party') and
3769 not f.LocalPath().startswith('third_party/blink') and
3770 not f.LocalPath().startswith('third_party\\blink')):
3771 continue
3772
3773 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3774 continue
3775
3776 for _, line in f.ChangedContents():
3777 if line.startswith('#include "'):
3778 included_file = line.split('"')[1]
3779 if _IsCPlusPlusFile(input_api, included_file):
3780 # The most common naming for external files with C++ code,
3781 # apart from standard headers, is to call them foo.inc, but
3782 # Chromium sometimes uses foo-inc.cc so allow that as well.
3783 if not included_file.endswith(('.h', '-inc.cc')):
3784 results.append(output_api.PresubmitError(
3785 'Only header files or .inc files should be included in other\n'
3786 'C++ files. Compiling the contents of a cc file more than once\n'
3787 'will cause duplicate information in the build which may later\n'
3788 'result in strange link_errors.\n' +
3789 f.LocalPath() + ':\n ' +
3790 line))
3791
3792 return results
3793
3794
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203795def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3796 if not isinstance(key, ast.Str):
3797 return 'Key at line %d must be a string literal' % key.lineno
3798 if not isinstance(value, ast.Dict):
3799 return 'Value at line %d must be a dict' % value.lineno
3800 if len(value.keys) != 1:
3801 return 'Dict at line %d must have single entry' % value.lineno
3802 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3803 return (
3804 'Entry at line %d must have a string literal \'filepath\' as key' %
3805 value.lineno)
3806 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133807
Takeshi Yoshinoe387aa32017-08-02 13:16:133808
Sergey Ulanov4af16052018-11-08 02:41:463809def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203810 if not isinstance(key, ast.Str):
3811 return 'Key at line %d must be a string literal' % key.lineno
3812 if not isinstance(value, ast.List):
3813 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463814 for element in value.elts:
3815 if not isinstance(element, ast.Str):
3816 return 'Watchlist elements on line %d is not a string' % key.lineno
3817 if not email_regex.match(element.s):
3818 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3819 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203820 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133821
Takeshi Yoshinoe387aa32017-08-02 13:16:133822
Sergey Ulanov4af16052018-11-08 02:41:463823def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203824 mismatch_template = (
3825 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3826 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133827
Sergey Ulanov4af16052018-11-08 02:41:463828 email_regex = input_api.re.compile(
3829 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3830
3831 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203832 i = 0
3833 last_key = ''
3834 while True:
3835 if i >= len(wd_dict.keys):
3836 if i >= len(w_dict.keys):
3837 return None
3838 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3839 elif i >= len(w_dict.keys):
3840 return (
3841 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133842
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203843 wd_key = wd_dict.keys[i]
3844 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133845
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203846 result = _CheckWatchlistDefinitionsEntrySyntax(
3847 wd_key, wd_dict.values[i], ast)
3848 if result is not None:
3849 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133850
Sergey Ulanov4af16052018-11-08 02:41:463851 result = _CheckWatchlistsEntrySyntax(
3852 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203853 if result is not None:
3854 return 'Bad entry in WATCHLISTS dict: %s' % result
3855
3856 if wd_key.s != w_key.s:
3857 return mismatch_template % (
3858 '%s at line %d' % (wd_key.s, wd_key.lineno),
3859 '%s at line %d' % (w_key.s, w_key.lineno))
3860
3861 if wd_key.s < last_key:
3862 return (
3863 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3864 (wd_key.lineno, w_key.lineno))
3865 last_key = wd_key.s
3866
3867 i = i + 1
3868
3869
Sergey Ulanov4af16052018-11-08 02:41:463870def _CheckWATCHLISTSSyntax(expression, input_api):
3871 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203872 if not isinstance(expression, ast.Expression):
3873 return 'WATCHLISTS file must contain a valid expression'
3874 dictionary = expression.body
3875 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3876 return 'WATCHLISTS file must have single dict with exactly two entries'
3877
3878 first_key = dictionary.keys[0]
3879 first_value = dictionary.values[0]
3880 second_key = dictionary.keys[1]
3881 second_value = dictionary.values[1]
3882
3883 if (not isinstance(first_key, ast.Str) or
3884 first_key.s != 'WATCHLIST_DEFINITIONS' or
3885 not isinstance(first_value, ast.Dict)):
3886 return (
3887 'The first entry of the dict in WATCHLISTS file must be '
3888 'WATCHLIST_DEFINITIONS dict')
3889
3890 if (not isinstance(second_key, ast.Str) or
3891 second_key.s != 'WATCHLISTS' or
3892 not isinstance(second_value, ast.Dict)):
3893 return (
3894 'The second entry of the dict in WATCHLISTS file must be '
3895 'WATCHLISTS dict')
3896
Sergey Ulanov4af16052018-11-08 02:41:463897 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133898
3899
Saagar Sanghavifceeaae2020-08-12 16:40:363900def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133901 for f in input_api.AffectedFiles(include_deletes=False):
3902 if f.LocalPath() == 'WATCHLISTS':
3903 contents = input_api.ReadFile(f, 'r')
3904
3905 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203906 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133907 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203908 # Get an AST tree for it and scan the tree for detailed style checking.
3909 expression = input_api.ast.parse(
3910 contents, filename='WATCHLISTS', mode='eval')
3911 except ValueError as e:
3912 return [output_api.PresubmitError(
3913 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3914 except SyntaxError as e:
3915 return [output_api.PresubmitError(
3916 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3917 except TypeError as e:
3918 return [output_api.PresubmitError(
3919 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133920
Sergey Ulanov4af16052018-11-08 02:41:463921 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203922 if result is not None:
3923 return [output_api.PresubmitError(result)]
3924 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133925
3926 return []
3927
3928
Andrew Grieve1b290e4a22020-11-24 20:07:013929def CheckGnGlobForward(input_api, output_api):
3930 """Checks that forward_variables_from(invoker, "*") follows best practices.
3931
3932 As documented at //build/docs/writing_gn_templates.md
3933 """
3934 def gn_files(f):
3935 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3936
3937 problems = []
3938 for f in input_api.AffectedSourceFiles(gn_files):
3939 for line_num, line in f.ChangedContents():
3940 if 'forward_variables_from(invoker, "*")' in line:
3941 problems.append(
3942 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3943 f.LocalPath(), line_num))
3944
3945 if problems:
3946 return [output_api.PresubmitPromptWarning(
3947 'forward_variables_from("*") without exclusions',
3948 items=sorted(problems),
3949 long_text=('The variables "visibilty" and "test_only" should be '
3950 'explicitly listed in forward_variables_from(). For more '
3951 'details, see:\n'
3952 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
3953 'build/docs/writing_gn_templates.md'
3954 '#Using-forward_variables_from'))]
3955 return []
3956
3957
Saagar Sanghavifceeaae2020-08-12 16:40:363958def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193959 """Checks that newly added header files have corresponding GN changes.
3960 Note that this is only a heuristic. To be precise, run script:
3961 build/check_gn_headers.py.
3962 """
3963
3964 def headers(f):
3965 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443966 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193967
3968 new_headers = []
3969 for f in input_api.AffectedSourceFiles(headers):
3970 if f.Action() != 'A':
3971 continue
3972 new_headers.append(f.LocalPath())
3973
3974 def gn_files(f):
James Cook24a504192020-07-23 00:08:443975 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193976
3977 all_gn_changed_contents = ''
3978 for f in input_api.AffectedSourceFiles(gn_files):
3979 for _, line in f.ChangedContents():
3980 all_gn_changed_contents += line
3981
3982 problems = []
3983 for header in new_headers:
3984 basename = input_api.os_path.basename(header)
3985 if basename not in all_gn_changed_contents:
3986 problems.append(header)
3987
3988 if problems:
3989 return [output_api.PresubmitPromptWarning(
3990 'Missing GN changes for new header files', items=sorted(problems),
3991 long_text='Please double check whether newly added header files need '
3992 'corresponding changes in gn or gni files.\nThis checking is only a '
3993 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3994 'Read https://crbug.com/661774 for more info.')]
3995 return []
3996
3997
Saagar Sanghavifceeaae2020-08-12 16:40:363998def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:023999 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4000
4001 This assumes we won't intentionally reference one product from the other
4002 product.
4003 """
4004 all_problems = []
4005 test_cases = [{
4006 "filename_postfix": "google_chrome_strings.grd",
4007 "correct_name": "Chrome",
4008 "incorrect_name": "Chromium",
4009 }, {
4010 "filename_postfix": "chromium_strings.grd",
4011 "correct_name": "Chromium",
4012 "incorrect_name": "Chrome",
4013 }]
4014
4015 for test_case in test_cases:
4016 problems = []
4017 filename_filter = lambda x: x.LocalPath().endswith(
4018 test_case["filename_postfix"])
4019
4020 # Check each new line. Can yield false positives in multiline comments, but
4021 # easier than trying to parse the XML because messages can have nested
4022 # children, and associating message elements with affected lines is hard.
4023 for f in input_api.AffectedSourceFiles(filename_filter):
4024 for line_num, line in f.ChangedContents():
4025 if "<message" in line or "<!--" in line or "-->" in line:
4026 continue
4027 if test_case["incorrect_name"] in line:
4028 problems.append(
4029 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4030
4031 if problems:
4032 message = (
4033 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4034 % (test_case["correct_name"], test_case["correct_name"],
4035 test_case["incorrect_name"]))
4036 all_problems.append(
4037 output_api.PresubmitPromptWarning(message, items=problems))
4038
4039 return all_problems
4040
4041
Saagar Sanghavifceeaae2020-08-12 16:40:364042def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364043 """Avoid large files, especially binary files, in the repository since
4044 git doesn't scale well for those. They will be in everyone's repo
4045 clones forever, forever making Chromium slower to clone and work
4046 with."""
4047
4048 # Uploading files to cloud storage is not trivial so we don't want
4049 # to set the limit too low, but the upper limit for "normal" large
4050 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4051 # anything over 20 MB is exceptional.
4052 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4053
4054 too_large_files = []
4055 for f in input_api.AffectedFiles():
4056 # Check both added and modified files (but not deleted files).
4057 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384058 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364059 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4060 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4061
4062 if too_large_files:
4063 message = (
4064 'Do not commit large files to git since git scales badly for those.\n' +
4065 'Instead put the large files in cloud storage and use DEPS to\n' +
4066 'fetch them.\n' + '\n'.join(too_large_files)
4067 )
4068 return [output_api.PresubmitError(
4069 'Too large files found in commit', long_text=message + '\n')]
4070 else:
4071 return []
4072
Max Morozb47503b2019-08-08 21:03:274073
Saagar Sanghavifceeaae2020-08-12 16:40:364074def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274075 """Checks specific for fuzz target sources."""
4076 EXPORTED_SYMBOLS = [
4077 'LLVMFuzzerInitialize',
4078 'LLVMFuzzerCustomMutator',
4079 'LLVMFuzzerCustomCrossOver',
4080 'LLVMFuzzerMutate',
4081 ]
4082
4083 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4084
4085 def FilterFile(affected_file):
4086 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444087 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4088 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274089
4090 return input_api.FilterSourceFile(
4091 affected_file,
James Cook24a504192020-07-23 00:08:444092 files_to_check=[files_to_check],
4093 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274094
4095 files_with_missing_header = []
4096 for f in input_api.AffectedSourceFiles(FilterFile):
4097 contents = input_api.ReadFile(f, 'r')
4098 if REQUIRED_HEADER in contents:
4099 continue
4100
4101 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4102 files_with_missing_header.append(f.LocalPath())
4103
4104 if not files_with_missing_header:
4105 return []
4106
4107 long_text = (
4108 'If you define any of the libFuzzer optional functions (%s), it is '
4109 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4110 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4111 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4112 'to access command line arguments passed to the fuzzer. Instead, prefer '
4113 'static initialization and shared resources as documented in '
John Palmer0e0f72bf2021-06-07 09:10:204114 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
Max Morozb47503b2019-08-08 21:03:274115 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4116 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4117 )
4118
4119 return [output_api.PresubmitPromptWarning(
4120 message="Missing '%s' in:" % REQUIRED_HEADER,
4121 items=files_with_missing_header,
4122 long_text=long_text)]
4123
4124
Mohamed Heikald048240a2019-11-12 16:57:374125def _CheckNewImagesWarning(input_api, output_api):
4126 """
4127 Warns authors who add images into the repo to make sure their images are
4128 optimized before committing.
4129 """
4130 images_added = False
4131 image_paths = []
4132 errors = []
4133 filter_lambda = lambda x: input_api.FilterSourceFile(
4134 x,
James Cook24a504192020-07-23 00:08:444135 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4136 + input_api.DEFAULT_FILES_TO_SKIP),
4137 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374138 )
4139 for f in input_api.AffectedFiles(
4140 include_deletes=False, file_filter=filter_lambda):
4141 local_path = f.LocalPath().lower()
4142 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4143 images_added = True
4144 image_paths.append(f)
4145 if images_added:
4146 errors.append(output_api.PresubmitPromptWarning(
4147 'It looks like you are trying to commit some images. If these are '
4148 'non-test-only images, please make sure to read and apply the tips in '
4149 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4150 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4151 'FYI only and will not block your CL on the CQ.', image_paths))
4152 return errors
4153
4154
Saagar Sanghavifceeaae2020-08-12 16:40:364155def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574156 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224157 results = []
dgnaa68d5e2015-06-10 10:08:224158 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174159 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224160 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294161 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064162 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4163 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424164 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184165 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574166 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374167 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154168 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574169 return results
4170
Saagar Sanghavifceeaae2020-08-12 16:40:364171def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574172 """Groups commit checks that target android code."""
4173 results = []
4174 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224175 return results
4176
Chris Hall59f8d0c72020-05-01 07:31:194177# TODO(chrishall): could we additionally match on any path owned by
4178# ui/accessibility/OWNERS ?
4179_ACCESSIBILITY_PATHS = (
4180 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4181 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4182 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4183 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4184 r"^content[\\/]browser[\\/]accessibility[\\/]",
4185 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4186 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4187 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4188 r"^ui[\\/]accessibility[\\/]",
4189 r"^ui[\\/]views[\\/]accessibility[\\/]",
4190)
4191
Saagar Sanghavifceeaae2020-08-12 16:40:364192def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194193 """Checks that commits to accessibility code contain an AX-Relnotes field in
4194 their commit message."""
4195 def FileFilter(affected_file):
4196 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444197 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194198
4199 # Only consider changes affecting accessibility paths.
4200 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4201 return []
4202
Akihiro Ota08108e542020-05-20 15:30:534203 # AX-Relnotes can appear in either the description or the footer.
4204 # When searching the description, require 'AX-Relnotes:' to appear at the
4205 # beginning of a line.
4206 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4207 description_has_relnotes = any(ax_regex.match(line)
4208 for line in input_api.change.DescriptionText().lower().splitlines())
4209
4210 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4211 'AX-Relnotes', [])
4212 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194213 return []
4214
4215 # TODO(chrishall): link to Relnotes documentation in message.
4216 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4217 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4218 "user-facing changes"
4219 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4220 "user-facing effects"
4221 "\n if this is confusing or annoying then please contact members "
4222 "of ui/accessibility/OWNERS.")
4223
4224 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224225
seanmccullough4a9356252021-04-08 19:54:094226# string pattern, sequence of strings to show when pattern matches,
4227# error flag. True if match is a presubmit error, otherwise it's a warning.
4228_NON_INCLUSIVE_TERMS = (
4229 (
4230 # Note that \b pattern in python re is pretty particular. In this
4231 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4232 # ...' will not. This may require some tweaking to catch these cases
4233 # without triggering a lot of false positives. Leaving it naive and
4234 # less matchy for now.
4235 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4236 (
4237 'Please don\'t use blacklist, whitelist, ' # nocheck
4238 'or slave in your', # nocheck
4239 'code and make every effort to use other terms. Using "// nocheck"',
4240 '"# nocheck" or "<!-- nocheck -->"',
4241 'at the end of the offending line will bypass this PRESUBMIT error',
4242 'but avoid using this whenever possible. Reach out to',
4243 '[email protected] if you have questions'),
4244 True),)
4245
Saagar Sanghavifceeaae2020-08-12 16:40:364246def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394247 """Checks common to both upload and commit."""
4248 results = []
4249 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384250 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544251 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084252
4253 author = input_api.change.author_email
4254 if author and author not in _KNOWN_ROBOTS:
4255 results.extend(
4256 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4257
[email protected]9f919cc2013-07-31 03:04:044258 results.extend(
4259 input_api.canned_checks.CheckChangeHasNoTabs(
4260 input_api,
4261 output_api,
4262 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434263 results.extend(input_api.RunTests(
4264 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244265
Edward Lesmesce51df52020-08-04 22:10:174266 dirmd_bin = input_api.os_path.join(
4267 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4268 results.extend(input_api.RunTests(
4269 input_api.canned_checks.CheckDirMetadataFormat(
4270 input_api, output_api, dirmd_bin)))
4271 results.extend(
4272 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4273 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554274 results.extend(
4275 input_api.canned_checks.CheckNoNewMetadataInOwners(
4276 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094277 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4278 input_api, output_api,
4279 excluded_directories_relative_path = [
4280 'infra',
4281 'inclusive_language_presubmit_exempt_dirs.txt'
4282 ],
4283 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174284
Vaclav Brozekcdc7defb2018-03-20 09:54:354285 for f in input_api.AffectedFiles():
4286 path, name = input_api.os_path.split(f.LocalPath())
4287 if name == 'PRESUBMIT.py':
4288 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004289 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4290 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074291 # The PRESUBMIT.py file (and the directory containing it) might
4292 # have been affected by being moved or removed, so only try to
4293 # run the tests if they still exist.
Dirk Prankee3c9c62d2021-05-18 18:35:594294 use_python3 = False
4295 with open(f.LocalPath()) as fp:
Daniel Chengab582892021-09-30 20:53:194296 use_python3 = any(line.startswith('USE_PYTHON3 = True')
4297 for line in fp.readlines())
Dirk Prankee3c9c62d2021-05-18 18:35:594298
Dirk Pranke38557312018-04-18 00:53:074299 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4300 input_api, output_api, full_path,
Dirk Prankee3c9c62d2021-05-18 18:35:594301 files_to_check=[r'^PRESUBMIT_test\.py$'],
4302 run_on_python2=not use_python3,
Jonathan Njeunjee45f2bd2021-10-12 16:21:584303 run_on_python3=use_python3,
4304 skip_shebang_check=True))
[email protected]22c9bd72011-03-27 16:47:394305 return results
[email protected]1f7b4172010-01-28 01:17:344306
[email protected]b337cb5b2011-01-23 21:24:054307
Saagar Sanghavifceeaae2020-08-12 16:40:364308def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494309 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4310 if f.LocalPath().endswith(('.orig', '.rej'))]
danakj30f05352021-11-03 18:58:414311 # Cargo.toml.orig files are part of third-party crates downloaded from
4312 # crates.io and should be included.
4313 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
[email protected]b8079ae4a2012-12-05 19:56:494314 if problems:
4315 return [output_api.PresubmitError(
4316 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034317 else:
4318 return []
[email protected]b8079ae4a2012-12-05 19:56:494319
4320
Saagar Sanghavifceeaae2020-08-12 16:40:364321def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214322 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4323 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4324 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074325 include_re = input_api.re.compile(
4326 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4327 extension_re = input_api.re.compile(r'\.[a-z]+$')
4328 errors = []
Bruce Dawsonaae5e652021-06-24 15:05:394329 for f in input_api.AffectedFiles(include_deletes=False):
Kent Tamura5a8755d2017-06-29 23:37:074330 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4331 continue
4332 found_line_number = None
4333 found_macro = None
Bruce Dawsonaae5e652021-06-24 15:05:394334 all_lines = input_api.ReadFile(f, 'r').splitlines()
4335 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074336 match = macro_re.search(line)
4337 if match:
4338 found_line_number = line_num
4339 found_macro = match.group(2)
4340 break
4341 if not found_line_number:
4342 continue
4343
Bruce Dawsonaae5e652021-06-24 15:05:394344 found_include_line = -1
4345 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074346 if include_re.search(line):
Bruce Dawsonaae5e652021-06-24 15:05:394347 found_include_line = line_num
Kent Tamura5a8755d2017-06-29 23:37:074348 break
Bruce Dawsonaae5e652021-06-24 15:05:394349 if found_include_line >= 0 and found_include_line < found_line_number:
Kent Tamura5a8755d2017-06-29 23:37:074350 continue
4351
4352 if not f.LocalPath().endswith('.h'):
4353 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4354 try:
4355 content = input_api.ReadFile(primary_header_path, 'r')
4356 if include_re.search(content):
4357 continue
4358 except IOError:
4359 pass
Bruce Dawsonaae5e652021-06-24 15:05:394360 errors.append('%s:%d %s macro is used without first including build/'
Kent Tamura5a8755d2017-06-29 23:37:074361 'build_config.h.'
4362 % (f.LocalPath(), found_line_number, found_macro))
4363 if errors:
4364 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4365 return []
4366
4367
Lei Zhang1c12a22f2021-05-12 11:28:454368def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
4369 stl_include_re = input_api.re.compile(
Lei Zhang0643e342021-05-12 18:02:124370 r'^#include\s+<('
Lei Zhang1c12a22f2021-05-12 11:28:454371 r'algorithm|'
4372 r'array|'
4373 r'limits|'
4374 r'list|'
4375 r'map|'
4376 r'memory|'
4377 r'queue|'
4378 r'set|'
4379 r'string|'
4380 r'unordered_map|'
4381 r'unordered_set|'
4382 r'utility|'
Lei Zhang0643e342021-05-12 18:02:124383 r'vector)>')
Lei Zhang1c12a22f2021-05-12 11:28:454384 std_namespace_re = input_api.re.compile(r'std::')
4385 errors = []
4386 for f in input_api.AffectedFiles():
4387 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4388 continue
4389
4390 uses_std_namespace = False
4391 has_stl_include = False
4392 for line in f.NewContents():
4393 if has_stl_include and uses_std_namespace:
4394 break
4395
4396 if not has_stl_include and stl_include_re.search(line):
4397 has_stl_include = True
4398 continue
4399
4400 if not uses_std_namespace and std_namespace_re.search(line):
4401 uses_std_namespace = True
4402 continue
4403
4404 if has_stl_include and not uses_std_namespace:
4405 errors.append('%s: Includes STL header(s) but does not reference std::'
4406 % f.LocalPath())
4407 if errors:
4408 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4409 return []
4410
4411
[email protected]b00342e7f2013-03-26 16:21:544412def _DidYouMeanOSMacro(bad_macro):
4413 try:
4414 return {'A': 'OS_ANDROID',
4415 'B': 'OS_BSD',
4416 'C': 'OS_CHROMEOS',
4417 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444418 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544419 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444420 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544421 'N': 'OS_NACL',
4422 'O': 'OS_OPENBSD',
4423 'P': 'OS_POSIX',
4424 'S': 'OS_SOLARIS',
4425 'W': 'OS_WIN'}[bad_macro[3].upper()]
4426 except KeyError:
4427 return ''
4428
4429
4430def _CheckForInvalidOSMacrosInFile(input_api, f):
4431 """Check for sensible looking, totally invalid OS macros."""
4432 preprocessor_statement = input_api.re.compile(r'^\s*#')
4433 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4434 results = []
4435 for lnum, line in f.ChangedContents():
4436 if preprocessor_statement.search(line):
4437 for match in os_macro.finditer(line):
4438 if not match.group(1) in _VALID_OS_MACROS:
4439 good = _DidYouMeanOSMacro(match.group(1))
4440 did_you_mean = ' (did you mean %s?)' % good if good else ''
4441 results.append(' %s:%d %s%s' % (f.LocalPath(),
4442 lnum,
4443 match.group(1),
4444 did_you_mean))
4445 return results
4446
4447
Saagar Sanghavifceeaae2020-08-12 16:40:364448def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544449 """Check all affected files for invalid OS macros."""
4450 bad_macros = []
tzik3f295992018-12-04 20:32:234451 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474452 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544453 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4454
4455 if not bad_macros:
4456 return []
4457
4458 return [output_api.PresubmitError(
4459 'Possibly invalid OS macro[s] found. Please fix your code\n'
4460 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4461
lliabraa35bab3932014-10-01 12:16:444462
4463def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4464 """Check all affected files for invalid "if defined" macros."""
4465 ALWAYS_DEFINED_MACROS = (
4466 "TARGET_CPU_PPC",
4467 "TARGET_CPU_PPC64",
4468 "TARGET_CPU_68K",
4469 "TARGET_CPU_X86",
4470 "TARGET_CPU_ARM",
4471 "TARGET_CPU_MIPS",
4472 "TARGET_CPU_SPARC",
4473 "TARGET_CPU_ALPHA",
4474 "TARGET_IPHONE_SIMULATOR",
4475 "TARGET_OS_EMBEDDED",
4476 "TARGET_OS_IPHONE",
4477 "TARGET_OS_MAC",
4478 "TARGET_OS_UNIX",
4479 "TARGET_OS_WIN32",
4480 )
4481 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4482 results = []
4483 for lnum, line in f.ChangedContents():
4484 for match in ifdef_macro.finditer(line):
4485 if match.group(1) in ALWAYS_DEFINED_MACROS:
4486 always_defined = ' %s is always defined. ' % match.group(1)
4487 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4488 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4489 lnum,
4490 always_defined,
4491 did_you_mean))
4492 return results
4493
4494
Saagar Sanghavifceeaae2020-08-12 16:40:364495def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444496 """Check all affected files for invalid "if defined" macros."""
4497 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054498 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444499 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054500 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214501 continue
lliabraa35bab3932014-10-01 12:16:444502 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4503 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4504
4505 if not bad_macros:
4506 return []
4507
4508 return [output_api.PresubmitError(
4509 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4510 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4511 bad_macros)]
4512
4513
Saagar Sanghavifceeaae2020-08-12 16:40:364514def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044515 """Check for same IPC rules described in
4516 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4517 """
4518 base_pattern = r'IPC_ENUM_TRAITS\('
4519 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4520 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4521
4522 problems = []
4523 for f in input_api.AffectedSourceFiles(None):
4524 local_path = f.LocalPath()
4525 if not local_path.endswith('.h'):
4526 continue
4527 for line_number, line in f.ChangedContents():
4528 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4529 problems.append(
4530 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4531
4532 if problems:
4533 return [output_api.PresubmitPromptWarning(
4534 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4535 else:
4536 return []
4537
[email protected]b00342e7f2013-03-26 16:21:544538
Saagar Sanghavifceeaae2020-08-12 16:40:364539def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054540 """Check to make sure no files being submitted have long paths.
4541 This causes issues on Windows.
4542 """
4543 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194544 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054545 local_path = f.LocalPath()
4546 # Windows has a path limit of 260 characters. Limit path length to 200 so
4547 # that we have some extra for the prefix on dev machines and the bots.
4548 if len(local_path) > 200:
4549 problems.append(local_path)
4550
4551 if problems:
4552 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4553 else:
4554 return []
4555
4556
Saagar Sanghavifceeaae2020-08-12 16:40:364557def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144558 """Check that header files have proper guards against multiple inclusion.
4559 If a file should not have such guards (and it probably should) then it
4560 should include the string "no-include-guard-because-multiply-included".
4561 """
Daniel Bratell6a75baef62018-06-04 10:04:454562 def is_chromium_header_file(f):
4563 # We only check header files under the control of the Chromium
4564 # project. That is, those outside third_party apart from
4565 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324566 # We also exclude *_message_generator.h headers as they use
4567 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454568 file_with_path = input_api.os_path.normpath(f.LocalPath())
4569 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324570 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454571 (not file_with_path.startswith('third_party') or
4572 file_with_path.startswith(
4573 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144574
4575 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344576 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144577
4578 errors = []
4579
Daniel Bratell6a75baef62018-06-04 10:04:454580 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144581 guard_name = None
4582 guard_line_number = None
4583 seen_guard_end = False
4584
4585 file_with_path = input_api.os_path.normpath(f.LocalPath())
4586 base_file_name = input_api.os_path.splitext(
4587 input_api.os_path.basename(file_with_path))[0]
4588 upper_base_file_name = base_file_name.upper()
4589
4590 expected_guard = replace_special_with_underscore(
4591 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144592
4593 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574594 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4595 # are too many (1000+) files with slight deviations from the
4596 # coding style. The most important part is that the include guard
4597 # is there, and that it's unique, not the name so this check is
4598 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144599 #
4600 # As code becomes more uniform, this could be made stricter.
4601
4602 guard_name_pattern_list = [
4603 # Anything with the right suffix (maybe with an extra _).
4604 r'\w+_H__?',
4605
Daniel Bratell39b5b062018-05-16 18:09:574606 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144607 r'\w+_h',
4608
4609 # Anything including the uppercase name of the file.
4610 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4611 upper_base_file_name)) + r'\w*',
4612 ]
4613 guard_name_pattern = '|'.join(guard_name_pattern_list)
4614 guard_pattern = input_api.re.compile(
4615 r'#ifndef\s+(' + guard_name_pattern + ')')
4616
4617 for line_number, line in enumerate(f.NewContents()):
4618 if 'no-include-guard-because-multiply-included' in line:
4619 guard_name = 'DUMMY' # To not trigger check outside the loop.
4620 break
4621
4622 if guard_name is None:
4623 match = guard_pattern.match(line)
4624 if match:
4625 guard_name = match.group(1)
4626 guard_line_number = line_number
4627
Daniel Bratell39b5b062018-05-16 18:09:574628 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454629 # don't match the chromium style guide, but new files should
4630 # get it right.
4631 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574632 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144633 errors.append(output_api.PresubmitPromptWarning(
4634 'Header using the wrong include guard name %s' % guard_name,
4635 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574636 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144637 else:
4638 # The line after #ifndef should have a #define of the same name.
4639 if line_number == guard_line_number + 1:
4640 expected_line = '#define %s' % guard_name
4641 if line != expected_line:
4642 errors.append(output_api.PresubmitPromptWarning(
4643 'Missing "%s" for include guard' % expected_line,
4644 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4645 'Expected: %r\nGot: %r' % (expected_line, line)))
4646
4647 if not seen_guard_end and line == '#endif // %s' % guard_name:
4648 seen_guard_end = True
4649 elif seen_guard_end:
4650 if line.strip() != '':
4651 errors.append(output_api.PresubmitPromptWarning(
4652 'Include guard %s not covering the whole file' % (
4653 guard_name), [f.LocalPath()]))
4654 break # Nothing else to check and enough to warn once.
4655
4656 if guard_name is None:
4657 errors.append(output_api.PresubmitPromptWarning(
4658 'Missing include guard %s' % expected_guard,
4659 [f.LocalPath()],
4660 'Missing include guard in %s\n'
4661 'Recommended name: %s\n'
4662 'This check can be disabled by having the string\n'
4663 'no-include-guard-because-multiply-included in the header.' %
4664 (f.LocalPath(), expected_guard)))
4665
4666 return errors
4667
4668
Saagar Sanghavifceeaae2020-08-12 16:40:364669def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234670 """Check source code and known ascii text files for Windows style line
4671 endings.
4672 """
Evan Stade6cfc964c12021-05-18 20:21:164673 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234674
4675 file_inclusion_pattern = (
4676 known_text_files,
Bruce Dawson6141d4a2021-06-08 15:56:114677 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4678 r'.+%s' % _HEADER_EXTENSIONS
mostynbb639aca52015-01-07 20:31:234679 )
4680
mostynbb639aca52015-01-07 20:31:234681 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534682 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444683 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534684 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504685 include_file = False
Bruce Dawsonb2cfdfe2021-06-10 19:01:204686 for line in input_api.ReadFile(f, 'r').splitlines(True):
mostynbb639aca52015-01-07 20:31:234687 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504688 include_file = True
4689 if include_file:
4690 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234691
4692 if problems:
4693 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4694 'these files to contain Windows style line endings?\n' +
4695 '\n'.join(problems))]
4696
4697 return []
4698
Evan Stade6cfc964c12021-05-18 20:21:164699def CheckIconFilesForLicenseHeaders(input_api, output_api):
4700 """Check that .icon files (which are fragments of C++) have license headers.
4701 """
4702
4703 icon_files = (r'.*\.icon$',)
4704
4705 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4706 return input_api.canned_checks.CheckLicense(
4707 input_api, output_api, source_file_filter=icons)
4708
Jose Magana2b456f22021-03-09 23:26:404709def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4710 """Check source code for use of Chrome App technologies being
4711 deprecated.
4712 """
4713
4714 def _CheckForDeprecatedTech(input_api, output_api,
4715 detection_list, files_to_check = None, files_to_skip = None):
4716
4717 if (files_to_check or files_to_skip):
4718 source_file_filter = lambda f: input_api.FilterSourceFile(
4719 f, files_to_check=files_to_check,
4720 files_to_skip=files_to_skip)
4721 else:
4722 source_file_filter = None
4723
4724 problems = []
4725
4726 for f in input_api.AffectedSourceFiles(source_file_filter):
4727 if f.Action() == 'D':
4728 continue
4729 for _, line in f.ChangedContents():
4730 if any( detect in line for detect in detection_list ):
4731 problems.append(f.LocalPath())
4732
4733 return problems
4734
4735 # to avoid this presubmit script triggering warnings
4736 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4737
4738 problems =[]
4739
4740 # NMF: any files with extensions .nmf or NMF
4741 _NMF_FILES = r'\.(nmf|NMF)$'
4742 problems += _CheckForDeprecatedTech(input_api, output_api,
4743 detection_list = [''], # any change to the file will trigger warning
4744 files_to_check = [ r'.+%s' % _NMF_FILES ])
4745
4746 # MANIFEST: any manifest.json that in its diff includes "app":
4747 _MANIFEST_FILES = r'(manifest\.json)$'
4748 problems += _CheckForDeprecatedTech(input_api, output_api,
4749 detection_list = ['"app":'],
4750 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4751
4752 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4753 problems += _CheckForDeprecatedTech(input_api, output_api,
4754 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4755 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4756
4757 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4758 problems += _CheckForDeprecatedTech(input_api, output_api,
4759 detection_list = ['#include "ppapi','#include <ppapi'],
4760 files_to_check = (
4761 r'.+%s' % _HEADER_EXTENSIONS,
4762 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4763 files_to_skip = [r"^ppapi[\\/]"] )
4764
Jose Magana2b456f22021-03-09 23:26:404765 if problems:
4766 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4767 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4768 ' PNaCl, PPAPI). See this blog post for more details:\n'
4769 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4770 'and this documentation for options to replace these technologies:\n'
4771 'https://developer.chrome.com/docs/apps/migration/\n'+
4772 '\n'.join(problems))]
4773
4774 return []
4775
mostynbb639aca52015-01-07 20:31:234776
Saagar Sanghavifceeaae2020-08-12 16:40:364777def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134778 """Checks that all source files use SYSLOG properly."""
4779 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364780 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564781 for line_number, line in f.ChangedContents():
4782 if 'SYSLOG' in line:
4783 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4784
pastarmovj89f7ee12016-09-20 14:58:134785 if syslog_files:
4786 return [output_api.PresubmitPromptWarning(
4787 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4788 ' calls.\nFiles to check:\n', items=syslog_files)]
4789 return []
4790
4791
[email protected]1f7b4172010-01-28 01:17:344792def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364793 if input_api.version < [2, 0, 0]:
4794 return [output_api.PresubmitError("Your depot_tools is out of date. "
4795 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4796 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344797 results = []
scottmg39b29952014-12-08 18:31:284798 results.extend(
jam93a6ee792017-02-08 23:59:224799 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544800 return results
[email protected]ca8d1982009-02-19 16:33:124801
4802
4803def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364804 if input_api.version < [2, 0, 0]:
4805 return [output_api.PresubmitError("Your depot_tools is out of date. "
4806 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4807 "but your version is %d.%d.%d" % tuple(input_api.version))]
4808
[email protected]fe5f57c52009-06-05 14:25:544809 results = []
[email protected]fe5f57c52009-06-05 14:25:544810 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274811 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344812 input_api,
4813 output_api,
[email protected]2fdd1f362013-01-16 03:56:034814 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274815
jam93a6ee792017-02-08 23:59:224816 results.extend(
4817 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544818 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4819 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384820 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4821 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414822 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4823 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544824 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144825
4826
Saagar Sanghavifceeaae2020-08-12 16:40:364827def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264828 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024829 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4830 # footer is set to true.
4831 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264832 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024833 footer.lower()
4834 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264835 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024836
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144837 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264838 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144839 import sys
4840 from io import StringIO
4841
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144842 new_or_added_paths = set(f.LocalPath()
4843 for f in input_api.AffectedFiles()
4844 if (f.Action() == 'A' or f.Action() == 'M'))
4845 removed_paths = set(f.LocalPath()
4846 for f in input_api.AffectedFiles(include_deletes=True)
4847 if f.Action() == 'D')
4848
Andrew Grieve0e8790c2020-09-03 17:27:324849 affected_grds = [
4850 f for f in input_api.AffectedFiles()
4851 if f.LocalPath().endswith(('.grd', '.grdp'))
4852 ]
4853 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164854 if not affected_grds:
4855 return []
4856
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144857 affected_png_paths = [f.AbsoluteLocalPath()
4858 for f in input_api.AffectedFiles()
4859 if (f.LocalPath().endswith('.png'))]
4860
4861 # Check for screenshots. Developers can upload screenshots using
4862 # tools/translation/upload_screenshots.py which finds and uploads
4863 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4864 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4865 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4866 #
4867 # The logic here is as follows:
4868 #
4869 # - If the CL has a .png file under the screenshots directory for a grd
4870 # file, warn the developer. Actual images should never be checked into the
4871 # Chrome repo.
4872 #
4873 # - If the CL contains modified or new messages in grd files and doesn't
4874 # contain the corresponding .sha1 files, warn the developer to add images
4875 # and upload them via tools/translation/upload_screenshots.py.
4876 #
4877 # - If the CL contains modified or new messages in grd files and the
4878 # corresponding .sha1 files, everything looks good.
4879 #
4880 # - If the CL contains removed messages in grd files but the corresponding
4881 # .sha1 files aren't removed, warn the developer to remove them.
4882 unnecessary_screenshots = []
4883 missing_sha1 = []
4884 unnecessary_sha1_files = []
4885
Rainhard Findlingfc31844c52020-05-15 09:58:264886 # This checks verifies that the ICU syntax of messages this CL touched is
4887 # valid, and reports any found syntax errors.
4888 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4889 # without developers being aware of them. Later on, such ICU syntax errors
4890 # break message extraction for translation, hence would block Chromium
4891 # translations until they are fixed.
4892 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144893
4894 def _CheckScreenshotAdded(screenshots_dir, message_id):
4895 sha1_path = input_api.os_path.join(
4896 screenshots_dir, message_id + '.png.sha1')
4897 if sha1_path not in new_or_added_paths:
4898 missing_sha1.append(sha1_path)
4899
4900
4901 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4902 sha1_path = input_api.os_path.join(
4903 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034904 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144905 unnecessary_sha1_files.append(sha1_path)
4906
Rainhard Findlingfc31844c52020-05-15 09:58:264907
4908 def _ValidateIcuSyntax(text, level, signatures):
Daniel Chengab582892021-09-30 20:53:194909 """Validates ICU syntax of a text string.
Rainhard Findlingfc31844c52020-05-15 09:58:264910
4911 Check if text looks similar to ICU and checks for ICU syntax correctness
4912 in this case. Reports various issues with ICU syntax and values of
4913 variants. Supports checking of nested messages. Accumulate information of
4914 each ICU messages found in the text for further checking.
4915
4916 Args:
4917 text: a string to check.
4918 level: a number of current nesting level.
4919 signatures: an accumulator, a list of tuple of (level, variable,
4920 kind, variants).
4921
4922 Returns:
4923 None if a string is not ICU or no issue detected.
4924 A tuple of (message, start index, end index) if an issue detected.
4925 """
Daniel Chengab582892021-09-30 20:53:194926 valid_types = {
4927 'plural': (frozenset(
4928 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4929 frozenset(['=1', 'other'])),
4930 'selectordinal': (frozenset(
4931 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4932 frozenset(['one', 'other'])),
4933 'select': (frozenset(), frozenset(['other'])),
4934 }
Rainhard Findlingfc31844c52020-05-15 09:58:264935
Daniel Chengab582892021-09-30 20:53:194936 # Check if the message looks like an attempt to use ICU
4937 # plural. If yes - check if its syntax strictly matches ICU format.
4938 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4939 if not like:
4940 signatures.append((level, None, None, None))
4941 return
Rainhard Findlingfc31844c52020-05-15 09:58:264942
Daniel Chengab582892021-09-30 20:53:194943 # Check for valid prefix and suffix
4944 m = re.match(
4945 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4946 r'(plural|selectordinal|select),\s*'
4947 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4948 if not m:
4949 return (('This message looks like an ICU plural, '
4950 'but does not follow ICU syntax.'), like.start(), like.end())
4951 starting, variable, kind, variant_pairs = m.groups()
4952 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4953 if depth:
4954 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4955 len(text))
4956 first = text[0]
4957 ending = text[last_pos:]
4958 if not starting:
4959 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4960 last_pos)
4961 if not ending or '}' not in ending:
4962 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4963 last_pos)
4964 elif first != '{':
4965 return (
4966 ('Invalid ICU format. Extra characters at the start of a complex '
4967 'message (go/icu-message-migration): "%s"') %
4968 starting, 0, len(starting))
4969 elif ending != '}':
4970 return (('Invalid ICU format. Extra characters at the end of a complex '
4971 'message (go/icu-message-migration): "%s"')
4972 % ending, last_pos - 1, len(text) - 1)
4973 if kind not in valid_types:
4974 return (('Unknown ICU message type %s. '
4975 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4976 known, required = valid_types[kind]
4977 defined_variants = set()
4978 for variant, variant_range, value, value_range in variants:
4979 start, end = variant_range
4980 if variant in defined_variants:
4981 return ('Variant "%s" is defined more than once' % variant,
4982 start, end)
4983 elif known and variant not in known:
4984 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4985 start, end)
4986 defined_variants.add(variant)
4987 # Check for nested structure
4988 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4989 if res:
4990 return (res[0], res[1] + value_range[0] + 1,
4991 res[2] + value_range[0] + 1)
4992 missing = required - defined_variants
4993 if missing:
4994 return ('Required variants missing: %s' % ', '.join(missing), 0,
4995 len(text))
4996 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:264997
4998
4999 def _ParseIcuVariants(text, offset=0):
5000 """Parse variants part of ICU complex message.
5001
5002 Builds a tuple of variant names and values, as well as
5003 their offsets in the input string.
5004
5005 Args:
5006 text: a string to parse
5007 offset: additional offset to add to positions in the text to get correct
5008 position in the complete ICU string.
5009
5010 Returns:
5011 List of tuples, each tuple consist of four fields: variant name,
5012 variant name span (tuple of two integers), variant value, value
5013 span (tuple of two integers).
5014 """
5015 depth, start, end = 0, -1, -1
5016 variants = []
5017 key = None
5018 for idx, char in enumerate(text):
5019 if char == '{':
5020 if not depth:
5021 start = idx
5022 chunk = text[end + 1:start]
5023 key = chunk.strip()
5024 pos = offset + end + 1 + chunk.find(key)
5025 span = (pos, pos + len(key))
5026 depth += 1
5027 elif char == '}':
5028 if not depth:
5029 return variants, depth, offset + idx
5030 depth -= 1
5031 if not depth:
5032 end = idx
5033 variants.append((key, span, text[start:end + 1], (offset + start,
5034 offset + end + 1)))
5035 return variants, depth, offset + end + 1
5036
meacer8c0d3832019-12-26 21:46:165037 try:
5038 old_sys_path = sys.path
5039 sys.path = sys.path + [input_api.os_path.join(
5040 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5041 from helper import grd_helper
5042 finally:
5043 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145044
5045 for f in affected_grds:
5046 file_path = f.LocalPath()
5047 old_id_to_msg_map = {}
5048 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385049 # Note that this code doesn't check if the file has been deleted. This is
5050 # OK because it only uses the old and new file contents and doesn't load
5051 # the file via its path.
5052 # It's also possible that a file's content refers to a renamed or deleted
5053 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5054 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5055 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145056 if file_path.endswith('.grdp'):
5057 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585058 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595059 '\n'.join(f.OldContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145060 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585061 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595062 '\n'.join(f.NewContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145063 else:
meacerff8a9b62019-12-10 19:43:585064 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145065 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585066 old_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595067 StringIO('\n'.join(f.OldContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145068 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585069 new_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595070 StringIO('\n'.join(f.NewContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145071
Rainhard Findlingd8d04372020-08-13 13:30:095072 grd_name, ext = input_api.os_path.splitext(
5073 input_api.os_path.basename(file_path))
5074 screenshots_dir = input_api.os_path.join(
5075 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5076
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145077 # Compute added, removed and modified message IDs.
5078 old_ids = set(old_id_to_msg_map)
5079 new_ids = set(new_id_to_msg_map)
5080 added_ids = new_ids - old_ids
5081 removed_ids = old_ids - new_ids
5082 modified_ids = set([])
5083 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355084 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095085 != new_id_to_msg_map[key].ContentsAsXml('', True)):
Daniel Chengab582892021-09-30 20:53:195086 # The message content itself changed. Require an updated screenshot.
5087 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355088 elif old_id_to_msg_map[key].attrs['meaning'] != \
5089 new_id_to_msg_map[key].attrs['meaning']:
5090 # The message meaning changed. Ensure there is a screenshot for it.
5091 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5092 if sha1_path not in new_or_added_paths and not \
5093 input_api.os_path.exists(sha1_path):
5094 # There is neither a previous screenshot nor is a new one added now.
5095 # Require a screenshot.
5096 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145097
Rainhard Findlingfc31844c52020-05-15 09:58:265098 if run_screenshot_check:
5099 # Check the screenshot directory for .png files. Warn if there is any.
5100 for png_path in affected_png_paths:
5101 if png_path.startswith(screenshots_dir):
5102 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145103
Rainhard Findlingfc31844c52020-05-15 09:58:265104 for added_id in added_ids:
5105 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145106
Rainhard Findlingfc31844c52020-05-15 09:58:265107 for modified_id in modified_ids:
5108 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145109
Rainhard Findlingfc31844c52020-05-15 09:58:265110 for removed_id in removed_ids:
5111 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5112
5113 # Check new and changed strings for ICU syntax errors.
5114 for key in added_ids.union(modified_ids):
5115 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5116 err = _ValidateIcuSyntax(msg, 0, [])
5117 if err is not None:
5118 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145119
5120 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265121 if run_screenshot_check:
5122 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005123 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265124 'Do not include actual screenshots in the changelist. Run '
5125 'tools/translate/upload_screenshots.py to upload them instead:',
5126 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145127
Rainhard Findlingfc31844c52020-05-15 09:58:265128 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005129 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265130 'You are adding or modifying UI strings.\n'
5131 'To ensure the best translations, take screenshots of the relevant UI '
5132 '(https://g.co/chrome/translation) and add these files to your '
5133 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145134
Rainhard Findlingfc31844c52020-05-15 09:58:265135 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005136 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265137 'You removed strings associated with these files. Remove:',
5138 sorted(unnecessary_sha1_files)))
5139 else:
5140 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5141 'screenshots check.'))
5142
5143 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075144 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265145 'ICU syntax errors were found in the following strings (problems or '
5146 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145147
5148 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125149
5150
Saagar Sanghavifceeaae2020-08-12 16:40:365151def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125152 repo_root=None,
5153 translation_expectations_path=None,
5154 grd_files=None):
5155 import sys
5156 affected_grds = [f for f in input_api.AffectedFiles()
5157 if (f.LocalPath().endswith('.grd') or
5158 f.LocalPath().endswith('.grdp'))]
5159 if not affected_grds:
5160 return []
5161
5162 try:
5163 old_sys_path = sys.path
5164 sys.path = sys.path + [
5165 input_api.os_path.join(
5166 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5167 from helper import git_helper
5168 from helper import translation_helper
5169 finally:
5170 sys.path = old_sys_path
5171
5172 # Check that translation expectations can be parsed and we can get a list of
5173 # translatable grd files. |repo_root| and |translation_expectations_path| are
5174 # only passed by tests.
5175 if not repo_root:
5176 repo_root = input_api.PresubmitLocalPath()
5177 if not translation_expectations_path:
5178 translation_expectations_path = input_api.os_path.join(
5179 repo_root, 'tools', 'gritsettings',
5180 'translation_expectations.pyl')
5181 if not grd_files:
5182 grd_files = git_helper.list_grds_in_repository(repo_root)
5183
dpapad8e21b472020-10-23 17:15:035184 # Ignore bogus grd files used only for testing
5185 # ui/webui/resoucres/tools/generate_grd.py.
5186 ignore_path = input_api.os_path.join(
5187 'ui', 'webui', 'resources', 'tools', 'tests')
Dirk Prankee3c9c62d2021-05-18 18:35:595188 grd_files = [p for p in grd_files if ignore_path not in p]
dpapad8e21b472020-10-23 17:15:035189
Mustafa Emre Acer51f2f742020-03-09 19:41:125190 try:
5191 translation_helper.get_translatable_grds(repo_root, grd_files,
5192 translation_expectations_path)
5193 except Exception as e:
5194 return [output_api.PresubmitNotifyResult(
5195 'Failed to get a list of translatable grd files. This happens when:\n'
5196 ' - One of the modified grd or grdp files cannot be parsed or\n'
5197 ' - %s is not updated.\n'
5198 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5199 return []
Ken Rockotc31f4832020-05-29 18:58:515200
5201
Saagar Sanghavifceeaae2020-08-12 16:40:365202def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515203 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095204 changed_mojoms = input_api.AffectedFiles(
5205 include_deletes=True,
5206 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525207
5208 if not changed_mojoms:
5209 return []
5210
Ken Rockotc31f4832020-05-29 18:58:515211 delta = []
5212 for mojom in changed_mojoms:
5213 old_contents = ''.join(mojom.OldContents()) or None
5214 new_contents = ''.join(mojom.NewContents()) or None
5215 delta.append({
5216 'filename': mojom.LocalPath(),
5217 'old': '\n'.join(mojom.OldContents()) or None,
5218 'new': '\n'.join(mojom.NewContents()) or None,
5219 })
5220
5221 process = input_api.subprocess.Popen(
5222 [input_api.python_executable,
5223 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5224 'public', 'tools', 'mojom',
5225 'check_stable_mojom_compatibility.py'),
5226 '--src-root', input_api.PresubmitLocalPath()],
5227 stdin=input_api.subprocess.PIPE,
5228 stdout=input_api.subprocess.PIPE,
5229 stderr=input_api.subprocess.PIPE,
5230 universal_newlines=True)
5231 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5232 if process.returncode:
5233 return [output_api.PresubmitError(
5234 'One or more [Stable] mojom definitions appears to have been changed '
5235 'in a way that is not backward-compatible.',
5236 long_text=error)]
5237 return []
Dominic Battre645d42342020-12-04 16:14:105238
5239def CheckDeprecationOfPreferences(input_api, output_api):
5240 """Removing a preference should come with a deprecation."""
5241
5242 def FilterFile(affected_file):
5243 """Accept only .cc files and the like."""
5244 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5245 files_to_skip = (_EXCLUDED_PATHS +
5246 _TEST_CODE_EXCLUDED_PATHS +
5247 input_api.DEFAULT_FILES_TO_SKIP)
5248 return input_api.FilterSourceFile(
5249 affected_file,
5250 files_to_check=file_inclusion_pattern,
5251 files_to_skip=files_to_skip)
5252
5253 def ModifiedLines(affected_file):
5254 """Returns a list of tuples (line number, line text) of added and removed
5255 lines.
5256
5257 Deleted lines share the same line number as the previous line.
5258
5259 This relies on the scm diff output describing each changed code section
5260 with a line of the form
5261
5262 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5263 """
5264 line_num = 0
5265 modified_lines = []
5266 for line in affected_file.GenerateScmDiff().splitlines():
5267 # Extract <new line num> of the patch fragment (see format above).
5268 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5269 if m:
5270 line_num = int(m.groups(1)[0])
5271 continue
5272 if ((line.startswith('+') and not line.startswith('++')) or
5273 (line.startswith('-') and not line.startswith('--'))):
5274 modified_lines.append((line_num, line))
5275
5276 if not line.startswith('-'):
5277 line_num += 1
5278 return modified_lines
5279
5280 def FindLineWith(lines, needle):
5281 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5282
5283 If 0 or >1 lines contain `needle`, -1 is returned.
5284 """
5285 matching_line_numbers = [
5286 # + 1 for 1-based counting of line numbers.
5287 i + 1 for i, line
5288 in enumerate(lines)
5289 if needle in line]
5290 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5291
5292 def ModifiedPrefMigration(affected_file):
5293 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5294 # Determine first and last lines of MigrateObsolete.*Pref functions.
5295 new_contents = affected_file.NewContents();
5296 range_1 = (
5297 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5298 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5299 range_2 = (
5300 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5301 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5302 if (-1 in range_1 + range_2):
5303 raise Exception(
5304 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5305
5306 # Check whether any of the modified lines are part of the
5307 # MigrateObsolete.*Pref functions.
5308 for line_nr, line in ModifiedLines(affected_file):
5309 if (range_1[0] <= line_nr <= range_1[1] or
5310 range_2[0] <= line_nr <= range_2[1]):
5311 return True
5312 return False
5313
5314 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5315 browser_prefs_file_pattern = input_api.re.compile(
5316 r'chrome/browser/prefs/browser_prefs.cc')
5317
5318 changes = input_api.AffectedFiles(include_deletes=True,
5319 file_filter=FilterFile)
5320 potential_problems = []
5321 for f in changes:
5322 for line in f.GenerateScmDiff().splitlines():
5323 # Check deleted lines for pref registrations.
5324 if (line.startswith('-') and not line.startswith('--') and
5325 register_pref_pattern.search(line)):
5326 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5327
5328 if browser_prefs_file_pattern.search(f.LocalPath()):
5329 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5330 # assume that they knew that they have to deprecate preferences and don't
5331 # warn.
5332 try:
5333 if ModifiedPrefMigration(f):
5334 return []
5335 except Exception as e:
5336 return [output_api.PresubmitError(str(e))]
5337
5338 if potential_problems:
5339 return [output_api.PresubmitPromptWarning(
5340 'Discovered possible removal of preference registrations.\n\n'
5341 'Please make sure to properly deprecate preferences by clearing their\n'
5342 'value for a couple of milestones before finally removing the code.\n'
5343 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195344 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5345 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105346 'This may be a false positive warning (e.g. if you move preference\n'
5347 'registrations to a different place).\n',
5348 potential_problems
5349 )]
5350 return []
Matt Stark6ef08872021-07-29 01:21:465351
5352def CheckConsistentGrdChanges(input_api, output_api):
5353 """Changes to GRD files must be consistent for tools to read them."""
5354 changed_grds = input_api.AffectedFiles(
5355 include_deletes=False,
5356 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5357 errors = []
Daniel Chengab582892021-09-30 20:53:195358 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5359 for matcher, msg in _INVALID_GRD_FILE_LINE]
Matt Stark6ef08872021-07-29 01:21:465360 for grd in changed_grds:
5361 for i, line in enumerate(grd.NewContents()):
5362 for matcher, msg in invalid_file_regexes:
5363 if matcher.search(line):
Daniel Chengab582892021-09-30 20:53:195364 errors.append(
5365 output_api.PresubmitError('Problem on {grd}:{i} - {msg}'.format(
5366 grd=grd.LocalPath(), i=i + 1, msg=msg)))
Matt Stark6ef08872021-07-29 01:21:465367 return errors
Kevin McNee967dd2d22021-11-15 16:09:295368
5369def CheckMPArchApiUsage(input_api, output_api):
5370 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5371 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5372 """
5373
5374 # Only consider top-level directories that (1) can use content APIs, (2)
5375 # apply to desktop or android chrome, and (3) are known to have a significant
5376 # number of uses of the APIs of concern.
5377 files_to_check = (
5378 r'^(chrome|components|content|extensions)[\\/].+%s' %
5379 _IMPLEMENTATION_EXTENSIONS,
5380 r'^(chrome|components|content|extensions)[\\/].+%s' % _HEADER_EXTENSIONS,
5381 )
5382 files_to_skip=(_EXCLUDED_PATHS +
5383 _TEST_CODE_EXCLUDED_PATHS +
5384 input_api.DEFAULT_FILES_TO_SKIP)
5385 source_file_filter = lambda f: input_api.FilterSourceFile(
5386 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5387
5388 # Note that since these are are just regular expressions and we don't have
5389 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5390 # could have a method named IsInMainFrame).
5391 concerning_class_pattern = input_api.re.compile(
5392 r'WebContentsObserver|WebContentsUserData')
5393 # A subset of WebContentsObserver overrides where there's particular risk for
5394 # confusing tab and page level operations and data (e.g. incorrectly
5395 # resetting page state in DidFinishNavigation).
5396 concerning_wco_methods = [
5397 'DidStartNavigation',
5398 'ReadyToCommitNavigation',
5399 'DidFinishNavigation',
5400 'RenderViewReady',
5401 'RenderViewDeleted',
5402 'RenderViewHostChanged',
5403 'DocumentAvailableInMainFrame',
5404 'DocumentOnLoadCompletedInMainFrame',
5405 'DOMContentLoaded',
5406 'DidFinishLoad',
5407 ]
5408 concerning_nav_handle_methods = [
5409 'IsInMainFrame',
5410 ]
5411 concerning_web_contents_methods = [
5412 'ForEachFrame',
5413 'GetAllFrames',
5414 'FromRenderFrameHost',
5415 'FromRenderViewHost',
5416 'GetMainFrame',
5417 'GetRenderViewHost',
5418 ]
5419 concerning_rfh_methods = [
5420 'GetParent',
5421 'GetMainFrame',
5422 'GetFrameTreeNodeId',
5423 ]
5424 concerning_method_pattern = input_api.re.compile(
5425 r'(' +
5426 r'|'.join(
5427 item
5428 for sublist in [concerning_wco_methods,
5429 concerning_nav_handle_methods,
5430 concerning_web_contents_methods,
5431 concerning_rfh_methods]
5432 for item in sublist) +
5433 r')\(')
5434
5435 uses_concerning_api = False
5436 for f in input_api.AffectedFiles(include_deletes=False,
5437 file_filter=source_file_filter):
5438 for line_num, line in f.ChangedContents():
5439 if (concerning_class_pattern.search(line) or
5440 concerning_method_pattern.search(line)):
5441 uses_concerning_api = True
5442 break
5443 if uses_concerning_api:
5444 break
5445
5446 if uses_concerning_api:
5447 output_api.AppendCC('[email protected]')
5448
5449 return []