blob: 2664f04664e10ff2f63b8f72fd8d29e9eeabd043 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Saagar Sanghavifceeaae2020-08-12 16:40:3610PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1211
Dirk Prankee3c9c62d2021-05-18 18:35:5912# This line is 'magic' in that git-cl looks for it to decide whether to
13# use Python3 instead of Python2 when running the code in this file.
14USE_PYTHON3 = True
15
[email protected]379e7dd2010-01-28 17:39:2116_EXCLUDED_PATHS = (
Mila Greene3aa7222021-09-07 16:34:0817 # File needs to write to stdout to emulate a tool it's replacing.
Mila Greend3fc6a42021-09-10 17:38:2318 r"chrome[\\/]updater[\\/]mac[\\/]keystone[\\/]ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4719 # Generated file.
20 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2621 r"client_variations.js"),
Mila Greene3aa7222021-09-07 16:34:0822 r"^native_client_sdksrc[\\/]build_tools[\\/]make_rules.py",
Egor Paskoce145c42018-09-28 19:31:0423 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
24 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
25 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
26 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4927 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0428 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4629 # sqlite is an imported third party dependency.
30 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0431 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5432 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5333 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1234 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0435 r".+[\\/]pnacl_shim\.c$",
36 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0437 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1438 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0439 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5440 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0441 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4042)
[email protected]ca8d1982009-02-19 16:33:1243
John Abd-El-Malek759fea62021-03-13 03:41:1444_EXCLUDED_SET_NO_PARENT_PATHS = (
45 # It's for historical reasons that blink isn't a top level directory, where
46 # it would be allowed to have "set noparent" to avoid top level owners
47 # accidentally +1ing changes.
48 'third_party/blink/OWNERS',
49)
50
wnwenbdc444e2016-05-25 13:44:1551
[email protected]06e6d0ff2012-12-11 01:36:4452# Fragment of a regular expression that matches C++ and Objective-C++
53# implementation files.
54_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
55
wnwenbdc444e2016-05-25 13:44:1556
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1957# Fragment of a regular expression that matches C++ and Objective-C++
58# header files.
59_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
60
61
[email protected]06e6d0ff2012-12-11 01:36:4462# Regular expression that matches code only used for test binaries
63# (best effort).
64_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0465 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4466 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1367 # Test suite files, like:
68 # foo_browsertest.cc
69 # bar_unittest_mac.cc (suffix)
70 # baz_unittests.cc (plural)
71 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1272 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1873 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2174 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0475 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4376 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0477 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4378 # Web test harness.
79 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4780 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0481 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0882 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0483 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4184 # EarlGrey app side code for tests.
85 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1786 # Views Examples code
87 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4188 # Chromium Codelab
89 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4490)
[email protected]ca8d1982009-02-19 16:33:1291
Daniel Bratell609102be2019-03-27 20:53:2192_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1593
[email protected]eea609a2011-11-18 13:10:1294_TEST_ONLY_WARNING = (
95 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5596 'production code. If you are doing this from inside another method\n'
97 'named as *ForTesting(), then consider exposing things to have tests\n'
98 'make that same call directly.\n'
99 'If that is not possible, you may put a comment on the same line with\n'
100 ' // IN-TEST \n'
101 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
102 'method and can be ignored. Do not do this inside production code.\n'
103 'The android-binary-size trybot will block if the method exists in the\n'
104 'release apk.')
[email protected]eea609a2011-11-18 13:10:12105
106
[email protected]cf9b78f2012-11-14 11:40:28107_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:40108 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:21109 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
110 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:28111
Michael Thiessen44457642020-02-06 00:24:15112# Format: Sequence of tuples containing:
113# * Full import path.
114# * Sequence of strings to show when the pattern matches.
115# * Sequence of path or filename exceptions to this rule
116_BANNED_JAVA_IMPORTS = (
117 (
Colin Blundell170d78c82020-03-12 13:56:04118 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15119 (
120 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
121 ),
122 (
123 'net/android/javatests/src/org/chromium/net/'
124 'AndroidProxySelectorTest.java',
125 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04126 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15127 ),
128 ),
Michael Thiessened631912020-08-07 19:01:31129 (
130 'android.support.test.rule.UiThreadTestRule;',
131 (
132 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43133 '@org.chromium.base.test.UiThreadTest on test methods that should run '
134 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31135 ),
136 (),
137 ),
138 (
139 'android.support.test.annotation.UiThreadTest;',
140 (
141 'Do not use android.support.test.annotation.UiThreadTest, use '
142 'org.chromium.base.test.UiThreadTest instead. See '
143 'https://crbug.com/1111893.',
144 ),
145 ()
Michael Thiessenfd6919b2020-12-08 20:44:01146 ),
147 (
148 'android.support.test.rule.ActivityTestRule;',
149 (
150 'Do not use ActivityTestRule, use '
151 'org.chromium.base.test.BaseActivityTestRule instead.',
152 ),
153 (
154 'components/cronet/',
155 )
Michael Thiessened631912020-08-07 19:01:31156 )
Michael Thiessen44457642020-02-06 00:24:15157)
wnwenbdc444e2016-05-25 13:44:15158
Daniel Bratell609102be2019-03-27 20:53:21159# Format: Sequence of tuples containing:
160# * String pattern or, if starting with a slash, a regular expression.
161# * Sequence of strings to show when the pattern matches.
162# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41163_BANNED_JAVA_FUNCTIONS = (
164 (
165 'StrictMode.allowThreadDiskReads()',
166 (
167 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
168 'directly.',
169 ),
170 False,
171 ),
172 (
173 'StrictMode.allowThreadDiskWrites()',
174 (
175 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
176 'directly.',
177 ),
178 False,
179 ),
Michael Thiessen0f2547e2020-07-27 21:55:36180 (
181 '.waitForIdleSync()',
182 (
183 'Do not use waitForIdleSync as it masks underlying issues. There is '
184 'almost always something else you should wait on instead.',
185 ),
186 False,
187 ),
Eric Stevensona9a980972017-09-23 00:04:41188)
189
Daniel Bratell609102be2019-03-27 20:53:21190# Format: Sequence of tuples containing:
191# * String pattern or, if starting with a slash, a regular expression.
192# * Sequence of strings to show when the pattern matches.
193# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59194_BANNED_OBJC_FUNCTIONS = (
195 (
196 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20197 (
198 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59199 'prohibited. Please use CrTrackingArea instead.',
200 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
201 ),
202 False,
203 ),
204 (
[email protected]eaae1972014-04-16 04:17:26205 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20206 (
207 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59208 'instead.',
209 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
210 ),
211 False,
212 ),
213 (
214 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20215 (
216 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59217 'Please use |convertPoint:(point) fromView:nil| instead.',
218 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
219 ),
220 True,
221 ),
222 (
223 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20224 (
225 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59226 'Please use |convertPoint:(point) toView:nil| instead.',
227 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
228 ),
229 True,
230 ),
231 (
232 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20233 (
234 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59235 'Please use |convertRect:(point) fromView:nil| instead.',
236 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
237 ),
238 True,
239 ),
240 (
241 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20242 (
243 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59244 'Please use |convertRect:(point) toView:nil| instead.',
245 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
246 ),
247 True,
248 ),
249 (
250 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20251 (
252 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59253 'Please use |convertSize:(point) fromView:nil| instead.',
254 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
255 ),
256 True,
257 ),
258 (
259 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20260 (
261 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59262 'Please use |convertSize:(point) toView:nil| instead.',
263 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
264 ),
265 True,
266 ),
jif65398702016-10-27 10:19:48267 (
268 r"/\s+UTF8String\s*]",
269 (
270 'The use of -[NSString UTF8String] is dangerous as it can return null',
271 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
272 'Please use |SysNSStringToUTF8| instead.',
273 ),
274 True,
275 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34276 (
277 r'__unsafe_unretained',
278 (
279 'The use of __unsafe_unretained is almost certainly wrong, unless',
280 'when interacting with NSFastEnumeration or NSInvocation.',
281 'Please use __weak in files build with ARC, nothing otherwise.',
282 ),
283 False,
284 ),
Avi Drissman7382afa02019-04-29 23:27:13285 (
286 'freeWhenDone:NO',
287 (
288 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
289 'Foundation types is prohibited.',
290 ),
291 True,
292 ),
[email protected]127f18ec2012-06-16 05:05:59293)
294
Daniel Bratell609102be2019-03-27 20:53:21295# Format: Sequence of tuples containing:
296# * String pattern or, if starting with a slash, a regular expression.
297# * Sequence of strings to show when the pattern matches.
298# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54299_BANNED_IOS_OBJC_FUNCTIONS = (
300 (
301 r'/\bTEST[(]',
302 (
303 'TEST() macro should not be used in Objective-C++ code as it does not ',
304 'drain the autorelease pool at the end of the test. Use TEST_F() ',
305 'macro instead with a fixture inheriting from PlatformTest (or a ',
306 'typedef).'
307 ),
308 True,
309 ),
310 (
311 r'/\btesting::Test\b',
312 (
313 'testing::Test should not be used in Objective-C++ code as it does ',
314 'not drain the autorelease pool at the end of the test. Use ',
315 'PlatformTest instead.'
316 ),
317 True,
318 ),
319)
320
Peter K. Lee6c03ccff2019-07-15 14:40:05321# Format: Sequence of tuples containing:
322# * String pattern or, if starting with a slash, a regular expression.
323# * Sequence of strings to show when the pattern matches.
324# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
325_BANNED_IOS_EGTEST_FUNCTIONS = (
326 (
327 r'/\bEXPECT_OCMOCK_VERIFY\b',
328 (
329 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
330 'it is meant for GTests. Use [mock verify] instead.'
331 ),
332 True,
333 ),
334)
335
Daniel Bratell609102be2019-03-27 20:53:21336# Format: Sequence of tuples containing:
337# * String pattern or, if starting with a slash, a regular expression.
338# * Sequence of strings to show when the pattern matches.
339# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
340# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59341_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20342 (
Peter Kasting94a56c42019-10-25 21:54:04343 r'/\busing namespace ',
344 (
345 'Using directives ("using namespace x") are banned by the Google Style',
346 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
347 'Explicitly qualify symbols or use using declarations ("using x::foo").',
348 ),
349 True,
350 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
351 ),
Antonio Gomes07300d02019-03-13 20:59:57352 # Make sure that gtest's FRIEND_TEST() macro is not used; the
353 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
354 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53355 (
[email protected]23e6cbc2012-06-16 18:51:20356 'FRIEND_TEST(',
357 (
[email protected]e3c945502012-06-26 20:01:49358 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20359 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
360 ),
361 False,
[email protected]7345da02012-11-27 14:31:49362 (),
[email protected]23e6cbc2012-06-16 18:51:20363 ),
364 (
tomhudsone2c14d552016-05-26 17:07:46365 'setMatrixClip',
366 (
367 'Overriding setMatrixClip() is prohibited; ',
368 'the base function is deprecated. ',
369 ),
370 True,
371 (),
372 ),
373 (
[email protected]52657f62013-05-20 05:30:31374 'SkRefPtr',
375 (
376 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22377 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31378 ),
379 True,
380 (),
381 ),
382 (
383 'SkAutoRef',
384 (
385 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22386 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31387 ),
388 True,
389 (),
390 ),
391 (
392 'SkAutoTUnref',
393 (
394 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22395 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31396 ),
397 True,
398 (),
399 ),
400 (
401 'SkAutoUnref',
402 (
403 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
404 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22405 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31406 ),
407 True,
408 (),
409 ),
[email protected]d89eec82013-12-03 14:10:59410 (
411 r'/HANDLE_EINTR\(.*close',
412 (
413 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
414 'descriptor will be closed, and it is incorrect to retry the close.',
415 'Either call close directly and ignore its return value, or wrap close',
416 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
417 ),
418 True,
419 (),
420 ),
421 (
422 r'/IGNORE_EINTR\((?!.*close)',
423 (
424 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
425 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
426 ),
427 True,
428 (
429 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04430 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
431 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59432 ),
433 ),
[email protected]ec5b3f02014-04-04 18:43:43434 (
435 r'/v8::Extension\(',
436 (
437 'Do not introduce new v8::Extensions into the code base, use',
438 'gin::Wrappable instead. See http://crbug.com/334679',
439 ),
440 True,
[email protected]f55c90ee62014-04-12 00:50:03441 (
Egor Paskoce145c42018-09-28 19:31:04442 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03443 ),
[email protected]ec5b3f02014-04-04 18:43:43444 ),
skyostilf9469f72015-04-20 10:38:52445 (
jame2d1a952016-04-02 00:27:10446 '#pragma comment(lib,',
447 (
448 'Specify libraries to link with in build files and not in the source.',
449 ),
450 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41451 (
tzik3f295992018-12-04 20:32:23452 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04453 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41454 ),
jame2d1a952016-04-02 00:27:10455 ),
fdorayc4ac18d2017-05-01 21:39:59456 (
Gabriel Charette7cc6c432018-04-25 20:52:02457 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59458 (
459 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
460 ),
461 False,
462 (),
463 ),
464 (
Gabriel Charette7cc6c432018-04-25 20:52:02465 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59466 (
467 'Consider using THREAD_CHECKER macros instead of the class directly.',
468 ),
469 False,
470 (),
471 ),
dbeamb6f4fde2017-06-15 04:03:06472 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06473 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
474 (
475 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
476 'deprecated (http://crbug.com/634507). Please avoid converting away',
477 'from the Time types in Chromium code, especially if any math is',
478 'being done on time values. For interfacing with platform/library',
479 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
480 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48481 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06482 'other use cases, please contact base/time/OWNERS.',
483 ),
484 False,
485 (),
486 ),
487 (
dbeamb6f4fde2017-06-15 04:03:06488 'CallJavascriptFunctionUnsafe',
489 (
490 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
491 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
492 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
493 ),
494 False,
495 (
Egor Paskoce145c42018-09-28 19:31:04496 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
497 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
498 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06499 ),
500 ),
dskiba1474c2bfd62017-07-20 02:19:24501 (
502 'leveldb::DB::Open',
503 (
504 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
505 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
506 "Chrome's tracing, making their memory usage visible.",
507 ),
508 True,
509 (
510 r'^third_party/leveldatabase/.*\.(cc|h)$',
511 ),
Gabriel Charette0592c3a2017-07-26 12:02:04512 ),
513 (
Chris Mumfordc38afb62017-10-09 17:55:08514 'leveldb::NewMemEnv',
515 (
516 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58517 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
518 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08519 ),
520 True,
521 (
522 r'^third_party/leveldatabase/.*\.(cc|h)$',
523 ),
524 ),
525 (
Gabriel Charetted9839bc2017-07-29 14:17:47526 'RunLoop::QuitCurrent',
527 (
Robert Liao64b7ab22017-08-04 23:03:43528 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
529 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47530 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41531 False,
Gabriel Charetted9839bc2017-07-29 14:17:47532 (),
Gabriel Charettea44975052017-08-21 23:14:04533 ),
534 (
535 'base::ScopedMockTimeMessageLoopTaskRunner',
536 (
Gabriel Charette87cc1af2018-04-25 20:52:51537 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11538 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51539 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
540 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
541 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04542 ),
Gabriel Charette87cc1af2018-04-25 20:52:51543 False,
Gabriel Charettea44975052017-08-21 23:14:04544 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57545 ),
546 (
Dave Tapuska98199b612019-07-10 13:30:44547 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57548 (
549 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02550 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57551 ),
552 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16553 # Abseil's benchmarks never linked into chrome.
554 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38555 ),
556 (
Peter Kasting991618a62019-06-17 22:00:09557 r'/\bstd::stoi\b',
558 (
559 'std::stoi uses exceptions to communicate results. ',
560 'Use base::StringToInt() instead.',
561 ),
562 True,
563 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
564 ),
565 (
566 r'/\bstd::stol\b',
567 (
568 'std::stol uses exceptions to communicate results. ',
569 'Use base::StringToInt() instead.',
570 ),
571 True,
572 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
573 ),
574 (
575 r'/\bstd::stoul\b',
576 (
577 'std::stoul uses exceptions to communicate results. ',
578 'Use base::StringToUint() instead.',
579 ),
580 True,
581 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
582 ),
583 (
584 r'/\bstd::stoll\b',
585 (
586 'std::stoll uses exceptions to communicate results. ',
587 'Use base::StringToInt64() instead.',
588 ),
589 True,
590 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
591 ),
592 (
593 r'/\bstd::stoull\b',
594 (
595 'std::stoull uses exceptions to communicate results. ',
596 'Use base::StringToUint64() instead.',
597 ),
598 True,
599 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
600 ),
601 (
602 r'/\bstd::stof\b',
603 (
604 'std::stof uses exceptions to communicate results. ',
605 'For locale-independent values, e.g. reading numbers from disk',
606 'profiles, use base::StringToDouble().',
607 'For user-visible values, parse using ICU.',
608 ),
609 True,
610 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
611 ),
612 (
613 r'/\bstd::stod\b',
614 (
615 'std::stod uses exceptions to communicate results. ',
616 'For locale-independent values, e.g. reading numbers from disk',
617 'profiles, use base::StringToDouble().',
618 'For user-visible values, parse using ICU.',
619 ),
620 True,
621 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
622 ),
623 (
624 r'/\bstd::stold\b',
625 (
626 'std::stold uses exceptions to communicate results. ',
627 'For locale-independent values, e.g. reading numbers from disk',
628 'profiles, use base::StringToDouble().',
629 'For user-visible values, parse using ICU.',
630 ),
631 True,
632 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
633 ),
634 (
Daniel Bratell69334cc2019-03-26 11:07:45635 r'/\bstd::to_string\b',
636 (
637 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09638 'For locale-independent strings, e.g. writing numbers to disk',
639 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45640 'For user-visible strings, use base::FormatNumber() and',
641 'the related functions in base/i18n/number_formatting.h.',
642 ),
Peter Kasting991618a62019-06-17 22:00:09643 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21644 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45645 ),
646 (
647 r'/\bstd::shared_ptr\b',
648 (
649 'std::shared_ptr should not be used. Use scoped_refptr instead.',
650 ),
651 True,
Ulan Degenbaev947043882021-02-10 14:02:31652 [
653 # Needed for interop with third-party library.
654 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57655 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58656 '^third_party/blink/renderer/bindings/core/v8/' +
657 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58658 '^gin/array_buffer\.(cc|h)',
659 '^chrome/services/sharing/nearby/',
Meilin Wang00efc7c2021-05-13 01:12:42660 # gRPC provides some C++ libraries that use std::shared_ptr<>.
661 '^chromeos/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59662 '^chromecast/cast_core/grpc',
663 '^chromecast/cast_core/runtime/browser',
Wez5f56be52021-05-04 09:30:58664 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
665 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57666 # Needed for clang plugin tests
667 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57668 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21669 ),
670 (
Peter Kasting991618a62019-06-17 22:00:09671 r'/\bstd::weak_ptr\b',
672 (
673 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
674 ),
675 True,
676 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
677 ),
678 (
Daniel Bratell609102be2019-03-27 20:53:21679 r'/\blong long\b',
680 (
681 'long long is banned. Use stdint.h if you need a 64 bit number.',
682 ),
683 False, # Only a warning since it is already used.
684 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
685 ),
686 (
Daniel Chengc05fcc62022-01-12 16:54:29687 r'\b(absl|std)::any\b',
688 (
689 'absl::any / std::any are not safe to use in a component build.'
690 ),
691 True,
692 # Not an error in third party folders, though it probably should be :)
693 [_THIRD_PARTY_EXCEPT_BLINK],
694 ),
695 (
Daniel Bratell609102be2019-03-27 20:53:21696 r'/\bstd::bind\b',
697 (
698 'std::bind is banned because of lifetime risks.',
699 'Use base::BindOnce or base::BindRepeating instead.',
700 ),
701 True,
702 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
703 ),
704 (
705 r'/\b#include <chrono>\b',
706 (
707 '<chrono> overlaps with Time APIs in base. Keep using',
708 'base classes.',
709 ),
710 True,
711 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
712 ),
713 (
714 r'/\b#include <exception>\b',
715 (
716 'Exceptions are banned and disabled in Chromium.',
717 ),
718 True,
719 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
720 ),
721 (
722 r'/\bstd::function\b',
723 (
Colin Blundellea615d422021-05-12 09:35:41724 'std::function is banned. Instead use base::OnceCallback or ',
725 'base::RepeatingCallback, which directly support Chromium\'s weak ',
726 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21727 ),
Peter Kasting991618a62019-06-17 22:00:09728 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21729 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
730 ),
731 (
732 r'/\b#include <random>\b',
733 (
734 'Do not use any random number engines from <random>. Instead',
735 'use base::RandomBitGenerator.',
736 ),
737 True,
738 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
739 ),
740 (
Tom Andersona95e12042020-09-09 23:08:00741 r'/\b#include <X11/',
742 (
743 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
744 ),
745 True,
746 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
747 ),
748 (
Daniel Bratell609102be2019-03-27 20:53:21749 r'/\bstd::ratio\b',
750 (
751 'std::ratio is banned by the Google Style Guide.',
752 ),
753 True,
754 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45755 ),
756 (
Gabriel Charetted90bcc92021-09-21 00:23:10757 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:38758 (
Gabriel Charetted90bcc92021-09-21 00:23:10759 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:38760 ),
Gabriel Charette04b138f2018-08-06 00:03:22761 False,
Francois Doray43670e32017-09-27 12:40:38762 (),
763 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38764 (
Michael Giuffrida7f93d6922019-04-19 14:39:58765 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19766 (
767 'RunMessageLoop is deprecated, use RunLoop instead.',
768 ),
769 False,
770 (),
771 ),
772 (
Dave Tapuska98199b612019-07-10 13:30:44773 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19774 (
775 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
776 ),
777 False,
778 (),
779 ),
780 (
Dave Tapuska98199b612019-07-10 13:30:44781 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19782 (
783 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
784 "if you're convinced you need this.",
785 ),
786 False,
787 (),
788 ),
789 (
Dave Tapuska98199b612019-07-10 13:30:44790 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19791 (
792 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04793 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19794 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
795 'async events instead of flushing threads.',
796 ),
797 False,
798 (),
799 ),
800 (
801 r'MessageLoopRunner',
802 (
803 'MessageLoopRunner is deprecated, use RunLoop instead.',
804 ),
805 False,
806 (),
807 ),
808 (
Dave Tapuska98199b612019-07-10 13:30:44809 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19810 (
811 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
812 "gab@ if you found a use case where this is the only solution.",
813 ),
814 False,
815 (),
816 ),
817 (
Victor Costane48a2e82019-03-15 22:02:34818 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16819 (
Victor Costane48a2e82019-03-15 22:02:34820 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16821 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
822 ),
823 True,
824 (
825 r'^sql/initialization\.(cc|h)$',
826 r'^third_party/sqlite/.*\.(c|cc|h)$',
827 ),
828 ),
Matt Menke7f520a82018-03-28 21:38:37829 (
Dave Tapuska98199b612019-07-10 13:30:44830 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47831 (
832 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
833 'base::RandomShuffle instead.'
834 ),
835 True,
836 (),
837 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24838 (
839 'ios/web/public/test/http_server',
840 (
841 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
842 ),
843 False,
844 (),
845 ),
Robert Liao764c9492019-01-24 18:46:28846 (
847 'GetAddressOf',
848 (
849 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53850 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11851 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53852 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28853 ),
854 True,
855 (),
856 ),
Antonio Gomes07300d02019-03-13 20:59:57857 (
Ben Lewisa9514602019-04-29 17:53:05858 'SHFileOperation',
859 (
860 'SHFileOperation was deprecated in Windows Vista, and there are less ',
861 'complex functions to achieve the same goals. Use IFileOperation for ',
862 'any esoteric actions instead.'
863 ),
864 True,
865 (),
866 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18867 (
Cliff Smolinsky81951642019-04-30 21:39:51868 'StringFromGUID2',
869 (
870 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24871 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51872 ),
873 True,
874 (
875 r'/base/win/win_util_unittest.cc'
876 ),
877 ),
878 (
879 'StringFromCLSID',
880 (
881 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24882 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51883 ),
884 True,
885 (
886 r'/base/win/win_util_unittest.cc'
887 ),
888 ),
889 (
Avi Drissman7382afa02019-04-29 23:27:13890 'kCFAllocatorNull',
891 (
892 'The use of kCFAllocatorNull with the NoCopy creation of ',
893 'CoreFoundation types is prohibited.',
894 ),
895 True,
896 (),
897 ),
Oksana Zhuravlovafd247772019-05-16 16:57:29898 (
899 'mojo::ConvertTo',
900 (
901 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
902 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
903 'StringTraits if you would like to convert between custom types and',
904 'the wire format of mojom types.'
905 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22906 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29907 (
Wezf89dec092019-09-11 19:38:33908 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
909 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29910 r'^third_party/blink/.*\.(cc|h)$',
911 r'^content/renderer/.*\.(cc|h)$',
912 ),
913 ),
Robert Liao1d78df52019-11-11 20:02:01914 (
Oksana Zhuravlovac8222d22019-12-19 19:21:16915 'GetInterfaceProvider',
916 (
917 'InterfaceProvider is deprecated.',
918 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
919 'or Platform::GetBrowserInterfaceBroker.'
920 ),
921 False,
922 (),
923 ),
924 (
Robert Liao1d78df52019-11-11 20:02:01925 'CComPtr',
926 (
927 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
928 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
929 'details.'
930 ),
931 False,
932 (),
933 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:20934 (
935 r'/\b(IFACE|STD)METHOD_?\(',
936 (
937 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
938 'Instead, always use IFACEMETHODIMP in the declaration.'
939 ),
940 False,
941 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
942 ),
Allen Bauer53b43fb12020-03-12 17:21:47943 (
944 'set_owned_by_client',
945 (
946 'set_owned_by_client is deprecated.',
947 'views::View already owns the child views by default. This introduces ',
948 'a competing ownership model which makes the code difficult to reason ',
949 'about. See http://crbug.com/1044687 for more details.'
950 ),
951 False,
952 (),
953 ),
Eric Secklerbe6f48d2020-05-06 18:09:12954 (
Peter Boström7ff41522021-07-29 03:43:27955 'RemoveAllChildViewsWithoutDeleting',
956 (
957 'RemoveAllChildViewsWithoutDeleting is deprecated.',
958 'This method is deemed dangerous as, unless raw pointers are re-added,',
959 'calls to this method introduce memory leaks.'
960 ),
961 False,
962 (),
963 ),
964 (
Eric Secklerbe6f48d2020-05-06 18:09:12965 r'/\bTRACE_EVENT_ASYNC_',
966 (
967 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
968 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
969 ),
970 False,
971 (
972 r'^base/trace_event/.*',
973 r'^base/tracing/.*',
974 ),
975 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:26976 (
Robert Liao22f66a52021-04-10 00:57:52977 'RoInitialize',
978 (
Robert Liao48018922021-04-16 23:03:02979 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:52980 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
981 'instead. See http://crbug.com/1197722 for more information.'
982 ),
983 True,
Robert Liao48018922021-04-16 23:03:02984 (
985 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$'
986 ),
Robert Liao22f66a52021-04-10 00:57:52987 ),
[email protected]127f18ec2012-06-16 05:05:59988)
989
Mario Sanchez Prada2472cab2019-09-18 10:58:31990# Format: Sequence of tuples containing:
991# * String pattern or, if starting with a slash, a regular expression.
992# * Sequence of strings to show when the pattern matches.
993_DEPRECATED_MOJO_TYPES = (
994 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31995 r'/\bmojo::AssociatedInterfacePtrInfo\b',
996 (
997 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
998 'Use mojo::PendingAssociatedRemote<Interface> instead.',
999 ),
1000 ),
1001 (
1002 r'/\bmojo::AssociatedInterfaceRequest\b',
1003 (
1004 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1005 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1006 ),
1007 ),
1008 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311009 r'/\bmojo::InterfacePtr\b',
1010 (
1011 'mojo::InterfacePtr<Interface> is deprecated.',
1012 'Use mojo::Remote<Interface> instead.',
1013 ),
1014 ),
1015 (
1016 r'/\bmojo::InterfacePtrInfo\b',
1017 (
1018 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1019 'Use mojo::PendingRemote<Interface> instead.',
1020 ),
1021 ),
1022 (
1023 r'/\bmojo::InterfaceRequest\b',
1024 (
1025 'mojo::InterfaceRequest<Interface> is deprecated.',
1026 'Use mojo::PendingReceiver<Interface> instead.',
1027 ),
1028 ),
1029 (
1030 r'/\bmojo::MakeRequest\b',
1031 (
1032 'mojo::MakeRequest is deprecated.',
1033 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1034 ),
1035 ),
Mario Sanchez Prada2472cab2019-09-18 10:58:311036)
wnwenbdc444e2016-05-25 13:44:151037
mlamouria82272622014-09-16 18:45:041038_IPC_ENUM_TRAITS_DEPRECATED = (
1039 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501040 'See http://www.chromium.org/Home/chromium-security/education/'
1041 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041042
Stephen Martinis97a394142018-06-07 23:06:051043_LONG_PATH_ERROR = (
1044 'Some files included in this CL have file names that are too long (> 200'
1045 ' characters). If committed, these files will cause issues on Windows. See'
1046 ' https://crbug.com/612667 for more details.'
1047)
1048
Shenghua Zhangbfaa38b82017-11-16 21:58:021049_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041050 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041051 r".*[\\/]BuildHooksAndroidImpl\.java",
1052 r".*[\\/]LicenseContentProvider\.java",
1053 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281054 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021055]
[email protected]127f18ec2012-06-16 05:05:591056
Mohamed Heikald048240a2019-11-12 16:57:371057# List of image extensions that are used as resources in chromium.
1058_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1059
Sean Kau46e29bc2017-08-28 16:31:161060# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401061_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041062 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401063 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041064 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1065 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041066 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431067 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161068]
1069
Andrew Grieveb773bad2020-06-05 18:00:381070# These are not checked on the public chromium-presubmit trybot.
1071# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041072# checkouts.
agrievef32bcc72016-04-04 14:57:401073_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381074 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381075]
1076
1077
1078_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041079 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361080 'base/android/jni_generator/jni_generator.pydeps',
1081 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361082 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041083 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361084 'build/android/gyp/aar.pydeps',
1085 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271086 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361087 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381088 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361089 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021090 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221091 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111092 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361093 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361094 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361095 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111096 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041097 'build/android/gyp/create_app_bundle_apks.pydeps',
1098 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361099 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121100 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091101 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221102 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001103 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361104 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421105 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041106 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361107 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361108 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211109 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361110 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361111 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361112 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581113 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361114 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141115 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261116 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471117 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011118 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041119 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361120 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361121 'build/android/gyp/merge_manifest.pydeps',
1122 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221123 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361124 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461125 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301126 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241127 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361128 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461129 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561130 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361131 'build/android/incremental_install/generate_android_manifest.pydeps',
1132 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041133 'build/android/resource_sizes.pydeps',
1134 'build/android/test_runner.pydeps',
1135 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361136 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361137 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321138 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271139 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1140 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041141 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001142 'components/cronet/tools/generate_javadoc.pydeps',
1143 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381144 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001145 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381146 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041147 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181148 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041149 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421150 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1151 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131152 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501153 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061154 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221155 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401156]
1157
wnwenbdc444e2016-05-25 13:44:151158
agrievef32bcc72016-04-04 14:57:401159_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1160
1161
Eric Boren6fd2b932018-01-25 15:05:081162# Bypass the AUTHORS check for these accounts.
1163_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591164 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451165 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591166 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521167 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231168 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471169 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Jieting Yang668bde92022-01-27 18:40:431170 'infra-try-recipes-tester', 'lacros-tracking-roller')
Eric Boren835d71f2018-09-07 21:09:041171 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271172 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041173 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161174 for s in ('chromium-internal-autoroll',)
1175 ) | set('%[email protected]' % s
1176 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081177
Matt Stark6ef08872021-07-29 01:21:461178_INVALID_GRD_FILE_LINE = [
1179 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1180]
Eric Boren6fd2b932018-01-25 15:05:081181
Daniel Bratell65b033262019-04-23 08:17:061182def _IsCPlusPlusFile(input_api, file_path):
1183 """Returns True if this file contains C++-like code (and not Python,
1184 Go, Java, MarkDown, ...)"""
1185
1186 ext = input_api.os_path.splitext(file_path)[1]
1187 # This list is compatible with CppChecker.IsCppFile but we should
1188 # consider adding ".c" to it. If we do that we can use this function
1189 # at more places in the code.
1190 return ext in (
1191 '.h',
1192 '.cc',
1193 '.cpp',
1194 '.m',
1195 '.mm',
1196 )
1197
1198def _IsCPlusPlusHeaderFile(input_api, file_path):
1199 return input_api.os_path.splitext(file_path)[1] == ".h"
1200
1201
1202def _IsJavaFile(input_api, file_path):
1203 return input_api.os_path.splitext(file_path)[1] == ".java"
1204
1205
1206def _IsProtoFile(input_api, file_path):
1207 return input_api.os_path.splitext(file_path)[1] == ".proto"
1208
Mohamed Heikal5e5b7922020-10-29 18:57:591209
Erik Staabc734cd7a2021-11-23 03:11:521210def _IsXmlOrGrdFile(input_api, file_path):
1211 ext = input_api.os_path.splitext(file_path)[1]
1212 return ext in ('.grd', '.xml')
1213
1214
Mohamed Heikal5e5b7922020-10-29 18:57:591215def CheckNoUpstreamDepsOnClank(input_api, output_api):
1216 """Prevent additions of dependencies from the upstream repo on //clank."""
1217 # clank can depend on clank
1218 if input_api.change.RepositoryRoot().endswith('clank'):
1219 return []
1220 build_file_patterns = [
1221 r'(.+/)?BUILD\.gn',
1222 r'.+\.gni',
1223 ]
1224 excluded_files = [
1225 r'build[/\\]config[/\\]android[/\\]config\.gni'
1226 ]
1227 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1228
1229 error_message = 'Disallowed import on //clank in an upstream build file:'
1230
1231 def FilterFile(affected_file):
1232 return input_api.FilterSourceFile(
1233 affected_file,
1234 files_to_check=build_file_patterns,
1235 files_to_skip=excluded_files)
1236
1237 problems = []
1238 for f in input_api.AffectedSourceFiles(FilterFile):
1239 local_path = f.LocalPath()
1240 for line_number, line in f.ChangedContents():
1241 if (bad_pattern.search(line)):
1242 problems.append(
1243 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1244 if problems:
1245 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1246 else:
1247 return []
1248
1249
Saagar Sanghavifceeaae2020-08-12 16:40:361250def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191251 """Attempts to prevent use of functions intended only for testing in
1252 non-testing code. For now this is just a best-effort implementation
1253 that ignores header files and may have some false positives. A
1254 better implementation would probably need a proper C++ parser.
1255 """
1256 # We only scan .cc files and the like, as the declaration of
1257 # for-testing functions in header files are hard to distinguish from
1258 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491259 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191260
jochenc0d4808c2015-07-27 09:25:421261 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191262 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091263 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131264 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191265 exclusion_pattern = input_api.re.compile(
1266 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1267 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131268 # Avoid a false positive in this case, where the method name, the ::, and
1269 # the closing { are all on different lines due to line wrapping.
1270 # HelperClassForTesting::
1271 # HelperClassForTesting(
1272 # args)
1273 # : member(0) {}
1274 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191275
1276 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441277 files_to_skip = (_EXCLUDED_PATHS +
1278 _TEST_CODE_EXCLUDED_PATHS +
1279 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191280 return input_api.FilterSourceFile(
1281 affected_file,
James Cook24a504192020-07-23 00:08:441282 files_to_check=file_inclusion_pattern,
1283 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191284
1285 problems = []
1286 for f in input_api.AffectedSourceFiles(FilterFile):
1287 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131288 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241289 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031290 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461291 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131292 not exclusion_pattern.search(line) and
1293 not allowlist_pattern.search(line) and
1294 not in_method_defn):
[email protected]55459852011-08-10 15:17:191295 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031296 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131297 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191298
1299 if problems:
[email protected]f7051d52013-04-02 18:31:421300 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031301 else:
1302 return []
[email protected]55459852011-08-10 15:17:191303
1304
Saagar Sanghavifceeaae2020-08-12 16:40:361305def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231306 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591307 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231308 """
1309 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1310 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1311 name_pattern = r'ForTest(s|ing)?'
1312 # Describes an occurrence of "ForTest*" inside a // comment.
1313 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501314 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551315 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231316 # Catch calls.
1317 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1318 # Ignore definitions. (Comments are ignored separately.)
1319 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1320
1321 problems = []
1322 sources = lambda x: input_api.FilterSourceFile(
1323 x,
James Cook24a504192020-07-23 00:08:441324 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1325 + input_api.DEFAULT_FILES_TO_SKIP),
1326 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231327 )
1328 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1329 local_path = f.LocalPath()
1330 is_inside_javadoc = False
1331 for line_number, line in f.ChangedContents():
1332 if is_inside_javadoc and javadoc_end_re.search(line):
1333 is_inside_javadoc = False
1334 if not is_inside_javadoc and javadoc_start_re.search(line):
1335 is_inside_javadoc = True
1336 if is_inside_javadoc:
1337 continue
1338 if (inclusion_re.search(line) and
1339 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501340 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231341 not exclusion_re.search(line)):
1342 problems.append(
1343 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1344
1345 if problems:
1346 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1347 else:
1348 return []
1349
1350
Saagar Sanghavifceeaae2020-08-12 16:40:361351def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541352 """Checks to make sure no .h files include <iostream>."""
1353 files = []
1354 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1355 input_api.re.MULTILINE)
1356 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1357 if not f.LocalPath().endswith('.h'):
1358 continue
1359 contents = input_api.ReadFile(f)
1360 if pattern.search(contents):
1361 files.append(f)
1362
1363 if len(files):
yolandyandaabc6d2016-04-18 18:29:391364 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061365 'Do not #include <iostream> in header files, since it inserts static '
1366 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541367 '#include <ostream>. See http://crbug.com/94794',
1368 files) ]
1369 return []
1370
Danil Chapovalov3518f362018-08-11 16:13:431371def _CheckNoStrCatRedefines(input_api, output_api):
1372 """Checks no windows headers with StrCat redefined are included directly."""
1373 files = []
1374 pattern_deny = input_api.re.compile(
1375 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1376 input_api.re.MULTILINE)
1377 pattern_allow = input_api.re.compile(
1378 r'^#include\s"base/win/windows_defines.inc"',
1379 input_api.re.MULTILINE)
1380 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1381 contents = input_api.ReadFile(f)
1382 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1383 files.append(f.LocalPath())
1384
1385 if len(files):
1386 return [output_api.PresubmitError(
1387 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1388 'directly since they pollute code with StrCat macro. Instead, '
1389 'include matching header from base/win. See http://crbug.com/856536',
1390 files) ]
1391 return []
1392
[email protected]10689ca2011-09-02 02:31:541393
Saagar Sanghavifceeaae2020-08-12 16:40:361394def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521395 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181396 problems = []
1397 for f in input_api.AffectedFiles():
1398 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1399 continue
1400
1401 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041402 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181403 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1404
1405 if not problems:
1406 return []
1407 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1408 '\n'.join(problems))]
1409
Saagar Sanghavifceeaae2020-08-12 16:40:361410def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341411 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1412
1413 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1414 instead of DISABLED_. To filter false positives, reports are only generated
1415 if a corresponding MAYBE_ line exists.
1416 """
1417 problems = []
1418
1419 # The following two patterns are looked for in tandem - is a test labeled
1420 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1421 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1422 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1423
1424 # This is for the case that a test is disabled on all platforms.
1425 full_disable_pattern = input_api.re.compile(
1426 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1427 input_api.re.MULTILINE)
1428
Katie Df13948e2018-09-25 07:33:441429 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341430 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1431 continue
1432
1433 # Search for MABYE_, DISABLE_ pairs.
1434 disable_lines = {} # Maps of test name to line number.
1435 maybe_lines = {}
1436 for line_num, line in f.ChangedContents():
1437 disable_match = disable_pattern.search(line)
1438 if disable_match:
1439 disable_lines[disable_match.group(1)] = line_num
1440 maybe_match = maybe_pattern.search(line)
1441 if maybe_match:
1442 maybe_lines[maybe_match.group(1)] = line_num
1443
1444 # Search for DISABLE_ occurrences within a TEST() macro.
1445 disable_tests = set(disable_lines.keys())
1446 maybe_tests = set(maybe_lines.keys())
1447 for test in disable_tests.intersection(maybe_tests):
1448 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1449
1450 contents = input_api.ReadFile(f)
1451 full_disable_match = full_disable_pattern.search(contents)
1452 if full_disable_match:
1453 problems.append(' %s' % f.LocalPath())
1454
1455 if not problems:
1456 return []
1457 return [
1458 output_api.PresubmitPromptWarning(
1459 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1460 '\n'.join(problems))
1461 ]
1462
Nina Satragnof7660532021-09-20 18:03:351463def CheckForgettingMAYBEInTests(input_api, output_api):
1464 """Checks to make sure tests disabled conditionally are not missing a
1465 corresponding MAYBE_ prefix.
1466 """
1467 # Expect at least a lowercase character in the test name. This helps rule out
1468 # false positives with macros wrapping the actual tests name.
1469 define_maybe_pattern = input_api.re.compile(
1470 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
1471 test_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*\w+,\s*MAYBE_{test_name}\)'
1472 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1473 warnings = []
1474
1475 # Read the entire files. We can't just read the affected lines, forgetting to
1476 # add MAYBE_ on a change would not show up otherwise.
1477 for f in input_api.AffectedFiles(False):
1478 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1479 continue
1480 contents = input_api.ReadFile(f)
1481 lines = contents.splitlines(True)
1482 current_position = 0
1483 warning_test_names = set()
1484 for line_num, line in enumerate(lines, start=1):
1485 current_position += len(line)
1486 maybe_match = define_maybe_pattern.search(line)
1487 if maybe_match:
1488 test_name = maybe_match.group('test_name')
1489 # Do not warn twice for the same test.
1490 if (test_name in warning_test_names):
1491 continue
1492 warning_test_names.add(test_name)
1493
1494 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1495 # the current position.
1496 test_match = input_api.re.compile(
1497 test_maybe_pattern.format(test_name=test_name),
1498 input_api.re.MULTILINE).search(contents, current_position)
1499 suite_match = input_api.re.compile(
1500 suite_maybe_pattern.format(test_name=test_name),
1501 input_api.re.MULTILINE).search(contents, current_position)
1502 if not test_match and not suite_match:
1503 warnings.append(
1504 output_api.PresubmitPromptWarning(
1505 '%s:%d found MAYBE_ defined without corresponding test %s' %
1506 (f.LocalPath(), line_num, test_name)))
1507 return warnings
[email protected]72df4e782012-06-21 16:28:181508
Saagar Sanghavifceeaae2020-08-12 16:40:361509def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571510 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521511 errors = []
Hans Wennborg944479f2020-06-25 21:39:251512 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521513 input_api.re.MULTILINE)
1514 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1515 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1516 continue
1517 for lnum, line in f.ChangedContents():
1518 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171519 errors.append(output_api.PresubmitError(
1520 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571521 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171522 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521523 return errors
1524
1525
Weilun Shia487fad2020-10-28 00:10:341526# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1527# more reliable way. See
1528# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191529
wnwenbdc444e2016-05-25 13:44:151530
Saagar Sanghavifceeaae2020-08-12 16:40:361531def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391532 """Check that FlakyTest annotation is our own instead of the android one"""
1533 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1534 files = []
1535 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1536 if f.LocalPath().endswith('Test.java'):
1537 if pattern.search(input_api.ReadFile(f)):
1538 files.append(f)
1539 if len(files):
1540 return [output_api.PresubmitError(
1541 'Use org.chromium.base.test.util.FlakyTest instead of '
1542 'android.test.FlakyTest',
1543 files)]
1544 return []
mcasasb7440c282015-02-04 14:52:191545
wnwenbdc444e2016-05-25 13:44:151546
Saagar Sanghavifceeaae2020-08-12 16:40:361547def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441548 """Make sure .DEPS.git is never modified manually."""
1549 if any(f.LocalPath().endswith('.DEPS.git') for f in
1550 input_api.AffectedFiles()):
1551 return [output_api.PresubmitError(
1552 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1553 'automated system based on what\'s in DEPS and your changes will be\n'
1554 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501555 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1556 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441557 'for more information')]
1558 return []
1559
1560
Saagar Sanghavifceeaae2020-08-12 16:40:361561def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471562 """Checks that DEPS file deps are from allowed_hosts."""
1563 # Run only if DEPS file has been modified to annoy fewer bystanders.
1564 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1565 return []
1566 # Outsource work to gclient verify
1567 try:
John Budorickf20c0042019-04-25 23:23:401568 gclient_path = input_api.os_path.join(
1569 input_api.PresubmitLocalPath(),
1570 'third_party', 'depot_tools', 'gclient.py')
1571 input_api.subprocess.check_output(
1572 [input_api.python_executable, gclient_path, 'verify'],
1573 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471574 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201575 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471576 return [output_api.PresubmitError(
1577 'DEPS file must have only git dependencies.',
1578 long_text=error.output)]
1579
1580
Mario Sanchez Prada2472cab2019-09-18 10:58:311581def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1582 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591583 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311584
1585 Returns an string composed of the name of the file, the line number where the
1586 match has been found and the additional text passed as |message| in case the
1587 target type name matches the text inside the line passed as parameter.
1588 """
Peng Huang9c5949a02020-06-11 19:20:541589 result = []
1590
danakjd18e8892020-12-17 17:42:011591 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1592 return result
1593 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541594 return result
1595
Mario Sanchez Prada2472cab2019-09-18 10:58:311596 matched = False
1597 if type_name[0:1] == '/':
1598 regex = type_name[1:]
1599 if input_api.re.search(regex, line):
1600 matched = True
1601 elif type_name in line:
1602 matched = True
1603
Mario Sanchez Prada2472cab2019-09-18 10:58:311604 if matched:
1605 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1606 for message_line in message:
1607 result.append(' %s' % message_line)
1608
1609 return result
1610
1611
Saagar Sanghavifceeaae2020-08-12 16:40:361612def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591613 """Make sure that banned functions are not used."""
1614 warnings = []
1615 errors = []
1616
James Cook24a504192020-07-23 00:08:441617 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151618 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441619 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151620 if input_api.re.match(item, local_path):
1621 return True
1622 return False
1623
Peter K. Lee6c03ccff2019-07-15 14:40:051624 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541625 local_path = affected_file.LocalPath()
1626 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1627 return False
1628 basename = input_api.os_path.basename(local_path)
1629 if 'ios' in basename.split('_'):
1630 return True
1631 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1632 if sep and 'ios' in local_path.split(sep):
1633 return True
1634 return False
1635
wnwenbdc444e2016-05-25 13:44:151636 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311637 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1638 func_name, message)
1639 if problems:
wnwenbdc444e2016-05-25 13:44:151640 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311641 errors.extend(problems)
1642 else:
1643 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151644
Eric Stevensona9a980972017-09-23 00:04:411645 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1646 for f in input_api.AffectedFiles(file_filter=file_filter):
1647 for line_num, line in f.ChangedContents():
1648 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1649 CheckForMatch(f, line_num, line, func_name, message, error)
1650
[email protected]127f18ec2012-06-16 05:05:591651 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1652 for f in input_api.AffectedFiles(file_filter=file_filter):
1653 for line_num, line in f.ChangedContents():
1654 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151655 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591656
Peter K. Lee6c03ccff2019-07-15 14:40:051657 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541658 for line_num, line in f.ChangedContents():
1659 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1660 CheckForMatch(f, line_num, line, func_name, message, error)
1661
Peter K. Lee6c03ccff2019-07-15 14:40:051662 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1663 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1664 for line_num, line in f.ChangedContents():
1665 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1666 CheckForMatch(f, line_num, line, func_name, message, error)
1667
[email protected]127f18ec2012-06-16 05:05:591668 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1669 for f in input_api.AffectedFiles(file_filter=file_filter):
1670 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491671 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441672 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491673 continue
wnwenbdc444e2016-05-25 13:44:151674 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591675
1676 result = []
1677 if (warnings):
1678 result.append(output_api.PresubmitPromptWarning(
1679 'Banned functions were used.\n' + '\n'.join(warnings)))
1680 if (errors):
1681 result.append(output_api.PresubmitError(
1682 'Banned functions were used.\n' + '\n'.join(errors)))
1683 return result
1684
1685
Michael Thiessen44457642020-02-06 00:24:151686def _CheckAndroidNoBannedImports(input_api, output_api):
1687 """Make sure that banned java imports are not used."""
1688 errors = []
1689
1690 def IsException(path, exceptions):
1691 for exception in exceptions:
1692 if (path.startswith(exception)):
1693 return True
1694 return False
1695
1696 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1697 for f in input_api.AffectedFiles(file_filter=file_filter):
1698 for line_num, line in f.ChangedContents():
1699 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1700 if IsException(f.LocalPath(), exceptions):
1701 continue;
1702 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1703 'import ' + import_name, message)
1704 if problems:
1705 errors.extend(problems)
1706 result = []
1707 if (errors):
1708 result.append(output_api.PresubmitError(
1709 'Banned imports were used.\n' + '\n'.join(errors)))
1710 return result
1711
1712
Saagar Sanghavifceeaae2020-08-12 16:40:361713def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311714 """Make sure that old Mojo types are not used."""
1715 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571716 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311717
Mario Sanchez Pradaaab91382019-12-19 08:57:091718 # For any path that is not an "ok" or an "error" path, a warning will be
1719 # raised if deprecated mojo types are found.
1720 ok_paths = ['components/arc']
1721 error_paths = ['third_party/blink', 'content']
1722
Mario Sanchez Prada2472cab2019-09-18 10:58:311723 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1724 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571725 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091726 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311727 continue
1728
1729 for line_num, line in f.ChangedContents():
1730 for func_name, message in _DEPRECATED_MOJO_TYPES:
1731 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1732 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571733
Mario Sanchez Prada2472cab2019-09-18 10:58:311734 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091735 # Raise errors inside |error_paths| and warnings everywhere else.
1736 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571737 errors.extend(problems)
1738 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311739 warnings.extend(problems)
1740
1741 result = []
1742 if (warnings):
1743 result.append(output_api.PresubmitPromptWarning(
1744 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571745 if (errors):
1746 result.append(output_api.PresubmitError(
1747 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311748 return result
1749
1750
Saagar Sanghavifceeaae2020-08-12 16:40:361751def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061752 """Make sure that banned functions are not used."""
1753 files = []
1754 pattern = input_api.re.compile(r'^#pragma\s+once',
1755 input_api.re.MULTILINE)
1756 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1757 if not f.LocalPath().endswith('.h'):
1758 continue
1759 contents = input_api.ReadFile(f)
1760 if pattern.search(contents):
1761 files.append(f)
1762
1763 if files:
1764 return [output_api.PresubmitError(
1765 'Do not use #pragma once in header files.\n'
1766 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1767 files)]
1768 return []
1769
[email protected]127f18ec2012-06-16 05:05:591770
Saagar Sanghavifceeaae2020-08-12 16:40:361771def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121772 """Checks to make sure we don't introduce use of foo ? true : false."""
1773 problems = []
1774 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1775 for f in input_api.AffectedFiles():
1776 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1777 continue
1778
1779 for line_num, line in f.ChangedContents():
1780 if pattern.match(line):
1781 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1782
1783 if not problems:
1784 return []
1785 return [output_api.PresubmitPromptWarning(
1786 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1787 '\n'.join(problems))]
1788
1789
Saagar Sanghavifceeaae2020-08-12 16:40:361790def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281791 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181792 change. Breaking - rules is an error, breaking ! rules is a
1793 warning.
1794 """
Erik Staabc734cd7a2021-11-23 03:11:521795 # Return early if no relevant file types were modified.
1796 for f in input_api.AffectedFiles():
1797 path = f.LocalPath()
1798 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path) or
1799 _IsJavaFile(input_api, path)):
1800 break
1801 else:
1802 return []
1803
mohan.reddyf21db962014-10-16 12:26:471804 import sys
[email protected]55f9f382012-07-31 11:02:181805 # We need to wait until we have an input_api object and use this
1806 # roundabout construct to import checkdeps because this file is
1807 # eval-ed and thus doesn't have __file__.
1808 original_sys_path = sys.path
1809 try:
1810 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471811 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181812 import checkdeps
[email protected]55f9f382012-07-31 11:02:181813 from rules import Rule
1814 finally:
1815 # Restore sys.path to what it was before.
1816 sys.path = original_sys_path
1817
1818 added_includes = []
rhalavati08acd232017-04-03 07:23:281819 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241820 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181821 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061822 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501823 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081824 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061825 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501826 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081827 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061828 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501829 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081830 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181831
[email protected]26385172013-05-09 23:11:351832 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181833
1834 error_descriptions = []
1835 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281836 error_subjects = set()
1837 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361838
[email protected]55f9f382012-07-31 11:02:181839 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1840 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081841 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181842 description_with_path = '%s\n %s' % (path, rule_description)
1843 if rule_type == Rule.DISALLOW:
1844 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281845 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181846 else:
1847 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281848 warning_subjects.add("#includes")
1849
1850 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1851 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081852 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281853 description_with_path = '%s\n %s' % (path, rule_description)
1854 if rule_type == Rule.DISALLOW:
1855 error_descriptions.append(description_with_path)
1856 error_subjects.add("imports")
1857 else:
1858 warning_descriptions.append(description_with_path)
1859 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181860
Jinsuk Kim5a092672017-10-24 22:42:241861 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021862 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081863 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241864 description_with_path = '%s\n %s' % (path, rule_description)
1865 if rule_type == Rule.DISALLOW:
1866 error_descriptions.append(description_with_path)
1867 error_subjects.add("imports")
1868 else:
1869 warning_descriptions.append(description_with_path)
1870 warning_subjects.add("imports")
1871
[email protected]55f9f382012-07-31 11:02:181872 results = []
1873 if error_descriptions:
1874 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281875 'You added one or more %s that violate checkdeps rules.'
1876 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181877 error_descriptions))
1878 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421879 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281880 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181881 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281882 '%s? See relevant DEPS file(s) for details and contacts.' %
1883 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181884 warning_descriptions))
1885 return results
1886
1887
Saagar Sanghavifceeaae2020-08-12 16:40:361888def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:221889 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151890 if input_api.platform == 'win32':
1891 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291892 checkperms_tool = input_api.os_path.join(
1893 input_api.PresubmitLocalPath(),
1894 'tools', 'checkperms', 'checkperms.py')
1895 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471896 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391897 with input_api.CreateTemporaryFile() as file_list:
1898 for f in input_api.AffectedFiles():
1899 # checkperms.py file/directory arguments must be relative to the
1900 # repository.
Dirk Prankee3c9c62d2021-05-18 18:35:591901 file_list.write((f.LocalPath() + '\n').encode('utf8'))
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391902 file_list.close()
1903 args += ['--file-list', file_list.name]
1904 try:
1905 input_api.subprocess.check_output(args)
1906 return []
1907 except input_api.subprocess.CalledProcessError as error:
1908 return [output_api.PresubmitError(
1909 'checkperms.py failed:',
Ari Chivukula45f58dd52021-06-18 04:23:041910 long_text=error.output.decode('utf-8', 'ignore'))]
[email protected]fbcafe5a2012-08-08 15:31:221911
1912
Saagar Sanghavifceeaae2020-08-12 16:40:361913def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:491914 """Makes sure we don't include ui/aura/window_property.h
1915 in header files.
1916 """
1917 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1918 errors = []
1919 for f in input_api.AffectedFiles():
1920 if not f.LocalPath().endswith('.h'):
1921 continue
1922 for line_num, line in f.ChangedContents():
1923 if pattern.match(line):
1924 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1925
1926 results = []
1927 if errors:
1928 results.append(output_api.PresubmitError(
1929 'Header files should not include ui/aura/window_property.h', errors))
1930 return results
1931
1932
Omer Katzcc77ea92021-04-26 10:23:281933def CheckNoInternalHeapIncludes(input_api, output_api):
1934 """Makes sure we don't include any headers from
1935 third_party/blink/renderer/platform/heap/impl or
1936 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1937 third_party/blink/renderer/platform/heap
1938 """
1939 impl_pattern = input_api.re.compile(
1940 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1941 v8_wrapper_pattern = input_api.re.compile(
1942 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"')
1943 file_filter = lambda f: not input_api.re.match(
1944 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1945 f.LocalPath())
1946 errors = []
1947
1948 for f in input_api.AffectedFiles(file_filter=file_filter):
1949 for line_num, line in f.ChangedContents():
1950 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1951 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1952
1953 results = []
1954 if errors:
1955 results.append(output_api.PresubmitError(
1956 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1957 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1958 'relevant counterparts from third_party/blink/renderer/platform/heap',
1959 errors))
1960 return results
1961
1962
[email protected]70ca77752012-11-20 03:45:031963def _CheckForVersionControlConflictsInFile(input_api, f):
1964 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1965 errors = []
1966 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161967 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231968 # First-level headers in markdown look a lot like version control
1969 # conflict markers. http://daringfireball.net/projects/markdown/basics
1970 continue
[email protected]70ca77752012-11-20 03:45:031971 if pattern.match(line):
1972 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1973 return errors
1974
1975
Saagar Sanghavifceeaae2020-08-12 16:40:361976def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:031977 """Usually this is not intentional and will cause a compile failure."""
1978 errors = []
1979 for f in input_api.AffectedFiles():
1980 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1981
1982 results = []
1983 if errors:
1984 results.append(output_api.PresubmitError(
1985 'Version control conflict markers found, please resolve.', errors))
1986 return results
1987
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201988
Saagar Sanghavifceeaae2020-08-12 16:40:361989def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:161990 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1991 errors = []
1992 for f in input_api.AffectedFiles():
1993 for line_num, line in f.ChangedContents():
1994 if pattern.search(line):
1995 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1996
1997 results = []
1998 if errors:
1999 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502000 'Found Google support URL addressed by answer number. Please replace '
2001 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162002 return results
2003
[email protected]70ca77752012-11-20 03:45:032004
Saagar Sanghavifceeaae2020-08-12 16:40:362005def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442006 def FilterFile(affected_file):
2007 """Filter function for use with input_api.AffectedSourceFiles,
2008 below. This filters out everything except non-test files from
2009 top-level directories that generally speaking should not hard-code
2010 service URLs (e.g. src/android_webview/, src/content/ and others).
2011 """
2012 return input_api.FilterSourceFile(
2013 affected_file,
James Cook24a504192020-07-23 00:08:442014 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2015 files_to_skip=(_EXCLUDED_PATHS +
2016 _TEST_CODE_EXCLUDED_PATHS +
2017 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442018
reillyi38965732015-11-16 18:27:332019 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2020 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462021 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2022 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442023 problems = [] # items are (filename, line_number, line)
2024 for f in input_api.AffectedSourceFiles(FilterFile):
2025 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462026 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442027 problems.append((f.LocalPath(), line_num, line))
2028
2029 if problems:
[email protected]f7051d52013-04-02 18:31:422030 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442031 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582032 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442033 [' %s:%d: %s' % (
2034 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032035 else:
2036 return []
[email protected]06e6d0ff2012-12-11 01:36:442037
2038
Saagar Sanghavifceeaae2020-08-12 16:40:362039def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292040 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2041 def FileFilter(affected_file):
2042 """Includes directories known to be Chrome OS only."""
2043 return input_api.FilterSourceFile(
2044 affected_file,
James Cook24a504192020-07-23 00:08:442045 files_to_check=('^ash/',
2046 '^chromeos/', # Top-level src/chromeos.
Henrique Ferreiro2e1aa1092021-11-29 22:22:122047 '.*/chromeos/', # Any path component.
James Cook24a504192020-07-23 00:08:442048 '^components/arc',
2049 '^components/exo'),
2050 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292051
2052 prefs = []
2053 priority_prefs = []
2054 for f in input_api.AffectedFiles(file_filter=FileFilter):
2055 for line_num, line in f.ChangedContents():
2056 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2057 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2058 prefs.append(' %s' % line)
2059 if input_api.re.search(
2060 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2061 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2062 priority_prefs.append(' %s' % line)
2063
2064 results = []
2065 if (prefs):
2066 results.append(output_api.PresubmitPromptWarning(
2067 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2068 'by browser sync settings. If these prefs should be controlled by OS '
2069 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2070 if (priority_prefs):
2071 results.append(output_api.PresubmitPromptWarning(
2072 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2073 'controlled by browser sync settings. If these prefs should be '
2074 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2075 'instead.\n' + '\n'.join(prefs)))
2076 return results
2077
2078
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492079# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362080def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272081 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312082 The native_client_sdk directory is excluded because it has auto-generated PNG
2083 files for documentation.
[email protected]d2530012013-01-25 16:39:272084 """
[email protected]d2530012013-01-25 16:39:272085 errors = []
James Cook24a504192020-07-23 00:08:442086 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2087 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312088 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442089 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312090 for f in input_api.AffectedFiles(include_deletes=False,
2091 file_filter=file_filter):
2092 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272093
2094 results = []
2095 if errors:
2096 results.append(output_api.PresubmitError(
2097 'The name of PNG files should not have abbreviations. \n'
2098 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2099 'Contact [email protected] if you have questions.', errors))
2100 return results
2101
2102
Daniel Cheng4dcdb6b2017-04-13 08:30:172103def _ExtractAddRulesFromParsedDeps(parsed_deps):
2104 """Extract the rules that add dependencies from a parsed DEPS file.
2105
2106 Args:
2107 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2108 add_rules = set()
2109 add_rules.update([
2110 rule[1:] for rule in parsed_deps.get('include_rules', [])
2111 if rule.startswith('+') or rule.startswith('!')
2112 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502113 for _, rules in parsed_deps.get('specific_include_rules',
Dirk Prankee3c9c62d2021-05-18 18:35:592114 {}).items():
Daniel Cheng4dcdb6b2017-04-13 08:30:172115 add_rules.update([
2116 rule[1:] for rule in rules
2117 if rule.startswith('+') or rule.startswith('!')
2118 ])
2119 return add_rules
2120
2121
2122def _ParseDeps(contents):
2123 """Simple helper for parsing DEPS files."""
2124 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172125 class _VarImpl:
2126
2127 def __init__(self, local_scope):
2128 self._local_scope = local_scope
2129
2130 def Lookup(self, var_name):
2131 """Implements the Var syntax."""
2132 try:
2133 return self._local_scope['vars'][var_name]
2134 except KeyError:
2135 raise Exception('Var is not defined: %s' % var_name)
2136
2137 local_scope = {}
2138 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172139 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592140 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172141 }
Dirk Pranke1b9e06382021-05-14 01:16:222142
Dirk Prankee3c9c62d2021-05-18 18:35:592143 exec(contents, global_scope, local_scope)
Daniel Cheng4dcdb6b2017-04-13 08:30:172144 return local_scope
2145
2146
2147def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592148 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412149 a set of DEPS entries that we should look up.
2150
2151 For a directory (rather than a specific filename) we fake a path to
2152 a specific filename by adding /DEPS. This is chosen as a file that
2153 will seldom or never be subject to per-file include_rules.
2154 """
[email protected]2b438d62013-11-14 17:54:142155 # We ignore deps entries on auto-generated directories.
2156 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082157
Daniel Cheng4dcdb6b2017-04-13 08:30:172158 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2159 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2160
2161 added_deps = new_deps.difference(old_deps)
2162
[email protected]2b438d62013-11-14 17:54:142163 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172164 for added_dep in added_deps:
2165 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2166 continue
2167 # Assume that a rule that ends in .h is a rule for a specific file.
2168 if added_dep.endswith('.h'):
2169 results.add(added_dep)
2170 else:
2171 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082172 return results
2173
2174
Saagar Sanghavifceeaae2020-08-12 16:40:362175def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552176 """When a dependency prefixed with + is added to a DEPS file, we
2177 want to make sure that the change is reviewed by an OWNER of the
2178 target file or directory, to avoid layering violations from being
2179 introduced. This check verifies that this happens.
2180 """
Joey Mou57048132021-02-26 22:17:552181 # We rely on Gerrit's code-owners to check approvals.
2182 # input_api.gerrit is always set for Chromium, but other projects
2183 # might not use Gerrit.
2184 if not input_api.gerrit:
2185 return []
Edward Lesmes44feb2332021-03-19 01:27:522186 if (input_api.change.issue and
2187 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232188 # Skip OWNERS check when Owners-Override label is approved. This is intended
2189 # for global owners, trusted bots, and on-call sheriffs. Review is still
2190 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522191 return []
Edward Lesmes6fba51082021-01-20 04:20:232192
Daniel Cheng4dcdb6b2017-04-13 08:30:172193 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242194
2195 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492196 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242197 for f in input_api.AffectedFiles(include_deletes=False,
2198 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552199 filename = input_api.os_path.basename(f.LocalPath())
2200 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172201 virtual_depended_on_files.update(_CalculateAddedDeps(
2202 input_api.os_path,
2203 '\n'.join(f.OldContents()),
2204 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552205
[email protected]e871964c2013-05-13 14:14:552206 if not virtual_depended_on_files:
2207 return []
2208
2209 if input_api.is_committing:
2210 if input_api.tbr:
2211 return [output_api.PresubmitNotifyResult(
2212 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272213 if input_api.dry_run:
2214 return [output_api.PresubmitNotifyResult(
2215 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552216 if not input_api.change.issue:
2217 return [output_api.PresubmitError(
2218 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402219 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552220 output = output_api.PresubmitError
2221 else:
2222 output = output_api.PresubmitNotifyResult
2223
tandriied3b7e12016-05-12 14:38:502224 owner_email, reviewers = (
2225 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2226 input_api,
Edward Lesmesa3846442021-02-08 20:20:032227 None,
tandriied3b7e12016-05-12 14:38:502228 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552229
2230 owner_email = owner_email or input_api.change.author_email
2231
Edward Lesmesa3846442021-02-08 20:20:032232 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2233 virtual_depended_on_files, reviewers.union([owner_email]), [])
2234 missing_files = [
2235 f for f in virtual_depended_on_files
2236 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412237
2238 # We strip the /DEPS part that was added by
2239 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2240 # directory.
2241 def StripDeps(path):
2242 start_deps = path.rfind('/DEPS')
2243 if start_deps != -1:
2244 return path[:start_deps]
2245 else:
2246 return path
2247 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552248 for path in missing_files]
2249
2250 if unapproved_dependencies:
2251 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152252 output('You need LGTM from owners of depends-on paths in DEPS that were '
2253 'modified in this CL:\n %s' %
2254 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032255 suggested_owners = input_api.owners_client.SuggestOwners(
2256 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152257 output_list.append(output(
2258 'Suggested missing target path OWNERS:\n %s' %
2259 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552260 return output_list
2261
2262 return []
2263
2264
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492265# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362266def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492267 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442268 files_to_skip = (_EXCLUDED_PATHS +
2269 _TEST_CODE_EXCLUDED_PATHS +
2270 input_api.DEFAULT_FILES_TO_SKIP +
2271 (r"^base[\\/]logging\.h$",
2272 r"^base[\\/]logging\.cc$",
2273 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2274 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2275 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2276 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2277 r"startup_browser_creator\.cc$",
2278 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2279 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2280 r"diagnostics_writer\.cc$",
2281 r"^chrome[\\/]chrome_cleaner[\\/].*",
2282 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2283 r"dll_hash_main\.cc$",
2284 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2285 r"^chromecast[\\/]",
2286 r"^cloud_print[\\/]",
2287 r"^components[\\/]browser_watcher[\\/]"
2288 r"dump_stability_report_main_win.cc$",
2289 r"^components[\\/]media_control[\\/]renderer[\\/]"
2290 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352291 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2292 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442293 r"^components[\\/]zucchini[\\/].*",
2294 # TODO(peter): Remove exception. https://crbug.com/534537
2295 r"^content[\\/]browser[\\/]notifications[\\/]"
2296 r"notification_event_dispatcher_impl\.cc$",
2297 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2298 r"gl_helper_benchmark\.cc$",
2299 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2300 r"^courgette[\\/]courgette_tool\.cc$",
2301 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
David Dorwinfa9aef42021-08-17 06:46:202302 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
James Cook24a504192020-07-23 00:08:442303 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Sergey Ulanov6db14b4d62021-05-10 07:59:482304 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
James Cook24a504192020-07-23 00:08:442305 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2306 r"^ipc[\\/]ipc_logging\.cc$",
2307 r"^native_client_sdk[\\/]",
2308 r"^remoting[\\/]base[\\/]logging\.h$",
2309 r"^remoting[\\/]host[\\/].*",
2310 r"^sandbox[\\/]linux[\\/].*",
2311 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2312 r"dump_file_system.cc$",
2313 r"^tools[\\/]",
2314 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2315 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2316 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2317 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2318 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402319 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442320 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402321
thomasanderson625d3932017-03-29 07:16:582322 log_info = set([])
2323 printf = set([])
[email protected]85218562013-11-22 07:41:402324
2325 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582326 for _, line in f.ChangedContents():
2327 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2328 log_info.add(f.LocalPath())
2329 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2330 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372331
thomasanderson625d3932017-03-29 07:16:582332 if input_api.re.search(r"\bprintf\(", line):
2333 printf.add(f.LocalPath())
2334 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2335 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402336
2337 if log_info:
2338 return [output_api.PresubmitError(
2339 'These files spam the console log with LOG(INFO):',
2340 items=log_info)]
2341 if printf:
2342 return [output_api.PresubmitError(
2343 'These files spam the console log with printf/fprintf:',
2344 items=printf)]
2345 return []
2346
2347
Saagar Sanghavifceeaae2020-08-12 16:40:362348def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162349 """These types are all expected to hold locks while in scope and
2350 so should never be anonymous (which causes them to be immediately
2351 destroyed)."""
2352 they_who_must_be_named = [
2353 'base::AutoLock',
2354 'base::AutoReset',
2355 'base::AutoUnlock',
2356 'SkAutoAlphaRestore',
2357 'SkAutoBitmapShaderInstall',
2358 'SkAutoBlitterChoose',
2359 'SkAutoBounderCommit',
2360 'SkAutoCallProc',
2361 'SkAutoCanvasRestore',
2362 'SkAutoCommentBlock',
2363 'SkAutoDescriptor',
2364 'SkAutoDisableDirectionCheck',
2365 'SkAutoDisableOvalCheck',
2366 'SkAutoFree',
2367 'SkAutoGlyphCache',
2368 'SkAutoHDC',
2369 'SkAutoLockColors',
2370 'SkAutoLockPixels',
2371 'SkAutoMalloc',
2372 'SkAutoMaskFreeImage',
2373 'SkAutoMutexAcquire',
2374 'SkAutoPathBoundsUpdate',
2375 'SkAutoPDFRelease',
2376 'SkAutoRasterClipValidate',
2377 'SkAutoRef',
2378 'SkAutoTime',
2379 'SkAutoTrace',
2380 'SkAutoUnref',
2381 ]
2382 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2383 # bad: base::AutoLock(lock.get());
2384 # not bad: base::AutoLock lock(lock.get());
2385 bad_pattern = input_api.re.compile(anonymous)
2386 # good: new base::AutoLock(lock.get())
2387 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2388 errors = []
2389
2390 for f in input_api.AffectedFiles():
2391 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2392 continue
2393 for linenum, line in f.ChangedContents():
2394 if bad_pattern.search(line) and not good_pattern.search(line):
2395 errors.append('%s:%d' % (f.LocalPath(), linenum))
2396
2397 if errors:
2398 return [output_api.PresubmitError(
2399 'These lines create anonymous variables that need to be named:',
2400 items=errors)]
2401 return []
2402
2403
Saagar Sanghavifceeaae2020-08-12 16:40:362404def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532405 # Returns whether |template_str| is of the form <T, U...> for some types T
2406 # and U. Assumes that |template_str| is already in the form <...>.
2407 def HasMoreThanOneArg(template_str):
2408 # Level of <...> nesting.
2409 nesting = 0
2410 for c in template_str:
2411 if c == '<':
2412 nesting += 1
2413 elif c == '>':
2414 nesting -= 1
2415 elif c == ',' and nesting == 1:
2416 return True
2417 return False
2418
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492419 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102420 sources = lambda affected_file: input_api.FilterSourceFile(
2421 affected_file,
James Cook24a504192020-07-23 00:08:442422 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2423 input_api.DEFAULT_FILES_TO_SKIP),
2424 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552425
2426 # Pattern to capture a single "<...>" block of template arguments. It can
2427 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2428 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2429 # latter would likely require counting that < and > match, which is not
2430 # expressible in regular languages. Should the need arise, one can introduce
2431 # limited counting (matching up to a total number of nesting depth), which
2432 # should cover all practical cases for already a low nesting limit.
2433 template_arg_pattern = (
2434 r'<[^>]*' # Opening block of <.
2435 r'>([^<]*>)?') # Closing block of >.
2436 # Prefix expressing that whatever follows is not already inside a <...>
2437 # block.
2438 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102439 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552440 not_inside_template_arg_pattern
2441 + r'\bstd::unique_ptr'
2442 + template_arg_pattern
2443 + r'\(\)')
2444
2445 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2446 template_arg_no_array_pattern = (
2447 r'<[^>]*[^]]' # Opening block of <.
2448 r'>([^(<]*[^]]>)?') # Closing block of >.
2449 # Prefix saying that what follows is the start of an expression.
2450 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2451 # Suffix saying that what follows are call parentheses with a non-empty list
2452 # of arguments.
2453 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532454 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552455 return_construct_pattern = input_api.re.compile(
2456 start_of_expr_pattern
2457 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532458 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552459 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532460 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552461 + nonempty_arg_list_pattern)
2462
Vaclav Brozek851d9602018-04-04 16:13:052463 problems_constructor = []
2464 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102465 for f in input_api.AffectedSourceFiles(sources):
2466 for line_number, line in f.ChangedContents():
2467 # Disallow:
2468 # return std::unique_ptr<T>(foo);
2469 # bar = std::unique_ptr<T>(foo);
2470 # But allow:
2471 # return std::unique_ptr<T[]>(foo);
2472 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532473 # And also allow cases when the second template argument is present. Those
2474 # cases cannot be handled by std::make_unique:
2475 # return std::unique_ptr<T, U>(foo);
2476 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052477 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532478 return_construct_result = return_construct_pattern.search(line)
2479 if return_construct_result and not HasMoreThanOneArg(
2480 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052481 problems_constructor.append(
2482 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102483 # Disallow:
2484 # std::unique_ptr<T>()
2485 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052486 problems_nullptr.append(
2487 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2488
2489 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162490 if problems_nullptr:
Daniel Cheng2dbf9c42021-10-06 21:26:112491 errors.append(output_api.PresubmitPromptWarning(
Vaclav Brozek851d9602018-04-04 16:13:052492 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162493 problems_nullptr))
2494 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052495 errors.append(output_api.PresubmitError(
Yao Li7f5a705d2021-11-23 22:30:562496 'The following files use explicit std::unique_ptr constructor. '
2497 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2498 'std::make_unique is not an option.',
Vaclav Brozekc2fecf42018-04-06 16:40:162499 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102500 return errors
2501
2502
Saagar Sanghavifceeaae2020-08-12 16:40:362503def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082504 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522505 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082506 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522507 # If actions.xml is already included in the changelist, the PRESUBMIT
2508 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082509 return []
2510
Alexei Svitkine64505a92021-03-11 22:00:542511 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2512 files_to_skip = (_EXCLUDED_PATHS +
2513 _TEST_CODE_EXCLUDED_PATHS +
2514 input_api.DEFAULT_FILES_TO_SKIP )
2515 file_filter = lambda f: input_api.FilterSourceFile(
2516 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2517
[email protected]999261d2014-03-03 20:08:082518 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522519 current_actions = None
[email protected]999261d2014-03-03 20:08:082520 for f in input_api.AffectedFiles(file_filter=file_filter):
2521 for line_num, line in f.ChangedContents():
2522 match = input_api.re.search(action_re, line)
2523 if match:
[email protected]2f92dec2014-03-07 19:21:522524 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2525 # loaded only once.
2526 if not current_actions:
2527 with open('tools/metrics/actions/actions.xml') as actions_f:
2528 current_actions = actions_f.read()
2529 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082530 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522531 action = 'name="{0}"'.format(action_name)
2532 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082533 return [output_api.PresubmitPromptWarning(
2534 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522535 'tools/metrics/actions/actions.xml. Please run '
2536 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082537 % (f.LocalPath(), line_num, action_name))]
2538 return []
2539
2540
Daniel Cheng13ca61a882017-08-25 15:11:252541def _ImportJSONCommentEater(input_api):
2542 import sys
2543 sys.path = sys.path + [input_api.os_path.join(
2544 input_api.PresubmitLocalPath(),
2545 'tools', 'json_comment_eater')]
2546 import json_comment_eater
2547 return json_comment_eater
2548
2549
[email protected]99171a92014-06-03 08:44:472550def _GetJSONParseError(input_api, filename, eat_comments=True):
2551 try:
2552 contents = input_api.ReadFile(filename)
2553 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252554 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132555 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472556
2557 input_api.json.loads(contents)
2558 except ValueError as e:
2559 return e
2560 return None
2561
2562
2563def _GetIDLParseError(input_api, filename):
2564 try:
2565 contents = input_api.ReadFile(filename)
2566 idl_schema = input_api.os_path.join(
2567 input_api.PresubmitLocalPath(),
2568 'tools', 'json_schema_compiler', 'idl_schema.py')
2569 process = input_api.subprocess.Popen(
2570 [input_api.python_executable, idl_schema],
2571 stdin=input_api.subprocess.PIPE,
2572 stdout=input_api.subprocess.PIPE,
2573 stderr=input_api.subprocess.PIPE,
2574 universal_newlines=True)
2575 (_, error) = process.communicate(input=contents)
2576 return error or None
2577 except ValueError as e:
2578 return e
2579
2580
Saagar Sanghavifceeaae2020-08-12 16:40:362581def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472582 """Check that IDL and JSON files do not contain syntax errors."""
2583 actions = {
2584 '.idl': _GetIDLParseError,
2585 '.json': _GetJSONParseError,
2586 }
[email protected]99171a92014-06-03 08:44:472587 # Most JSON files are preprocessed and support comments, but these do not.
2588 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042589 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472590 ]
2591 # Only run IDL checker on files in these directories.
2592 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042593 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2594 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472595 ]
2596
2597 def get_action(affected_file):
2598 filename = affected_file.LocalPath()
2599 return actions.get(input_api.os_path.splitext(filename)[1])
2600
[email protected]99171a92014-06-03 08:44:472601 def FilterFile(affected_file):
2602 action = get_action(affected_file)
2603 if not action:
2604 return False
2605 path = affected_file.LocalPath()
2606
Erik Staab2dd72b12020-04-16 15:03:402607 if _MatchesFile(input_api,
2608 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2609 path):
[email protected]99171a92014-06-03 08:44:472610 return False
2611
2612 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162613 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472614 return False
2615 return True
2616
2617 results = []
2618 for affected_file in input_api.AffectedFiles(
2619 file_filter=FilterFile, include_deletes=False):
2620 action = get_action(affected_file)
2621 kwargs = {}
2622 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162623 _MatchesFile(input_api, json_no_comments_patterns,
2624 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472625 kwargs['eat_comments'] = False
2626 parse_error = action(input_api,
2627 affected_file.AbsoluteLocalPath(),
2628 **kwargs)
2629 if parse_error:
2630 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2631 (affected_file.LocalPath(), parse_error)))
2632 return results
2633
2634
Saagar Sanghavifceeaae2020-08-12 16:40:362635def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492636 """Runs checkstyle on changed java files and returns errors if any exist."""
Erik Staabc734cd7a2021-11-23 03:11:522637
2638 # Return early if no java files were modified.
2639 if not any(_IsJavaFile(input_api, f.LocalPath()) for f in
2640 input_api.AffectedFiles()):
2641 return []
2642
mohan.reddyf21db962014-10-16 12:26:472643 import sys
[email protected]760deea2013-12-10 19:33:492644 original_sys_path = sys.path
2645 try:
2646 sys.path = sys.path + [input_api.os_path.join(
2647 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2648 import checkstyle
2649 finally:
2650 # Restore sys.path to what it was before.
2651 sys.path = original_sys_path
2652
2653 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092654 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442655 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492656
2657
Saagar Sanghavifceeaae2020-08-12 16:40:362658def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002659 """Checks to make sure devil is initialized correctly in python scripts."""
2660 script_common_initialize_pattern = input_api.re.compile(
2661 r'script_common\.InitializeEnvironment\(')
2662 devil_env_config_initialize = input_api.re.compile(
2663 r'devil_env\.config\.Initialize\(')
2664
2665 errors = []
2666
2667 sources = lambda affected_file: input_api.FilterSourceFile(
2668 affected_file,
James Cook24a504192020-07-23 00:08:442669 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2670 (r'^build[\\/]android[\\/]devil_chromium\.py',
2671 r'^third_party[\\/].*',)),
2672 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002673
2674 for f in input_api.AffectedSourceFiles(sources):
2675 for line_num, line in f.ChangedContents():
2676 if (script_common_initialize_pattern.search(line) or
2677 devil_env_config_initialize.search(line)):
2678 errors.append("%s:%d" % (f.LocalPath(), line_num))
2679
2680 results = []
2681
2682 if errors:
2683 results.append(output_api.PresubmitError(
2684 'Devil initialization should always be done using '
2685 'devil_chromium.Initialize() in the chromium project, to use better '
2686 'defaults for dependencies (ex. up-to-date version of adb).',
2687 errors))
2688
2689 return results
2690
2691
Sean Kau46e29bc2017-08-28 16:31:162692def _MatchesFile(input_api, patterns, path):
2693 for pattern in patterns:
2694 if input_api.re.search(pattern, path):
2695 return True
2696 return False
2697
2698
Daniel Cheng7052cdf2017-11-21 19:23:292699def _GetOwnersFilesToCheckForIpcOwners(input_api):
2700 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172701
Daniel Cheng7052cdf2017-11-21 19:23:292702 Returns:
2703 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2704 contain to cover IPC-related files with noparent reviewer rules.
2705 """
2706 # Whether or not a file affects IPC is (mostly) determined by a simple list
2707 # of filename patterns.
dchenge07de812016-06-20 19:27:172708 file_patterns = [
palmerb19a0932017-01-24 04:00:312709 # Legacy IPC:
dchenge07de812016-06-20 19:27:172710 '*_messages.cc',
2711 '*_messages*.h',
2712 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312713 # Mojo IPC:
dchenge07de812016-06-20 19:27:172714 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472715 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172716 '*_struct_traits*.*',
2717 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312718 '*.typemap',
2719 # Android native IPC:
2720 '*.aidl',
2721 # Blink uses a different file naming convention:
2722 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472723 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172724 '*StructTraits*.*',
2725 '*TypeConverter*.*',
2726 ]
2727
scottmg7a6ed5ba2016-11-04 18:22:042728 # These third_party directories do not contain IPCs, but contain files
2729 # matching the above patterns, which trigger false positives.
2730 exclude_paths = [
2731 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162732 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232733 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292734 'third_party/win_build_output/*',
Scott Violet9f82d362019-11-06 21:42:162735 # These files are just used to communicate between class loaders running
2736 # in the same process.
2737 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572738 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2739
scottmg7a6ed5ba2016-11-04 18:22:042740 ]
2741
dchenge07de812016-06-20 19:27:172742 # Dictionary mapping an OWNERS file path to Patterns.
2743 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2744 # rules ) to a PatternEntry.
2745 # PatternEntry is a dictionary with two keys:
2746 # - 'files': the files that are matched by this pattern
2747 # - 'rules': the per-file rules needed for this pattern
2748 # For example, if we expect OWNERS file to contain rules for *.mojom and
2749 # *_struct_traits*.*, Patterns might look like this:
2750 # {
2751 # '*.mojom': {
2752 # 'files': ...,
2753 # 'rules': [
2754 # 'per-file *.mojom=set noparent',
2755 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2756 # ],
2757 # },
2758 # '*_struct_traits*.*': {
2759 # 'files': ...,
2760 # 'rules': [
2761 # 'per-file *_struct_traits*.*=set noparent',
2762 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2763 # ],
2764 # },
2765 # }
2766 to_check = {}
2767
Daniel Cheng13ca61a882017-08-25 15:11:252768 def AddPatternToCheck(input_file, pattern):
2769 owners_file = input_api.os_path.join(
Shimi Zhang15a9e882022-01-21 23:53:162770 input_api.os_path.dirname(input_file.AbsoluteLocalPath()), 'OWNERS')
Daniel Cheng13ca61a882017-08-25 15:11:252771 if owners_file not in to_check:
2772 to_check[owners_file] = {}
2773 if pattern not in to_check[owners_file]:
2774 to_check[owners_file][pattern] = {
2775 'files': [],
2776 'rules': [
2777 'per-file %s=set noparent' % pattern,
2778 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2779 ]
2780 }
Vaclav Brozekd5de76a2018-03-17 07:57:502781 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252782
dchenge07de812016-06-20 19:27:172783 # Iterate through the affected files to see what we actually need to check
2784 # for. We should only nag patch authors about per-file rules if a file in that
2785 # directory would match that pattern. If a directory only contains *.mojom
2786 # files and no *_messages*.h files, we should only nag about rules for
2787 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252788 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262789 # Manifest files don't have a strong naming convention. Instead, try to find
2790 # affected .cc and .h files which look like they contain a manifest
2791 # definition.
2792 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2793 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2794 if (manifest_pattern.search(f.LocalPath()) and not
2795 test_manifest_pattern.search(f.LocalPath())):
2796 # We expect all actual service manifest files to contain at least one
2797 # qualified reference to service_manager::Manifest.
2798 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252799 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172800 for pattern in file_patterns:
2801 if input_api.fnmatch.fnmatch(
2802 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042803 skip = False
2804 for exclude in exclude_paths:
2805 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2806 skip = True
2807 break
2808 if skip:
2809 continue
Daniel Cheng13ca61a882017-08-25 15:11:252810 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172811 break
2812
Daniel Cheng7052cdf2017-11-21 19:23:292813 return to_check
2814
2815
Wez17c66962020-04-29 15:26:032816def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2817 """Adds OWNERS files to check for correct Fuchsia security owners."""
2818
2819 file_patterns = [
2820 # Component specifications.
2821 '*.cml', # Component Framework v2.
2822 '*.cmx', # Component Framework v1.
2823
2824 # Fuchsia IDL protocol specifications.
2825 '*.fidl',
2826 ]
2827
Joshua Peraza1ca6d392020-12-08 00:14:092828 # Don't check for owners files for changes in these directories.
2829 exclude_paths = [
2830 'third_party/crashpad/*',
2831 ]
2832
Wez17c66962020-04-29 15:26:032833 def AddPatternToCheck(input_file, pattern):
2834 owners_file = input_api.os_path.join(
2835 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2836 if owners_file not in to_check:
2837 to_check[owners_file] = {}
2838 if pattern not in to_check[owners_file]:
2839 to_check[owners_file][pattern] = {
2840 'files': [],
2841 'rules': [
2842 'per-file %s=set noparent' % pattern,
2843 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2844 ]
2845 }
2846 to_check[owners_file][pattern]['files'].append(input_file)
2847
2848 # Iterate through the affected files to see what we actually need to check
2849 # for. We should only nag patch authors about per-file rules if a file in that
2850 # directory would match that pattern.
2851 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092852 skip = False
2853 for exclude in exclude_paths:
2854 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2855 skip = True
2856 if skip:
2857 continue
2858
Wez17c66962020-04-29 15:26:032859 for pattern in file_patterns:
2860 if input_api.fnmatch.fnmatch(
2861 input_api.os_path.basename(f.LocalPath()), pattern):
2862 AddPatternToCheck(f, pattern)
2863 break
2864
2865 return to_check
2866
2867
Saagar Sanghavifceeaae2020-08-12 16:40:362868def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292869 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2870 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032871 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292872
2873 if to_check:
2874 # If there are any OWNERS files to check, there are IPC-related changes in
2875 # this CL. Auto-CC the review list.
2876 output_api.AppendCC('[email protected]')
2877
2878 # Go through the OWNERS files to check, filtering out rules that are already
2879 # present in that OWNERS file.
Dirk Prankee3c9c62d2021-05-18 18:35:592880 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172881 try:
Dirk Prankee3c9c62d2021-05-18 18:35:592882 with open(owners_file) as f:
dchenge07de812016-06-20 19:27:172883 lines = set(f.read().splitlines())
Jeffrey Youngf3a5c8c42021-05-14 21:56:102884 for entry in patterns.values():
dchenge07de812016-06-20 19:27:172885 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2886 ]
2887 except IOError:
2888 # No OWNERS file, so all the rules are definitely missing.
2889 continue
2890
2891 # All the remaining lines weren't found in OWNERS files, so emit an error.
2892 errors = []
Dirk Prankee3c9c62d2021-05-18 18:35:592893 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172894 missing_lines = []
2895 files = []
Dirk Prankee3c9c62d2021-05-18 18:35:592896 for _, entry in patterns.items():
dchenge07de812016-06-20 19:27:172897 missing_lines.extend(entry['rules'])
2898 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2899 if missing_lines:
2900 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052901 'Because of the presence of files:\n%s\n\n'
2902 '%s needs the following %d lines added:\n\n%s' %
2903 ('\n'.join(files), owners_file, len(missing_lines),
2904 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172905
2906 results = []
2907 if errors:
vabrf5ce3bf92016-07-11 14:52:412908 if input_api.is_committing:
2909 output = output_api.PresubmitError
2910 else:
2911 output = output_api.PresubmitPromptWarning
2912 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592913 'Found OWNERS files that need to be updated for IPC security ' +
2914 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172915 long_text='\n\n'.join(errors)))
2916
2917 return results
2918
2919
Robert Sesek2c905332020-05-06 23:17:132920def _GetFilesUsingSecurityCriticalFunctions(input_api):
2921 """Checks affected files for changes to security-critical calls. This
2922 function checks the full change diff, to catch both additions/changes
2923 and removals.
2924
2925 Returns a dict keyed by file name, and the value is a set of detected
2926 functions.
2927 """
2928 # Map of function pretty name (displayed in an error) to the pattern to
2929 # match it with.
2930 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:372931 'content::GetServiceSandboxType<>()':
2932 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:132933 }
2934 _PATTERNS_TO_CHECK = {
2935 k: input_api.re.compile(v)
2936 for k, v in _PATTERNS_TO_CHECK.items()
2937 }
2938
2939 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2940 files_to_functions = {}
2941 for f in input_api.AffectedFiles():
2942 diff = f.GenerateScmDiff()
2943 for line in diff.split('\n'):
2944 # Not using just RightHandSideLines() because removing a
2945 # call to a security-critical function can be just as important
2946 # as adding or changing the arguments.
2947 if line.startswith('-') or (line.startswith('+') and
2948 not line.startswith('++')):
2949 for name, pattern in _PATTERNS_TO_CHECK.items():
2950 if pattern.search(line):
2951 path = f.LocalPath()
2952 if not path in files_to_functions:
2953 files_to_functions[path] = set()
2954 files_to_functions[path].add(name)
2955 return files_to_functions
2956
2957
Saagar Sanghavifceeaae2020-08-12 16:40:362958def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:132959 """Checks that changes involving security-critical functions are reviewed
2960 by the security team.
2961 """
2962 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:122963 if not len(files_to_functions):
2964 return []
Robert Sesek2c905332020-05-06 23:17:132965
Edward Lesmes1e9fade2021-02-08 20:31:122966 owner_email, reviewers = (
2967 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2968 input_api,
2969 None,
2970 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:132971
Edward Lesmes1e9fade2021-02-08 20:31:122972 # Load the OWNERS file for security changes.
2973 owners_file = 'ipc/SECURITY_OWNERS'
2974 security_owners = input_api.owners_client.ListOwners(owners_file)
2975 has_security_owner = any([owner in reviewers for owner in security_owners])
2976 if has_security_owner:
2977 return []
Robert Sesek2c905332020-05-06 23:17:132978
Edward Lesmes1e9fade2021-02-08 20:31:122979 msg = 'The following files change calls to security-sensive functions\n' \
2980 'that need to be reviewed by {}.\n'.format(owners_file)
2981 for path, names in files_to_functions.items():
2982 msg += ' {}\n'.format(path)
2983 for name in names:
2984 msg += ' {}\n'.format(name)
2985 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:132986
Edward Lesmes1e9fade2021-02-08 20:31:122987 if input_api.is_committing:
2988 output = output_api.PresubmitError
2989 else:
2990 output = output_api.PresubmitNotifyResult
2991 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:132992
2993
Saagar Sanghavifceeaae2020-08-12 16:40:362994def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:262995 """Checks that set noparent is only used together with an OWNERS file in
2996 //build/OWNERS.setnoparent (see also
2997 //docs/code_reviews.md#owners-files-details)
2998 """
Erik Staabc734cd7a2021-11-23 03:11:522999 # Return early if no OWNERS files were modified.
3000 if not any(f.LocalPath().endswith('OWNERS') for f in
3001 input_api.AffectedFiles(include_deletes=False)):
3002 return []
3003
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263004 errors = []
3005
3006 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3007 allowed_owners_files = set()
3008 with open(allowed_owners_files_file, 'r') as f:
3009 for line in f:
3010 line = line.strip()
3011 if not line or line.startswith('#'):
3012 continue
3013 allowed_owners_files.add(line)
3014
3015 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3016
3017 for f in input_api.AffectedFiles(include_deletes=False):
3018 if not f.LocalPath().endswith('OWNERS'):
3019 continue
3020
3021 found_owners_files = set()
3022 found_set_noparent_lines = dict()
3023
3024 # Parse the OWNERS file.
3025 for lineno, line in enumerate(f.NewContents(), 1):
3026 line = line.strip()
3027 if line.startswith('set noparent'):
3028 found_set_noparent_lines[''] = lineno
3029 if line.startswith('file://'):
3030 if line in allowed_owners_files:
3031 found_owners_files.add('')
3032 if line.startswith('per-file'):
3033 match = per_file_pattern.match(line)
3034 if match:
3035 glob = match.group(1).strip()
3036 directive = match.group(2).strip()
3037 if directive == 'set noparent':
3038 found_set_noparent_lines[glob] = lineno
3039 if directive.startswith('file://'):
3040 if directive in allowed_owners_files:
3041 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153042
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263043 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403044 # listed in build/OWNERS.setnoparent. An exception is made for top level
3045 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143046 if (f.LocalPath().count('/') != 1 and
3047 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403048 for set_noparent_line in found_set_noparent_lines:
3049 if set_noparent_line in found_owners_files:
3050 continue
3051 errors.append(' %s:%d' % (f.LocalPath(),
3052 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263053
3054 results = []
3055 if errors:
3056 if input_api.is_committing:
3057 output = output_api.PresubmitError
3058 else:
3059 output = output_api.PresubmitPromptWarning
3060 results.append(output(
3061 'Found the following "set noparent" restrictions in OWNERS files that '
3062 'do not include owners from build/OWNERS.setnoparent:',
3063 long_text='\n\n'.join(errors)))
3064 return results
3065
3066
Saagar Sanghavifceeaae2020-08-12 16:40:363067def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313068 """Checks that added or removed lines in non third party affected
3069 header files do not lead to new useless class or struct forward
3070 declaration.
jbriance9e12f162016-11-25 07:57:503071 """
3072 results = []
3073 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3074 input_api.re.MULTILINE)
3075 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3076 input_api.re.MULTILINE)
3077 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313078 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193079 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493080 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313081 continue
3082
jbriance9e12f162016-11-25 07:57:503083 if not f.LocalPath().endswith('.h'):
3084 continue
3085
3086 contents = input_api.ReadFile(f)
3087 fwd_decls = input_api.re.findall(class_pattern, contents)
3088 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3089
3090 useless_fwd_decls = []
3091 for decl in fwd_decls:
3092 count = sum(1 for _ in input_api.re.finditer(
3093 r'\b%s\b' % input_api.re.escape(decl), contents))
3094 if count == 1:
3095 useless_fwd_decls.append(decl)
3096
3097 if not useless_fwd_decls:
3098 continue
3099
3100 for line in f.GenerateScmDiff().splitlines():
3101 if (line.startswith('-') and not line.startswith('--') or
3102 line.startswith('+') and not line.startswith('++')):
3103 for decl in useless_fwd_decls:
3104 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3105 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243106 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503107 (f.LocalPath(), decl)))
3108 useless_fwd_decls.remove(decl)
3109
3110 return results
3111
Jinsong Fan91ebbbd2019-04-16 14:57:173112def _CheckAndroidDebuggableBuild(input_api, output_api):
3113 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3114 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3115 this is a debuggable build of Android.
3116 """
3117 build_type_check_pattern = input_api.re.compile(
3118 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3119
3120 errors = []
3121
3122 sources = lambda affected_file: input_api.FilterSourceFile(
3123 affected_file,
James Cook24a504192020-07-23 00:08:443124 files_to_skip=(_EXCLUDED_PATHS +
3125 _TEST_CODE_EXCLUDED_PATHS +
3126 input_api.DEFAULT_FILES_TO_SKIP +
3127 (r"^android_webview[\\/]support_library[\\/]"
3128 "boundary_interfaces[\\/]",
3129 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3130 r'^third_party[\\/].*',
3131 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3132 r"webview[\\/]chromium[\\/]License.*",)),
3133 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173134
3135 for f in input_api.AffectedSourceFiles(sources):
3136 for line_num, line in f.ChangedContents():
3137 if build_type_check_pattern.search(line):
3138 errors.append("%s:%d" % (f.LocalPath(), line_num))
3139
3140 results = []
3141
3142 if errors:
3143 results.append(output_api.PresubmitPromptWarning(
3144 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3145 ' Please use BuildInfo.isDebugAndroid() instead.',
3146 errors))
3147
3148 return results
jbriance9e12f162016-11-25 07:57:503149
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493150# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293151def _CheckAndroidToastUsage(input_api, output_api):
3152 """Checks that code uses org.chromium.ui.widget.Toast instead of
3153 android.widget.Toast (Chromium Toast doesn't force hardware
3154 acceleration on low-end devices, saving memory).
3155 """
3156 toast_import_pattern = input_api.re.compile(
3157 r'^import android\.widget\.Toast;$')
3158
3159 errors = []
3160
3161 sources = lambda affected_file: input_api.FilterSourceFile(
3162 affected_file,
James Cook24a504192020-07-23 00:08:443163 files_to_skip=(_EXCLUDED_PATHS +
3164 _TEST_CODE_EXCLUDED_PATHS +
3165 input_api.DEFAULT_FILES_TO_SKIP +
3166 (r'^chromecast[\\/].*',
3167 r'^remoting[\\/].*')),
3168 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293169
3170 for f in input_api.AffectedSourceFiles(sources):
3171 for line_num, line in f.ChangedContents():
3172 if toast_import_pattern.search(line):
3173 errors.append("%s:%d" % (f.LocalPath(), line_num))
3174
3175 results = []
3176
3177 if errors:
3178 results.append(output_api.PresubmitError(
3179 'android.widget.Toast usage is detected. Android toasts use hardware'
3180 ' acceleration, and can be\ncostly on low-end devices. Please use'
3181 ' org.chromium.ui.widget.Toast instead.\n'
3182 'Contact [email protected] if you have any questions.',
3183 errors))
3184
3185 return results
3186
3187
dgnaa68d5e2015-06-10 10:08:223188def _CheckAndroidCrLogUsage(input_api, output_api):
3189 """Checks that new logs using org.chromium.base.Log:
3190 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513191 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223192 """
pkotwicza1dd0b002016-05-16 14:41:043193
torne89540622017-03-24 19:41:303194 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043195 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303196 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043197 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303198 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043199 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3200 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093201 # The customtabs_benchmark is a small app that does not depend on Chromium
3202 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043203 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043204 ]
3205
dgnaa68d5e2015-06-10 10:08:223206 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123207 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3208 class_in_base_pattern = input_api.re.compile(
3209 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3210 has_some_log_import_pattern = input_api.re.compile(
3211 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223212 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553213 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223214 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463215 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553216 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223217
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463218 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443219 sources = lambda x: input_api.FilterSourceFile(x,
3220 files_to_check=[r'.*\.java$'],
3221 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123222
dgnaa68d5e2015-06-10 10:08:223223 tag_decl_errors = []
3224 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123225 tag_errors = []
dgn38736db2015-09-18 19:20:513226 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123227 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223228
3229 for f in input_api.AffectedSourceFiles(sources):
3230 file_content = input_api.ReadFile(f)
3231 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223232 # Per line checks
dgn87d9fb62015-06-12 09:15:123233 if (cr_log_import_pattern.search(file_content) or
3234 (class_in_base_pattern.search(file_content) and
3235 not has_some_log_import_pattern.search(file_content))):
3236 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223237 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553238 if rough_log_decl_pattern.search(line):
3239 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223240
3241 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123242 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223243 if match:
3244 has_modified_logs = True
3245
3246 # Make sure it uses "TAG"
3247 if not match.group('tag') == 'TAG':
3248 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123249 else:
3250 # Report non cr Log function calls in changed lines
3251 for line_num, line in f.ChangedContents():
3252 if log_call_pattern.search(line):
3253 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223254
3255 # Per file checks
3256 if has_modified_logs:
3257 # Make sure the tag is using the "cr" prefix and is not too long
3258 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513259 tag_name = match.group('name') if match else None
3260 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223261 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513262 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223263 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513264 elif '.' in tag_name:
3265 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223266
3267 results = []
3268 if tag_decl_errors:
3269 results.append(output_api.PresubmitPromptWarning(
3270 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513271 '"private static final String TAG = "<package tag>".\n'
3272 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223273 tag_decl_errors))
3274
3275 if tag_length_errors:
3276 results.append(output_api.PresubmitError(
3277 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513278 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223279 tag_length_errors))
3280
3281 if tag_errors:
3282 results.append(output_api.PresubmitPromptWarning(
3283 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3284 tag_errors))
3285
dgn87d9fb62015-06-12 09:15:123286 if util_log_errors:
dgn4401aa52015-04-29 16:26:173287 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123288 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3289 util_log_errors))
3290
dgn38736db2015-09-18 19:20:513291 if tag_with_dot_errors:
3292 results.append(output_api.PresubmitPromptWarning(
3293 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3294 tag_with_dot_errors))
3295
dgn4401aa52015-04-29 16:26:173296 return results
3297
3298
Yoland Yanb92fa522017-08-28 17:37:063299def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3300 """Checks that junit.framework.* is no longer used."""
3301 deprecated_junit_framework_pattern = input_api.re.compile(
3302 r'^import junit\.framework\..*;',
3303 input_api.re.MULTILINE)
3304 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443305 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063306 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133307 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063308 for line_num, line in f.ChangedContents():
3309 if deprecated_junit_framework_pattern.search(line):
3310 errors.append("%s:%d" % (f.LocalPath(), line_num))
3311
3312 results = []
3313 if errors:
3314 results.append(output_api.PresubmitError(
3315 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3316 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3317 ' if you have any question.', errors))
3318 return results
3319
3320
3321def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3322 """Checks that if new Java test classes have inheritance.
3323 Either the new test class is JUnit3 test or it is a JUnit4 test class
3324 with a base class, either case is undesirable.
3325 """
3326 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3327
3328 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443329 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063330 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133331 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063332 if not f.OldContents():
3333 class_declaration_start_flag = False
3334 for line_num, line in f.ChangedContents():
3335 if class_declaration_pattern.search(line):
3336 class_declaration_start_flag = True
3337 if class_declaration_start_flag and ' extends ' in line:
3338 errors.append('%s:%d' % (f.LocalPath(), line_num))
3339 if '{' in line:
3340 class_declaration_start_flag = False
3341
3342 results = []
3343 if errors:
3344 results.append(output_api.PresubmitPromptWarning(
3345 'The newly created files include Test classes that inherits from base'
3346 ' class. Please do not use inheritance in JUnit4 tests or add new'
3347 ' JUnit3 tests. Contact [email protected] if you have any'
3348 ' questions.', errors))
3349 return results
3350
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203351
yolandyan45001472016-12-21 21:12:423352def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3353 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3354 deprecated_annotation_import_pattern = input_api.re.compile(
3355 r'^import android\.test\.suitebuilder\.annotation\..*;',
3356 input_api.re.MULTILINE)
3357 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443358 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423359 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133360 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423361 for line_num, line in f.ChangedContents():
3362 if deprecated_annotation_import_pattern.search(line):
3363 errors.append("%s:%d" % (f.LocalPath(), line_num))
3364
3365 results = []
3366 if errors:
3367 results.append(output_api.PresubmitError(
3368 'Annotations in android.test.suitebuilder.annotation have been'
3369 ' deprecated since API level 24. Please use android.support.test.filters'
3370 ' from //third_party/android_support_test_runner:runner_java instead.'
3371 ' Contact [email protected] if you have any questions.', errors))
3372 return results
3373
3374
agrieve7b6479d82015-10-07 14:24:223375def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3376 """Checks if MDPI assets are placed in a correct directory."""
3377 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3378 ('/res/drawable/' in f.LocalPath() or
3379 '/res/drawable-ldrtl/' in f.LocalPath()))
3380 errors = []
3381 for f in input_api.AffectedFiles(include_deletes=False,
3382 file_filter=file_filter):
3383 errors.append(' %s' % f.LocalPath())
3384
3385 results = []
3386 if errors:
3387 results.append(output_api.PresubmitError(
3388 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3389 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3390 '/res/drawable-ldrtl/.\n'
3391 'Contact [email protected] if you have questions.', errors))
3392 return results
3393
3394
Nate Fischer535972b2017-09-16 01:06:183395def _CheckAndroidWebkitImports(input_api, output_api):
3396 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353397 android.webview.ValueCallback except in the WebView glue layer
3398 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183399 """
3400 valuecallback_import_pattern = input_api.re.compile(
3401 r'^import android\.webkit\.ValueCallback;$')
3402
3403 errors = []
3404
3405 sources = lambda affected_file: input_api.FilterSourceFile(
3406 affected_file,
James Cook24a504192020-07-23 00:08:443407 files_to_skip=(_EXCLUDED_PATHS +
3408 _TEST_CODE_EXCLUDED_PATHS +
3409 input_api.DEFAULT_FILES_TO_SKIP +
3410 (r'^android_webview[\\/]glue[\\/].*',
3411 r'^weblayer[\\/].*',)),
3412 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183413
3414 for f in input_api.AffectedSourceFiles(sources):
3415 for line_num, line in f.ChangedContents():
3416 if valuecallback_import_pattern.search(line):
3417 errors.append("%s:%d" % (f.LocalPath(), line_num))
3418
3419 results = []
3420
3421 if errors:
3422 results.append(output_api.PresubmitError(
3423 'android.webkit.ValueCallback usage is detected outside of the glue'
3424 ' layer. To stay compatible with the support library, android.webkit.*'
3425 ' classes should only be used inside the glue layer and'
3426 ' org.chromium.base.Callback should be used instead.',
3427 errors))
3428
3429 return results
3430
3431
Becky Zhou7c69b50992018-12-10 19:37:573432def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3433 """Checks Android XML styles """
Erik Staabc734cd7a2021-11-23 03:11:523434
3435 # Return early if no relevant files were modified.
3436 if not any(_IsXmlOrGrdFile(input_api, f.LocalPath()) for f in
3437 input_api.AffectedFiles(include_deletes=False)):
3438 return []
3439
Becky Zhou7c69b50992018-12-10 19:37:573440 import sys
3441 original_sys_path = sys.path
3442 try:
3443 sys.path = sys.path + [input_api.os_path.join(
3444 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3445 import checkxmlstyle
3446 finally:
3447 # Restore sys.path to what it was before.
3448 sys.path = original_sys_path
3449
3450 if is_check_on_upload:
3451 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3452 else:
3453 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3454
Lijin Shen260f0852021-12-16 17:20:333455def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3456 """Checks Android Infobar Deprecation """
3457
3458 import sys
3459 original_sys_path = sys.path
3460 try:
3461 sys.path = sys.path + [input_api.os_path.join(
3462 input_api.PresubmitLocalPath(), 'tools', 'android',
3463 'infobar_deprecation')]
3464 import infobar_deprecation
3465 finally:
3466 # Restore sys.path to what it was before.
3467 sys.path = original_sys_path
3468
3469 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3470
Becky Zhou7c69b50992018-12-10 19:37:573471
agrievef32bcc72016-04-04 14:57:403472class PydepsChecker(object):
3473 def __init__(self, input_api, pydeps_files):
3474 self._file_cache = {}
3475 self._input_api = input_api
3476 self._pydeps_files = pydeps_files
3477
3478 def _LoadFile(self, path):
3479 """Returns the list of paths within a .pydeps file relative to //."""
3480 if path not in self._file_cache:
Mohamed Heikal112874d2021-11-15 14:42:203481 with open(path, encoding='utf-8') as f:
agrievef32bcc72016-04-04 14:57:403482 self._file_cache[path] = f.read()
3483 return self._file_cache[path]
3484
3485 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3486 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393487 pydeps_data = self._LoadFile(pydeps_path)
3488 uses_gn_paths = '--gn-paths' in pydeps_data
3489 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3490 if uses_gn_paths:
3491 # Paths look like: //foo/bar/baz
3492 return (e[2:] for e in entries)
3493 else:
3494 # Paths look like: path/relative/to/file.pydeps
3495 os_path = self._input_api.os_path
3496 pydeps_dir = os_path.dirname(pydeps_path)
3497 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403498
3499 def _CreateFilesToPydepsMap(self):
3500 """Returns a map of local_path -> list_of_pydeps."""
3501 ret = {}
3502 for pydep_local_path in self._pydeps_files:
3503 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3504 ret.setdefault(path, []).append(pydep_local_path)
3505 return ret
3506
3507 def ComputeAffectedPydeps(self):
3508 """Returns an iterable of .pydeps files that might need regenerating."""
3509 affected_pydeps = set()
3510 file_to_pydeps_map = None
3511 for f in self._input_api.AffectedFiles(include_deletes=True):
3512 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463513 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3514 # subrepositories. We can't figure out which files change, so re-check
3515 # all files.
3516 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383517 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3518 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403519 return self._pydeps_files
3520 elif local_path.endswith('.pydeps'):
3521 if local_path in self._pydeps_files:
3522 affected_pydeps.add(local_path)
3523 elif local_path.endswith('.py'):
3524 if file_to_pydeps_map is None:
3525 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3526 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3527 return affected_pydeps
3528
3529 def DetermineIfStale(self, pydeps_path):
3530 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413531 import difflib
John Budorick47ca3fe2018-02-10 00:53:103532 import os
3533
agrievef32bcc72016-04-04 14:57:403534 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033535 if old_pydeps_data:
3536 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393537 if '--output' not in cmd:
3538 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033539 old_contents = old_pydeps_data[2:]
3540 else:
3541 # A default cmd that should work in most cases (as long as pydeps filename
3542 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3543 # file is empty/new.
3544 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3545 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3546 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103547 env = dict(os.environ)
3548 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403549 new_pydeps_data = self._input_api.subprocess.check_output(
Mohamed Heikal112874d2021-11-15 14:42:203550 cmd + ' --output ""', shell=True, env=env, encoding='utf-8')
phajdan.jr0d9878552016-11-04 10:49:413551 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033552 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413553 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403554
3555
Tibor Goldschwendt360793f72019-06-25 18:23:493556def _ParseGclientArgs():
3557 args = {}
3558 with open('build/config/gclient_args.gni', 'r') as f:
3559 for line in f:
3560 line = line.strip()
3561 if not line or line.startswith('#'):
3562 continue
3563 attribute, value = line.split('=')
3564 args[attribute.strip()] = value.strip()
3565 return args
3566
3567
Saagar Sanghavifceeaae2020-08-12 16:40:363568def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403569 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403570 # This check is for Python dependency lists (.pydeps files), and involves
3571 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
Erik Staabc734cd7a2021-11-23 03:11:523572 # doesn't work on Windows and Mac, so skip it on other platforms and skip if
3573 # no pydeps files are affected.
Mohamed Heikal112874d2021-11-15 14:42:203574 if not input_api.platform.startswith('linux'):
agrievebb9c5b472016-04-22 15:13:003575 return []
Erik Staabc734cd7a2021-11-23 03:11:523576 if not any(f.LocalPath().endswith('.pydeps') for f in input_api.AffectedFiles(
3577 include_deletes=True)):
3578 return []
3579
Tibor Goldschwendt360793f72019-06-25 18:23:493580 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403581 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403582 results = []
3583 # First, check for new / deleted .pydeps.
3584 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033585 # Check whether we are running the presubmit check for a file in src.
3586 # f.LocalPath is relative to repo (src, or internal repo).
3587 # os_path.exists is relative to src repo.
3588 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3589 # to src and we can conclude that the pydeps is in src.
3590 if input_api.os_path.exists(f.LocalPath()):
3591 if f.LocalPath().endswith('.pydeps'):
3592 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3593 results.append(output_api.PresubmitError(
3594 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3595 'remove %s' % f.LocalPath()))
3596 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3597 results.append(output_api.PresubmitError(
3598 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3599 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403600
3601 if results:
3602 return results
3603
Mohamed Heikal7cd4d8312020-06-16 16:49:403604 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3605 affected_pydeps = set(checker.ComputeAffectedPydeps())
3606 affected_android_pydeps = affected_pydeps.intersection(
3607 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3608 if affected_android_pydeps and not is_android:
3609 results.append(output_api.PresubmitPromptOrNotify(
3610 'You have changed python files that may affect pydeps for android\n'
3611 'specific scripts. However, the relevant presumbit check cannot be\n'
3612 'run because you are not using an Android checkout. To validate that\n'
3613 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3614 'use the android-internal-presubmit optional trybot.\n'
3615 'Possibly stale pydeps files:\n{}'.format(
3616 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403617
Mohamed Heikal7cd4d8312020-06-16 16:49:403618 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3619 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403620 try:
phajdan.jr0d9878552016-11-04 10:49:413621 result = checker.DetermineIfStale(pydep_path)
3622 if result:
3623 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403624 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413625 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3626 'To regenerate, run:\n\n %s' %
3627 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403628 except input_api.subprocess.CalledProcessError as error:
3629 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3630 long_text=error.output)]
3631
3632 return results
3633
3634
Saagar Sanghavifceeaae2020-08-12 16:40:363635def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433636 """Checks to make sure no header files have |Singleton<|."""
3637 def FileFilter(affected_file):
3638 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443639 files_to_skip = (_EXCLUDED_PATHS +
3640 input_api.DEFAULT_FILES_TO_SKIP +
3641 (r"^base[\\/]memory[\\/]singleton\.h$",
3642 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3643 r"quic_singleton_impl\.h$"))
3644 return input_api.FilterSourceFile(affected_file,
3645 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433646
sergeyu34d21222015-09-16 00:11:443647 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433648 files = []
3649 for f in input_api.AffectedSourceFiles(FileFilter):
3650 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3651 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3652 contents = input_api.ReadFile(f)
3653 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243654 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433655 pattern.search(line)):
3656 files.append(f)
3657 break
3658
3659 if files:
yolandyandaabc6d2016-04-18 18:29:393660 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443661 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433662 'Please move them to an appropriate source file so that the ' +
3663 'template gets instantiated in a single compilation unit.',
3664 files) ]
3665 return []
3666
3667
[email protected]fd20b902014-05-09 02:14:533668_DEPRECATED_CSS = [
3669 # Values
3670 ( "-webkit-box", "flex" ),
3671 ( "-webkit-inline-box", "inline-flex" ),
3672 ( "-webkit-flex", "flex" ),
3673 ( "-webkit-inline-flex", "inline-flex" ),
3674 ( "-webkit-min-content", "min-content" ),
3675 ( "-webkit-max-content", "max-content" ),
3676
3677 # Properties
3678 ( "-webkit-background-clip", "background-clip" ),
3679 ( "-webkit-background-origin", "background-origin" ),
3680 ( "-webkit-background-size", "background-size" ),
3681 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443682 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533683
3684 # Functions
3685 ( "-webkit-gradient", "gradient" ),
3686 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3687 ( "-webkit-linear-gradient", "linear-gradient" ),
3688 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3689 ( "-webkit-radial-gradient", "radial-gradient" ),
3690 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3691]
3692
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203693
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493694# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363695def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533696 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253697 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343698 documentation and iOS CSS for dom distiller
3699 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253700 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533701 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493702 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443703 files_to_skip = (_EXCLUDED_PATHS +
3704 _TEST_CODE_EXCLUDED_PATHS +
3705 input_api.DEFAULT_FILES_TO_SKIP +
3706 (r"^chrome/common/extensions/docs",
3707 r"^chrome/docs",
James Cook24a504192020-07-23 00:08:443708 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253709 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443710 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533711 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3712 for line_num, line in fpath.ChangedContents():
3713 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023714 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533715 results.append(output_api.PresubmitError(
3716 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3717 (fpath.LocalPath(), line_num, deprecated_value, value)))
3718 return results
3719
mohan.reddyf21db962014-10-16 12:26:473720
Saagar Sanghavifceeaae2020-08-12 16:40:363721def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363722 bad_files = {}
3723 for f in input_api.AffectedFiles(include_deletes=False):
3724 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493725 not f.LocalPath().startswith('third_party/blink') and
3726 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363727 continue
3728
Daniel Bratell65b033262019-04-23 08:17:063729 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363730 continue
3731
Vaclav Brozekd5de76a2018-03-17 07:57:503732 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363733 if "#include" in line and "../" in line]
3734 if not relative_includes:
3735 continue
3736 bad_files[f.LocalPath()] = relative_includes
3737
3738 if not bad_files:
3739 return []
3740
3741 error_descriptions = []
Dirk Prankee3c9c62d2021-05-18 18:35:593742 for file_path, bad_lines in bad_files.items():
rlanday6802cf632017-05-30 17:48:363743 error_description = file_path
3744 for line in bad_lines:
3745 error_description += '\n ' + line
3746 error_descriptions.append(error_description)
3747
3748 results = []
3749 results.append(output_api.PresubmitError(
3750 'You added one or more relative #include paths (including "../").\n'
3751 'These shouldn\'t be used because they can be used to include headers\n'
3752 'from code that\'s not correctly specified as a dependency in the\n'
3753 'relevant BUILD.gn file(s).',
3754 error_descriptions))
3755
3756 return results
3757
Takeshi Yoshinoe387aa32017-08-02 13:16:133758
Saagar Sanghavifceeaae2020-08-12 16:40:363759def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063760 """Check that nobody tries to include a cc file. It's a relatively
3761 common error which results in duplicate symbols in object
3762 files. This may not always break the build until someone later gets
3763 very confusing linking errors."""
3764 results = []
3765 for f in input_api.AffectedFiles(include_deletes=False):
3766 # We let third_party code do whatever it wants
3767 if (f.LocalPath().startswith('third_party') and
3768 not f.LocalPath().startswith('third_party/blink') and
3769 not f.LocalPath().startswith('third_party\\blink')):
3770 continue
3771
3772 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3773 continue
3774
3775 for _, line in f.ChangedContents():
3776 if line.startswith('#include "'):
3777 included_file = line.split('"')[1]
3778 if _IsCPlusPlusFile(input_api, included_file):
3779 # The most common naming for external files with C++ code,
3780 # apart from standard headers, is to call them foo.inc, but
3781 # Chromium sometimes uses foo-inc.cc so allow that as well.
3782 if not included_file.endswith(('.h', '-inc.cc')):
3783 results.append(output_api.PresubmitError(
3784 'Only header files or .inc files should be included in other\n'
3785 'C++ files. Compiling the contents of a cc file more than once\n'
3786 'will cause duplicate information in the build which may later\n'
3787 'result in strange link_errors.\n' +
3788 f.LocalPath() + ':\n ' +
3789 line))
3790
3791 return results
3792
3793
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203794def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3795 if not isinstance(key, ast.Str):
3796 return 'Key at line %d must be a string literal' % key.lineno
3797 if not isinstance(value, ast.Dict):
3798 return 'Value at line %d must be a dict' % value.lineno
3799 if len(value.keys) != 1:
3800 return 'Dict at line %d must have single entry' % value.lineno
3801 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3802 return (
3803 'Entry at line %d must have a string literal \'filepath\' as key' %
3804 value.lineno)
3805 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133806
Takeshi Yoshinoe387aa32017-08-02 13:16:133807
Sergey Ulanov4af16052018-11-08 02:41:463808def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203809 if not isinstance(key, ast.Str):
3810 return 'Key at line %d must be a string literal' % key.lineno
3811 if not isinstance(value, ast.List):
3812 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463813 for element in value.elts:
3814 if not isinstance(element, ast.Str):
3815 return 'Watchlist elements on line %d is not a string' % key.lineno
3816 if not email_regex.match(element.s):
3817 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3818 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203819 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133820
Takeshi Yoshinoe387aa32017-08-02 13:16:133821
Sergey Ulanov4af16052018-11-08 02:41:463822def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203823 mismatch_template = (
3824 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3825 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133826
Sergey Ulanov4af16052018-11-08 02:41:463827 email_regex = input_api.re.compile(
3828 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3829
3830 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203831 i = 0
3832 last_key = ''
3833 while True:
3834 if i >= len(wd_dict.keys):
3835 if i >= len(w_dict.keys):
3836 return None
3837 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3838 elif i >= len(w_dict.keys):
3839 return (
3840 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133841
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203842 wd_key = wd_dict.keys[i]
3843 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133844
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203845 result = _CheckWatchlistDefinitionsEntrySyntax(
3846 wd_key, wd_dict.values[i], ast)
3847 if result is not None:
3848 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133849
Sergey Ulanov4af16052018-11-08 02:41:463850 result = _CheckWatchlistsEntrySyntax(
3851 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203852 if result is not None:
3853 return 'Bad entry in WATCHLISTS dict: %s' % result
3854
3855 if wd_key.s != w_key.s:
3856 return mismatch_template % (
3857 '%s at line %d' % (wd_key.s, wd_key.lineno),
3858 '%s at line %d' % (w_key.s, w_key.lineno))
3859
3860 if wd_key.s < last_key:
3861 return (
3862 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3863 (wd_key.lineno, w_key.lineno))
3864 last_key = wd_key.s
3865
3866 i = i + 1
3867
3868
Sergey Ulanov4af16052018-11-08 02:41:463869def _CheckWATCHLISTSSyntax(expression, input_api):
3870 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203871 if not isinstance(expression, ast.Expression):
3872 return 'WATCHLISTS file must contain a valid expression'
3873 dictionary = expression.body
3874 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3875 return 'WATCHLISTS file must have single dict with exactly two entries'
3876
3877 first_key = dictionary.keys[0]
3878 first_value = dictionary.values[0]
3879 second_key = dictionary.keys[1]
3880 second_value = dictionary.values[1]
3881
3882 if (not isinstance(first_key, ast.Str) or
3883 first_key.s != 'WATCHLIST_DEFINITIONS' or
3884 not isinstance(first_value, ast.Dict)):
3885 return (
3886 'The first entry of the dict in WATCHLISTS file must be '
3887 'WATCHLIST_DEFINITIONS dict')
3888
3889 if (not isinstance(second_key, ast.Str) or
3890 second_key.s != 'WATCHLISTS' or
3891 not isinstance(second_value, ast.Dict)):
3892 return (
3893 'The second entry of the dict in WATCHLISTS file must be '
3894 'WATCHLISTS dict')
3895
Sergey Ulanov4af16052018-11-08 02:41:463896 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133897
3898
Saagar Sanghavifceeaae2020-08-12 16:40:363899def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133900 for f in input_api.AffectedFiles(include_deletes=False):
3901 if f.LocalPath() == 'WATCHLISTS':
3902 contents = input_api.ReadFile(f, 'r')
3903
3904 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203905 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133906 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203907 # Get an AST tree for it and scan the tree for detailed style checking.
3908 expression = input_api.ast.parse(
3909 contents, filename='WATCHLISTS', mode='eval')
3910 except ValueError as e:
3911 return [output_api.PresubmitError(
3912 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3913 except SyntaxError as e:
3914 return [output_api.PresubmitError(
3915 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3916 except TypeError as e:
3917 return [output_api.PresubmitError(
3918 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133919
Sergey Ulanov4af16052018-11-08 02:41:463920 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203921 if result is not None:
3922 return [output_api.PresubmitError(result)]
3923 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133924
3925 return []
3926
3927
Andrew Grieve1b290e4a22020-11-24 20:07:013928def CheckGnGlobForward(input_api, output_api):
3929 """Checks that forward_variables_from(invoker, "*") follows best practices.
3930
3931 As documented at //build/docs/writing_gn_templates.md
3932 """
3933 def gn_files(f):
3934 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3935
3936 problems = []
3937 for f in input_api.AffectedSourceFiles(gn_files):
3938 for line_num, line in f.ChangedContents():
3939 if 'forward_variables_from(invoker, "*")' in line:
3940 problems.append(
3941 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3942 f.LocalPath(), line_num))
3943
3944 if problems:
3945 return [output_api.PresubmitPromptWarning(
3946 'forward_variables_from("*") without exclusions',
3947 items=sorted(problems),
3948 long_text=('The variables "visibilty" and "test_only" should be '
3949 'explicitly listed in forward_variables_from(). For more '
3950 'details, see:\n'
3951 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
3952 'build/docs/writing_gn_templates.md'
3953 '#Using-forward_variables_from'))]
3954 return []
3955
3956
Saagar Sanghavifceeaae2020-08-12 16:40:363957def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193958 """Checks that newly added header files have corresponding GN changes.
3959 Note that this is only a heuristic. To be precise, run script:
3960 build/check_gn_headers.py.
3961 """
3962
3963 def headers(f):
3964 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443965 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193966
3967 new_headers = []
3968 for f in input_api.AffectedSourceFiles(headers):
3969 if f.Action() != 'A':
3970 continue
3971 new_headers.append(f.LocalPath())
3972
3973 def gn_files(f):
James Cook24a504192020-07-23 00:08:443974 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193975
3976 all_gn_changed_contents = ''
3977 for f in input_api.AffectedSourceFiles(gn_files):
3978 for _, line in f.ChangedContents():
3979 all_gn_changed_contents += line
3980
3981 problems = []
3982 for header in new_headers:
3983 basename = input_api.os_path.basename(header)
3984 if basename not in all_gn_changed_contents:
3985 problems.append(header)
3986
3987 if problems:
3988 return [output_api.PresubmitPromptWarning(
3989 'Missing GN changes for new header files', items=sorted(problems),
3990 long_text='Please double check whether newly added header files need '
3991 'corresponding changes in gn or gni files.\nThis checking is only a '
3992 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3993 'Read https://crbug.com/661774 for more info.')]
3994 return []
3995
3996
Saagar Sanghavifceeaae2020-08-12 16:40:363997def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:023998 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3999
4000 This assumes we won't intentionally reference one product from the other
4001 product.
4002 """
4003 all_problems = []
4004 test_cases = [{
4005 "filename_postfix": "google_chrome_strings.grd",
4006 "correct_name": "Chrome",
4007 "incorrect_name": "Chromium",
4008 }, {
4009 "filename_postfix": "chromium_strings.grd",
4010 "correct_name": "Chromium",
4011 "incorrect_name": "Chrome",
4012 }]
4013
4014 for test_case in test_cases:
4015 problems = []
4016 filename_filter = lambda x: x.LocalPath().endswith(
4017 test_case["filename_postfix"])
4018
4019 # Check each new line. Can yield false positives in multiline comments, but
4020 # easier than trying to parse the XML because messages can have nested
4021 # children, and associating message elements with affected lines is hard.
4022 for f in input_api.AffectedSourceFiles(filename_filter):
4023 for line_num, line in f.ChangedContents():
4024 if "<message" in line or "<!--" in line or "-->" in line:
4025 continue
4026 if test_case["incorrect_name"] in line:
4027 problems.append(
4028 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4029
4030 if problems:
4031 message = (
4032 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4033 % (test_case["correct_name"], test_case["correct_name"],
4034 test_case["incorrect_name"]))
4035 all_problems.append(
4036 output_api.PresubmitPromptWarning(message, items=problems))
4037
4038 return all_problems
4039
4040
Saagar Sanghavifceeaae2020-08-12 16:40:364041def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364042 """Avoid large files, especially binary files, in the repository since
4043 git doesn't scale well for those. They will be in everyone's repo
4044 clones forever, forever making Chromium slower to clone and work
4045 with."""
4046
4047 # Uploading files to cloud storage is not trivial so we don't want
4048 # to set the limit too low, but the upper limit for "normal" large
4049 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4050 # anything over 20 MB is exceptional.
4051 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4052
4053 too_large_files = []
4054 for f in input_api.AffectedFiles():
4055 # Check both added and modified files (but not deleted files).
4056 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384057 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364058 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4059 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4060
4061 if too_large_files:
4062 message = (
4063 'Do not commit large files to git since git scales badly for those.\n' +
4064 'Instead put the large files in cloud storage and use DEPS to\n' +
4065 'fetch them.\n' + '\n'.join(too_large_files)
4066 )
4067 return [output_api.PresubmitError(
4068 'Too large files found in commit', long_text=message + '\n')]
4069 else:
4070 return []
4071
Max Morozb47503b2019-08-08 21:03:274072
Saagar Sanghavifceeaae2020-08-12 16:40:364073def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274074 """Checks specific for fuzz target sources."""
4075 EXPORTED_SYMBOLS = [
4076 'LLVMFuzzerInitialize',
4077 'LLVMFuzzerCustomMutator',
4078 'LLVMFuzzerCustomCrossOver',
4079 'LLVMFuzzerMutate',
4080 ]
4081
4082 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4083
4084 def FilterFile(affected_file):
4085 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444086 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4087 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274088
4089 return input_api.FilterSourceFile(
4090 affected_file,
James Cook24a504192020-07-23 00:08:444091 files_to_check=[files_to_check],
4092 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274093
4094 files_with_missing_header = []
4095 for f in input_api.AffectedSourceFiles(FilterFile):
4096 contents = input_api.ReadFile(f, 'r')
4097 if REQUIRED_HEADER in contents:
4098 continue
4099
4100 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4101 files_with_missing_header.append(f.LocalPath())
4102
4103 if not files_with_missing_header:
4104 return []
4105
4106 long_text = (
4107 'If you define any of the libFuzzer optional functions (%s), it is '
4108 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4109 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4110 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4111 'to access command line arguments passed to the fuzzer. Instead, prefer '
4112 'static initialization and shared resources as documented in '
John Palmer0e0f72bf2021-06-07 09:10:204113 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
Max Morozb47503b2019-08-08 21:03:274114 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4115 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4116 )
4117
4118 return [output_api.PresubmitPromptWarning(
4119 message="Missing '%s' in:" % REQUIRED_HEADER,
4120 items=files_with_missing_header,
4121 long_text=long_text)]
4122
4123
Mohamed Heikald048240a2019-11-12 16:57:374124def _CheckNewImagesWarning(input_api, output_api):
4125 """
4126 Warns authors who add images into the repo to make sure their images are
4127 optimized before committing.
4128 """
4129 images_added = False
4130 image_paths = []
4131 errors = []
4132 filter_lambda = lambda x: input_api.FilterSourceFile(
4133 x,
James Cook24a504192020-07-23 00:08:444134 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4135 + input_api.DEFAULT_FILES_TO_SKIP),
4136 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374137 )
4138 for f in input_api.AffectedFiles(
4139 include_deletes=False, file_filter=filter_lambda):
4140 local_path = f.LocalPath().lower()
4141 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4142 images_added = True
4143 image_paths.append(f)
4144 if images_added:
4145 errors.append(output_api.PresubmitPromptWarning(
4146 'It looks like you are trying to commit some images. If these are '
4147 'non-test-only images, please make sure to read and apply the tips in '
4148 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4149 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4150 'FYI only and will not block your CL on the CQ.', image_paths))
4151 return errors
4152
4153
Saagar Sanghavifceeaae2020-08-12 16:40:364154def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574155 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224156 results = []
dgnaa68d5e2015-06-10 10:08:224157 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174158 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224159 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294160 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064161 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4162 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424163 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184164 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574165 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374166 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154167 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Lijin Shen260f0852021-12-16 17:20:334168 results.extend(_CheckAndroidInfoBarDeprecation(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
Mark Schillacie5a0be22022-01-19 00:38:394226
4227_ACCESSIBILITY_EVENTS_TEST_PATH = (
4228 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]event[\\/].*\.html",
4229)
4230
4231_ACCESSIBILITY_TREE_TEST_PATH = (
4232 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]accname[\\/].*\.html",
4233 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]aria[\\/].*\.html",
4234 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]css[\\/].*\.html",
4235 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]html[\\/].*\.html",
4236)
4237
4238_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
4239 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4240)
4241
4242_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
4243 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4244)
4245
4246def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
4247 """Checks that commits that include a newly added, renamed/moved, or deleted
4248 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4249 change to the Android test."""
4250 def FilePathFilter(affected_file):
4251 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4252 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
4253
4254 def AndroidFilePathFilter(affected_file):
4255 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4256 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
4257
4258 # Only consider changes in the events test data path with html type.
4259 if not any(input_api.AffectedFiles(include_deletes=True,
4260 file_filter=FilePathFilter)):
4261 return []
4262
4263 # If the commit contains any change to the Android test file, ignore.
4264 if any(input_api.AffectedFiles(include_deletes=True,
4265 file_filter=AndroidFilePathFilter)):
4266 return []
4267
4268 # Only consider changes that are adding/renaming or deleting a file
4269 message = []
4270 for f in input_api.AffectedFiles(include_deletes=True,
4271 file_filter=FilePathFilter):
4272 if f.Action()=='A' or f.Action()=='D':
4273 message = ("It appears that you are adding, renaming or deleting"
4274 "\na dump_accessibility_events* test, but have not included"
4275 "\na corresponding change for Android."
4276 "\nPlease include (or remove) the test from:"
4277 "\n content/public/android/javatests/src/org/chromium/"
4278 "content/browser/accessibility/"
4279 "WebContentsAccessibilityEventsTest.java"
4280 "\nIf this message is confusing or annoying, please contact"
4281 "\nmembers of ui/accessibility/OWNERS.")
4282
4283 # If no message was set, return empty.
4284 if not len(message):
4285 return []
4286
4287 return [output_api.PresubmitPromptWarning(message)]
4288
4289def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
4290 """Checks that commits that include a newly added, renamed/moved, or deleted
4291 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4292 change to the Android test."""
4293 def FilePathFilter(affected_file):
4294 paths = _ACCESSIBILITY_TREE_TEST_PATH
4295 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
4296
4297 def AndroidFilePathFilter(affected_file):
4298 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4299 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
4300
4301 # Only consider changes in the various tree test data paths with html type.
4302 if not any(input_api.AffectedFiles(include_deletes=True,
4303 file_filter=FilePathFilter)):
4304 return []
4305
4306 # If the commit contains any change to the Android test file, ignore.
4307 if any(input_api.AffectedFiles(include_deletes=True,
4308 file_filter=AndroidFilePathFilter)):
4309 return []
4310
4311 # Only consider changes that are adding/renaming or deleting a file
4312 message = []
4313 for f in input_api.AffectedFiles(include_deletes=True,
4314 file_filter=FilePathFilter):
4315 if f.Action()=='A' or f.Action()=='D':
4316 message = ("It appears that you are adding, renaming or deleting"
4317 "\na dump_accessibility_tree* test, but have not included"
4318 "\na corresponding change for Android."
4319 "\nPlease include (or remove) the test from:"
4320 "\n content/public/android/javatests/src/org/chromium/"
4321 "content/browser/accessibility/"
4322 "WebContentsAccessibilityTreeTest.java"
4323 "\nIf this message is confusing or annoying, please contact"
4324 "\nmembers of ui/accessibility/OWNERS.")
4325
4326 # If no message was set, return empty.
4327 if not len(message):
4328 return []
4329
4330 return [output_api.PresubmitPromptWarning(message)]
4331
4332
seanmccullough4a9356252021-04-08 19:54:094333# string pattern, sequence of strings to show when pattern matches,
4334# error flag. True if match is a presubmit error, otherwise it's a warning.
4335_NON_INCLUSIVE_TERMS = (
4336 (
4337 # Note that \b pattern in python re is pretty particular. In this
4338 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4339 # ...' will not. This may require some tweaking to catch these cases
4340 # without triggering a lot of false positives. Leaving it naive and
4341 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324342 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094343 (
4344 'Please don\'t use blacklist, whitelist, ' # nocheck
4345 'or slave in your', # nocheck
4346 'code and make every effort to use other terms. Using "// nocheck"',
4347 '"# nocheck" or "<!-- nocheck -->"',
4348 'at the end of the offending line will bypass this PRESUBMIT error',
4349 'but avoid using this whenever possible. Reach out to',
4350 '[email protected] if you have questions'),
4351 True),)
4352
Saagar Sanghavifceeaae2020-08-12 16:40:364353def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394354 """Checks common to both upload and commit."""
4355 results = []
4356 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384357 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544358 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084359
4360 author = input_api.change.author_email
4361 if author and author not in _KNOWN_ROBOTS:
4362 results.extend(
4363 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4364
[email protected]9f919cc2013-07-31 03:04:044365 results.extend(
4366 input_api.canned_checks.CheckChangeHasNoTabs(
4367 input_api,
4368 output_api,
4369 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434370 results.extend(input_api.RunTests(
4371 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244372
Edward Lesmesce51df52020-08-04 22:10:174373 dirmd_bin = input_api.os_path.join(
4374 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4375 results.extend(input_api.RunTests(
4376 input_api.canned_checks.CheckDirMetadataFormat(
4377 input_api, output_api, dirmd_bin)))
4378 results.extend(
4379 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4380 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554381 results.extend(
4382 input_api.canned_checks.CheckNoNewMetadataInOwners(
4383 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094384 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4385 input_api, output_api,
4386 excluded_directories_relative_path = [
4387 'infra',
4388 'inclusive_language_presubmit_exempt_dirs.txt'
4389 ],
4390 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174391
Vaclav Brozekcdc7defb2018-03-20 09:54:354392 for f in input_api.AffectedFiles():
4393 path, name = input_api.os_path.split(f.LocalPath())
4394 if name == 'PRESUBMIT.py':
4395 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004396 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4397 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074398 # The PRESUBMIT.py file (and the directory containing it) might
4399 # have been affected by being moved or removed, so only try to
4400 # run the tests if they still exist.
Dirk Prankee3c9c62d2021-05-18 18:35:594401 use_python3 = False
4402 with open(f.LocalPath()) as fp:
Daniel Chengab582892021-09-30 20:53:194403 use_python3 = any(line.startswith('USE_PYTHON3 = True')
4404 for line in fp.readlines())
Dirk Prankee3c9c62d2021-05-18 18:35:594405
Dirk Pranke38557312018-04-18 00:53:074406 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4407 input_api, output_api, full_path,
Dirk Prankee3c9c62d2021-05-18 18:35:594408 files_to_check=[r'^PRESUBMIT_test\.py$'],
4409 run_on_python2=not use_python3,
Jonathan Njeunjee45f2bd2021-10-12 16:21:584410 run_on_python3=use_python3,
4411 skip_shebang_check=True))
[email protected]22c9bd72011-03-27 16:47:394412 return results
[email protected]1f7b4172010-01-28 01:17:344413
[email protected]b337cb5b2011-01-23 21:24:054414
Saagar Sanghavifceeaae2020-08-12 16:40:364415def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494416 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4417 if f.LocalPath().endswith(('.orig', '.rej'))]
danakj30f05352021-11-03 18:58:414418 # Cargo.toml.orig files are part of third-party crates downloaded from
4419 # crates.io and should be included.
4420 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
[email protected]b8079ae4a2012-12-05 19:56:494421 if problems:
4422 return [output_api.PresubmitError(
4423 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034424 else:
4425 return []
[email protected]b8079ae4a2012-12-05 19:56:494426
4427
Saagar Sanghavifceeaae2020-08-12 16:40:364428def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214429 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
Xiaohan Wang42d96c22022-01-20 17:23:114430 macro_re = input_api.re.compile(
4431 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074432 include_re = input_api.re.compile(
4433 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4434 extension_re = input_api.re.compile(r'\.[a-z]+$')
4435 errors = []
Bruce Dawsonaae5e652021-06-24 15:05:394436 for f in input_api.AffectedFiles(include_deletes=False):
Kent Tamura5a8755d2017-06-29 23:37:074437 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4438 continue
4439 found_line_number = None
4440 found_macro = None
Bruce Dawsonaae5e652021-06-24 15:05:394441 all_lines = input_api.ReadFile(f, 'r').splitlines()
4442 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074443 match = macro_re.search(line)
4444 if match:
4445 found_line_number = line_num
4446 found_macro = match.group(2)
4447 break
4448 if not found_line_number:
4449 continue
4450
Bruce Dawsonaae5e652021-06-24 15:05:394451 found_include_line = -1
4452 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074453 if include_re.search(line):
Bruce Dawsonaae5e652021-06-24 15:05:394454 found_include_line = line_num
Kent Tamura5a8755d2017-06-29 23:37:074455 break
Bruce Dawsonaae5e652021-06-24 15:05:394456 if found_include_line >= 0 and found_include_line < found_line_number:
Kent Tamura5a8755d2017-06-29 23:37:074457 continue
4458
4459 if not f.LocalPath().endswith('.h'):
4460 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4461 try:
4462 content = input_api.ReadFile(primary_header_path, 'r')
4463 if include_re.search(content):
4464 continue
4465 except IOError:
4466 pass
Bruce Dawsonaae5e652021-06-24 15:05:394467 errors.append('%s:%d %s macro is used without first including build/'
Kent Tamura5a8755d2017-06-29 23:37:074468 'build_config.h.'
4469 % (f.LocalPath(), found_line_number, found_macro))
4470 if errors:
4471 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4472 return []
4473
4474
Lei Zhang1c12a22f2021-05-12 11:28:454475def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
4476 stl_include_re = input_api.re.compile(
Lei Zhang0643e342021-05-12 18:02:124477 r'^#include\s+<('
Lei Zhang1c12a22f2021-05-12 11:28:454478 r'algorithm|'
4479 r'array|'
4480 r'limits|'
4481 r'list|'
4482 r'map|'
4483 r'memory|'
4484 r'queue|'
4485 r'set|'
4486 r'string|'
4487 r'unordered_map|'
4488 r'unordered_set|'
4489 r'utility|'
Lei Zhang0643e342021-05-12 18:02:124490 r'vector)>')
Lei Zhang1c12a22f2021-05-12 11:28:454491 std_namespace_re = input_api.re.compile(r'std::')
4492 errors = []
4493 for f in input_api.AffectedFiles():
4494 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4495 continue
4496
4497 uses_std_namespace = False
4498 has_stl_include = False
4499 for line in f.NewContents():
4500 if has_stl_include and uses_std_namespace:
4501 break
4502
4503 if not has_stl_include and stl_include_re.search(line):
4504 has_stl_include = True
4505 continue
4506
4507 if not uses_std_namespace and std_namespace_re.search(line):
4508 uses_std_namespace = True
4509 continue
4510
4511 if has_stl_include and not uses_std_namespace:
4512 errors.append('%s: Includes STL header(s) but does not reference std::'
4513 % f.LocalPath())
4514 if errors:
4515 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4516 return []
4517
4518
Xiaohan Wang42d96c22022-01-20 17:23:114519def _CheckForDeprecatedOSMacrosInFile(input_api, f):
[email protected]b00342e7f2013-03-26 16:21:544520 """Check for sensible looking, totally invalid OS macros."""
4521 preprocessor_statement = input_api.re.compile(r'^\s*#')
Xiaohan Wang42d96c22022-01-20 17:23:114522 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
[email protected]b00342e7f2013-03-26 16:21:544523 results = []
4524 for lnum, line in f.ChangedContents():
4525 if preprocessor_statement.search(line):
4526 for match in os_macro.finditer(line):
Xiaohan Wang42d96c22022-01-20 17:23:114527 results.append(' %s:%d: %s' % (f.LocalPath(), lnum, 'defined(OS_' +
4528 match.group(1) + ') -> BUILDFLAG(IS_' + match.group(1) +
4529 ')'))
[email protected]b00342e7f2013-03-26 16:21:544530 return results
4531
4532
Xiaohan Wang42d96c22022-01-20 17:23:114533def CheckForDeprecatedOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544534 """Check all affected files for invalid OS macros."""
4535 bad_macros = []
tzik3f295992018-12-04 20:32:234536 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474537 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
Xiaohan Wang42d96c22022-01-20 17:23:114538 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:544539
4540 if not bad_macros:
4541 return []
4542
4543 return [output_api.PresubmitError(
Xiaohan Wang42d96c22022-01-20 17:23:114544 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
4545 'defined in build_config.h):', bad_macros)]
[email protected]b00342e7f2013-03-26 16:21:544546
lliabraa35bab3932014-10-01 12:16:444547
4548def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4549 """Check all affected files for invalid "if defined" macros."""
4550 ALWAYS_DEFINED_MACROS = (
4551 "TARGET_CPU_PPC",
4552 "TARGET_CPU_PPC64",
4553 "TARGET_CPU_68K",
4554 "TARGET_CPU_X86",
4555 "TARGET_CPU_ARM",
4556 "TARGET_CPU_MIPS",
4557 "TARGET_CPU_SPARC",
4558 "TARGET_CPU_ALPHA",
4559 "TARGET_IPHONE_SIMULATOR",
4560 "TARGET_OS_EMBEDDED",
4561 "TARGET_OS_IPHONE",
4562 "TARGET_OS_MAC",
4563 "TARGET_OS_UNIX",
4564 "TARGET_OS_WIN32",
4565 )
4566 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4567 results = []
4568 for lnum, line in f.ChangedContents():
4569 for match in ifdef_macro.finditer(line):
4570 if match.group(1) in ALWAYS_DEFINED_MACROS:
4571 always_defined = ' %s is always defined. ' % match.group(1)
4572 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4573 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4574 lnum,
4575 always_defined,
4576 did_you_mean))
4577 return results
4578
4579
Saagar Sanghavifceeaae2020-08-12 16:40:364580def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444581 """Check all affected files for invalid "if defined" macros."""
4582 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054583 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444584 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054585 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214586 continue
lliabraa35bab3932014-10-01 12:16:444587 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4588 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4589
4590 if not bad_macros:
4591 return []
4592
4593 return [output_api.PresubmitError(
4594 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4595 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4596 bad_macros)]
4597
4598
Saagar Sanghavifceeaae2020-08-12 16:40:364599def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044600 """Check for same IPC rules described in
4601 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4602 """
4603 base_pattern = r'IPC_ENUM_TRAITS\('
4604 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4605 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4606
4607 problems = []
4608 for f in input_api.AffectedSourceFiles(None):
4609 local_path = f.LocalPath()
4610 if not local_path.endswith('.h'):
4611 continue
4612 for line_number, line in f.ChangedContents():
4613 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4614 problems.append(
4615 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4616
4617 if problems:
4618 return [output_api.PresubmitPromptWarning(
4619 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4620 else:
4621 return []
4622
[email protected]b00342e7f2013-03-26 16:21:544623
Saagar Sanghavifceeaae2020-08-12 16:40:364624def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054625 """Check to make sure no files being submitted have long paths.
4626 This causes issues on Windows.
4627 """
4628 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194629 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054630 local_path = f.LocalPath()
4631 # Windows has a path limit of 260 characters. Limit path length to 200 so
4632 # that we have some extra for the prefix on dev machines and the bots.
4633 if len(local_path) > 200:
4634 problems.append(local_path)
4635
4636 if problems:
4637 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4638 else:
4639 return []
4640
4641
Saagar Sanghavifceeaae2020-08-12 16:40:364642def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144643 """Check that header files have proper guards against multiple inclusion.
4644 If a file should not have such guards (and it probably should) then it
4645 should include the string "no-include-guard-because-multiply-included".
4646 """
Daniel Bratell6a75baef62018-06-04 10:04:454647 def is_chromium_header_file(f):
4648 # We only check header files under the control of the Chromium
4649 # project. That is, those outside third_party apart from
4650 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324651 # We also exclude *_message_generator.h headers as they use
4652 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454653 file_with_path = input_api.os_path.normpath(f.LocalPath())
4654 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324655 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454656 (not file_with_path.startswith('third_party') or
4657 file_with_path.startswith(
4658 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144659
4660 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344661 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144662
4663 errors = []
4664
Daniel Bratell6a75baef62018-06-04 10:04:454665 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144666 guard_name = None
4667 guard_line_number = None
4668 seen_guard_end = False
4669
4670 file_with_path = input_api.os_path.normpath(f.LocalPath())
4671 base_file_name = input_api.os_path.splitext(
4672 input_api.os_path.basename(file_with_path))[0]
4673 upper_base_file_name = base_file_name.upper()
4674
4675 expected_guard = replace_special_with_underscore(
4676 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144677
4678 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574679 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4680 # are too many (1000+) files with slight deviations from the
4681 # coding style. The most important part is that the include guard
4682 # is there, and that it's unique, not the name so this check is
4683 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144684 #
4685 # As code becomes more uniform, this could be made stricter.
4686
4687 guard_name_pattern_list = [
4688 # Anything with the right suffix (maybe with an extra _).
4689 r'\w+_H__?',
4690
Daniel Bratell39b5b062018-05-16 18:09:574691 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144692 r'\w+_h',
4693
4694 # Anything including the uppercase name of the file.
4695 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4696 upper_base_file_name)) + r'\w*',
4697 ]
4698 guard_name_pattern = '|'.join(guard_name_pattern_list)
4699 guard_pattern = input_api.re.compile(
4700 r'#ifndef\s+(' + guard_name_pattern + ')')
4701
4702 for line_number, line in enumerate(f.NewContents()):
4703 if 'no-include-guard-because-multiply-included' in line:
4704 guard_name = 'DUMMY' # To not trigger check outside the loop.
4705 break
4706
4707 if guard_name is None:
4708 match = guard_pattern.match(line)
4709 if match:
4710 guard_name = match.group(1)
4711 guard_line_number = line_number
4712
Daniel Bratell39b5b062018-05-16 18:09:574713 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454714 # don't match the chromium style guide, but new files should
4715 # get it right.
4716 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574717 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144718 errors.append(output_api.PresubmitPromptWarning(
4719 'Header using the wrong include guard name %s' % guard_name,
4720 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574721 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144722 else:
4723 # The line after #ifndef should have a #define of the same name.
4724 if line_number == guard_line_number + 1:
4725 expected_line = '#define %s' % guard_name
4726 if line != expected_line:
4727 errors.append(output_api.PresubmitPromptWarning(
4728 'Missing "%s" for include guard' % expected_line,
4729 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4730 'Expected: %r\nGot: %r' % (expected_line, line)))
4731
4732 if not seen_guard_end and line == '#endif // %s' % guard_name:
4733 seen_guard_end = True
4734 elif seen_guard_end:
4735 if line.strip() != '':
4736 errors.append(output_api.PresubmitPromptWarning(
4737 'Include guard %s not covering the whole file' % (
4738 guard_name), [f.LocalPath()]))
4739 break # Nothing else to check and enough to warn once.
4740
4741 if guard_name is None:
4742 errors.append(output_api.PresubmitPromptWarning(
4743 'Missing include guard %s' % expected_guard,
4744 [f.LocalPath()],
4745 'Missing include guard in %s\n'
4746 'Recommended name: %s\n'
4747 'This check can be disabled by having the string\n'
4748 'no-include-guard-because-multiply-included in the header.' %
4749 (f.LocalPath(), expected_guard)))
4750
4751 return errors
4752
4753
Saagar Sanghavifceeaae2020-08-12 16:40:364754def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234755 """Check source code and known ascii text files for Windows style line
4756 endings.
4757 """
Evan Stade6cfc964c12021-05-18 20:21:164758 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234759
4760 file_inclusion_pattern = (
4761 known_text_files,
Bruce Dawson6141d4a2021-06-08 15:56:114762 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4763 r'.+%s' % _HEADER_EXTENSIONS
mostynbb639aca52015-01-07 20:31:234764 )
4765
mostynbb639aca52015-01-07 20:31:234766 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534767 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444768 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534769 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504770 include_file = False
Bruce Dawsonb2cfdfe2021-06-10 19:01:204771 for line in input_api.ReadFile(f, 'r').splitlines(True):
mostynbb639aca52015-01-07 20:31:234772 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504773 include_file = True
4774 if include_file:
4775 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234776
4777 if problems:
4778 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4779 'these files to contain Windows style line endings?\n' +
4780 '\n'.join(problems))]
4781
4782 return []
4783
Evan Stade6cfc964c12021-05-18 20:21:164784def CheckIconFilesForLicenseHeaders(input_api, output_api):
4785 """Check that .icon files (which are fragments of C++) have license headers.
4786 """
4787
4788 icon_files = (r'.*\.icon$',)
4789
4790 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4791 return input_api.canned_checks.CheckLicense(
4792 input_api, output_api, source_file_filter=icons)
4793
Jose Magana2b456f22021-03-09 23:26:404794def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4795 """Check source code for use of Chrome App technologies being
4796 deprecated.
4797 """
4798
4799 def _CheckForDeprecatedTech(input_api, output_api,
4800 detection_list, files_to_check = None, files_to_skip = None):
4801
4802 if (files_to_check or files_to_skip):
4803 source_file_filter = lambda f: input_api.FilterSourceFile(
4804 f, files_to_check=files_to_check,
4805 files_to_skip=files_to_skip)
4806 else:
4807 source_file_filter = None
4808
4809 problems = []
4810
4811 for f in input_api.AffectedSourceFiles(source_file_filter):
4812 if f.Action() == 'D':
4813 continue
4814 for _, line in f.ChangedContents():
4815 if any( detect in line for detect in detection_list ):
4816 problems.append(f.LocalPath())
4817
4818 return problems
4819
4820 # to avoid this presubmit script triggering warnings
4821 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4822
4823 problems =[]
4824
4825 # NMF: any files with extensions .nmf or NMF
4826 _NMF_FILES = r'\.(nmf|NMF)$'
4827 problems += _CheckForDeprecatedTech(input_api, output_api,
4828 detection_list = [''], # any change to the file will trigger warning
4829 files_to_check = [ r'.+%s' % _NMF_FILES ])
4830
4831 # MANIFEST: any manifest.json that in its diff includes "app":
4832 _MANIFEST_FILES = r'(manifest\.json)$'
4833 problems += _CheckForDeprecatedTech(input_api, output_api,
4834 detection_list = ['"app":'],
4835 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4836
4837 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4838 problems += _CheckForDeprecatedTech(input_api, output_api,
4839 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4840 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4841
4842 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4843 problems += _CheckForDeprecatedTech(input_api, output_api,
4844 detection_list = ['#include "ppapi','#include <ppapi'],
4845 files_to_check = (
4846 r'.+%s' % _HEADER_EXTENSIONS,
4847 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4848 files_to_skip = [r"^ppapi[\\/]"] )
4849
Jose Magana2b456f22021-03-09 23:26:404850 if problems:
4851 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4852 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4853 ' PNaCl, PPAPI). See this blog post for more details:\n'
4854 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4855 'and this documentation for options to replace these technologies:\n'
4856 'https://developer.chrome.com/docs/apps/migration/\n'+
4857 '\n'.join(problems))]
4858
4859 return []
4860
mostynbb639aca52015-01-07 20:31:234861
Saagar Sanghavifceeaae2020-08-12 16:40:364862def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134863 """Checks that all source files use SYSLOG properly."""
4864 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364865 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564866 for line_number, line in f.ChangedContents():
4867 if 'SYSLOG' in line:
4868 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4869
pastarmovj89f7ee12016-09-20 14:58:134870 if syslog_files:
4871 return [output_api.PresubmitPromptWarning(
4872 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4873 ' calls.\nFiles to check:\n', items=syslog_files)]
4874 return []
4875
4876
[email protected]1f7b4172010-01-28 01:17:344877def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364878 if input_api.version < [2, 0, 0]:
4879 return [output_api.PresubmitError("Your depot_tools is out of date. "
4880 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4881 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344882 results = []
scottmg39b29952014-12-08 18:31:284883 results.extend(
jam93a6ee792017-02-08 23:59:224884 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544885 return results
[email protected]ca8d1982009-02-19 16:33:124886
4887
4888def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364889 if input_api.version < [2, 0, 0]:
4890 return [output_api.PresubmitError("Your depot_tools is out of date. "
4891 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4892 "but your version is %d.%d.%d" % tuple(input_api.version))]
4893
[email protected]fe5f57c52009-06-05 14:25:544894 results = []
[email protected]fe5f57c52009-06-05 14:25:544895 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274896 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344897 input_api,
4898 output_api,
[email protected]2fdd1f362013-01-16 03:56:034899 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274900
jam93a6ee792017-02-08 23:59:224901 results.extend(
4902 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544903 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4904 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384905 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4906 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414907 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4908 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544909 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144910
4911
Saagar Sanghavifceeaae2020-08-12 16:40:364912def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264913 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024914 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4915 # footer is set to true.
4916 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264917 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024918 footer.lower()
4919 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264920 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024921
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144922 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264923 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144924 import sys
4925 from io import StringIO
4926
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144927 new_or_added_paths = set(f.LocalPath()
4928 for f in input_api.AffectedFiles()
4929 if (f.Action() == 'A' or f.Action() == 'M'))
4930 removed_paths = set(f.LocalPath()
4931 for f in input_api.AffectedFiles(include_deletes=True)
4932 if f.Action() == 'D')
4933
Andrew Grieve0e8790c2020-09-03 17:27:324934 affected_grds = [
4935 f for f in input_api.AffectedFiles()
4936 if f.LocalPath().endswith(('.grd', '.grdp'))
4937 ]
4938 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164939 if not affected_grds:
4940 return []
4941
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144942 affected_png_paths = [f.AbsoluteLocalPath()
4943 for f in input_api.AffectedFiles()
4944 if (f.LocalPath().endswith('.png'))]
4945
4946 # Check for screenshots. Developers can upload screenshots using
4947 # tools/translation/upload_screenshots.py which finds and uploads
4948 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4949 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4950 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4951 #
4952 # The logic here is as follows:
4953 #
4954 # - If the CL has a .png file under the screenshots directory for a grd
4955 # file, warn the developer. Actual images should never be checked into the
4956 # Chrome repo.
4957 #
4958 # - If the CL contains modified or new messages in grd files and doesn't
4959 # contain the corresponding .sha1 files, warn the developer to add images
4960 # and upload them via tools/translation/upload_screenshots.py.
4961 #
4962 # - If the CL contains modified or new messages in grd files and the
4963 # corresponding .sha1 files, everything looks good.
4964 #
4965 # - If the CL contains removed messages in grd files but the corresponding
4966 # .sha1 files aren't removed, warn the developer to remove them.
4967 unnecessary_screenshots = []
4968 missing_sha1 = []
4969 unnecessary_sha1_files = []
4970
Rainhard Findlingfc31844c52020-05-15 09:58:264971 # This checks verifies that the ICU syntax of messages this CL touched is
4972 # valid, and reports any found syntax errors.
4973 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4974 # without developers being aware of them. Later on, such ICU syntax errors
4975 # break message extraction for translation, hence would block Chromium
4976 # translations until they are fixed.
4977 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144978
4979 def _CheckScreenshotAdded(screenshots_dir, message_id):
4980 sha1_path = input_api.os_path.join(
4981 screenshots_dir, message_id + '.png.sha1')
4982 if sha1_path not in new_or_added_paths:
4983 missing_sha1.append(sha1_path)
4984
4985
4986 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4987 sha1_path = input_api.os_path.join(
4988 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034989 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144990 unnecessary_sha1_files.append(sha1_path)
4991
Rainhard Findlingfc31844c52020-05-15 09:58:264992
4993 def _ValidateIcuSyntax(text, level, signatures):
Daniel Chengab582892021-09-30 20:53:194994 """Validates ICU syntax of a text string.
Rainhard Findlingfc31844c52020-05-15 09:58:264995
4996 Check if text looks similar to ICU and checks for ICU syntax correctness
4997 in this case. Reports various issues with ICU syntax and values of
4998 variants. Supports checking of nested messages. Accumulate information of
4999 each ICU messages found in the text for further checking.
5000
5001 Args:
5002 text: a string to check.
5003 level: a number of current nesting level.
5004 signatures: an accumulator, a list of tuple of (level, variable,
5005 kind, variants).
5006
5007 Returns:
5008 None if a string is not ICU or no issue detected.
5009 A tuple of (message, start index, end index) if an issue detected.
5010 """
Daniel Chengab582892021-09-30 20:53:195011 valid_types = {
5012 'plural': (frozenset(
5013 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5014 frozenset(['=1', 'other'])),
5015 'selectordinal': (frozenset(
5016 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5017 frozenset(['one', 'other'])),
5018 'select': (frozenset(), frozenset(['other'])),
5019 }
Rainhard Findlingfc31844c52020-05-15 09:58:265020
Daniel Chengab582892021-09-30 20:53:195021 # Check if the message looks like an attempt to use ICU
5022 # plural. If yes - check if its syntax strictly matches ICU format.
5023 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
5024 if not like:
5025 signatures.append((level, None, None, None))
5026 return
Rainhard Findlingfc31844c52020-05-15 09:58:265027
Daniel Chengab582892021-09-30 20:53:195028 # Check for valid prefix and suffix
5029 m = re.match(
5030 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5031 r'(plural|selectordinal|select),\s*'
5032 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5033 if not m:
5034 return (('This message looks like an ICU plural, '
5035 'but does not follow ICU syntax.'), like.start(), like.end())
5036 starting, variable, kind, variant_pairs = m.groups()
5037 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5038 if depth:
5039 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5040 len(text))
5041 first = text[0]
5042 ending = text[last_pos:]
5043 if not starting:
5044 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5045 last_pos)
5046 if not ending or '}' not in ending:
5047 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5048 last_pos)
5049 elif first != '{':
5050 return (
5051 ('Invalid ICU format. Extra characters at the start of a complex '
5052 'message (go/icu-message-migration): "%s"') %
5053 starting, 0, len(starting))
5054 elif ending != '}':
5055 return (('Invalid ICU format. Extra characters at the end of a complex '
5056 'message (go/icu-message-migration): "%s"')
5057 % ending, last_pos - 1, len(text) - 1)
5058 if kind not in valid_types:
5059 return (('Unknown ICU message type %s. '
5060 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5061 known, required = valid_types[kind]
5062 defined_variants = set()
5063 for variant, variant_range, value, value_range in variants:
5064 start, end = variant_range
5065 if variant in defined_variants:
5066 return ('Variant "%s" is defined more than once' % variant,
5067 start, end)
5068 elif known and variant not in known:
5069 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5070 start, end)
5071 defined_variants.add(variant)
5072 # Check for nested structure
5073 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5074 if res:
5075 return (res[0], res[1] + value_range[0] + 1,
5076 res[2] + value_range[0] + 1)
5077 missing = required - defined_variants
5078 if missing:
5079 return ('Required variants missing: %s' % ', '.join(missing), 0,
5080 len(text))
5081 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265082
5083
5084 def _ParseIcuVariants(text, offset=0):
5085 """Parse variants part of ICU complex message.
5086
5087 Builds a tuple of variant names and values, as well as
5088 their offsets in the input string.
5089
5090 Args:
5091 text: a string to parse
5092 offset: additional offset to add to positions in the text to get correct
5093 position in the complete ICU string.
5094
5095 Returns:
5096 List of tuples, each tuple consist of four fields: variant name,
5097 variant name span (tuple of two integers), variant value, value
5098 span (tuple of two integers).
5099 """
5100 depth, start, end = 0, -1, -1
5101 variants = []
5102 key = None
5103 for idx, char in enumerate(text):
5104 if char == '{':
5105 if not depth:
5106 start = idx
5107 chunk = text[end + 1:start]
5108 key = chunk.strip()
5109 pos = offset + end + 1 + chunk.find(key)
5110 span = (pos, pos + len(key))
5111 depth += 1
5112 elif char == '}':
5113 if not depth:
5114 return variants, depth, offset + idx
5115 depth -= 1
5116 if not depth:
5117 end = idx
5118 variants.append((key, span, text[start:end + 1], (offset + start,
5119 offset + end + 1)))
5120 return variants, depth, offset + end + 1
5121
meacer8c0d3832019-12-26 21:46:165122 try:
5123 old_sys_path = sys.path
5124 sys.path = sys.path + [input_api.os_path.join(
5125 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5126 from helper import grd_helper
5127 finally:
5128 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145129
5130 for f in affected_grds:
5131 file_path = f.LocalPath()
5132 old_id_to_msg_map = {}
5133 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385134 # Note that this code doesn't check if the file has been deleted. This is
5135 # OK because it only uses the old and new file contents and doesn't load
5136 # the file via its path.
5137 # It's also possible that a file's content refers to a renamed or deleted
5138 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5139 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5140 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145141 if file_path.endswith('.grdp'):
5142 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585143 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595144 '\n'.join(f.OldContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145145 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585146 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595147 '\n'.join(f.NewContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145148 else:
meacerff8a9b62019-12-10 19:43:585149 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145150 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585151 old_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595152 StringIO('\n'.join(f.OldContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145153 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585154 new_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595155 StringIO('\n'.join(f.NewContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145156
Rainhard Findlingd8d04372020-08-13 13:30:095157 grd_name, ext = input_api.os_path.splitext(
5158 input_api.os_path.basename(file_path))
5159 screenshots_dir = input_api.os_path.join(
5160 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5161
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145162 # Compute added, removed and modified message IDs.
5163 old_ids = set(old_id_to_msg_map)
5164 new_ids = set(new_id_to_msg_map)
5165 added_ids = new_ids - old_ids
5166 removed_ids = old_ids - new_ids
5167 modified_ids = set([])
5168 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355169 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095170 != new_id_to_msg_map[key].ContentsAsXml('', True)):
Daniel Chengab582892021-09-30 20:53:195171 # The message content itself changed. Require an updated screenshot.
5172 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355173 elif old_id_to_msg_map[key].attrs['meaning'] != \
5174 new_id_to_msg_map[key].attrs['meaning']:
5175 # The message meaning changed. Ensure there is a screenshot for it.
5176 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5177 if sha1_path not in new_or_added_paths and not \
5178 input_api.os_path.exists(sha1_path):
5179 # There is neither a previous screenshot nor is a new one added now.
5180 # Require a screenshot.
5181 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145182
Rainhard Findlingfc31844c52020-05-15 09:58:265183 if run_screenshot_check:
5184 # Check the screenshot directory for .png files. Warn if there is any.
5185 for png_path in affected_png_paths:
5186 if png_path.startswith(screenshots_dir):
5187 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145188
Rainhard Findlingfc31844c52020-05-15 09:58:265189 for added_id in added_ids:
5190 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145191
Rainhard Findlingfc31844c52020-05-15 09:58:265192 for modified_id in modified_ids:
5193 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145194
Rainhard Findlingfc31844c52020-05-15 09:58:265195 for removed_id in removed_ids:
5196 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5197
5198 # Check new and changed strings for ICU syntax errors.
5199 for key in added_ids.union(modified_ids):
5200 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5201 err = _ValidateIcuSyntax(msg, 0, [])
5202 if err is not None:
5203 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145204
5205 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265206 if run_screenshot_check:
5207 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005208 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265209 'Do not include actual screenshots in the changelist. Run '
5210 'tools/translate/upload_screenshots.py to upload them instead:',
5211 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145212
Rainhard Findlingfc31844c52020-05-15 09:58:265213 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005214 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265215 'You are adding or modifying UI strings.\n'
5216 'To ensure the best translations, take screenshots of the relevant UI '
5217 '(https://g.co/chrome/translation) and add these files to your '
5218 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145219
Rainhard Findlingfc31844c52020-05-15 09:58:265220 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005221 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265222 'You removed strings associated with these files. Remove:',
5223 sorted(unnecessary_sha1_files)))
5224 else:
5225 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5226 'screenshots check.'))
5227
5228 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075229 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265230 'ICU syntax errors were found in the following strings (problems or '
5231 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145232
5233 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125234
5235
Saagar Sanghavifceeaae2020-08-12 16:40:365236def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125237 repo_root=None,
5238 translation_expectations_path=None,
5239 grd_files=None):
5240 import sys
5241 affected_grds = [f for f in input_api.AffectedFiles()
5242 if (f.LocalPath().endswith('.grd') or
5243 f.LocalPath().endswith('.grdp'))]
5244 if not affected_grds:
5245 return []
5246
5247 try:
5248 old_sys_path = sys.path
5249 sys.path = sys.path + [
5250 input_api.os_path.join(
5251 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5252 from helper import git_helper
5253 from helper import translation_helper
5254 finally:
5255 sys.path = old_sys_path
5256
5257 # Check that translation expectations can be parsed and we can get a list of
5258 # translatable grd files. |repo_root| and |translation_expectations_path| are
5259 # only passed by tests.
5260 if not repo_root:
5261 repo_root = input_api.PresubmitLocalPath()
5262 if not translation_expectations_path:
5263 translation_expectations_path = input_api.os_path.join(
5264 repo_root, 'tools', 'gritsettings',
5265 'translation_expectations.pyl')
5266 if not grd_files:
5267 grd_files = git_helper.list_grds_in_repository(repo_root)
5268
dpapad8e21b472020-10-23 17:15:035269 # Ignore bogus grd files used only for testing
5270 # ui/webui/resoucres/tools/generate_grd.py.
5271 ignore_path = input_api.os_path.join(
5272 'ui', 'webui', 'resources', 'tools', 'tests')
Dirk Prankee3c9c62d2021-05-18 18:35:595273 grd_files = [p for p in grd_files if ignore_path not in p]
dpapad8e21b472020-10-23 17:15:035274
Mustafa Emre Acer51f2f742020-03-09 19:41:125275 try:
5276 translation_helper.get_translatable_grds(repo_root, grd_files,
5277 translation_expectations_path)
5278 except Exception as e:
5279 return [output_api.PresubmitNotifyResult(
5280 'Failed to get a list of translatable grd files. This happens when:\n'
5281 ' - One of the modified grd or grdp files cannot be parsed or\n'
5282 ' - %s is not updated.\n'
5283 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5284 return []
Ken Rockotc31f4832020-05-29 18:58:515285
5286
Saagar Sanghavifceeaae2020-08-12 16:40:365287def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515288 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095289 changed_mojoms = input_api.AffectedFiles(
5290 include_deletes=True,
5291 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525292
5293 if not changed_mojoms:
5294 return []
5295
Ken Rockotc31f4832020-05-29 18:58:515296 delta = []
5297 for mojom in changed_mojoms:
5298 old_contents = ''.join(mojom.OldContents()) or None
5299 new_contents = ''.join(mojom.NewContents()) or None
5300 delta.append({
5301 'filename': mojom.LocalPath(),
5302 'old': '\n'.join(mojom.OldContents()) or None,
5303 'new': '\n'.join(mojom.NewContents()) or None,
5304 })
5305
5306 process = input_api.subprocess.Popen(
5307 [input_api.python_executable,
5308 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5309 'public', 'tools', 'mojom',
5310 'check_stable_mojom_compatibility.py'),
5311 '--src-root', input_api.PresubmitLocalPath()],
5312 stdin=input_api.subprocess.PIPE,
5313 stdout=input_api.subprocess.PIPE,
5314 stderr=input_api.subprocess.PIPE,
5315 universal_newlines=True)
5316 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5317 if process.returncode:
5318 return [output_api.PresubmitError(
5319 'One or more [Stable] mojom definitions appears to have been changed '
5320 'in a way that is not backward-compatible.',
5321 long_text=error)]
5322 return []
Dominic Battre645d42342020-12-04 16:14:105323
5324def CheckDeprecationOfPreferences(input_api, output_api):
5325 """Removing a preference should come with a deprecation."""
5326
5327 def FilterFile(affected_file):
5328 """Accept only .cc files and the like."""
5329 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5330 files_to_skip = (_EXCLUDED_PATHS +
5331 _TEST_CODE_EXCLUDED_PATHS +
5332 input_api.DEFAULT_FILES_TO_SKIP)
5333 return input_api.FilterSourceFile(
5334 affected_file,
5335 files_to_check=file_inclusion_pattern,
5336 files_to_skip=files_to_skip)
5337
5338 def ModifiedLines(affected_file):
5339 """Returns a list of tuples (line number, line text) of added and removed
5340 lines.
5341
5342 Deleted lines share the same line number as the previous line.
5343
5344 This relies on the scm diff output describing each changed code section
5345 with a line of the form
5346
5347 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5348 """
5349 line_num = 0
5350 modified_lines = []
5351 for line in affected_file.GenerateScmDiff().splitlines():
5352 # Extract <new line num> of the patch fragment (see format above).
5353 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5354 if m:
5355 line_num = int(m.groups(1)[0])
5356 continue
5357 if ((line.startswith('+') and not line.startswith('++')) or
5358 (line.startswith('-') and not line.startswith('--'))):
5359 modified_lines.append((line_num, line))
5360
5361 if not line.startswith('-'):
5362 line_num += 1
5363 return modified_lines
5364
5365 def FindLineWith(lines, needle):
5366 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5367
5368 If 0 or >1 lines contain `needle`, -1 is returned.
5369 """
5370 matching_line_numbers = [
5371 # + 1 for 1-based counting of line numbers.
5372 i + 1 for i, line
5373 in enumerate(lines)
5374 if needle in line]
5375 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5376
5377 def ModifiedPrefMigration(affected_file):
5378 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5379 # Determine first and last lines of MigrateObsolete.*Pref functions.
5380 new_contents = affected_file.NewContents();
5381 range_1 = (
5382 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5383 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5384 range_2 = (
5385 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5386 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5387 if (-1 in range_1 + range_2):
5388 raise Exception(
5389 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5390
5391 # Check whether any of the modified lines are part of the
5392 # MigrateObsolete.*Pref functions.
5393 for line_nr, line in ModifiedLines(affected_file):
5394 if (range_1[0] <= line_nr <= range_1[1] or
5395 range_2[0] <= line_nr <= range_2[1]):
5396 return True
5397 return False
5398
5399 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5400 browser_prefs_file_pattern = input_api.re.compile(
5401 r'chrome/browser/prefs/browser_prefs.cc')
5402
5403 changes = input_api.AffectedFiles(include_deletes=True,
5404 file_filter=FilterFile)
5405 potential_problems = []
5406 for f in changes:
5407 for line in f.GenerateScmDiff().splitlines():
5408 # Check deleted lines for pref registrations.
5409 if (line.startswith('-') and not line.startswith('--') and
5410 register_pref_pattern.search(line)):
5411 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5412
5413 if browser_prefs_file_pattern.search(f.LocalPath()):
5414 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5415 # assume that they knew that they have to deprecate preferences and don't
5416 # warn.
5417 try:
5418 if ModifiedPrefMigration(f):
5419 return []
5420 except Exception as e:
5421 return [output_api.PresubmitError(str(e))]
5422
5423 if potential_problems:
5424 return [output_api.PresubmitPromptWarning(
5425 'Discovered possible removal of preference registrations.\n\n'
5426 'Please make sure to properly deprecate preferences by clearing their\n'
5427 'value for a couple of milestones before finally removing the code.\n'
5428 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195429 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5430 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105431 'This may be a false positive warning (e.g. if you move preference\n'
5432 'registrations to a different place).\n',
5433 potential_problems
5434 )]
5435 return []
Matt Stark6ef08872021-07-29 01:21:465436
5437def CheckConsistentGrdChanges(input_api, output_api):
5438 """Changes to GRD files must be consistent for tools to read them."""
5439 changed_grds = input_api.AffectedFiles(
5440 include_deletes=False,
5441 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5442 errors = []
Daniel Chengab582892021-09-30 20:53:195443 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5444 for matcher, msg in _INVALID_GRD_FILE_LINE]
Matt Stark6ef08872021-07-29 01:21:465445 for grd in changed_grds:
5446 for i, line in enumerate(grd.NewContents()):
5447 for matcher, msg in invalid_file_regexes:
5448 if matcher.search(line):
Daniel Chengab582892021-09-30 20:53:195449 errors.append(
5450 output_api.PresubmitError('Problem on {grd}:{i} - {msg}'.format(
5451 grd=grd.LocalPath(), i=i + 1, msg=msg)))
Matt Stark6ef08872021-07-29 01:21:465452 return errors
Kevin McNee967dd2d22021-11-15 16:09:295453
5454def CheckMPArchApiUsage(input_api, output_api):
5455 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5456 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5457 """
5458
5459 # Only consider top-level directories that (1) can use content APIs, (2)
5460 # apply to desktop or android chrome, and (3) are known to have a significant
5461 # number of uses of the APIs of concern.
5462 files_to_check = (
5463 r'^(chrome|components|content|extensions)[\\/].+%s' %
5464 _IMPLEMENTATION_EXTENSIONS,
5465 r'^(chrome|components|content|extensions)[\\/].+%s' % _HEADER_EXTENSIONS,
5466 )
5467 files_to_skip=(_EXCLUDED_PATHS +
5468 _TEST_CODE_EXCLUDED_PATHS +
5469 input_api.DEFAULT_FILES_TO_SKIP)
5470 source_file_filter = lambda f: input_api.FilterSourceFile(
5471 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5472
5473 # Note that since these are are just regular expressions and we don't have
5474 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5475 # could have a method named IsInMainFrame).
5476 concerning_class_pattern = input_api.re.compile(
5477 r'WebContentsObserver|WebContentsUserData')
5478 # A subset of WebContentsObserver overrides where there's particular risk for
5479 # confusing tab and page level operations and data (e.g. incorrectly
5480 # resetting page state in DidFinishNavigation).
5481 concerning_wco_methods = [
5482 'DidStartNavigation',
5483 'ReadyToCommitNavigation',
5484 'DidFinishNavigation',
5485 'RenderViewReady',
5486 'RenderViewDeleted',
5487 'RenderViewHostChanged',
5488 'DocumentAvailableInMainFrame',
Sreeja Kamishetty81347582022-01-06 12:46:335489 'DocumentOnLoadCompletedInPrimaryMainFrame',
Kevin McNee967dd2d22021-11-15 16:09:295490 'DOMContentLoaded',
5491 'DidFinishLoad',
5492 ]
5493 concerning_nav_handle_methods = [
5494 'IsInMainFrame',
5495 ]
5496 concerning_web_contents_methods = [
5497 'ForEachFrame',
5498 'GetAllFrames',
5499 'FromRenderFrameHost',
5500 'FromRenderViewHost',
5501 'GetMainFrame',
5502 'GetRenderViewHost',
5503 ]
5504 concerning_rfh_methods = [
5505 'GetParent',
5506 'GetMainFrame',
5507 'GetFrameTreeNodeId',
5508 ]
5509 concerning_method_pattern = input_api.re.compile(
5510 r'(' +
5511 r'|'.join(
5512 item
5513 for sublist in [concerning_wco_methods,
5514 concerning_nav_handle_methods,
5515 concerning_web_contents_methods,
5516 concerning_rfh_methods]
5517 for item in sublist) +
5518 r')\(')
5519
5520 uses_concerning_api = False
5521 for f in input_api.AffectedFiles(include_deletes=False,
5522 file_filter=source_file_filter):
5523 for line_num, line in f.ChangedContents():
5524 if (concerning_class_pattern.search(line) or
5525 concerning_method_pattern.search(line)):
5526 uses_concerning_api = True
5527 break
5528 if uses_concerning_api:
5529 break
5530
5531 if uses_concerning_api:
5532 output_api.AppendCC('[email protected]')
5533
5534 return []
Henrique Ferreiro2a4b55942021-11-29 23:45:365535
5536
5537def CheckAssertAshOnlyCode(input_api, output_api):
5538 """Errors if a BUILD.gn file in an ash/ directory doesn't include
5539 assert(is_chromeos_ash).
5540 """
5541
5542 def FileFilter(affected_file):
5543 """Includes directories known to be Ash only."""
5544 return input_api.FilterSourceFile(
5545 affected_file,
5546 files_to_check=(
5547 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
5548 r'.*/ash/.*BUILD\.gn'), # Any path component.
5549 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
5550
5551 errors = []
5552 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:565553 for f in input_api.AffectedFiles(include_deletes=False,
5554 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:365555 if (not pattern.search(input_api.ReadFile(f))):
5556 errors.append(
5557 output_api.PresubmitError(
5558 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
5559 'possible, please create and issue and add a comment such '
5560 'as:\n # TODO(https://crbug.com/XXX): add '
5561 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
5562 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:275563
5564
5565def _IsRendererOnlyCppFile(input_api, affected_file):
5566 path = affected_file.LocalPath()
5567 if not _IsCPlusPlusFile(input_api, path):
5568 return False
5569
5570 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
5571 if "/renderer/" in path:
5572 return True
5573
5574 # Blink's public/web API is only used/included by Renderer-only code. Note
5575 # that public/platform API may be used in non-Renderer processes (e.g. there
5576 # are some includes in code used by Utility, PDF, or Plugin processes).
5577 if "/blink/public/web/" in path:
5578 return True
5579
5580 # We assume that everything else may be used outside of Renderer processes.
5581 return False
5582
5583# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
5584# by the Chromium Clang Plugin (which will be preferable because it will
5585# 1) report errors earlier - at compile-time and 2) cover more rules).
5586def CheckRawPtrUsage(input_api, output_api):
5587 """Rough checks that raw_ptr<T> usage guidelines are followed."""
5588 errors = []
5589 # The regex below matches "raw_ptr<" following a word boundary, but not in a
5590 # C++ comment.
5591 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
5592 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
5593 for f, line_num, line in input_api.RightHandSideLines(file_filter):
5594 if raw_ptr_matcher.search(line):
5595 errors.append(
5596 output_api.PresubmitError(
5597 'Problem on {path}:{line} - '\
5598 'raw_ptr<T> should not be used in Renderer-only code '\
5599 '(as documented in the "Pointers to unprotected memory" '\
5600 'section in //base/memory/raw_ptr.md)'.format(
5601 path=f.LocalPath(), line=line_num)))
5602 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:565603
5604
5605def CheckPythonShebang(input_api, output_api):
5606 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
5607 system-wide python.
5608 """
5609 errors = []
5610 sources = lambda affected_file: input_api.FilterSourceFile(
5611 affected_file,
5612 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
5613 r'third_party/blink/web_tests/external/') + input_api.
5614 DEFAULT_FILES_TO_SKIP),
5615 files_to_check=[r'.*\.py$'])
5616 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:275617 for line_num, line in f.ChangedContents():
5618 if line_num == 1 and line.startswith('#!/usr/bin/python'):
5619 errors.append(f.LocalPath())
5620 break
Henrique Ferreirof9819f2e32021-11-30 13:31:565621
5622 result = []
5623 for file in errors:
5624 result.append(
5625 output_api.PresubmitError(
5626 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
5627 file))
5628 return result