blob: b0fe248b2ec1f78b32f3648e4515be29b0e1458f [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Saagar Sanghavifceeaae2020-08-12 16:40:3610PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1211
Dirk Prankee3c9c62d2021-05-18 18:35:5912# This line is 'magic' in that git-cl looks for it to decide whether to
13# use Python3 instead of Python2 when running the code in this file.
14USE_PYTHON3 = True
15
[email protected]379e7dd2010-01-28 17:39:2116_EXCLUDED_PATHS = (
Mila Greene3aa7222021-09-07 16:34:0817 # File needs to write to stdout to emulate a tool it's replacing.
Mila Greend3fc6a42021-09-10 17:38:2318 r"chrome[\\/]updater[\\/]mac[\\/]keystone[\\/]ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4719 # Generated file.
20 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2621 r"client_variations.js"),
Mila Greene3aa7222021-09-07 16:34:0822 r"^native_client_sdksrc[\\/]build_tools[\\/]make_rules.py",
Egor Paskoce145c42018-09-28 19:31:0423 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
24 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
25 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
26 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4927 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0428 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4629 # sqlite is an imported third party dependency.
30 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0431 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5432 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5333 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1234 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0435 r".+[\\/]pnacl_shim\.c$",
36 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0437 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1438 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0439 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5440 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0441 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4042)
[email protected]ca8d1982009-02-19 16:33:1243
John Abd-El-Malek759fea62021-03-13 03:41:1444_EXCLUDED_SET_NO_PARENT_PATHS = (
45 # It's for historical reasons that blink isn't a top level directory, where
46 # it would be allowed to have "set noparent" to avoid top level owners
47 # accidentally +1ing changes.
48 'third_party/blink/OWNERS',
49)
50
wnwenbdc444e2016-05-25 13:44:1551
[email protected]06e6d0ff2012-12-11 01:36:4452# Fragment of a regular expression that matches C++ and Objective-C++
53# implementation files.
54_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
55
wnwenbdc444e2016-05-25 13:44:1556
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1957# Fragment of a regular expression that matches C++ and Objective-C++
58# header files.
59_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
60
61
[email protected]06e6d0ff2012-12-11 01:36:4462# Regular expression that matches code only used for test binaries
63# (best effort).
64_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0465 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4466 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1367 # Test suite files, like:
68 # foo_browsertest.cc
69 # bar_unittest_mac.cc (suffix)
70 # baz_unittests.cc (plural)
71 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1272 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1873 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2174 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0475 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4376 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0477 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4378 # Web test harness.
79 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4780 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0481 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0882 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0483 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4184 # EarlGrey app side code for tests.
85 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1786 # Views Examples code
87 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4188 # Chromium Codelab
89 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4490)
[email protected]ca8d1982009-02-19 16:33:1291
Daniel Bratell609102be2019-03-27 20:53:2192_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1593
[email protected]eea609a2011-11-18 13:10:1294_TEST_ONLY_WARNING = (
95 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5596 'production code. If you are doing this from inside another method\n'
97 'named as *ForTesting(), then consider exposing things to have tests\n'
98 'make that same call directly.\n'
99 'If that is not possible, you may put a comment on the same line with\n'
100 ' // IN-TEST \n'
101 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
102 'method and can be ignored. Do not do this inside production code.\n'
103 'The android-binary-size trybot will block if the method exists in the\n'
104 'release apk.')
[email protected]eea609a2011-11-18 13:10:12105
106
[email protected]cf9b78f2012-11-14 11:40:28107_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:40108 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:21109 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
110 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:28111
Michael Thiessen44457642020-02-06 00:24:15112# Format: Sequence of tuples containing:
113# * Full import path.
114# * Sequence of strings to show when the pattern matches.
115# * Sequence of path or filename exceptions to this rule
116_BANNED_JAVA_IMPORTS = (
117 (
Colin Blundell170d78c82020-03-12 13:56:04118 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15119 (
120 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
121 ),
122 (
123 'net/android/javatests/src/org/chromium/net/'
124 'AndroidProxySelectorTest.java',
125 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04126 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15127 ),
128 ),
Michael Thiessened631912020-08-07 19:01:31129 (
130 'android.support.test.rule.UiThreadTestRule;',
131 (
132 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43133 '@org.chromium.base.test.UiThreadTest on test methods that should run '
134 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31135 ),
136 (),
137 ),
138 (
139 'android.support.test.annotation.UiThreadTest;',
140 (
141 'Do not use android.support.test.annotation.UiThreadTest, use '
142 'org.chromium.base.test.UiThreadTest instead. See '
143 'https://crbug.com/1111893.',
144 ),
145 ()
Michael Thiessenfd6919b2020-12-08 20:44:01146 ),
147 (
148 'android.support.test.rule.ActivityTestRule;',
149 (
150 'Do not use ActivityTestRule, use '
151 'org.chromium.base.test.BaseActivityTestRule instead.',
152 ),
153 (
154 'components/cronet/',
155 )
Michael Thiessened631912020-08-07 19:01:31156 )
Michael Thiessen44457642020-02-06 00:24:15157)
wnwenbdc444e2016-05-25 13:44:15158
Daniel Bratell609102be2019-03-27 20:53:21159# Format: Sequence of tuples containing:
160# * String pattern or, if starting with a slash, a regular expression.
161# * Sequence of strings to show when the pattern matches.
162# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41163_BANNED_JAVA_FUNCTIONS = (
164 (
165 'StrictMode.allowThreadDiskReads()',
166 (
167 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
168 'directly.',
169 ),
170 False,
171 ),
172 (
173 'StrictMode.allowThreadDiskWrites()',
174 (
175 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
176 'directly.',
177 ),
178 False,
179 ),
Michael Thiessen0f2547e2020-07-27 21:55:36180 (
181 '.waitForIdleSync()',
182 (
183 'Do not use waitForIdleSync as it masks underlying issues. There is '
184 'almost always something else you should wait on instead.',
185 ),
186 False,
187 ),
Eric Stevensona9a980972017-09-23 00:04:41188)
189
Daniel Bratell609102be2019-03-27 20:53:21190# Format: Sequence of tuples containing:
191# * String pattern or, if starting with a slash, a regular expression.
192# * Sequence of strings to show when the pattern matches.
193# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59194_BANNED_OBJC_FUNCTIONS = (
195 (
196 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20197 (
198 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59199 'prohibited. Please use CrTrackingArea instead.',
200 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
201 ),
202 False,
203 ),
204 (
[email protected]eaae1972014-04-16 04:17:26205 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20206 (
207 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59208 'instead.',
209 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
210 ),
211 False,
212 ),
213 (
214 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20215 (
216 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59217 'Please use |convertPoint:(point) fromView:nil| instead.',
218 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
219 ),
220 True,
221 ),
222 (
223 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20224 (
225 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59226 'Please use |convertPoint:(point) toView:nil| instead.',
227 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
228 ),
229 True,
230 ),
231 (
232 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20233 (
234 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59235 'Please use |convertRect:(point) fromView:nil| instead.',
236 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
237 ),
238 True,
239 ),
240 (
241 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20242 (
243 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59244 'Please use |convertRect:(point) toView:nil| instead.',
245 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
246 ),
247 True,
248 ),
249 (
250 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20251 (
252 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59253 'Please use |convertSize:(point) fromView:nil| instead.',
254 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
255 ),
256 True,
257 ),
258 (
259 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20260 (
261 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59262 'Please use |convertSize:(point) toView:nil| instead.',
263 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
264 ),
265 True,
266 ),
jif65398702016-10-27 10:19:48267 (
268 r"/\s+UTF8String\s*]",
269 (
270 'The use of -[NSString UTF8String] is dangerous as it can return null',
271 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
272 'Please use |SysNSStringToUTF8| instead.',
273 ),
274 True,
275 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34276 (
277 r'__unsafe_unretained',
278 (
279 'The use of __unsafe_unretained is almost certainly wrong, unless',
280 'when interacting with NSFastEnumeration or NSInvocation.',
281 'Please use __weak in files build with ARC, nothing otherwise.',
282 ),
283 False,
284 ),
Avi Drissman7382afa02019-04-29 23:27:13285 (
286 'freeWhenDone:NO',
287 (
288 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
289 'Foundation types is prohibited.',
290 ),
291 True,
292 ),
[email protected]127f18ec2012-06-16 05:05:59293)
294
Daniel Bratell609102be2019-03-27 20:53:21295# Format: Sequence of tuples containing:
296# * String pattern or, if starting with a slash, a regular expression.
297# * Sequence of strings to show when the pattern matches.
298# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54299_BANNED_IOS_OBJC_FUNCTIONS = (
300 (
301 r'/\bTEST[(]',
302 (
303 'TEST() macro should not be used in Objective-C++ code as it does not ',
304 'drain the autorelease pool at the end of the test. Use TEST_F() ',
305 'macro instead with a fixture inheriting from PlatformTest (or a ',
306 'typedef).'
307 ),
308 True,
309 ),
310 (
311 r'/\btesting::Test\b',
312 (
313 'testing::Test should not be used in Objective-C++ code as it does ',
314 'not drain the autorelease pool at the end of the test. Use ',
315 'PlatformTest instead.'
316 ),
317 True,
318 ),
319)
320
Peter K. Lee6c03ccff2019-07-15 14:40:05321# Format: Sequence of tuples containing:
322# * String pattern or, if starting with a slash, a regular expression.
323# * Sequence of strings to show when the pattern matches.
324# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
325_BANNED_IOS_EGTEST_FUNCTIONS = (
326 (
327 r'/\bEXPECT_OCMOCK_VERIFY\b',
328 (
329 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
330 'it is meant for GTests. Use [mock verify] instead.'
331 ),
332 True,
333 ),
334)
335
Daniel Bratell609102be2019-03-27 20:53:21336# Format: Sequence of tuples containing:
337# * String pattern or, if starting with a slash, a regular expression.
338# * Sequence of strings to show when the pattern matches.
339# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
340# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59341_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20342 (
Peter Kasting94a56c42019-10-25 21:54:04343 r'/\busing namespace ',
344 (
345 'Using directives ("using namespace x") are banned by the Google Style',
346 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
347 'Explicitly qualify symbols or use using declarations ("using x::foo").',
348 ),
349 True,
350 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
351 ),
Antonio Gomes07300d02019-03-13 20:59:57352 # Make sure that gtest's FRIEND_TEST() macro is not used; the
353 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
354 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53355 (
[email protected]23e6cbc2012-06-16 18:51:20356 'FRIEND_TEST(',
357 (
[email protected]e3c945502012-06-26 20:01:49358 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20359 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
360 ),
361 False,
[email protected]7345da02012-11-27 14:31:49362 (),
[email protected]23e6cbc2012-06-16 18:51:20363 ),
364 (
tomhudsone2c14d552016-05-26 17:07:46365 'setMatrixClip',
366 (
367 'Overriding setMatrixClip() is prohibited; ',
368 'the base function is deprecated. ',
369 ),
370 True,
371 (),
372 ),
373 (
[email protected]52657f62013-05-20 05:30:31374 'SkRefPtr',
375 (
376 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22377 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31378 ),
379 True,
380 (),
381 ),
382 (
383 'SkAutoRef',
384 (
385 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22386 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31387 ),
388 True,
389 (),
390 ),
391 (
392 'SkAutoTUnref',
393 (
394 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22395 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31396 ),
397 True,
398 (),
399 ),
400 (
401 'SkAutoUnref',
402 (
403 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
404 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22405 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31406 ),
407 True,
408 (),
409 ),
[email protected]d89eec82013-12-03 14:10:59410 (
411 r'/HANDLE_EINTR\(.*close',
412 (
413 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
414 'descriptor will be closed, and it is incorrect to retry the close.',
415 'Either call close directly and ignore its return value, or wrap close',
416 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
417 ),
418 True,
419 (),
420 ),
421 (
422 r'/IGNORE_EINTR\((?!.*close)',
423 (
424 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
425 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
426 ),
427 True,
428 (
429 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04430 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
431 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59432 ),
433 ),
[email protected]ec5b3f02014-04-04 18:43:43434 (
435 r'/v8::Extension\(',
436 (
437 'Do not introduce new v8::Extensions into the code base, use',
438 'gin::Wrappable instead. See http://crbug.com/334679',
439 ),
440 True,
[email protected]f55c90ee62014-04-12 00:50:03441 (
Egor Paskoce145c42018-09-28 19:31:04442 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03443 ),
[email protected]ec5b3f02014-04-04 18:43:43444 ),
skyostilf9469f72015-04-20 10:38:52445 (
jame2d1a952016-04-02 00:27:10446 '#pragma comment(lib,',
447 (
448 'Specify libraries to link with in build files and not in the source.',
449 ),
450 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41451 (
tzik3f295992018-12-04 20:32:23452 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04453 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41454 ),
jame2d1a952016-04-02 00:27:10455 ),
fdorayc4ac18d2017-05-01 21:39:59456 (
Gabriel Charette7cc6c432018-04-25 20:52:02457 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59458 (
459 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
460 ),
461 False,
462 (),
463 ),
464 (
Gabriel Charette7cc6c432018-04-25 20:52:02465 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59466 (
467 'Consider using THREAD_CHECKER macros instead of the class directly.',
468 ),
469 False,
470 (),
471 ),
dbeamb6f4fde2017-06-15 04:03:06472 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06473 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
474 (
475 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
476 'deprecated (http://crbug.com/634507). Please avoid converting away',
477 'from the Time types in Chromium code, especially if any math is',
478 'being done on time values. For interfacing with platform/library',
479 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
480 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48481 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06482 'other use cases, please contact base/time/OWNERS.',
483 ),
484 False,
485 (),
486 ),
487 (
dbeamb6f4fde2017-06-15 04:03:06488 'CallJavascriptFunctionUnsafe',
489 (
490 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
491 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
492 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
493 ),
494 False,
495 (
Egor Paskoce145c42018-09-28 19:31:04496 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
497 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
498 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06499 ),
500 ),
dskiba1474c2bfd62017-07-20 02:19:24501 (
502 'leveldb::DB::Open',
503 (
504 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
505 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
506 "Chrome's tracing, making their memory usage visible.",
507 ),
508 True,
509 (
510 r'^third_party/leveldatabase/.*\.(cc|h)$',
511 ),
Gabriel Charette0592c3a2017-07-26 12:02:04512 ),
513 (
Chris Mumfordc38afb62017-10-09 17:55:08514 'leveldb::NewMemEnv',
515 (
516 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58517 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
518 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08519 ),
520 True,
521 (
522 r'^third_party/leveldatabase/.*\.(cc|h)$',
523 ),
524 ),
525 (
Gabriel Charetted9839bc2017-07-29 14:17:47526 'RunLoop::QuitCurrent',
527 (
Robert Liao64b7ab22017-08-04 23:03:43528 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
529 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47530 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41531 False,
Gabriel Charetted9839bc2017-07-29 14:17:47532 (),
Gabriel Charettea44975052017-08-21 23:14:04533 ),
534 (
535 'base::ScopedMockTimeMessageLoopTaskRunner',
536 (
Gabriel Charette87cc1af2018-04-25 20:52:51537 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11538 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51539 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
540 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
541 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04542 ),
Gabriel Charette87cc1af2018-04-25 20:52:51543 False,
Gabriel Charettea44975052017-08-21 23:14:04544 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57545 ),
546 (
Dave Tapuska98199b612019-07-10 13:30:44547 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57548 (
549 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02550 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57551 ),
552 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16553 # Abseil's benchmarks never linked into chrome.
554 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38555 ),
556 (
Peter Kasting991618a62019-06-17 22:00:09557 r'/\bstd::stoi\b',
558 (
559 'std::stoi uses exceptions to communicate results. ',
560 'Use base::StringToInt() instead.',
561 ),
562 True,
563 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
564 ),
565 (
566 r'/\bstd::stol\b',
567 (
568 'std::stol uses exceptions to communicate results. ',
569 'Use base::StringToInt() instead.',
570 ),
571 True,
572 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
573 ),
574 (
575 r'/\bstd::stoul\b',
576 (
577 'std::stoul uses exceptions to communicate results. ',
578 'Use base::StringToUint() instead.',
579 ),
580 True,
581 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
582 ),
583 (
584 r'/\bstd::stoll\b',
585 (
586 'std::stoll uses exceptions to communicate results. ',
587 'Use base::StringToInt64() instead.',
588 ),
589 True,
590 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
591 ),
592 (
593 r'/\bstd::stoull\b',
594 (
595 'std::stoull uses exceptions to communicate results. ',
596 'Use base::StringToUint64() instead.',
597 ),
598 True,
599 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
600 ),
601 (
602 r'/\bstd::stof\b',
603 (
604 'std::stof uses exceptions to communicate results. ',
605 'For locale-independent values, e.g. reading numbers from disk',
606 'profiles, use base::StringToDouble().',
607 'For user-visible values, parse using ICU.',
608 ),
609 True,
610 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
611 ),
612 (
613 r'/\bstd::stod\b',
614 (
615 'std::stod uses exceptions to communicate results. ',
616 'For locale-independent values, e.g. reading numbers from disk',
617 'profiles, use base::StringToDouble().',
618 'For user-visible values, parse using ICU.',
619 ),
620 True,
621 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
622 ),
623 (
624 r'/\bstd::stold\b',
625 (
626 'std::stold uses exceptions to communicate results. ',
627 'For locale-independent values, e.g. reading numbers from disk',
628 'profiles, use base::StringToDouble().',
629 'For user-visible values, parse using ICU.',
630 ),
631 True,
632 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
633 ),
634 (
Daniel Bratell69334cc2019-03-26 11:07:45635 r'/\bstd::to_string\b',
636 (
637 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09638 'For locale-independent strings, e.g. writing numbers to disk',
639 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45640 'For user-visible strings, use base::FormatNumber() and',
641 'the related functions in base/i18n/number_formatting.h.',
642 ),
Peter Kasting991618a62019-06-17 22:00:09643 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21644 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45645 ),
646 (
647 r'/\bstd::shared_ptr\b',
648 (
649 'std::shared_ptr should not be used. Use scoped_refptr instead.',
650 ),
651 True,
Ulan Degenbaev947043882021-02-10 14:02:31652 [
653 # Needed for interop with third-party library.
654 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57655 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58656 '^third_party/blink/renderer/bindings/core/v8/' +
657 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58658 '^gin/array_buffer\.(cc|h)',
659 '^chrome/services/sharing/nearby/',
Meilin Wang00efc7c2021-05-13 01:12:42660 # gRPC provides some C++ libraries that use std::shared_ptr<>.
661 '^chromeos/services/libassistant/grpc/',
Wez5f56be52021-05-04 09:30:58662 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
663 '.*fuchsia.*test\.(cc|h)',
Alex Chau9eb03cdd52020-07-13 21:04:57664 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21665 ),
666 (
Peter Kasting991618a62019-06-17 22:00:09667 r'/\bstd::weak_ptr\b',
668 (
669 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
670 ),
671 True,
672 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
673 ),
674 (
Daniel Bratell609102be2019-03-27 20:53:21675 r'/\blong long\b',
676 (
677 'long long is banned. Use stdint.h if you need a 64 bit number.',
678 ),
679 False, # Only a warning since it is already used.
680 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
681 ),
682 (
683 r'/\bstd::bind\b',
684 (
685 'std::bind is banned because of lifetime risks.',
686 'Use base::BindOnce or base::BindRepeating instead.',
687 ),
688 True,
689 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
690 ),
691 (
692 r'/\b#include <chrono>\b',
693 (
694 '<chrono> overlaps with Time APIs in base. Keep using',
695 'base classes.',
696 ),
697 True,
698 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
699 ),
700 (
701 r'/\b#include <exception>\b',
702 (
703 'Exceptions are banned and disabled in Chromium.',
704 ),
705 True,
706 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
707 ),
708 (
709 r'/\bstd::function\b',
710 (
Colin Blundellea615d422021-05-12 09:35:41711 'std::function is banned. Instead use base::OnceCallback or ',
712 'base::RepeatingCallback, which directly support Chromium\'s weak ',
713 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21714 ),
Peter Kasting991618a62019-06-17 22:00:09715 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21716 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
717 ),
718 (
719 r'/\b#include <random>\b',
720 (
721 'Do not use any random number engines from <random>. Instead',
722 'use base::RandomBitGenerator.',
723 ),
724 True,
725 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
726 ),
727 (
Tom Andersona95e12042020-09-09 23:08:00728 r'/\b#include <X11/',
729 (
730 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
731 ),
732 True,
733 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
734 ),
735 (
Daniel Bratell609102be2019-03-27 20:53:21736 r'/\bstd::ratio\b',
737 (
738 'std::ratio is banned by the Google Style Guide.',
739 ),
740 True,
741 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45742 ),
743 (
Gabriel Charetted90bcc92021-09-21 00:23:10744 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:38745 (
Gabriel Charetted90bcc92021-09-21 00:23:10746 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:38747 ),
Gabriel Charette04b138f2018-08-06 00:03:22748 False,
Francois Doray43670e32017-09-27 12:40:38749 (),
750 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38751 (
Michael Giuffrida7f93d6922019-04-19 14:39:58752 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19753 (
754 'RunMessageLoop is deprecated, use RunLoop instead.',
755 ),
756 False,
757 (),
758 ),
759 (
Dave Tapuska98199b612019-07-10 13:30:44760 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19761 (
762 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
763 ),
764 False,
765 (),
766 ),
767 (
Dave Tapuska98199b612019-07-10 13:30:44768 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19769 (
770 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
771 "if you're convinced you need this.",
772 ),
773 False,
774 (),
775 ),
776 (
Dave Tapuska98199b612019-07-10 13:30:44777 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19778 (
779 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04780 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19781 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
782 'async events instead of flushing threads.',
783 ),
784 False,
785 (),
786 ),
787 (
788 r'MessageLoopRunner',
789 (
790 'MessageLoopRunner is deprecated, use RunLoop instead.',
791 ),
792 False,
793 (),
794 ),
795 (
Dave Tapuska98199b612019-07-10 13:30:44796 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19797 (
798 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
799 "gab@ if you found a use case where this is the only solution.",
800 ),
801 False,
802 (),
803 ),
804 (
Victor Costane48a2e82019-03-15 22:02:34805 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16806 (
Victor Costane48a2e82019-03-15 22:02:34807 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16808 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
809 ),
810 True,
811 (
812 r'^sql/initialization\.(cc|h)$',
813 r'^third_party/sqlite/.*\.(c|cc|h)$',
814 ),
815 ),
Matt Menke7f520a82018-03-28 21:38:37816 (
Dave Tapuska98199b612019-07-10 13:30:44817 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47818 (
819 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
820 'base::RandomShuffle instead.'
821 ),
822 True,
823 (),
824 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24825 (
826 'ios/web/public/test/http_server',
827 (
828 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
829 ),
830 False,
831 (),
832 ),
Robert Liao764c9492019-01-24 18:46:28833 (
834 'GetAddressOf',
835 (
836 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53837 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11838 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53839 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28840 ),
841 True,
842 (),
843 ),
Antonio Gomes07300d02019-03-13 20:59:57844 (
Ben Lewisa9514602019-04-29 17:53:05845 'SHFileOperation',
846 (
847 'SHFileOperation was deprecated in Windows Vista, and there are less ',
848 'complex functions to achieve the same goals. Use IFileOperation for ',
849 'any esoteric actions instead.'
850 ),
851 True,
852 (),
853 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18854 (
Cliff Smolinsky81951642019-04-30 21:39:51855 'StringFromGUID2',
856 (
857 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24858 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51859 ),
860 True,
861 (
862 r'/base/win/win_util_unittest.cc'
863 ),
864 ),
865 (
866 'StringFromCLSID',
867 (
868 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24869 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51870 ),
871 True,
872 (
873 r'/base/win/win_util_unittest.cc'
874 ),
875 ),
876 (
Avi Drissman7382afa02019-04-29 23:27:13877 'kCFAllocatorNull',
878 (
879 'The use of kCFAllocatorNull with the NoCopy creation of ',
880 'CoreFoundation types is prohibited.',
881 ),
882 True,
883 (),
884 ),
Oksana Zhuravlovafd247772019-05-16 16:57:29885 (
886 'mojo::ConvertTo',
887 (
888 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
889 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
890 'StringTraits if you would like to convert between custom types and',
891 'the wire format of mojom types.'
892 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22893 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29894 (
Wezf89dec092019-09-11 19:38:33895 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
896 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29897 r'^third_party/blink/.*\.(cc|h)$',
898 r'^content/renderer/.*\.(cc|h)$',
899 ),
900 ),
Robert Liao1d78df52019-11-11 20:02:01901 (
Oksana Zhuravlovac8222d22019-12-19 19:21:16902 'GetInterfaceProvider',
903 (
904 'InterfaceProvider is deprecated.',
905 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
906 'or Platform::GetBrowserInterfaceBroker.'
907 ),
908 False,
909 (),
910 ),
911 (
Robert Liao1d78df52019-11-11 20:02:01912 'CComPtr',
913 (
914 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
915 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
916 'details.'
917 ),
918 False,
919 (),
920 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:20921 (
922 r'/\b(IFACE|STD)METHOD_?\(',
923 (
924 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
925 'Instead, always use IFACEMETHODIMP in the declaration.'
926 ),
927 False,
928 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
929 ),
Allen Bauer53b43fb12020-03-12 17:21:47930 (
931 'set_owned_by_client',
932 (
933 'set_owned_by_client is deprecated.',
934 'views::View already owns the child views by default. This introduces ',
935 'a competing ownership model which makes the code difficult to reason ',
936 'about. See http://crbug.com/1044687 for more details.'
937 ),
938 False,
939 (),
940 ),
Eric Secklerbe6f48d2020-05-06 18:09:12941 (
Peter Boström7ff41522021-07-29 03:43:27942 'RemoveAllChildViewsWithoutDeleting',
943 (
944 'RemoveAllChildViewsWithoutDeleting is deprecated.',
945 'This method is deemed dangerous as, unless raw pointers are re-added,',
946 'calls to this method introduce memory leaks.'
947 ),
948 False,
949 (),
950 ),
951 (
Eric Secklerbe6f48d2020-05-06 18:09:12952 r'/\bTRACE_EVENT_ASYNC_',
953 (
954 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
955 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
956 ),
957 False,
958 (
959 r'^base/trace_event/.*',
960 r'^base/tracing/.*',
961 ),
962 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:26963 (
Robert Liao22f66a52021-04-10 00:57:52964 'RoInitialize',
965 (
Robert Liao48018922021-04-16 23:03:02966 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:52967 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
968 'instead. See http://crbug.com/1197722 for more information.'
969 ),
970 True,
Robert Liao48018922021-04-16 23:03:02971 (
972 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$'
973 ),
Robert Liao22f66a52021-04-10 00:57:52974 ),
[email protected]127f18ec2012-06-16 05:05:59975)
976
Mario Sanchez Prada2472cab2019-09-18 10:58:31977# Format: Sequence of tuples containing:
978# * String pattern or, if starting with a slash, a regular expression.
979# * Sequence of strings to show when the pattern matches.
980_DEPRECATED_MOJO_TYPES = (
981 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31982 r'/\bmojo::AssociatedInterfacePtrInfo\b',
983 (
984 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
985 'Use mojo::PendingAssociatedRemote<Interface> instead.',
986 ),
987 ),
988 (
989 r'/\bmojo::AssociatedInterfaceRequest\b',
990 (
991 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
992 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
993 ),
994 ),
995 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31996 r'/\bmojo::InterfacePtr\b',
997 (
998 'mojo::InterfacePtr<Interface> is deprecated.',
999 'Use mojo::Remote<Interface> instead.',
1000 ),
1001 ),
1002 (
1003 r'/\bmojo::InterfacePtrInfo\b',
1004 (
1005 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1006 'Use mojo::PendingRemote<Interface> instead.',
1007 ),
1008 ),
1009 (
1010 r'/\bmojo::InterfaceRequest\b',
1011 (
1012 'mojo::InterfaceRequest<Interface> is deprecated.',
1013 'Use mojo::PendingReceiver<Interface> instead.',
1014 ),
1015 ),
1016 (
1017 r'/\bmojo::MakeRequest\b',
1018 (
1019 'mojo::MakeRequest is deprecated.',
1020 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1021 ),
1022 ),
Mario Sanchez Prada2472cab2019-09-18 10:58:311023)
wnwenbdc444e2016-05-25 13:44:151024
mlamouria82272622014-09-16 18:45:041025_IPC_ENUM_TRAITS_DEPRECATED = (
1026 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501027 'See http://www.chromium.org/Home/chromium-security/education/'
1028 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041029
Stephen Martinis97a394142018-06-07 23:06:051030_LONG_PATH_ERROR = (
1031 'Some files included in this CL have file names that are too long (> 200'
1032 ' characters). If committed, these files will cause issues on Windows. See'
1033 ' https://crbug.com/612667 for more details.'
1034)
1035
Shenghua Zhangbfaa38b82017-11-16 21:58:021036_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041037 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041038 r".*[\\/]BuildHooksAndroidImpl\.java",
1039 r".*[\\/]LicenseContentProvider\.java",
1040 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281041 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021042]
[email protected]127f18ec2012-06-16 05:05:591043
Mohamed Heikald048240a2019-11-12 16:57:371044# List of image extensions that are used as resources in chromium.
1045_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1046
Sean Kau46e29bc2017-08-28 16:31:161047# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401048_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041049 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401050 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041051 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1052 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041053 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431054 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161055]
1056
1057
[email protected]b00342e7f2013-03-26 16:21:541058_VALID_OS_MACROS = (
1059 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081060 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541061 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441062 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121063 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541064 'OS_BSD',
1065 'OS_CAT', # For testing.
1066 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041067 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541068 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371069 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541070 'OS_IOS',
1071 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441072 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541073 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211074 'OS_NACL_NONSFI',
1075 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121076 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541077 'OS_OPENBSD',
1078 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371079 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541080 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541081 'OS_WIN',
1082)
1083
1084
Andrew Grieveb773bad2020-06-05 18:00:381085# These are not checked on the public chromium-presubmit trybot.
1086# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041087# checkouts.
agrievef32bcc72016-04-04 14:57:401088_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381089 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381090]
1091
1092
1093_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041094 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361095 'base/android/jni_generator/jni_generator.pydeps',
1096 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361097 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041098 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361099 'build/android/gyp/aar.pydeps',
1100 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271101 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361102 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381103 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361104 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021105 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221106 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111107 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361108 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361109 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361110 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111111 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041112 'build/android/gyp/create_app_bundle_apks.pydeps',
1113 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361114 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121115 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091116 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221117 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001118 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361119 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421120 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041121 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361122 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361123 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211124 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361125 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361126 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361127 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581128 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361129 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141130 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261131 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471132 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011133 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041134 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361135 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361136 'build/android/gyp/merge_manifest.pydeps',
1137 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221138 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361139 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461140 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301141 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241142 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361143 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461144 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561145 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361146 'build/android/incremental_install/generate_android_manifest.pydeps',
1147 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041148 'build/android/resource_sizes.pydeps',
1149 'build/android/test_runner.pydeps',
1150 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361151 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361152 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321153 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271154 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1155 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041156 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001157 'components/cronet/tools/generate_javadoc.pydeps',
1158 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381159 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001160 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381161 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041162 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181163 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041164 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421165 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1166 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131167 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501168 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061169 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221170 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401171]
1172
wnwenbdc444e2016-05-25 13:44:151173
agrievef32bcc72016-04-04 14:57:401174_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1175
1176
Eric Boren6fd2b932018-01-25 15:05:081177# Bypass the AUTHORS check for these accounts.
1178_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591179 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451180 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591181 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521182 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231183 'wpt-autoroller', 'chrome-weblayer-builder',
1184 'lacros-version-skew-roller', 'skylab-test-cros-roller')
Eric Boren835d71f2018-09-07 21:09:041185 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271186 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041187 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161188 for s in ('chromium-internal-autoroll',)
1189 ) | set('%[email protected]' % s
1190 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081191
Matt Stark6ef08872021-07-29 01:21:461192_INVALID_GRD_FILE_LINE = [
1193 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1194]
Eric Boren6fd2b932018-01-25 15:05:081195
Daniel Bratell65b033262019-04-23 08:17:061196def _IsCPlusPlusFile(input_api, file_path):
1197 """Returns True if this file contains C++-like code (and not Python,
1198 Go, Java, MarkDown, ...)"""
1199
1200 ext = input_api.os_path.splitext(file_path)[1]
1201 # This list is compatible with CppChecker.IsCppFile but we should
1202 # consider adding ".c" to it. If we do that we can use this function
1203 # at more places in the code.
1204 return ext in (
1205 '.h',
1206 '.cc',
1207 '.cpp',
1208 '.m',
1209 '.mm',
1210 )
1211
1212def _IsCPlusPlusHeaderFile(input_api, file_path):
1213 return input_api.os_path.splitext(file_path)[1] == ".h"
1214
1215
1216def _IsJavaFile(input_api, file_path):
1217 return input_api.os_path.splitext(file_path)[1] == ".java"
1218
1219
1220def _IsProtoFile(input_api, file_path):
1221 return input_api.os_path.splitext(file_path)[1] == ".proto"
1222
Mohamed Heikal5e5b7922020-10-29 18:57:591223
Erik Staabc734cd7a2021-11-23 03:11:521224def _IsXmlOrGrdFile(input_api, file_path):
1225 ext = input_api.os_path.splitext(file_path)[1]
1226 return ext in ('.grd', '.xml')
1227
1228
Mohamed Heikal5e5b7922020-10-29 18:57:591229def CheckNoUpstreamDepsOnClank(input_api, output_api):
1230 """Prevent additions of dependencies from the upstream repo on //clank."""
1231 # clank can depend on clank
1232 if input_api.change.RepositoryRoot().endswith('clank'):
1233 return []
1234 build_file_patterns = [
1235 r'(.+/)?BUILD\.gn',
1236 r'.+\.gni',
1237 ]
1238 excluded_files = [
1239 r'build[/\\]config[/\\]android[/\\]config\.gni'
1240 ]
1241 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1242
1243 error_message = 'Disallowed import on //clank in an upstream build file:'
1244
1245 def FilterFile(affected_file):
1246 return input_api.FilterSourceFile(
1247 affected_file,
1248 files_to_check=build_file_patterns,
1249 files_to_skip=excluded_files)
1250
1251 problems = []
1252 for f in input_api.AffectedSourceFiles(FilterFile):
1253 local_path = f.LocalPath()
1254 for line_number, line in f.ChangedContents():
1255 if (bad_pattern.search(line)):
1256 problems.append(
1257 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1258 if problems:
1259 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1260 else:
1261 return []
1262
1263
Saagar Sanghavifceeaae2020-08-12 16:40:361264def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191265 """Attempts to prevent use of functions intended only for testing in
1266 non-testing code. For now this is just a best-effort implementation
1267 that ignores header files and may have some false positives. A
1268 better implementation would probably need a proper C++ parser.
1269 """
1270 # We only scan .cc files and the like, as the declaration of
1271 # for-testing functions in header files are hard to distinguish from
1272 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491273 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191274
jochenc0d4808c2015-07-27 09:25:421275 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191276 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091277 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131278 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191279 exclusion_pattern = input_api.re.compile(
1280 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1281 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131282 # Avoid a false positive in this case, where the method name, the ::, and
1283 # the closing { are all on different lines due to line wrapping.
1284 # HelperClassForTesting::
1285 # HelperClassForTesting(
1286 # args)
1287 # : member(0) {}
1288 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191289
1290 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441291 files_to_skip = (_EXCLUDED_PATHS +
1292 _TEST_CODE_EXCLUDED_PATHS +
1293 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191294 return input_api.FilterSourceFile(
1295 affected_file,
James Cook24a504192020-07-23 00:08:441296 files_to_check=file_inclusion_pattern,
1297 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191298
1299 problems = []
1300 for f in input_api.AffectedSourceFiles(FilterFile):
1301 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131302 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241303 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031304 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461305 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131306 not exclusion_pattern.search(line) and
1307 not allowlist_pattern.search(line) and
1308 not in_method_defn):
[email protected]55459852011-08-10 15:17:191309 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031310 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131311 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191312
1313 if problems:
[email protected]f7051d52013-04-02 18:31:421314 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031315 else:
1316 return []
[email protected]55459852011-08-10 15:17:191317
1318
Saagar Sanghavifceeaae2020-08-12 16:40:361319def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231320 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591321 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231322 """
1323 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1324 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1325 name_pattern = r'ForTest(s|ing)?'
1326 # Describes an occurrence of "ForTest*" inside a // comment.
1327 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501328 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551329 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231330 # Catch calls.
1331 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1332 # Ignore definitions. (Comments are ignored separately.)
1333 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1334
1335 problems = []
1336 sources = lambda x: input_api.FilterSourceFile(
1337 x,
James Cook24a504192020-07-23 00:08:441338 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1339 + input_api.DEFAULT_FILES_TO_SKIP),
1340 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231341 )
1342 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1343 local_path = f.LocalPath()
1344 is_inside_javadoc = False
1345 for line_number, line in f.ChangedContents():
1346 if is_inside_javadoc and javadoc_end_re.search(line):
1347 is_inside_javadoc = False
1348 if not is_inside_javadoc and javadoc_start_re.search(line):
1349 is_inside_javadoc = True
1350 if is_inside_javadoc:
1351 continue
1352 if (inclusion_re.search(line) and
1353 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501354 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231355 not exclusion_re.search(line)):
1356 problems.append(
1357 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1358
1359 if problems:
1360 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1361 else:
1362 return []
1363
1364
Saagar Sanghavifceeaae2020-08-12 16:40:361365def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541366 """Checks to make sure no .h files include <iostream>."""
1367 files = []
1368 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1369 input_api.re.MULTILINE)
1370 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1371 if not f.LocalPath().endswith('.h'):
1372 continue
1373 contents = input_api.ReadFile(f)
1374 if pattern.search(contents):
1375 files.append(f)
1376
1377 if len(files):
yolandyandaabc6d2016-04-18 18:29:391378 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061379 'Do not #include <iostream> in header files, since it inserts static '
1380 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541381 '#include <ostream>. See http://crbug.com/94794',
1382 files) ]
1383 return []
1384
Danil Chapovalov3518f362018-08-11 16:13:431385def _CheckNoStrCatRedefines(input_api, output_api):
1386 """Checks no windows headers with StrCat redefined are included directly."""
1387 files = []
1388 pattern_deny = input_api.re.compile(
1389 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1390 input_api.re.MULTILINE)
1391 pattern_allow = input_api.re.compile(
1392 r'^#include\s"base/win/windows_defines.inc"',
1393 input_api.re.MULTILINE)
1394 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1395 contents = input_api.ReadFile(f)
1396 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1397 files.append(f.LocalPath())
1398
1399 if len(files):
1400 return [output_api.PresubmitError(
1401 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1402 'directly since they pollute code with StrCat macro. Instead, '
1403 'include matching header from base/win. See http://crbug.com/856536',
1404 files) ]
1405 return []
1406
[email protected]10689ca2011-09-02 02:31:541407
Saagar Sanghavifceeaae2020-08-12 16:40:361408def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521409 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181410 problems = []
1411 for f in input_api.AffectedFiles():
1412 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1413 continue
1414
1415 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041416 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181417 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1418
1419 if not problems:
1420 return []
1421 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1422 '\n'.join(problems))]
1423
Saagar Sanghavifceeaae2020-08-12 16:40:361424def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341425 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1426
1427 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1428 instead of DISABLED_. To filter false positives, reports are only generated
1429 if a corresponding MAYBE_ line exists.
1430 """
1431 problems = []
1432
1433 # The following two patterns are looked for in tandem - is a test labeled
1434 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1435 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1436 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1437
1438 # This is for the case that a test is disabled on all platforms.
1439 full_disable_pattern = input_api.re.compile(
1440 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1441 input_api.re.MULTILINE)
1442
Katie Df13948e2018-09-25 07:33:441443 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341444 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1445 continue
1446
1447 # Search for MABYE_, DISABLE_ pairs.
1448 disable_lines = {} # Maps of test name to line number.
1449 maybe_lines = {}
1450 for line_num, line in f.ChangedContents():
1451 disable_match = disable_pattern.search(line)
1452 if disable_match:
1453 disable_lines[disable_match.group(1)] = line_num
1454 maybe_match = maybe_pattern.search(line)
1455 if maybe_match:
1456 maybe_lines[maybe_match.group(1)] = line_num
1457
1458 # Search for DISABLE_ occurrences within a TEST() macro.
1459 disable_tests = set(disable_lines.keys())
1460 maybe_tests = set(maybe_lines.keys())
1461 for test in disable_tests.intersection(maybe_tests):
1462 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1463
1464 contents = input_api.ReadFile(f)
1465 full_disable_match = full_disable_pattern.search(contents)
1466 if full_disable_match:
1467 problems.append(' %s' % f.LocalPath())
1468
1469 if not problems:
1470 return []
1471 return [
1472 output_api.PresubmitPromptWarning(
1473 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1474 '\n'.join(problems))
1475 ]
1476
Nina Satragnof7660532021-09-20 18:03:351477def CheckForgettingMAYBEInTests(input_api, output_api):
1478 """Checks to make sure tests disabled conditionally are not missing a
1479 corresponding MAYBE_ prefix.
1480 """
1481 # Expect at least a lowercase character in the test name. This helps rule out
1482 # false positives with macros wrapping the actual tests name.
1483 define_maybe_pattern = input_api.re.compile(
1484 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
1485 test_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*\w+,\s*MAYBE_{test_name}\)'
1486 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1487 warnings = []
1488
1489 # Read the entire files. We can't just read the affected lines, forgetting to
1490 # add MAYBE_ on a change would not show up otherwise.
1491 for f in input_api.AffectedFiles(False):
1492 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1493 continue
1494 contents = input_api.ReadFile(f)
1495 lines = contents.splitlines(True)
1496 current_position = 0
1497 warning_test_names = set()
1498 for line_num, line in enumerate(lines, start=1):
1499 current_position += len(line)
1500 maybe_match = define_maybe_pattern.search(line)
1501 if maybe_match:
1502 test_name = maybe_match.group('test_name')
1503 # Do not warn twice for the same test.
1504 if (test_name in warning_test_names):
1505 continue
1506 warning_test_names.add(test_name)
1507
1508 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1509 # the current position.
1510 test_match = input_api.re.compile(
1511 test_maybe_pattern.format(test_name=test_name),
1512 input_api.re.MULTILINE).search(contents, current_position)
1513 suite_match = input_api.re.compile(
1514 suite_maybe_pattern.format(test_name=test_name),
1515 input_api.re.MULTILINE).search(contents, current_position)
1516 if not test_match and not suite_match:
1517 warnings.append(
1518 output_api.PresubmitPromptWarning(
1519 '%s:%d found MAYBE_ defined without corresponding test %s' %
1520 (f.LocalPath(), line_num, test_name)))
1521 return warnings
[email protected]72df4e782012-06-21 16:28:181522
Saagar Sanghavifceeaae2020-08-12 16:40:361523def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571524 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521525 errors = []
Hans Wennborg944479f2020-06-25 21:39:251526 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521527 input_api.re.MULTILINE)
1528 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1529 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1530 continue
1531 for lnum, line in f.ChangedContents():
1532 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171533 errors.append(output_api.PresubmitError(
1534 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571535 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171536 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521537 return errors
1538
1539
Weilun Shia487fad2020-10-28 00:10:341540# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1541# more reliable way. See
1542# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191543
wnwenbdc444e2016-05-25 13:44:151544
Saagar Sanghavifceeaae2020-08-12 16:40:361545def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391546 """Check that FlakyTest annotation is our own instead of the android one"""
1547 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1548 files = []
1549 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1550 if f.LocalPath().endswith('Test.java'):
1551 if pattern.search(input_api.ReadFile(f)):
1552 files.append(f)
1553 if len(files):
1554 return [output_api.PresubmitError(
1555 'Use org.chromium.base.test.util.FlakyTest instead of '
1556 'android.test.FlakyTest',
1557 files)]
1558 return []
mcasasb7440c282015-02-04 14:52:191559
wnwenbdc444e2016-05-25 13:44:151560
Saagar Sanghavifceeaae2020-08-12 16:40:361561def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441562 """Make sure .DEPS.git is never modified manually."""
1563 if any(f.LocalPath().endswith('.DEPS.git') for f in
1564 input_api.AffectedFiles()):
1565 return [output_api.PresubmitError(
1566 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1567 'automated system based on what\'s in DEPS and your changes will be\n'
1568 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501569 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1570 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441571 'for more information')]
1572 return []
1573
1574
Saagar Sanghavifceeaae2020-08-12 16:40:361575def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471576 """Checks that DEPS file deps are from allowed_hosts."""
1577 # Run only if DEPS file has been modified to annoy fewer bystanders.
1578 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1579 return []
1580 # Outsource work to gclient verify
1581 try:
John Budorickf20c0042019-04-25 23:23:401582 gclient_path = input_api.os_path.join(
1583 input_api.PresubmitLocalPath(),
1584 'third_party', 'depot_tools', 'gclient.py')
1585 input_api.subprocess.check_output(
1586 [input_api.python_executable, gclient_path, 'verify'],
1587 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471588 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201589 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471590 return [output_api.PresubmitError(
1591 'DEPS file must have only git dependencies.',
1592 long_text=error.output)]
1593
1594
Mario Sanchez Prada2472cab2019-09-18 10:58:311595def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1596 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591597 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311598
1599 Returns an string composed of the name of the file, the line number where the
1600 match has been found and the additional text passed as |message| in case the
1601 target type name matches the text inside the line passed as parameter.
1602 """
Peng Huang9c5949a02020-06-11 19:20:541603 result = []
1604
danakjd18e8892020-12-17 17:42:011605 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1606 return result
1607 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541608 return result
1609
Mario Sanchez Prada2472cab2019-09-18 10:58:311610 matched = False
1611 if type_name[0:1] == '/':
1612 regex = type_name[1:]
1613 if input_api.re.search(regex, line):
1614 matched = True
1615 elif type_name in line:
1616 matched = True
1617
Mario Sanchez Prada2472cab2019-09-18 10:58:311618 if matched:
1619 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1620 for message_line in message:
1621 result.append(' %s' % message_line)
1622
1623 return result
1624
1625
Saagar Sanghavifceeaae2020-08-12 16:40:361626def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591627 """Make sure that banned functions are not used."""
1628 warnings = []
1629 errors = []
1630
James Cook24a504192020-07-23 00:08:441631 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151632 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441633 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151634 if input_api.re.match(item, local_path):
1635 return True
1636 return False
1637
Peter K. Lee6c03ccff2019-07-15 14:40:051638 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541639 local_path = affected_file.LocalPath()
1640 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1641 return False
1642 basename = input_api.os_path.basename(local_path)
1643 if 'ios' in basename.split('_'):
1644 return True
1645 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1646 if sep and 'ios' in local_path.split(sep):
1647 return True
1648 return False
1649
wnwenbdc444e2016-05-25 13:44:151650 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311651 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1652 func_name, message)
1653 if problems:
wnwenbdc444e2016-05-25 13:44:151654 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311655 errors.extend(problems)
1656 else:
1657 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151658
Eric Stevensona9a980972017-09-23 00:04:411659 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1660 for f in input_api.AffectedFiles(file_filter=file_filter):
1661 for line_num, line in f.ChangedContents():
1662 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1663 CheckForMatch(f, line_num, line, func_name, message, error)
1664
[email protected]127f18ec2012-06-16 05:05:591665 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1666 for f in input_api.AffectedFiles(file_filter=file_filter):
1667 for line_num, line in f.ChangedContents():
1668 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151669 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591670
Peter K. Lee6c03ccff2019-07-15 14:40:051671 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541672 for line_num, line in f.ChangedContents():
1673 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1674 CheckForMatch(f, line_num, line, func_name, message, error)
1675
Peter K. Lee6c03ccff2019-07-15 14:40:051676 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1677 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1678 for line_num, line in f.ChangedContents():
1679 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1680 CheckForMatch(f, line_num, line, func_name, message, error)
1681
[email protected]127f18ec2012-06-16 05:05:591682 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1683 for f in input_api.AffectedFiles(file_filter=file_filter):
1684 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491685 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441686 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491687 continue
wnwenbdc444e2016-05-25 13:44:151688 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591689
1690 result = []
1691 if (warnings):
1692 result.append(output_api.PresubmitPromptWarning(
1693 'Banned functions were used.\n' + '\n'.join(warnings)))
1694 if (errors):
1695 result.append(output_api.PresubmitError(
1696 'Banned functions were used.\n' + '\n'.join(errors)))
1697 return result
1698
1699
Michael Thiessen44457642020-02-06 00:24:151700def _CheckAndroidNoBannedImports(input_api, output_api):
1701 """Make sure that banned java imports are not used."""
1702 errors = []
1703
1704 def IsException(path, exceptions):
1705 for exception in exceptions:
1706 if (path.startswith(exception)):
1707 return True
1708 return False
1709
1710 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1711 for f in input_api.AffectedFiles(file_filter=file_filter):
1712 for line_num, line in f.ChangedContents():
1713 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1714 if IsException(f.LocalPath(), exceptions):
1715 continue;
1716 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1717 'import ' + import_name, message)
1718 if problems:
1719 errors.extend(problems)
1720 result = []
1721 if (errors):
1722 result.append(output_api.PresubmitError(
1723 'Banned imports were used.\n' + '\n'.join(errors)))
1724 return result
1725
1726
Saagar Sanghavifceeaae2020-08-12 16:40:361727def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311728 """Make sure that old Mojo types are not used."""
1729 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571730 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311731
Mario Sanchez Pradaaab91382019-12-19 08:57:091732 # For any path that is not an "ok" or an "error" path, a warning will be
1733 # raised if deprecated mojo types are found.
1734 ok_paths = ['components/arc']
1735 error_paths = ['third_party/blink', 'content']
1736
Mario Sanchez Prada2472cab2019-09-18 10:58:311737 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1738 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571739 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091740 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311741 continue
1742
1743 for line_num, line in f.ChangedContents():
1744 for func_name, message in _DEPRECATED_MOJO_TYPES:
1745 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1746 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571747
Mario Sanchez Prada2472cab2019-09-18 10:58:311748 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091749 # Raise errors inside |error_paths| and warnings everywhere else.
1750 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571751 errors.extend(problems)
1752 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311753 warnings.extend(problems)
1754
1755 result = []
1756 if (warnings):
1757 result.append(output_api.PresubmitPromptWarning(
1758 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571759 if (errors):
1760 result.append(output_api.PresubmitError(
1761 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311762 return result
1763
1764
Saagar Sanghavifceeaae2020-08-12 16:40:361765def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061766 """Make sure that banned functions are not used."""
1767 files = []
1768 pattern = input_api.re.compile(r'^#pragma\s+once',
1769 input_api.re.MULTILINE)
1770 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1771 if not f.LocalPath().endswith('.h'):
1772 continue
1773 contents = input_api.ReadFile(f)
1774 if pattern.search(contents):
1775 files.append(f)
1776
1777 if files:
1778 return [output_api.PresubmitError(
1779 'Do not use #pragma once in header files.\n'
1780 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1781 files)]
1782 return []
1783
[email protected]127f18ec2012-06-16 05:05:591784
Saagar Sanghavifceeaae2020-08-12 16:40:361785def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121786 """Checks to make sure we don't introduce use of foo ? true : false."""
1787 problems = []
1788 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1789 for f in input_api.AffectedFiles():
1790 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1791 continue
1792
1793 for line_num, line in f.ChangedContents():
1794 if pattern.match(line):
1795 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1796
1797 if not problems:
1798 return []
1799 return [output_api.PresubmitPromptWarning(
1800 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1801 '\n'.join(problems))]
1802
1803
Saagar Sanghavifceeaae2020-08-12 16:40:361804def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281805 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181806 change. Breaking - rules is an error, breaking ! rules is a
1807 warning.
1808 """
Erik Staabc734cd7a2021-11-23 03:11:521809 # Return early if no relevant file types were modified.
1810 for f in input_api.AffectedFiles():
1811 path = f.LocalPath()
1812 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path) or
1813 _IsJavaFile(input_api, path)):
1814 break
1815 else:
1816 return []
1817
mohan.reddyf21db962014-10-16 12:26:471818 import sys
[email protected]55f9f382012-07-31 11:02:181819 # We need to wait until we have an input_api object and use this
1820 # roundabout construct to import checkdeps because this file is
1821 # eval-ed and thus doesn't have __file__.
1822 original_sys_path = sys.path
1823 try:
1824 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471825 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181826 import checkdeps
[email protected]55f9f382012-07-31 11:02:181827 from rules import Rule
1828 finally:
1829 # Restore sys.path to what it was before.
1830 sys.path = original_sys_path
1831
1832 added_includes = []
rhalavati08acd232017-04-03 07:23:281833 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241834 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181835 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061836 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501837 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081838 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061839 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501840 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081841 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061842 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501843 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081844 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181845
[email protected]26385172013-05-09 23:11:351846 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181847
1848 error_descriptions = []
1849 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281850 error_subjects = set()
1851 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361852
[email protected]55f9f382012-07-31 11:02:181853 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1854 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081855 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181856 description_with_path = '%s\n %s' % (path, rule_description)
1857 if rule_type == Rule.DISALLOW:
1858 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281859 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181860 else:
1861 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281862 warning_subjects.add("#includes")
1863
1864 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1865 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081866 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281867 description_with_path = '%s\n %s' % (path, rule_description)
1868 if rule_type == Rule.DISALLOW:
1869 error_descriptions.append(description_with_path)
1870 error_subjects.add("imports")
1871 else:
1872 warning_descriptions.append(description_with_path)
1873 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181874
Jinsuk Kim5a092672017-10-24 22:42:241875 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021876 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081877 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241878 description_with_path = '%s\n %s' % (path, rule_description)
1879 if rule_type == Rule.DISALLOW:
1880 error_descriptions.append(description_with_path)
1881 error_subjects.add("imports")
1882 else:
1883 warning_descriptions.append(description_with_path)
1884 warning_subjects.add("imports")
1885
[email protected]55f9f382012-07-31 11:02:181886 results = []
1887 if error_descriptions:
1888 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281889 'You added one or more %s that violate checkdeps rules.'
1890 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181891 error_descriptions))
1892 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421893 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281894 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181895 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281896 '%s? See relevant DEPS file(s) for details and contacts.' %
1897 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181898 warning_descriptions))
1899 return results
1900
1901
Saagar Sanghavifceeaae2020-08-12 16:40:361902def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:221903 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151904 if input_api.platform == 'win32':
1905 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291906 checkperms_tool = input_api.os_path.join(
1907 input_api.PresubmitLocalPath(),
1908 'tools', 'checkperms', 'checkperms.py')
1909 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471910 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391911 with input_api.CreateTemporaryFile() as file_list:
1912 for f in input_api.AffectedFiles():
1913 # checkperms.py file/directory arguments must be relative to the
1914 # repository.
Dirk Prankee3c9c62d2021-05-18 18:35:591915 file_list.write((f.LocalPath() + '\n').encode('utf8'))
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391916 file_list.close()
1917 args += ['--file-list', file_list.name]
1918 try:
1919 input_api.subprocess.check_output(args)
1920 return []
1921 except input_api.subprocess.CalledProcessError as error:
1922 return [output_api.PresubmitError(
1923 'checkperms.py failed:',
Ari Chivukula45f58dd52021-06-18 04:23:041924 long_text=error.output.decode('utf-8', 'ignore'))]
[email protected]fbcafe5a2012-08-08 15:31:221925
1926
Saagar Sanghavifceeaae2020-08-12 16:40:361927def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:491928 """Makes sure we don't include ui/aura/window_property.h
1929 in header files.
1930 """
1931 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1932 errors = []
1933 for f in input_api.AffectedFiles():
1934 if not f.LocalPath().endswith('.h'):
1935 continue
1936 for line_num, line in f.ChangedContents():
1937 if pattern.match(line):
1938 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1939
1940 results = []
1941 if errors:
1942 results.append(output_api.PresubmitError(
1943 'Header files should not include ui/aura/window_property.h', errors))
1944 return results
1945
1946
Omer Katzcc77ea92021-04-26 10:23:281947def CheckNoInternalHeapIncludes(input_api, output_api):
1948 """Makes sure we don't include any headers from
1949 third_party/blink/renderer/platform/heap/impl or
1950 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1951 third_party/blink/renderer/platform/heap
1952 """
1953 impl_pattern = input_api.re.compile(
1954 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1955 v8_wrapper_pattern = input_api.re.compile(
1956 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"')
1957 file_filter = lambda f: not input_api.re.match(
1958 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1959 f.LocalPath())
1960 errors = []
1961
1962 for f in input_api.AffectedFiles(file_filter=file_filter):
1963 for line_num, line in f.ChangedContents():
1964 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1965 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1966
1967 results = []
1968 if errors:
1969 results.append(output_api.PresubmitError(
1970 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1971 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1972 'relevant counterparts from third_party/blink/renderer/platform/heap',
1973 errors))
1974 return results
1975
1976
[email protected]70ca77752012-11-20 03:45:031977def _CheckForVersionControlConflictsInFile(input_api, f):
1978 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1979 errors = []
1980 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161981 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231982 # First-level headers in markdown look a lot like version control
1983 # conflict markers. http://daringfireball.net/projects/markdown/basics
1984 continue
[email protected]70ca77752012-11-20 03:45:031985 if pattern.match(line):
1986 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1987 return errors
1988
1989
Saagar Sanghavifceeaae2020-08-12 16:40:361990def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:031991 """Usually this is not intentional and will cause a compile failure."""
1992 errors = []
1993 for f in input_api.AffectedFiles():
1994 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1995
1996 results = []
1997 if errors:
1998 results.append(output_api.PresubmitError(
1999 'Version control conflict markers found, please resolve.', errors))
2000 return results
2001
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202002
Saagar Sanghavifceeaae2020-08-12 16:40:362003def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162004 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2005 errors = []
2006 for f in input_api.AffectedFiles():
2007 for line_num, line in f.ChangedContents():
2008 if pattern.search(line):
2009 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2010
2011 results = []
2012 if errors:
2013 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502014 'Found Google support URL addressed by answer number. Please replace '
2015 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162016 return results
2017
[email protected]70ca77752012-11-20 03:45:032018
Saagar Sanghavifceeaae2020-08-12 16:40:362019def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442020 def FilterFile(affected_file):
2021 """Filter function for use with input_api.AffectedSourceFiles,
2022 below. This filters out everything except non-test files from
2023 top-level directories that generally speaking should not hard-code
2024 service URLs (e.g. src/android_webview/, src/content/ and others).
2025 """
2026 return input_api.FilterSourceFile(
2027 affected_file,
James Cook24a504192020-07-23 00:08:442028 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2029 files_to_skip=(_EXCLUDED_PATHS +
2030 _TEST_CODE_EXCLUDED_PATHS +
2031 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442032
reillyi38965732015-11-16 18:27:332033 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2034 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462035 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2036 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442037 problems = [] # items are (filename, line_number, line)
2038 for f in input_api.AffectedSourceFiles(FilterFile):
2039 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462040 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442041 problems.append((f.LocalPath(), line_num, line))
2042
2043 if problems:
[email protected]f7051d52013-04-02 18:31:422044 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442045 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582046 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442047 [' %s:%d: %s' % (
2048 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032049 else:
2050 return []
[email protected]06e6d0ff2012-12-11 01:36:442051
2052
Saagar Sanghavifceeaae2020-08-12 16:40:362053def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292054 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2055 def FileFilter(affected_file):
2056 """Includes directories known to be Chrome OS only."""
2057 return input_api.FilterSourceFile(
2058 affected_file,
James Cook24a504192020-07-23 00:08:442059 files_to_check=('^ash/',
2060 '^chromeos/', # Top-level src/chromeos.
2061 '/chromeos/', # Any path component.
2062 '^components/arc',
2063 '^components/exo'),
2064 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292065
2066 prefs = []
2067 priority_prefs = []
2068 for f in input_api.AffectedFiles(file_filter=FileFilter):
2069 for line_num, line in f.ChangedContents():
2070 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2071 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2072 prefs.append(' %s' % line)
2073 if input_api.re.search(
2074 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2075 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2076 priority_prefs.append(' %s' % line)
2077
2078 results = []
2079 if (prefs):
2080 results.append(output_api.PresubmitPromptWarning(
2081 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2082 'by browser sync settings. If these prefs should be controlled by OS '
2083 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2084 if (priority_prefs):
2085 results.append(output_api.PresubmitPromptWarning(
2086 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2087 'controlled by browser sync settings. If these prefs should be '
2088 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2089 'instead.\n' + '\n'.join(prefs)))
2090 return results
2091
2092
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492093# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362094def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272095 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312096 The native_client_sdk directory is excluded because it has auto-generated PNG
2097 files for documentation.
[email protected]d2530012013-01-25 16:39:272098 """
[email protected]d2530012013-01-25 16:39:272099 errors = []
James Cook24a504192020-07-23 00:08:442100 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2101 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312102 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442103 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312104 for f in input_api.AffectedFiles(include_deletes=False,
2105 file_filter=file_filter):
2106 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272107
2108 results = []
2109 if errors:
2110 results.append(output_api.PresubmitError(
2111 'The name of PNG files should not have abbreviations. \n'
2112 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2113 'Contact [email protected] if you have questions.', errors))
2114 return results
2115
2116
Daniel Cheng4dcdb6b2017-04-13 08:30:172117def _ExtractAddRulesFromParsedDeps(parsed_deps):
2118 """Extract the rules that add dependencies from a parsed DEPS file.
2119
2120 Args:
2121 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2122 add_rules = set()
2123 add_rules.update([
2124 rule[1:] for rule in parsed_deps.get('include_rules', [])
2125 if rule.startswith('+') or rule.startswith('!')
2126 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502127 for _, rules in parsed_deps.get('specific_include_rules',
Dirk Prankee3c9c62d2021-05-18 18:35:592128 {}).items():
Daniel Cheng4dcdb6b2017-04-13 08:30:172129 add_rules.update([
2130 rule[1:] for rule in rules
2131 if rule.startswith('+') or rule.startswith('!')
2132 ])
2133 return add_rules
2134
2135
2136def _ParseDeps(contents):
2137 """Simple helper for parsing DEPS files."""
2138 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172139 class _VarImpl:
2140
2141 def __init__(self, local_scope):
2142 self._local_scope = local_scope
2143
2144 def Lookup(self, var_name):
2145 """Implements the Var syntax."""
2146 try:
2147 return self._local_scope['vars'][var_name]
2148 except KeyError:
2149 raise Exception('Var is not defined: %s' % var_name)
2150
2151 local_scope = {}
2152 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172153 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592154 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172155 }
Dirk Pranke1b9e06382021-05-14 01:16:222156
Dirk Prankee3c9c62d2021-05-18 18:35:592157 exec(contents, global_scope, local_scope)
Daniel Cheng4dcdb6b2017-04-13 08:30:172158 return local_scope
2159
2160
2161def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592162 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412163 a set of DEPS entries that we should look up.
2164
2165 For a directory (rather than a specific filename) we fake a path to
2166 a specific filename by adding /DEPS. This is chosen as a file that
2167 will seldom or never be subject to per-file include_rules.
2168 """
[email protected]2b438d62013-11-14 17:54:142169 # We ignore deps entries on auto-generated directories.
2170 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082171
Daniel Cheng4dcdb6b2017-04-13 08:30:172172 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2173 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2174
2175 added_deps = new_deps.difference(old_deps)
2176
[email protected]2b438d62013-11-14 17:54:142177 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172178 for added_dep in added_deps:
2179 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2180 continue
2181 # Assume that a rule that ends in .h is a rule for a specific file.
2182 if added_dep.endswith('.h'):
2183 results.add(added_dep)
2184 else:
2185 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082186 return results
2187
2188
Saagar Sanghavifceeaae2020-08-12 16:40:362189def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552190 """When a dependency prefixed with + is added to a DEPS file, we
2191 want to make sure that the change is reviewed by an OWNER of the
2192 target file or directory, to avoid layering violations from being
2193 introduced. This check verifies that this happens.
2194 """
Joey Mou57048132021-02-26 22:17:552195 # We rely on Gerrit's code-owners to check approvals.
2196 # input_api.gerrit is always set for Chromium, but other projects
2197 # might not use Gerrit.
2198 if not input_api.gerrit:
2199 return []
Edward Lesmes44feb2332021-03-19 01:27:522200 if (input_api.change.issue and
2201 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232202 # Skip OWNERS check when Owners-Override label is approved. This is intended
2203 # for global owners, trusted bots, and on-call sheriffs. Review is still
2204 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522205 return []
Edward Lesmes6fba51082021-01-20 04:20:232206
Daniel Cheng4dcdb6b2017-04-13 08:30:172207 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242208
2209 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492210 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242211 for f in input_api.AffectedFiles(include_deletes=False,
2212 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552213 filename = input_api.os_path.basename(f.LocalPath())
2214 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172215 virtual_depended_on_files.update(_CalculateAddedDeps(
2216 input_api.os_path,
2217 '\n'.join(f.OldContents()),
2218 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552219
[email protected]e871964c2013-05-13 14:14:552220 if not virtual_depended_on_files:
2221 return []
2222
2223 if input_api.is_committing:
2224 if input_api.tbr:
2225 return [output_api.PresubmitNotifyResult(
2226 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272227 if input_api.dry_run:
2228 return [output_api.PresubmitNotifyResult(
2229 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552230 if not input_api.change.issue:
2231 return [output_api.PresubmitError(
2232 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402233 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552234 output = output_api.PresubmitError
2235 else:
2236 output = output_api.PresubmitNotifyResult
2237
tandriied3b7e12016-05-12 14:38:502238 owner_email, reviewers = (
2239 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2240 input_api,
Edward Lesmesa3846442021-02-08 20:20:032241 None,
tandriied3b7e12016-05-12 14:38:502242 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552243
2244 owner_email = owner_email or input_api.change.author_email
2245
Edward Lesmesa3846442021-02-08 20:20:032246 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2247 virtual_depended_on_files, reviewers.union([owner_email]), [])
2248 missing_files = [
2249 f for f in virtual_depended_on_files
2250 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412251
2252 # We strip the /DEPS part that was added by
2253 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2254 # directory.
2255 def StripDeps(path):
2256 start_deps = path.rfind('/DEPS')
2257 if start_deps != -1:
2258 return path[:start_deps]
2259 else:
2260 return path
2261 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552262 for path in missing_files]
2263
2264 if unapproved_dependencies:
2265 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152266 output('You need LGTM from owners of depends-on paths in DEPS that were '
2267 'modified in this CL:\n %s' %
2268 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032269 suggested_owners = input_api.owners_client.SuggestOwners(
2270 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152271 output_list.append(output(
2272 'Suggested missing target path OWNERS:\n %s' %
2273 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552274 return output_list
2275
2276 return []
2277
2278
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492279# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362280def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492281 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442282 files_to_skip = (_EXCLUDED_PATHS +
2283 _TEST_CODE_EXCLUDED_PATHS +
2284 input_api.DEFAULT_FILES_TO_SKIP +
2285 (r"^base[\\/]logging\.h$",
2286 r"^base[\\/]logging\.cc$",
2287 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2288 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2289 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2290 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2291 r"startup_browser_creator\.cc$",
2292 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2293 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2294 r"diagnostics_writer\.cc$",
2295 r"^chrome[\\/]chrome_cleaner[\\/].*",
2296 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2297 r"dll_hash_main\.cc$",
2298 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2299 r"^chromecast[\\/]",
2300 r"^cloud_print[\\/]",
2301 r"^components[\\/]browser_watcher[\\/]"
2302 r"dump_stability_report_main_win.cc$",
2303 r"^components[\\/]media_control[\\/]renderer[\\/]"
2304 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352305 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2306 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442307 r"^components[\\/]zucchini[\\/].*",
2308 # TODO(peter): Remove exception. https://crbug.com/534537
2309 r"^content[\\/]browser[\\/]notifications[\\/]"
2310 r"notification_event_dispatcher_impl\.cc$",
2311 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2312 r"gl_helper_benchmark\.cc$",
2313 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2314 r"^courgette[\\/]courgette_tool\.cc$",
2315 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
David Dorwinfa9aef42021-08-17 06:46:202316 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
James Cook24a504192020-07-23 00:08:442317 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Sergey Ulanov6db14b4d62021-05-10 07:59:482318 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
James Cook24a504192020-07-23 00:08:442319 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2320 r"^ipc[\\/]ipc_logging\.cc$",
2321 r"^native_client_sdk[\\/]",
2322 r"^remoting[\\/]base[\\/]logging\.h$",
2323 r"^remoting[\\/]host[\\/].*",
2324 r"^sandbox[\\/]linux[\\/].*",
2325 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2326 r"dump_file_system.cc$",
2327 r"^tools[\\/]",
2328 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2329 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2330 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2331 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2332 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402333 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442334 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402335
thomasanderson625d3932017-03-29 07:16:582336 log_info = set([])
2337 printf = set([])
[email protected]85218562013-11-22 07:41:402338
2339 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582340 for _, line in f.ChangedContents():
2341 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2342 log_info.add(f.LocalPath())
2343 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2344 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372345
thomasanderson625d3932017-03-29 07:16:582346 if input_api.re.search(r"\bprintf\(", line):
2347 printf.add(f.LocalPath())
2348 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2349 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402350
2351 if log_info:
2352 return [output_api.PresubmitError(
2353 'These files spam the console log with LOG(INFO):',
2354 items=log_info)]
2355 if printf:
2356 return [output_api.PresubmitError(
2357 'These files spam the console log with printf/fprintf:',
2358 items=printf)]
2359 return []
2360
2361
Saagar Sanghavifceeaae2020-08-12 16:40:362362def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162363 """These types are all expected to hold locks while in scope and
2364 so should never be anonymous (which causes them to be immediately
2365 destroyed)."""
2366 they_who_must_be_named = [
2367 'base::AutoLock',
2368 'base::AutoReset',
2369 'base::AutoUnlock',
2370 'SkAutoAlphaRestore',
2371 'SkAutoBitmapShaderInstall',
2372 'SkAutoBlitterChoose',
2373 'SkAutoBounderCommit',
2374 'SkAutoCallProc',
2375 'SkAutoCanvasRestore',
2376 'SkAutoCommentBlock',
2377 'SkAutoDescriptor',
2378 'SkAutoDisableDirectionCheck',
2379 'SkAutoDisableOvalCheck',
2380 'SkAutoFree',
2381 'SkAutoGlyphCache',
2382 'SkAutoHDC',
2383 'SkAutoLockColors',
2384 'SkAutoLockPixels',
2385 'SkAutoMalloc',
2386 'SkAutoMaskFreeImage',
2387 'SkAutoMutexAcquire',
2388 'SkAutoPathBoundsUpdate',
2389 'SkAutoPDFRelease',
2390 'SkAutoRasterClipValidate',
2391 'SkAutoRef',
2392 'SkAutoTime',
2393 'SkAutoTrace',
2394 'SkAutoUnref',
2395 ]
2396 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2397 # bad: base::AutoLock(lock.get());
2398 # not bad: base::AutoLock lock(lock.get());
2399 bad_pattern = input_api.re.compile(anonymous)
2400 # good: new base::AutoLock(lock.get())
2401 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2402 errors = []
2403
2404 for f in input_api.AffectedFiles():
2405 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2406 continue
2407 for linenum, line in f.ChangedContents():
2408 if bad_pattern.search(line) and not good_pattern.search(line):
2409 errors.append('%s:%d' % (f.LocalPath(), linenum))
2410
2411 if errors:
2412 return [output_api.PresubmitError(
2413 'These lines create anonymous variables that need to be named:',
2414 items=errors)]
2415 return []
2416
2417
Saagar Sanghavifceeaae2020-08-12 16:40:362418def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532419 # Returns whether |template_str| is of the form <T, U...> for some types T
2420 # and U. Assumes that |template_str| is already in the form <...>.
2421 def HasMoreThanOneArg(template_str):
2422 # Level of <...> nesting.
2423 nesting = 0
2424 for c in template_str:
2425 if c == '<':
2426 nesting += 1
2427 elif c == '>':
2428 nesting -= 1
2429 elif c == ',' and nesting == 1:
2430 return True
2431 return False
2432
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492433 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102434 sources = lambda affected_file: input_api.FilterSourceFile(
2435 affected_file,
James Cook24a504192020-07-23 00:08:442436 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2437 input_api.DEFAULT_FILES_TO_SKIP),
2438 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552439
2440 # Pattern to capture a single "<...>" block of template arguments. It can
2441 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2442 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2443 # latter would likely require counting that < and > match, which is not
2444 # expressible in regular languages. Should the need arise, one can introduce
2445 # limited counting (matching up to a total number of nesting depth), which
2446 # should cover all practical cases for already a low nesting limit.
2447 template_arg_pattern = (
2448 r'<[^>]*' # Opening block of <.
2449 r'>([^<]*>)?') # Closing block of >.
2450 # Prefix expressing that whatever follows is not already inside a <...>
2451 # block.
2452 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102453 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552454 not_inside_template_arg_pattern
2455 + r'\bstd::unique_ptr'
2456 + template_arg_pattern
2457 + r'\(\)')
2458
2459 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2460 template_arg_no_array_pattern = (
2461 r'<[^>]*[^]]' # Opening block of <.
2462 r'>([^(<]*[^]]>)?') # Closing block of >.
2463 # Prefix saying that what follows is the start of an expression.
2464 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2465 # Suffix saying that what follows are call parentheses with a non-empty list
2466 # of arguments.
2467 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532468 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552469 return_construct_pattern = input_api.re.compile(
2470 start_of_expr_pattern
2471 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532472 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552473 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532474 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552475 + nonempty_arg_list_pattern)
2476
Vaclav Brozek851d9602018-04-04 16:13:052477 problems_constructor = []
2478 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102479 for f in input_api.AffectedSourceFiles(sources):
2480 for line_number, line in f.ChangedContents():
2481 # Disallow:
2482 # return std::unique_ptr<T>(foo);
2483 # bar = std::unique_ptr<T>(foo);
2484 # But allow:
2485 # return std::unique_ptr<T[]>(foo);
2486 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532487 # And also allow cases when the second template argument is present. Those
2488 # cases cannot be handled by std::make_unique:
2489 # return std::unique_ptr<T, U>(foo);
2490 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052491 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532492 return_construct_result = return_construct_pattern.search(line)
2493 if return_construct_result and not HasMoreThanOneArg(
2494 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052495 problems_constructor.append(
2496 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102497 # Disallow:
2498 # std::unique_ptr<T>()
2499 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052500 problems_nullptr.append(
2501 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2502
2503 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162504 if problems_nullptr:
Daniel Cheng2dbf9c42021-10-06 21:26:112505 errors.append(output_api.PresubmitPromptWarning(
Vaclav Brozek851d9602018-04-04 16:13:052506 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162507 problems_nullptr))
2508 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052509 errors.append(output_api.PresubmitError(
Yao Li7f5a705d2021-11-23 22:30:562510 'The following files use explicit std::unique_ptr constructor. '
2511 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2512 'std::make_unique is not an option.',
Vaclav Brozekc2fecf42018-04-06 16:40:162513 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102514 return errors
2515
2516
Saagar Sanghavifceeaae2020-08-12 16:40:362517def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082518 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522519 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082520 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522521 # If actions.xml is already included in the changelist, the PRESUBMIT
2522 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082523 return []
2524
Alexei Svitkine64505a92021-03-11 22:00:542525 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2526 files_to_skip = (_EXCLUDED_PATHS +
2527 _TEST_CODE_EXCLUDED_PATHS +
2528 input_api.DEFAULT_FILES_TO_SKIP )
2529 file_filter = lambda f: input_api.FilterSourceFile(
2530 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2531
[email protected]999261d2014-03-03 20:08:082532 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522533 current_actions = None
[email protected]999261d2014-03-03 20:08:082534 for f in input_api.AffectedFiles(file_filter=file_filter):
2535 for line_num, line in f.ChangedContents():
2536 match = input_api.re.search(action_re, line)
2537 if match:
[email protected]2f92dec2014-03-07 19:21:522538 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2539 # loaded only once.
2540 if not current_actions:
2541 with open('tools/metrics/actions/actions.xml') as actions_f:
2542 current_actions = actions_f.read()
2543 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082544 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522545 action = 'name="{0}"'.format(action_name)
2546 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082547 return [output_api.PresubmitPromptWarning(
2548 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522549 'tools/metrics/actions/actions.xml. Please run '
2550 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082551 % (f.LocalPath(), line_num, action_name))]
2552 return []
2553
2554
Daniel Cheng13ca61a882017-08-25 15:11:252555def _ImportJSONCommentEater(input_api):
2556 import sys
2557 sys.path = sys.path + [input_api.os_path.join(
2558 input_api.PresubmitLocalPath(),
2559 'tools', 'json_comment_eater')]
2560 import json_comment_eater
2561 return json_comment_eater
2562
2563
[email protected]99171a92014-06-03 08:44:472564def _GetJSONParseError(input_api, filename, eat_comments=True):
2565 try:
2566 contents = input_api.ReadFile(filename)
2567 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252568 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132569 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472570
2571 input_api.json.loads(contents)
2572 except ValueError as e:
2573 return e
2574 return None
2575
2576
2577def _GetIDLParseError(input_api, filename):
2578 try:
2579 contents = input_api.ReadFile(filename)
2580 idl_schema = input_api.os_path.join(
2581 input_api.PresubmitLocalPath(),
2582 'tools', 'json_schema_compiler', 'idl_schema.py')
2583 process = input_api.subprocess.Popen(
2584 [input_api.python_executable, idl_schema],
2585 stdin=input_api.subprocess.PIPE,
2586 stdout=input_api.subprocess.PIPE,
2587 stderr=input_api.subprocess.PIPE,
2588 universal_newlines=True)
2589 (_, error) = process.communicate(input=contents)
2590 return error or None
2591 except ValueError as e:
2592 return e
2593
2594
Saagar Sanghavifceeaae2020-08-12 16:40:362595def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472596 """Check that IDL and JSON files do not contain syntax errors."""
2597 actions = {
2598 '.idl': _GetIDLParseError,
2599 '.json': _GetJSONParseError,
2600 }
[email protected]99171a92014-06-03 08:44:472601 # Most JSON files are preprocessed and support comments, but these do not.
2602 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042603 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472604 ]
2605 # Only run IDL checker on files in these directories.
2606 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042607 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2608 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472609 ]
2610
2611 def get_action(affected_file):
2612 filename = affected_file.LocalPath()
2613 return actions.get(input_api.os_path.splitext(filename)[1])
2614
[email protected]99171a92014-06-03 08:44:472615 def FilterFile(affected_file):
2616 action = get_action(affected_file)
2617 if not action:
2618 return False
2619 path = affected_file.LocalPath()
2620
Erik Staab2dd72b12020-04-16 15:03:402621 if _MatchesFile(input_api,
2622 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2623 path):
[email protected]99171a92014-06-03 08:44:472624 return False
2625
2626 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162627 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472628 return False
2629 return True
2630
2631 results = []
2632 for affected_file in input_api.AffectedFiles(
2633 file_filter=FilterFile, include_deletes=False):
2634 action = get_action(affected_file)
2635 kwargs = {}
2636 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162637 _MatchesFile(input_api, json_no_comments_patterns,
2638 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472639 kwargs['eat_comments'] = False
2640 parse_error = action(input_api,
2641 affected_file.AbsoluteLocalPath(),
2642 **kwargs)
2643 if parse_error:
2644 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2645 (affected_file.LocalPath(), parse_error)))
2646 return results
2647
2648
Saagar Sanghavifceeaae2020-08-12 16:40:362649def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492650 """Runs checkstyle on changed java files and returns errors if any exist."""
Erik Staabc734cd7a2021-11-23 03:11:522651
2652 # Return early if no java files were modified.
2653 if not any(_IsJavaFile(input_api, f.LocalPath()) for f in
2654 input_api.AffectedFiles()):
2655 return []
2656
mohan.reddyf21db962014-10-16 12:26:472657 import sys
[email protected]760deea2013-12-10 19:33:492658 original_sys_path = sys.path
2659 try:
2660 sys.path = sys.path + [input_api.os_path.join(
2661 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2662 import checkstyle
2663 finally:
2664 # Restore sys.path to what it was before.
2665 sys.path = original_sys_path
2666
2667 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092668 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442669 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492670
2671
Saagar Sanghavifceeaae2020-08-12 16:40:362672def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002673 """Checks to make sure devil is initialized correctly in python scripts."""
2674 script_common_initialize_pattern = input_api.re.compile(
2675 r'script_common\.InitializeEnvironment\(')
2676 devil_env_config_initialize = input_api.re.compile(
2677 r'devil_env\.config\.Initialize\(')
2678
2679 errors = []
2680
2681 sources = lambda affected_file: input_api.FilterSourceFile(
2682 affected_file,
James Cook24a504192020-07-23 00:08:442683 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2684 (r'^build[\\/]android[\\/]devil_chromium\.py',
2685 r'^third_party[\\/].*',)),
2686 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002687
2688 for f in input_api.AffectedSourceFiles(sources):
2689 for line_num, line in f.ChangedContents():
2690 if (script_common_initialize_pattern.search(line) or
2691 devil_env_config_initialize.search(line)):
2692 errors.append("%s:%d" % (f.LocalPath(), line_num))
2693
2694 results = []
2695
2696 if errors:
2697 results.append(output_api.PresubmitError(
2698 'Devil initialization should always be done using '
2699 'devil_chromium.Initialize() in the chromium project, to use better '
2700 'defaults for dependencies (ex. up-to-date version of adb).',
2701 errors))
2702
2703 return results
2704
2705
Sean Kau46e29bc2017-08-28 16:31:162706def _MatchesFile(input_api, patterns, path):
2707 for pattern in patterns:
2708 if input_api.re.search(pattern, path):
2709 return True
2710 return False
2711
2712
Daniel Cheng7052cdf2017-11-21 19:23:292713def _GetOwnersFilesToCheckForIpcOwners(input_api):
2714 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172715
Daniel Cheng7052cdf2017-11-21 19:23:292716 Returns:
2717 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2718 contain to cover IPC-related files with noparent reviewer rules.
2719 """
2720 # Whether or not a file affects IPC is (mostly) determined by a simple list
2721 # of filename patterns.
dchenge07de812016-06-20 19:27:172722 file_patterns = [
palmerb19a0932017-01-24 04:00:312723 # Legacy IPC:
dchenge07de812016-06-20 19:27:172724 '*_messages.cc',
2725 '*_messages*.h',
2726 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312727 # Mojo IPC:
dchenge07de812016-06-20 19:27:172728 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472729 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172730 '*_struct_traits*.*',
2731 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312732 '*.typemap',
2733 # Android native IPC:
2734 '*.aidl',
2735 # Blink uses a different file naming convention:
2736 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472737 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172738 '*StructTraits*.*',
2739 '*TypeConverter*.*',
2740 ]
2741
scottmg7a6ed5ba2016-11-04 18:22:042742 # These third_party directories do not contain IPCs, but contain files
2743 # matching the above patterns, which trigger false positives.
2744 exclude_paths = [
2745 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162746 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232747 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292748 'third_party/win_build_output/*',
Scott Violet9f82d362019-11-06 21:42:162749 # These files are just used to communicate between class loaders running
2750 # in the same process.
2751 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572752 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2753
scottmg7a6ed5ba2016-11-04 18:22:042754 ]
2755
dchenge07de812016-06-20 19:27:172756 # Dictionary mapping an OWNERS file path to Patterns.
2757 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2758 # rules ) to a PatternEntry.
2759 # PatternEntry is a dictionary with two keys:
2760 # - 'files': the files that are matched by this pattern
2761 # - 'rules': the per-file rules needed for this pattern
2762 # For example, if we expect OWNERS file to contain rules for *.mojom and
2763 # *_struct_traits*.*, Patterns might look like this:
2764 # {
2765 # '*.mojom': {
2766 # 'files': ...,
2767 # 'rules': [
2768 # 'per-file *.mojom=set noparent',
2769 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2770 # ],
2771 # },
2772 # '*_struct_traits*.*': {
2773 # 'files': ...,
2774 # 'rules': [
2775 # 'per-file *_struct_traits*.*=set noparent',
2776 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2777 # ],
2778 # },
2779 # }
2780 to_check = {}
2781
Daniel Cheng13ca61a882017-08-25 15:11:252782 def AddPatternToCheck(input_file, pattern):
2783 owners_file = input_api.os_path.join(
2784 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2785 if owners_file not in to_check:
2786 to_check[owners_file] = {}
2787 if pattern not in to_check[owners_file]:
2788 to_check[owners_file][pattern] = {
2789 'files': [],
2790 'rules': [
2791 'per-file %s=set noparent' % pattern,
2792 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2793 ]
2794 }
Vaclav Brozekd5de76a2018-03-17 07:57:502795 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252796
dchenge07de812016-06-20 19:27:172797 # Iterate through the affected files to see what we actually need to check
2798 # for. We should only nag patch authors about per-file rules if a file in that
2799 # directory would match that pattern. If a directory only contains *.mojom
2800 # files and no *_messages*.h files, we should only nag about rules for
2801 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252802 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262803 # Manifest files don't have a strong naming convention. Instead, try to find
2804 # affected .cc and .h files which look like they contain a manifest
2805 # definition.
2806 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2807 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2808 if (manifest_pattern.search(f.LocalPath()) and not
2809 test_manifest_pattern.search(f.LocalPath())):
2810 # We expect all actual service manifest files to contain at least one
2811 # qualified reference to service_manager::Manifest.
2812 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252813 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172814 for pattern in file_patterns:
2815 if input_api.fnmatch.fnmatch(
2816 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042817 skip = False
2818 for exclude in exclude_paths:
2819 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2820 skip = True
2821 break
2822 if skip:
2823 continue
Daniel Cheng13ca61a882017-08-25 15:11:252824 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172825 break
2826
Daniel Cheng7052cdf2017-11-21 19:23:292827 return to_check
2828
2829
Wez17c66962020-04-29 15:26:032830def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2831 """Adds OWNERS files to check for correct Fuchsia security owners."""
2832
2833 file_patterns = [
2834 # Component specifications.
2835 '*.cml', # Component Framework v2.
2836 '*.cmx', # Component Framework v1.
2837
2838 # Fuchsia IDL protocol specifications.
2839 '*.fidl',
2840 ]
2841
Joshua Peraza1ca6d392020-12-08 00:14:092842 # Don't check for owners files for changes in these directories.
2843 exclude_paths = [
2844 'third_party/crashpad/*',
2845 ]
2846
Wez17c66962020-04-29 15:26:032847 def AddPatternToCheck(input_file, pattern):
2848 owners_file = input_api.os_path.join(
2849 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2850 if owners_file not in to_check:
2851 to_check[owners_file] = {}
2852 if pattern not in to_check[owners_file]:
2853 to_check[owners_file][pattern] = {
2854 'files': [],
2855 'rules': [
2856 'per-file %s=set noparent' % pattern,
2857 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2858 ]
2859 }
2860 to_check[owners_file][pattern]['files'].append(input_file)
2861
2862 # Iterate through the affected files to see what we actually need to check
2863 # for. We should only nag patch authors about per-file rules if a file in that
2864 # directory would match that pattern.
2865 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092866 skip = False
2867 for exclude in exclude_paths:
2868 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2869 skip = True
2870 if skip:
2871 continue
2872
Wez17c66962020-04-29 15:26:032873 for pattern in file_patterns:
2874 if input_api.fnmatch.fnmatch(
2875 input_api.os_path.basename(f.LocalPath()), pattern):
2876 AddPatternToCheck(f, pattern)
2877 break
2878
2879 return to_check
2880
2881
Saagar Sanghavifceeaae2020-08-12 16:40:362882def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292883 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2884 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032885 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292886
2887 if to_check:
2888 # If there are any OWNERS files to check, there are IPC-related changes in
2889 # this CL. Auto-CC the review list.
2890 output_api.AppendCC('[email protected]')
2891
2892 # Go through the OWNERS files to check, filtering out rules that are already
2893 # present in that OWNERS file.
Dirk Prankee3c9c62d2021-05-18 18:35:592894 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172895 try:
Dirk Prankee3c9c62d2021-05-18 18:35:592896 with open(owners_file) as f:
dchenge07de812016-06-20 19:27:172897 lines = set(f.read().splitlines())
Jeffrey Youngf3a5c8c42021-05-14 21:56:102898 for entry in patterns.values():
dchenge07de812016-06-20 19:27:172899 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2900 ]
2901 except IOError:
2902 # No OWNERS file, so all the rules are definitely missing.
2903 continue
2904
2905 # All the remaining lines weren't found in OWNERS files, so emit an error.
2906 errors = []
Dirk Prankee3c9c62d2021-05-18 18:35:592907 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172908 missing_lines = []
2909 files = []
Dirk Prankee3c9c62d2021-05-18 18:35:592910 for _, entry in patterns.items():
dchenge07de812016-06-20 19:27:172911 missing_lines.extend(entry['rules'])
2912 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2913 if missing_lines:
2914 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052915 'Because of the presence of files:\n%s\n\n'
2916 '%s needs the following %d lines added:\n\n%s' %
2917 ('\n'.join(files), owners_file, len(missing_lines),
2918 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172919
2920 results = []
2921 if errors:
vabrf5ce3bf92016-07-11 14:52:412922 if input_api.is_committing:
2923 output = output_api.PresubmitError
2924 else:
2925 output = output_api.PresubmitPromptWarning
2926 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592927 'Found OWNERS files that need to be updated for IPC security ' +
2928 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172929 long_text='\n\n'.join(errors)))
2930
2931 return results
2932
2933
Robert Sesek2c905332020-05-06 23:17:132934def _GetFilesUsingSecurityCriticalFunctions(input_api):
2935 """Checks affected files for changes to security-critical calls. This
2936 function checks the full change diff, to catch both additions/changes
2937 and removals.
2938
2939 Returns a dict keyed by file name, and the value is a set of detected
2940 functions.
2941 """
2942 # Map of function pretty name (displayed in an error) to the pattern to
2943 # match it with.
2944 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:372945 'content::GetServiceSandboxType<>()':
2946 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:132947 }
2948 _PATTERNS_TO_CHECK = {
2949 k: input_api.re.compile(v)
2950 for k, v in _PATTERNS_TO_CHECK.items()
2951 }
2952
2953 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2954 files_to_functions = {}
2955 for f in input_api.AffectedFiles():
2956 diff = f.GenerateScmDiff()
2957 for line in diff.split('\n'):
2958 # Not using just RightHandSideLines() because removing a
2959 # call to a security-critical function can be just as important
2960 # as adding or changing the arguments.
2961 if line.startswith('-') or (line.startswith('+') and
2962 not line.startswith('++')):
2963 for name, pattern in _PATTERNS_TO_CHECK.items():
2964 if pattern.search(line):
2965 path = f.LocalPath()
2966 if not path in files_to_functions:
2967 files_to_functions[path] = set()
2968 files_to_functions[path].add(name)
2969 return files_to_functions
2970
2971
Saagar Sanghavifceeaae2020-08-12 16:40:362972def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:132973 """Checks that changes involving security-critical functions are reviewed
2974 by the security team.
2975 """
2976 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:122977 if not len(files_to_functions):
2978 return []
Robert Sesek2c905332020-05-06 23:17:132979
Edward Lesmes1e9fade2021-02-08 20:31:122980 owner_email, reviewers = (
2981 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2982 input_api,
2983 None,
2984 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:132985
Edward Lesmes1e9fade2021-02-08 20:31:122986 # Load the OWNERS file for security changes.
2987 owners_file = 'ipc/SECURITY_OWNERS'
2988 security_owners = input_api.owners_client.ListOwners(owners_file)
2989 has_security_owner = any([owner in reviewers for owner in security_owners])
2990 if has_security_owner:
2991 return []
Robert Sesek2c905332020-05-06 23:17:132992
Edward Lesmes1e9fade2021-02-08 20:31:122993 msg = 'The following files change calls to security-sensive functions\n' \
2994 'that need to be reviewed by {}.\n'.format(owners_file)
2995 for path, names in files_to_functions.items():
2996 msg += ' {}\n'.format(path)
2997 for name in names:
2998 msg += ' {}\n'.format(name)
2999 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133000
Edward Lesmes1e9fade2021-02-08 20:31:123001 if input_api.is_committing:
3002 output = output_api.PresubmitError
3003 else:
3004 output = output_api.PresubmitNotifyResult
3005 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133006
3007
Saagar Sanghavifceeaae2020-08-12 16:40:363008def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263009 """Checks that set noparent is only used together with an OWNERS file in
3010 //build/OWNERS.setnoparent (see also
3011 //docs/code_reviews.md#owners-files-details)
3012 """
Erik Staabc734cd7a2021-11-23 03:11:523013 # Return early if no OWNERS files were modified.
3014 if not any(f.LocalPath().endswith('OWNERS') for f in
3015 input_api.AffectedFiles(include_deletes=False)):
3016 return []
3017
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263018 errors = []
3019
3020 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3021 allowed_owners_files = set()
3022 with open(allowed_owners_files_file, 'r') as f:
3023 for line in f:
3024 line = line.strip()
3025 if not line or line.startswith('#'):
3026 continue
3027 allowed_owners_files.add(line)
3028
3029 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3030
3031 for f in input_api.AffectedFiles(include_deletes=False):
3032 if not f.LocalPath().endswith('OWNERS'):
3033 continue
3034
3035 found_owners_files = set()
3036 found_set_noparent_lines = dict()
3037
3038 # Parse the OWNERS file.
3039 for lineno, line in enumerate(f.NewContents(), 1):
3040 line = line.strip()
3041 if line.startswith('set noparent'):
3042 found_set_noparent_lines[''] = lineno
3043 if line.startswith('file://'):
3044 if line in allowed_owners_files:
3045 found_owners_files.add('')
3046 if line.startswith('per-file'):
3047 match = per_file_pattern.match(line)
3048 if match:
3049 glob = match.group(1).strip()
3050 directive = match.group(2).strip()
3051 if directive == 'set noparent':
3052 found_set_noparent_lines[glob] = lineno
3053 if directive.startswith('file://'):
3054 if directive in allowed_owners_files:
3055 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153056
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263057 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403058 # listed in build/OWNERS.setnoparent. An exception is made for top level
3059 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143060 if (f.LocalPath().count('/') != 1 and
3061 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403062 for set_noparent_line in found_set_noparent_lines:
3063 if set_noparent_line in found_owners_files:
3064 continue
3065 errors.append(' %s:%d' % (f.LocalPath(),
3066 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263067
3068 results = []
3069 if errors:
3070 if input_api.is_committing:
3071 output = output_api.PresubmitError
3072 else:
3073 output = output_api.PresubmitPromptWarning
3074 results.append(output(
3075 'Found the following "set noparent" restrictions in OWNERS files that '
3076 'do not include owners from build/OWNERS.setnoparent:',
3077 long_text='\n\n'.join(errors)))
3078 return results
3079
3080
Saagar Sanghavifceeaae2020-08-12 16:40:363081def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313082 """Checks that added or removed lines in non third party affected
3083 header files do not lead to new useless class or struct forward
3084 declaration.
jbriance9e12f162016-11-25 07:57:503085 """
3086 results = []
3087 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3088 input_api.re.MULTILINE)
3089 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3090 input_api.re.MULTILINE)
3091 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313092 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193093 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493094 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313095 continue
3096
jbriance9e12f162016-11-25 07:57:503097 if not f.LocalPath().endswith('.h'):
3098 continue
3099
3100 contents = input_api.ReadFile(f)
3101 fwd_decls = input_api.re.findall(class_pattern, contents)
3102 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3103
3104 useless_fwd_decls = []
3105 for decl in fwd_decls:
3106 count = sum(1 for _ in input_api.re.finditer(
3107 r'\b%s\b' % input_api.re.escape(decl), contents))
3108 if count == 1:
3109 useless_fwd_decls.append(decl)
3110
3111 if not useless_fwd_decls:
3112 continue
3113
3114 for line in f.GenerateScmDiff().splitlines():
3115 if (line.startswith('-') and not line.startswith('--') or
3116 line.startswith('+') and not line.startswith('++')):
3117 for decl in useless_fwd_decls:
3118 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3119 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243120 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503121 (f.LocalPath(), decl)))
3122 useless_fwd_decls.remove(decl)
3123
3124 return results
3125
Jinsong Fan91ebbbd2019-04-16 14:57:173126def _CheckAndroidDebuggableBuild(input_api, output_api):
3127 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3128 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3129 this is a debuggable build of Android.
3130 """
3131 build_type_check_pattern = input_api.re.compile(
3132 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3133
3134 errors = []
3135
3136 sources = lambda affected_file: input_api.FilterSourceFile(
3137 affected_file,
James Cook24a504192020-07-23 00:08:443138 files_to_skip=(_EXCLUDED_PATHS +
3139 _TEST_CODE_EXCLUDED_PATHS +
3140 input_api.DEFAULT_FILES_TO_SKIP +
3141 (r"^android_webview[\\/]support_library[\\/]"
3142 "boundary_interfaces[\\/]",
3143 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3144 r'^third_party[\\/].*',
3145 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3146 r"webview[\\/]chromium[\\/]License.*",)),
3147 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173148
3149 for f in input_api.AffectedSourceFiles(sources):
3150 for line_num, line in f.ChangedContents():
3151 if build_type_check_pattern.search(line):
3152 errors.append("%s:%d" % (f.LocalPath(), line_num))
3153
3154 results = []
3155
3156 if errors:
3157 results.append(output_api.PresubmitPromptWarning(
3158 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3159 ' Please use BuildInfo.isDebugAndroid() instead.',
3160 errors))
3161
3162 return results
jbriance9e12f162016-11-25 07:57:503163
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493164# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293165def _CheckAndroidToastUsage(input_api, output_api):
3166 """Checks that code uses org.chromium.ui.widget.Toast instead of
3167 android.widget.Toast (Chromium Toast doesn't force hardware
3168 acceleration on low-end devices, saving memory).
3169 """
3170 toast_import_pattern = input_api.re.compile(
3171 r'^import android\.widget\.Toast;$')
3172
3173 errors = []
3174
3175 sources = lambda affected_file: input_api.FilterSourceFile(
3176 affected_file,
James Cook24a504192020-07-23 00:08:443177 files_to_skip=(_EXCLUDED_PATHS +
3178 _TEST_CODE_EXCLUDED_PATHS +
3179 input_api.DEFAULT_FILES_TO_SKIP +
3180 (r'^chromecast[\\/].*',
3181 r'^remoting[\\/].*')),
3182 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293183
3184 for f in input_api.AffectedSourceFiles(sources):
3185 for line_num, line in f.ChangedContents():
3186 if toast_import_pattern.search(line):
3187 errors.append("%s:%d" % (f.LocalPath(), line_num))
3188
3189 results = []
3190
3191 if errors:
3192 results.append(output_api.PresubmitError(
3193 'android.widget.Toast usage is detected. Android toasts use hardware'
3194 ' acceleration, and can be\ncostly on low-end devices. Please use'
3195 ' org.chromium.ui.widget.Toast instead.\n'
3196 'Contact [email protected] if you have any questions.',
3197 errors))
3198
3199 return results
3200
3201
dgnaa68d5e2015-06-10 10:08:223202def _CheckAndroidCrLogUsage(input_api, output_api):
3203 """Checks that new logs using org.chromium.base.Log:
3204 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513205 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223206 """
pkotwicza1dd0b002016-05-16 14:41:043207
torne89540622017-03-24 19:41:303208 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043209 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303210 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043211 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303212 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043213 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3214 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093215 # The customtabs_benchmark is a small app that does not depend on Chromium
3216 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043217 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043218 ]
3219
dgnaa68d5e2015-06-10 10:08:223220 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123221 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3222 class_in_base_pattern = input_api.re.compile(
3223 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3224 has_some_log_import_pattern = input_api.re.compile(
3225 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223226 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553227 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223228 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463229 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553230 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223231
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463232 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443233 sources = lambda x: input_api.FilterSourceFile(x,
3234 files_to_check=[r'.*\.java$'],
3235 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123236
dgnaa68d5e2015-06-10 10:08:223237 tag_decl_errors = []
3238 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123239 tag_errors = []
dgn38736db2015-09-18 19:20:513240 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123241 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223242
3243 for f in input_api.AffectedSourceFiles(sources):
3244 file_content = input_api.ReadFile(f)
3245 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223246 # Per line checks
dgn87d9fb62015-06-12 09:15:123247 if (cr_log_import_pattern.search(file_content) or
3248 (class_in_base_pattern.search(file_content) and
3249 not has_some_log_import_pattern.search(file_content))):
3250 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223251 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553252 if rough_log_decl_pattern.search(line):
3253 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223254
3255 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123256 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223257 if match:
3258 has_modified_logs = True
3259
3260 # Make sure it uses "TAG"
3261 if not match.group('tag') == 'TAG':
3262 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123263 else:
3264 # Report non cr Log function calls in changed lines
3265 for line_num, line in f.ChangedContents():
3266 if log_call_pattern.search(line):
3267 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223268
3269 # Per file checks
3270 if has_modified_logs:
3271 # Make sure the tag is using the "cr" prefix and is not too long
3272 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513273 tag_name = match.group('name') if match else None
3274 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223275 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513276 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223277 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513278 elif '.' in tag_name:
3279 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223280
3281 results = []
3282 if tag_decl_errors:
3283 results.append(output_api.PresubmitPromptWarning(
3284 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513285 '"private static final String TAG = "<package tag>".\n'
3286 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223287 tag_decl_errors))
3288
3289 if tag_length_errors:
3290 results.append(output_api.PresubmitError(
3291 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513292 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223293 tag_length_errors))
3294
3295 if tag_errors:
3296 results.append(output_api.PresubmitPromptWarning(
3297 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3298 tag_errors))
3299
dgn87d9fb62015-06-12 09:15:123300 if util_log_errors:
dgn4401aa52015-04-29 16:26:173301 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123302 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3303 util_log_errors))
3304
dgn38736db2015-09-18 19:20:513305 if tag_with_dot_errors:
3306 results.append(output_api.PresubmitPromptWarning(
3307 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3308 tag_with_dot_errors))
3309
dgn4401aa52015-04-29 16:26:173310 return results
3311
3312
Yoland Yanb92fa522017-08-28 17:37:063313def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3314 """Checks that junit.framework.* is no longer used."""
3315 deprecated_junit_framework_pattern = input_api.re.compile(
3316 r'^import junit\.framework\..*;',
3317 input_api.re.MULTILINE)
3318 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443319 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063320 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133321 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063322 for line_num, line in f.ChangedContents():
3323 if deprecated_junit_framework_pattern.search(line):
3324 errors.append("%s:%d" % (f.LocalPath(), line_num))
3325
3326 results = []
3327 if errors:
3328 results.append(output_api.PresubmitError(
3329 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3330 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3331 ' if you have any question.', errors))
3332 return results
3333
3334
3335def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3336 """Checks that if new Java test classes have inheritance.
3337 Either the new test class is JUnit3 test or it is a JUnit4 test class
3338 with a base class, either case is undesirable.
3339 """
3340 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3341
3342 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443343 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063344 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133345 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063346 if not f.OldContents():
3347 class_declaration_start_flag = False
3348 for line_num, line in f.ChangedContents():
3349 if class_declaration_pattern.search(line):
3350 class_declaration_start_flag = True
3351 if class_declaration_start_flag and ' extends ' in line:
3352 errors.append('%s:%d' % (f.LocalPath(), line_num))
3353 if '{' in line:
3354 class_declaration_start_flag = False
3355
3356 results = []
3357 if errors:
3358 results.append(output_api.PresubmitPromptWarning(
3359 'The newly created files include Test classes that inherits from base'
3360 ' class. Please do not use inheritance in JUnit4 tests or add new'
3361 ' JUnit3 tests. Contact [email protected] if you have any'
3362 ' questions.', errors))
3363 return results
3364
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203365
yolandyan45001472016-12-21 21:12:423366def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3367 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3368 deprecated_annotation_import_pattern = input_api.re.compile(
3369 r'^import android\.test\.suitebuilder\.annotation\..*;',
3370 input_api.re.MULTILINE)
3371 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443372 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423373 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133374 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423375 for line_num, line in f.ChangedContents():
3376 if deprecated_annotation_import_pattern.search(line):
3377 errors.append("%s:%d" % (f.LocalPath(), line_num))
3378
3379 results = []
3380 if errors:
3381 results.append(output_api.PresubmitError(
3382 'Annotations in android.test.suitebuilder.annotation have been'
3383 ' deprecated since API level 24. Please use android.support.test.filters'
3384 ' from //third_party/android_support_test_runner:runner_java instead.'
3385 ' Contact [email protected] if you have any questions.', errors))
3386 return results
3387
3388
agrieve7b6479d82015-10-07 14:24:223389def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3390 """Checks if MDPI assets are placed in a correct directory."""
3391 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3392 ('/res/drawable/' in f.LocalPath() or
3393 '/res/drawable-ldrtl/' in f.LocalPath()))
3394 errors = []
3395 for f in input_api.AffectedFiles(include_deletes=False,
3396 file_filter=file_filter):
3397 errors.append(' %s' % f.LocalPath())
3398
3399 results = []
3400 if errors:
3401 results.append(output_api.PresubmitError(
3402 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3403 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3404 '/res/drawable-ldrtl/.\n'
3405 'Contact [email protected] if you have questions.', errors))
3406 return results
3407
3408
Nate Fischer535972b2017-09-16 01:06:183409def _CheckAndroidWebkitImports(input_api, output_api):
3410 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353411 android.webview.ValueCallback except in the WebView glue layer
3412 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183413 """
3414 valuecallback_import_pattern = input_api.re.compile(
3415 r'^import android\.webkit\.ValueCallback;$')
3416
3417 errors = []
3418
3419 sources = lambda affected_file: input_api.FilterSourceFile(
3420 affected_file,
James Cook24a504192020-07-23 00:08:443421 files_to_skip=(_EXCLUDED_PATHS +
3422 _TEST_CODE_EXCLUDED_PATHS +
3423 input_api.DEFAULT_FILES_TO_SKIP +
3424 (r'^android_webview[\\/]glue[\\/].*',
3425 r'^weblayer[\\/].*',)),
3426 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183427
3428 for f in input_api.AffectedSourceFiles(sources):
3429 for line_num, line in f.ChangedContents():
3430 if valuecallback_import_pattern.search(line):
3431 errors.append("%s:%d" % (f.LocalPath(), line_num))
3432
3433 results = []
3434
3435 if errors:
3436 results.append(output_api.PresubmitError(
3437 'android.webkit.ValueCallback usage is detected outside of the glue'
3438 ' layer. To stay compatible with the support library, android.webkit.*'
3439 ' classes should only be used inside the glue layer and'
3440 ' org.chromium.base.Callback should be used instead.',
3441 errors))
3442
3443 return results
3444
3445
Becky Zhou7c69b50992018-12-10 19:37:573446def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3447 """Checks Android XML styles """
Erik Staabc734cd7a2021-11-23 03:11:523448
3449 # Return early if no relevant files were modified.
3450 if not any(_IsXmlOrGrdFile(input_api, f.LocalPath()) for f in
3451 input_api.AffectedFiles(include_deletes=False)):
3452 return []
3453
Becky Zhou7c69b50992018-12-10 19:37:573454 import sys
3455 original_sys_path = sys.path
3456 try:
3457 sys.path = sys.path + [input_api.os_path.join(
3458 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3459 import checkxmlstyle
3460 finally:
3461 # Restore sys.path to what it was before.
3462 sys.path = original_sys_path
3463
3464 if is_check_on_upload:
3465 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3466 else:
3467 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3468
3469
agrievef32bcc72016-04-04 14:57:403470class PydepsChecker(object):
3471 def __init__(self, input_api, pydeps_files):
3472 self._file_cache = {}
3473 self._input_api = input_api
3474 self._pydeps_files = pydeps_files
3475
3476 def _LoadFile(self, path):
3477 """Returns the list of paths within a .pydeps file relative to //."""
3478 if path not in self._file_cache:
Mohamed Heikal112874d2021-11-15 14:42:203479 with open(path, encoding='utf-8') as f:
agrievef32bcc72016-04-04 14:57:403480 self._file_cache[path] = f.read()
3481 return self._file_cache[path]
3482
3483 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3484 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393485 pydeps_data = self._LoadFile(pydeps_path)
3486 uses_gn_paths = '--gn-paths' in pydeps_data
3487 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3488 if uses_gn_paths:
3489 # Paths look like: //foo/bar/baz
3490 return (e[2:] for e in entries)
3491 else:
3492 # Paths look like: path/relative/to/file.pydeps
3493 os_path = self._input_api.os_path
3494 pydeps_dir = os_path.dirname(pydeps_path)
3495 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403496
3497 def _CreateFilesToPydepsMap(self):
3498 """Returns a map of local_path -> list_of_pydeps."""
3499 ret = {}
3500 for pydep_local_path in self._pydeps_files:
3501 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3502 ret.setdefault(path, []).append(pydep_local_path)
3503 return ret
3504
3505 def ComputeAffectedPydeps(self):
3506 """Returns an iterable of .pydeps files that might need regenerating."""
3507 affected_pydeps = set()
3508 file_to_pydeps_map = None
3509 for f in self._input_api.AffectedFiles(include_deletes=True):
3510 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463511 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3512 # subrepositories. We can't figure out which files change, so re-check
3513 # all files.
3514 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383515 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3516 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403517 return self._pydeps_files
3518 elif local_path.endswith('.pydeps'):
3519 if local_path in self._pydeps_files:
3520 affected_pydeps.add(local_path)
3521 elif local_path.endswith('.py'):
3522 if file_to_pydeps_map is None:
3523 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3524 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3525 return affected_pydeps
3526
3527 def DetermineIfStale(self, pydeps_path):
3528 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413529 import difflib
John Budorick47ca3fe2018-02-10 00:53:103530 import os
3531
agrievef32bcc72016-04-04 14:57:403532 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033533 if old_pydeps_data:
3534 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393535 if '--output' not in cmd:
3536 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033537 old_contents = old_pydeps_data[2:]
3538 else:
3539 # A default cmd that should work in most cases (as long as pydeps filename
3540 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3541 # file is empty/new.
3542 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3543 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3544 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103545 env = dict(os.environ)
3546 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403547 new_pydeps_data = self._input_api.subprocess.check_output(
Mohamed Heikal112874d2021-11-15 14:42:203548 cmd + ' --output ""', shell=True, env=env, encoding='utf-8')
phajdan.jr0d9878552016-11-04 10:49:413549 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033550 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413551 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403552
3553
Tibor Goldschwendt360793f72019-06-25 18:23:493554def _ParseGclientArgs():
3555 args = {}
3556 with open('build/config/gclient_args.gni', 'r') as f:
3557 for line in f:
3558 line = line.strip()
3559 if not line or line.startswith('#'):
3560 continue
3561 attribute, value = line.split('=')
3562 args[attribute.strip()] = value.strip()
3563 return args
3564
3565
Saagar Sanghavifceeaae2020-08-12 16:40:363566def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403567 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403568 # This check is for Python dependency lists (.pydeps files), and involves
3569 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
Erik Staabc734cd7a2021-11-23 03:11:523570 # doesn't work on Windows and Mac, so skip it on other platforms and skip if
3571 # no pydeps files are affected.
Mohamed Heikal112874d2021-11-15 14:42:203572 if not input_api.platform.startswith('linux'):
agrievebb9c5b472016-04-22 15:13:003573 return []
Erik Staabc734cd7a2021-11-23 03:11:523574 if not any(f.LocalPath().endswith('.pydeps') for f in input_api.AffectedFiles(
3575 include_deletes=True)):
3576 return []
3577
Tibor Goldschwendt360793f72019-06-25 18:23:493578 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403579 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403580 results = []
3581 # First, check for new / deleted .pydeps.
3582 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033583 # Check whether we are running the presubmit check for a file in src.
3584 # f.LocalPath is relative to repo (src, or internal repo).
3585 # os_path.exists is relative to src repo.
3586 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3587 # to src and we can conclude that the pydeps is in src.
3588 if input_api.os_path.exists(f.LocalPath()):
3589 if f.LocalPath().endswith('.pydeps'):
3590 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3591 results.append(output_api.PresubmitError(
3592 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3593 'remove %s' % f.LocalPath()))
3594 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3595 results.append(output_api.PresubmitError(
3596 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3597 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403598
3599 if results:
3600 return results
3601
Mohamed Heikal7cd4d8312020-06-16 16:49:403602 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3603 affected_pydeps = set(checker.ComputeAffectedPydeps())
3604 affected_android_pydeps = affected_pydeps.intersection(
3605 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3606 if affected_android_pydeps and not is_android:
3607 results.append(output_api.PresubmitPromptOrNotify(
3608 'You have changed python files that may affect pydeps for android\n'
3609 'specific scripts. However, the relevant presumbit check cannot be\n'
3610 'run because you are not using an Android checkout. To validate that\n'
3611 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3612 'use the android-internal-presubmit optional trybot.\n'
3613 'Possibly stale pydeps files:\n{}'.format(
3614 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403615
Mohamed Heikal7cd4d8312020-06-16 16:49:403616 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3617 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403618 try:
phajdan.jr0d9878552016-11-04 10:49:413619 result = checker.DetermineIfStale(pydep_path)
3620 if result:
3621 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403622 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413623 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3624 'To regenerate, run:\n\n %s' %
3625 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403626 except input_api.subprocess.CalledProcessError as error:
3627 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3628 long_text=error.output)]
3629
3630 return results
3631
3632
Saagar Sanghavifceeaae2020-08-12 16:40:363633def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433634 """Checks to make sure no header files have |Singleton<|."""
3635 def FileFilter(affected_file):
3636 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443637 files_to_skip = (_EXCLUDED_PATHS +
3638 input_api.DEFAULT_FILES_TO_SKIP +
3639 (r"^base[\\/]memory[\\/]singleton\.h$",
3640 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3641 r"quic_singleton_impl\.h$"))
3642 return input_api.FilterSourceFile(affected_file,
3643 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433644
sergeyu34d21222015-09-16 00:11:443645 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433646 files = []
3647 for f in input_api.AffectedSourceFiles(FileFilter):
3648 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3649 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3650 contents = input_api.ReadFile(f)
3651 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243652 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433653 pattern.search(line)):
3654 files.append(f)
3655 break
3656
3657 if files:
yolandyandaabc6d2016-04-18 18:29:393658 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443659 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433660 'Please move them to an appropriate source file so that the ' +
3661 'template gets instantiated in a single compilation unit.',
3662 files) ]
3663 return []
3664
3665
[email protected]fd20b902014-05-09 02:14:533666_DEPRECATED_CSS = [
3667 # Values
3668 ( "-webkit-box", "flex" ),
3669 ( "-webkit-inline-box", "inline-flex" ),
3670 ( "-webkit-flex", "flex" ),
3671 ( "-webkit-inline-flex", "inline-flex" ),
3672 ( "-webkit-min-content", "min-content" ),
3673 ( "-webkit-max-content", "max-content" ),
3674
3675 # Properties
3676 ( "-webkit-background-clip", "background-clip" ),
3677 ( "-webkit-background-origin", "background-origin" ),
3678 ( "-webkit-background-size", "background-size" ),
3679 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443680 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533681
3682 # Functions
3683 ( "-webkit-gradient", "gradient" ),
3684 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3685 ( "-webkit-linear-gradient", "linear-gradient" ),
3686 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3687 ( "-webkit-radial-gradient", "radial-gradient" ),
3688 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3689]
3690
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203691
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493692# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363693def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533694 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253695 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343696 documentation and iOS CSS for dom distiller
3697 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253698 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533699 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493700 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443701 files_to_skip = (_EXCLUDED_PATHS +
3702 _TEST_CODE_EXCLUDED_PATHS +
3703 input_api.DEFAULT_FILES_TO_SKIP +
3704 (r"^chrome/common/extensions/docs",
3705 r"^chrome/docs",
3706 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3707 r"^components/neterror/resources/neterror.css",
3708 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))
Becky Zhou7c69b50992018-12-10 19:37:574168 return results
4169
Saagar Sanghavifceeaae2020-08-12 16:40:364170def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574171 """Groups commit checks that target android code."""
4172 results = []
4173 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224174 return results
4175
Chris Hall59f8d0c72020-05-01 07:31:194176# TODO(chrishall): could we additionally match on any path owned by
4177# ui/accessibility/OWNERS ?
4178_ACCESSIBILITY_PATHS = (
4179 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4180 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4181 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4182 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4183 r"^content[\\/]browser[\\/]accessibility[\\/]",
4184 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4185 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4186 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4187 r"^ui[\\/]accessibility[\\/]",
4188 r"^ui[\\/]views[\\/]accessibility[\\/]",
4189)
4190
Saagar Sanghavifceeaae2020-08-12 16:40:364191def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194192 """Checks that commits to accessibility code contain an AX-Relnotes field in
4193 their commit message."""
4194 def FileFilter(affected_file):
4195 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444196 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194197
4198 # Only consider changes affecting accessibility paths.
4199 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4200 return []
4201
Akihiro Ota08108e542020-05-20 15:30:534202 # AX-Relnotes can appear in either the description or the footer.
4203 # When searching the description, require 'AX-Relnotes:' to appear at the
4204 # beginning of a line.
4205 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4206 description_has_relnotes = any(ax_regex.match(line)
4207 for line in input_api.change.DescriptionText().lower().splitlines())
4208
4209 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4210 'AX-Relnotes', [])
4211 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194212 return []
4213
4214 # TODO(chrishall): link to Relnotes documentation in message.
4215 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4216 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4217 "user-facing changes"
4218 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4219 "user-facing effects"
4220 "\n if this is confusing or annoying then please contact members "
4221 "of ui/accessibility/OWNERS.")
4222
4223 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224224
seanmccullough4a9356252021-04-08 19:54:094225# string pattern, sequence of strings to show when pattern matches,
4226# error flag. True if match is a presubmit error, otherwise it's a warning.
4227_NON_INCLUSIVE_TERMS = (
4228 (
4229 # Note that \b pattern in python re is pretty particular. In this
4230 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4231 # ...' will not. This may require some tweaking to catch these cases
4232 # without triggering a lot of false positives. Leaving it naive and
4233 # less matchy for now.
4234 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4235 (
4236 'Please don\'t use blacklist, whitelist, ' # nocheck
4237 'or slave in your', # nocheck
4238 'code and make every effort to use other terms. Using "// nocheck"',
4239 '"# nocheck" or "<!-- nocheck -->"',
4240 'at the end of the offending line will bypass this PRESUBMIT error',
4241 'but avoid using this whenever possible. Reach out to',
4242 '[email protected] if you have questions'),
4243 True),)
4244
Saagar Sanghavifceeaae2020-08-12 16:40:364245def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394246 """Checks common to both upload and commit."""
4247 results = []
4248 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384249 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544250 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084251
4252 author = input_api.change.author_email
4253 if author and author not in _KNOWN_ROBOTS:
4254 results.extend(
4255 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4256
[email protected]9f919cc2013-07-31 03:04:044257 results.extend(
4258 input_api.canned_checks.CheckChangeHasNoTabs(
4259 input_api,
4260 output_api,
4261 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434262 results.extend(input_api.RunTests(
4263 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244264
Edward Lesmesce51df52020-08-04 22:10:174265 dirmd_bin = input_api.os_path.join(
4266 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4267 results.extend(input_api.RunTests(
4268 input_api.canned_checks.CheckDirMetadataFormat(
4269 input_api, output_api, dirmd_bin)))
4270 results.extend(
4271 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4272 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554273 results.extend(
4274 input_api.canned_checks.CheckNoNewMetadataInOwners(
4275 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094276 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4277 input_api, output_api,
4278 excluded_directories_relative_path = [
4279 'infra',
4280 'inclusive_language_presubmit_exempt_dirs.txt'
4281 ],
4282 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174283
Vaclav Brozekcdc7defb2018-03-20 09:54:354284 for f in input_api.AffectedFiles():
4285 path, name = input_api.os_path.split(f.LocalPath())
4286 if name == 'PRESUBMIT.py':
4287 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004288 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4289 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074290 # The PRESUBMIT.py file (and the directory containing it) might
4291 # have been affected by being moved or removed, so only try to
4292 # run the tests if they still exist.
Dirk Prankee3c9c62d2021-05-18 18:35:594293 use_python3 = False
4294 with open(f.LocalPath()) as fp:
Daniel Chengab582892021-09-30 20:53:194295 use_python3 = any(line.startswith('USE_PYTHON3 = True')
4296 for line in fp.readlines())
Dirk Prankee3c9c62d2021-05-18 18:35:594297
Dirk Pranke38557312018-04-18 00:53:074298 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4299 input_api, output_api, full_path,
Dirk Prankee3c9c62d2021-05-18 18:35:594300 files_to_check=[r'^PRESUBMIT_test\.py$'],
4301 run_on_python2=not use_python3,
Jonathan Njeunjee45f2bd2021-10-12 16:21:584302 run_on_python3=use_python3,
4303 skip_shebang_check=True))
[email protected]22c9bd72011-03-27 16:47:394304 return results
[email protected]1f7b4172010-01-28 01:17:344305
[email protected]b337cb5b2011-01-23 21:24:054306
Saagar Sanghavifceeaae2020-08-12 16:40:364307def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494308 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4309 if f.LocalPath().endswith(('.orig', '.rej'))]
danakj30f05352021-11-03 18:58:414310 # Cargo.toml.orig files are part of third-party crates downloaded from
4311 # crates.io and should be included.
4312 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
[email protected]b8079ae4a2012-12-05 19:56:494313 if problems:
4314 return [output_api.PresubmitError(
4315 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034316 else:
4317 return []
[email protected]b8079ae4a2012-12-05 19:56:494318
4319
Saagar Sanghavifceeaae2020-08-12 16:40:364320def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214321 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4322 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4323 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074324 include_re = input_api.re.compile(
4325 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4326 extension_re = input_api.re.compile(r'\.[a-z]+$')
4327 errors = []
Bruce Dawsonaae5e652021-06-24 15:05:394328 for f in input_api.AffectedFiles(include_deletes=False):
Kent Tamura5a8755d2017-06-29 23:37:074329 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4330 continue
4331 found_line_number = None
4332 found_macro = None
Bruce Dawsonaae5e652021-06-24 15:05:394333 all_lines = input_api.ReadFile(f, 'r').splitlines()
4334 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074335 match = macro_re.search(line)
4336 if match:
4337 found_line_number = line_num
4338 found_macro = match.group(2)
4339 break
4340 if not found_line_number:
4341 continue
4342
Bruce Dawsonaae5e652021-06-24 15:05:394343 found_include_line = -1
4344 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074345 if include_re.search(line):
Bruce Dawsonaae5e652021-06-24 15:05:394346 found_include_line = line_num
Kent Tamura5a8755d2017-06-29 23:37:074347 break
Bruce Dawsonaae5e652021-06-24 15:05:394348 if found_include_line >= 0 and found_include_line < found_line_number:
Kent Tamura5a8755d2017-06-29 23:37:074349 continue
4350
4351 if not f.LocalPath().endswith('.h'):
4352 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4353 try:
4354 content = input_api.ReadFile(primary_header_path, 'r')
4355 if include_re.search(content):
4356 continue
4357 except IOError:
4358 pass
Bruce Dawsonaae5e652021-06-24 15:05:394359 errors.append('%s:%d %s macro is used without first including build/'
Kent Tamura5a8755d2017-06-29 23:37:074360 'build_config.h.'
4361 % (f.LocalPath(), found_line_number, found_macro))
4362 if errors:
4363 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4364 return []
4365
4366
Lei Zhang1c12a22f2021-05-12 11:28:454367def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
4368 stl_include_re = input_api.re.compile(
Lei Zhang0643e342021-05-12 18:02:124369 r'^#include\s+<('
Lei Zhang1c12a22f2021-05-12 11:28:454370 r'algorithm|'
4371 r'array|'
4372 r'limits|'
4373 r'list|'
4374 r'map|'
4375 r'memory|'
4376 r'queue|'
4377 r'set|'
4378 r'string|'
4379 r'unordered_map|'
4380 r'unordered_set|'
4381 r'utility|'
Lei Zhang0643e342021-05-12 18:02:124382 r'vector)>')
Lei Zhang1c12a22f2021-05-12 11:28:454383 std_namespace_re = input_api.re.compile(r'std::')
4384 errors = []
4385 for f in input_api.AffectedFiles():
4386 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4387 continue
4388
4389 uses_std_namespace = False
4390 has_stl_include = False
4391 for line in f.NewContents():
4392 if has_stl_include and uses_std_namespace:
4393 break
4394
4395 if not has_stl_include and stl_include_re.search(line):
4396 has_stl_include = True
4397 continue
4398
4399 if not uses_std_namespace and std_namespace_re.search(line):
4400 uses_std_namespace = True
4401 continue
4402
4403 if has_stl_include and not uses_std_namespace:
4404 errors.append('%s: Includes STL header(s) but does not reference std::'
4405 % f.LocalPath())
4406 if errors:
4407 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4408 return []
4409
4410
[email protected]b00342e7f2013-03-26 16:21:544411def _DidYouMeanOSMacro(bad_macro):
4412 try:
4413 return {'A': 'OS_ANDROID',
4414 'B': 'OS_BSD',
4415 'C': 'OS_CHROMEOS',
4416 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444417 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544418 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444419 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544420 'N': 'OS_NACL',
4421 'O': 'OS_OPENBSD',
4422 'P': 'OS_POSIX',
4423 'S': 'OS_SOLARIS',
4424 'W': 'OS_WIN'}[bad_macro[3].upper()]
4425 except KeyError:
4426 return ''
4427
4428
4429def _CheckForInvalidOSMacrosInFile(input_api, f):
4430 """Check for sensible looking, totally invalid OS macros."""
4431 preprocessor_statement = input_api.re.compile(r'^\s*#')
4432 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4433 results = []
4434 for lnum, line in f.ChangedContents():
4435 if preprocessor_statement.search(line):
4436 for match in os_macro.finditer(line):
4437 if not match.group(1) in _VALID_OS_MACROS:
4438 good = _DidYouMeanOSMacro(match.group(1))
4439 did_you_mean = ' (did you mean %s?)' % good if good else ''
4440 results.append(' %s:%d %s%s' % (f.LocalPath(),
4441 lnum,
4442 match.group(1),
4443 did_you_mean))
4444 return results
4445
4446
Saagar Sanghavifceeaae2020-08-12 16:40:364447def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544448 """Check all affected files for invalid OS macros."""
4449 bad_macros = []
tzik3f295992018-12-04 20:32:234450 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474451 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544452 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4453
4454 if not bad_macros:
4455 return []
4456
4457 return [output_api.PresubmitError(
4458 'Possibly invalid OS macro[s] found. Please fix your code\n'
4459 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4460
lliabraa35bab3932014-10-01 12:16:444461
4462def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4463 """Check all affected files for invalid "if defined" macros."""
4464 ALWAYS_DEFINED_MACROS = (
4465 "TARGET_CPU_PPC",
4466 "TARGET_CPU_PPC64",
4467 "TARGET_CPU_68K",
4468 "TARGET_CPU_X86",
4469 "TARGET_CPU_ARM",
4470 "TARGET_CPU_MIPS",
4471 "TARGET_CPU_SPARC",
4472 "TARGET_CPU_ALPHA",
4473 "TARGET_IPHONE_SIMULATOR",
4474 "TARGET_OS_EMBEDDED",
4475 "TARGET_OS_IPHONE",
4476 "TARGET_OS_MAC",
4477 "TARGET_OS_UNIX",
4478 "TARGET_OS_WIN32",
4479 )
4480 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4481 results = []
4482 for lnum, line in f.ChangedContents():
4483 for match in ifdef_macro.finditer(line):
4484 if match.group(1) in ALWAYS_DEFINED_MACROS:
4485 always_defined = ' %s is always defined. ' % match.group(1)
4486 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4487 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4488 lnum,
4489 always_defined,
4490 did_you_mean))
4491 return results
4492
4493
Saagar Sanghavifceeaae2020-08-12 16:40:364494def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444495 """Check all affected files for invalid "if defined" macros."""
4496 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054497 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444498 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054499 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214500 continue
lliabraa35bab3932014-10-01 12:16:444501 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4502 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4503
4504 if not bad_macros:
4505 return []
4506
4507 return [output_api.PresubmitError(
4508 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4509 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4510 bad_macros)]
4511
4512
Saagar Sanghavifceeaae2020-08-12 16:40:364513def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044514 """Check for same IPC rules described in
4515 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4516 """
4517 base_pattern = r'IPC_ENUM_TRAITS\('
4518 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4519 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4520
4521 problems = []
4522 for f in input_api.AffectedSourceFiles(None):
4523 local_path = f.LocalPath()
4524 if not local_path.endswith('.h'):
4525 continue
4526 for line_number, line in f.ChangedContents():
4527 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4528 problems.append(
4529 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4530
4531 if problems:
4532 return [output_api.PresubmitPromptWarning(
4533 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4534 else:
4535 return []
4536
[email protected]b00342e7f2013-03-26 16:21:544537
Saagar Sanghavifceeaae2020-08-12 16:40:364538def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054539 """Check to make sure no files being submitted have long paths.
4540 This causes issues on Windows.
4541 """
4542 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194543 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054544 local_path = f.LocalPath()
4545 # Windows has a path limit of 260 characters. Limit path length to 200 so
4546 # that we have some extra for the prefix on dev machines and the bots.
4547 if len(local_path) > 200:
4548 problems.append(local_path)
4549
4550 if problems:
4551 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4552 else:
4553 return []
4554
4555
Saagar Sanghavifceeaae2020-08-12 16:40:364556def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144557 """Check that header files have proper guards against multiple inclusion.
4558 If a file should not have such guards (and it probably should) then it
4559 should include the string "no-include-guard-because-multiply-included".
4560 """
Daniel Bratell6a75baef62018-06-04 10:04:454561 def is_chromium_header_file(f):
4562 # We only check header files under the control of the Chromium
4563 # project. That is, those outside third_party apart from
4564 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324565 # We also exclude *_message_generator.h headers as they use
4566 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454567 file_with_path = input_api.os_path.normpath(f.LocalPath())
4568 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324569 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454570 (not file_with_path.startswith('third_party') or
4571 file_with_path.startswith(
4572 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144573
4574 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344575 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144576
4577 errors = []
4578
Daniel Bratell6a75baef62018-06-04 10:04:454579 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144580 guard_name = None
4581 guard_line_number = None
4582 seen_guard_end = False
4583
4584 file_with_path = input_api.os_path.normpath(f.LocalPath())
4585 base_file_name = input_api.os_path.splitext(
4586 input_api.os_path.basename(file_with_path))[0]
4587 upper_base_file_name = base_file_name.upper()
4588
4589 expected_guard = replace_special_with_underscore(
4590 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144591
4592 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574593 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4594 # are too many (1000+) files with slight deviations from the
4595 # coding style. The most important part is that the include guard
4596 # is there, and that it's unique, not the name so this check is
4597 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144598 #
4599 # As code becomes more uniform, this could be made stricter.
4600
4601 guard_name_pattern_list = [
4602 # Anything with the right suffix (maybe with an extra _).
4603 r'\w+_H__?',
4604
Daniel Bratell39b5b062018-05-16 18:09:574605 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144606 r'\w+_h',
4607
4608 # Anything including the uppercase name of the file.
4609 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4610 upper_base_file_name)) + r'\w*',
4611 ]
4612 guard_name_pattern = '|'.join(guard_name_pattern_list)
4613 guard_pattern = input_api.re.compile(
4614 r'#ifndef\s+(' + guard_name_pattern + ')')
4615
4616 for line_number, line in enumerate(f.NewContents()):
4617 if 'no-include-guard-because-multiply-included' in line:
4618 guard_name = 'DUMMY' # To not trigger check outside the loop.
4619 break
4620
4621 if guard_name is None:
4622 match = guard_pattern.match(line)
4623 if match:
4624 guard_name = match.group(1)
4625 guard_line_number = line_number
4626
Daniel Bratell39b5b062018-05-16 18:09:574627 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454628 # don't match the chromium style guide, but new files should
4629 # get it right.
4630 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574631 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144632 errors.append(output_api.PresubmitPromptWarning(
4633 'Header using the wrong include guard name %s' % guard_name,
4634 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574635 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144636 else:
4637 # The line after #ifndef should have a #define of the same name.
4638 if line_number == guard_line_number + 1:
4639 expected_line = '#define %s' % guard_name
4640 if line != expected_line:
4641 errors.append(output_api.PresubmitPromptWarning(
4642 'Missing "%s" for include guard' % expected_line,
4643 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4644 'Expected: %r\nGot: %r' % (expected_line, line)))
4645
4646 if not seen_guard_end and line == '#endif // %s' % guard_name:
4647 seen_guard_end = True
4648 elif seen_guard_end:
4649 if line.strip() != '':
4650 errors.append(output_api.PresubmitPromptWarning(
4651 'Include guard %s not covering the whole file' % (
4652 guard_name), [f.LocalPath()]))
4653 break # Nothing else to check and enough to warn once.
4654
4655 if guard_name is None:
4656 errors.append(output_api.PresubmitPromptWarning(
4657 'Missing include guard %s' % expected_guard,
4658 [f.LocalPath()],
4659 'Missing include guard in %s\n'
4660 'Recommended name: %s\n'
4661 'This check can be disabled by having the string\n'
4662 'no-include-guard-because-multiply-included in the header.' %
4663 (f.LocalPath(), expected_guard)))
4664
4665 return errors
4666
4667
Saagar Sanghavifceeaae2020-08-12 16:40:364668def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234669 """Check source code and known ascii text files for Windows style line
4670 endings.
4671 """
Evan Stade6cfc964c12021-05-18 20:21:164672 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234673
4674 file_inclusion_pattern = (
4675 known_text_files,
Bruce Dawson6141d4a2021-06-08 15:56:114676 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4677 r'.+%s' % _HEADER_EXTENSIONS
mostynbb639aca52015-01-07 20:31:234678 )
4679
mostynbb639aca52015-01-07 20:31:234680 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534681 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444682 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534683 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504684 include_file = False
Bruce Dawsonb2cfdfe2021-06-10 19:01:204685 for line in input_api.ReadFile(f, 'r').splitlines(True):
mostynbb639aca52015-01-07 20:31:234686 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504687 include_file = True
4688 if include_file:
4689 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234690
4691 if problems:
4692 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4693 'these files to contain Windows style line endings?\n' +
4694 '\n'.join(problems))]
4695
4696 return []
4697
Evan Stade6cfc964c12021-05-18 20:21:164698def CheckIconFilesForLicenseHeaders(input_api, output_api):
4699 """Check that .icon files (which are fragments of C++) have license headers.
4700 """
4701
4702 icon_files = (r'.*\.icon$',)
4703
4704 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4705 return input_api.canned_checks.CheckLicense(
4706 input_api, output_api, source_file_filter=icons)
4707
Jose Magana2b456f22021-03-09 23:26:404708def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4709 """Check source code for use of Chrome App technologies being
4710 deprecated.
4711 """
4712
4713 def _CheckForDeprecatedTech(input_api, output_api,
4714 detection_list, files_to_check = None, files_to_skip = None):
4715
4716 if (files_to_check or files_to_skip):
4717 source_file_filter = lambda f: input_api.FilterSourceFile(
4718 f, files_to_check=files_to_check,
4719 files_to_skip=files_to_skip)
4720 else:
4721 source_file_filter = None
4722
4723 problems = []
4724
4725 for f in input_api.AffectedSourceFiles(source_file_filter):
4726 if f.Action() == 'D':
4727 continue
4728 for _, line in f.ChangedContents():
4729 if any( detect in line for detect in detection_list ):
4730 problems.append(f.LocalPath())
4731
4732 return problems
4733
4734 # to avoid this presubmit script triggering warnings
4735 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4736
4737 problems =[]
4738
4739 # NMF: any files with extensions .nmf or NMF
4740 _NMF_FILES = r'\.(nmf|NMF)$'
4741 problems += _CheckForDeprecatedTech(input_api, output_api,
4742 detection_list = [''], # any change to the file will trigger warning
4743 files_to_check = [ r'.+%s' % _NMF_FILES ])
4744
4745 # MANIFEST: any manifest.json that in its diff includes "app":
4746 _MANIFEST_FILES = r'(manifest\.json)$'
4747 problems += _CheckForDeprecatedTech(input_api, output_api,
4748 detection_list = ['"app":'],
4749 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4750
4751 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4752 problems += _CheckForDeprecatedTech(input_api, output_api,
4753 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4754 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4755
4756 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4757 problems += _CheckForDeprecatedTech(input_api, output_api,
4758 detection_list = ['#include "ppapi','#include <ppapi'],
4759 files_to_check = (
4760 r'.+%s' % _HEADER_EXTENSIONS,
4761 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4762 files_to_skip = [r"^ppapi[\\/]"] )
4763
Jose Magana2b456f22021-03-09 23:26:404764 if problems:
4765 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4766 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4767 ' PNaCl, PPAPI). See this blog post for more details:\n'
4768 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4769 'and this documentation for options to replace these technologies:\n'
4770 'https://developer.chrome.com/docs/apps/migration/\n'+
4771 '\n'.join(problems))]
4772
4773 return []
4774
mostynbb639aca52015-01-07 20:31:234775
Saagar Sanghavifceeaae2020-08-12 16:40:364776def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134777 """Checks that all source files use SYSLOG properly."""
4778 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364779 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564780 for line_number, line in f.ChangedContents():
4781 if 'SYSLOG' in line:
4782 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4783
pastarmovj89f7ee12016-09-20 14:58:134784 if syslog_files:
4785 return [output_api.PresubmitPromptWarning(
4786 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4787 ' calls.\nFiles to check:\n', items=syslog_files)]
4788 return []
4789
4790
[email protected]1f7b4172010-01-28 01:17:344791def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364792 if input_api.version < [2, 0, 0]:
4793 return [output_api.PresubmitError("Your depot_tools is out of date. "
4794 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4795 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344796 results = []
scottmg39b29952014-12-08 18:31:284797 results.extend(
jam93a6ee792017-02-08 23:59:224798 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544799 return results
[email protected]ca8d1982009-02-19 16:33:124800
4801
4802def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364803 if input_api.version < [2, 0, 0]:
4804 return [output_api.PresubmitError("Your depot_tools is out of date. "
4805 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4806 "but your version is %d.%d.%d" % tuple(input_api.version))]
4807
[email protected]fe5f57c52009-06-05 14:25:544808 results = []
[email protected]fe5f57c52009-06-05 14:25:544809 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274810 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344811 input_api,
4812 output_api,
[email protected]2fdd1f362013-01-16 03:56:034813 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274814
jam93a6ee792017-02-08 23:59:224815 results.extend(
4816 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544817 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4818 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384819 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4820 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414821 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4822 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544823 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144824
4825
Saagar Sanghavifceeaae2020-08-12 16:40:364826def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264827 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024828 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4829 # footer is set to true.
4830 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264831 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024832 footer.lower()
4833 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264834 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024835
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144836 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264837 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144838 import sys
4839 from io import StringIO
4840
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144841 new_or_added_paths = set(f.LocalPath()
4842 for f in input_api.AffectedFiles()
4843 if (f.Action() == 'A' or f.Action() == 'M'))
4844 removed_paths = set(f.LocalPath()
4845 for f in input_api.AffectedFiles(include_deletes=True)
4846 if f.Action() == 'D')
4847
Andrew Grieve0e8790c2020-09-03 17:27:324848 affected_grds = [
4849 f for f in input_api.AffectedFiles()
4850 if f.LocalPath().endswith(('.grd', '.grdp'))
4851 ]
4852 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164853 if not affected_grds:
4854 return []
4855
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144856 affected_png_paths = [f.AbsoluteLocalPath()
4857 for f in input_api.AffectedFiles()
4858 if (f.LocalPath().endswith('.png'))]
4859
4860 # Check for screenshots. Developers can upload screenshots using
4861 # tools/translation/upload_screenshots.py which finds and uploads
4862 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4863 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4864 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4865 #
4866 # The logic here is as follows:
4867 #
4868 # - If the CL has a .png file under the screenshots directory for a grd
4869 # file, warn the developer. Actual images should never be checked into the
4870 # Chrome repo.
4871 #
4872 # - If the CL contains modified or new messages in grd files and doesn't
4873 # contain the corresponding .sha1 files, warn the developer to add images
4874 # and upload them via tools/translation/upload_screenshots.py.
4875 #
4876 # - If the CL contains modified or new messages in grd files and the
4877 # corresponding .sha1 files, everything looks good.
4878 #
4879 # - If the CL contains removed messages in grd files but the corresponding
4880 # .sha1 files aren't removed, warn the developer to remove them.
4881 unnecessary_screenshots = []
4882 missing_sha1 = []
4883 unnecessary_sha1_files = []
4884
Rainhard Findlingfc31844c52020-05-15 09:58:264885 # This checks verifies that the ICU syntax of messages this CL touched is
4886 # valid, and reports any found syntax errors.
4887 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4888 # without developers being aware of them. Later on, such ICU syntax errors
4889 # break message extraction for translation, hence would block Chromium
4890 # translations until they are fixed.
4891 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144892
4893 def _CheckScreenshotAdded(screenshots_dir, message_id):
4894 sha1_path = input_api.os_path.join(
4895 screenshots_dir, message_id + '.png.sha1')
4896 if sha1_path not in new_or_added_paths:
4897 missing_sha1.append(sha1_path)
4898
4899
4900 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4901 sha1_path = input_api.os_path.join(
4902 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034903 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144904 unnecessary_sha1_files.append(sha1_path)
4905
Rainhard Findlingfc31844c52020-05-15 09:58:264906
4907 def _ValidateIcuSyntax(text, level, signatures):
Daniel Chengab582892021-09-30 20:53:194908 """Validates ICU syntax of a text string.
Rainhard Findlingfc31844c52020-05-15 09:58:264909
4910 Check if text looks similar to ICU and checks for ICU syntax correctness
4911 in this case. Reports various issues with ICU syntax and values of
4912 variants. Supports checking of nested messages. Accumulate information of
4913 each ICU messages found in the text for further checking.
4914
4915 Args:
4916 text: a string to check.
4917 level: a number of current nesting level.
4918 signatures: an accumulator, a list of tuple of (level, variable,
4919 kind, variants).
4920
4921 Returns:
4922 None if a string is not ICU or no issue detected.
4923 A tuple of (message, start index, end index) if an issue detected.
4924 """
Daniel Chengab582892021-09-30 20:53:194925 valid_types = {
4926 'plural': (frozenset(
4927 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4928 frozenset(['=1', 'other'])),
4929 'selectordinal': (frozenset(
4930 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4931 frozenset(['one', 'other'])),
4932 'select': (frozenset(), frozenset(['other'])),
4933 }
Rainhard Findlingfc31844c52020-05-15 09:58:264934
Daniel Chengab582892021-09-30 20:53:194935 # Check if the message looks like an attempt to use ICU
4936 # plural. If yes - check if its syntax strictly matches ICU format.
4937 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4938 if not like:
4939 signatures.append((level, None, None, None))
4940 return
Rainhard Findlingfc31844c52020-05-15 09:58:264941
Daniel Chengab582892021-09-30 20:53:194942 # Check for valid prefix and suffix
4943 m = re.match(
4944 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4945 r'(plural|selectordinal|select),\s*'
4946 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4947 if not m:
4948 return (('This message looks like an ICU plural, '
4949 'but does not follow ICU syntax.'), like.start(), like.end())
4950 starting, variable, kind, variant_pairs = m.groups()
4951 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4952 if depth:
4953 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4954 len(text))
4955 first = text[0]
4956 ending = text[last_pos:]
4957 if not starting:
4958 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4959 last_pos)
4960 if not ending or '}' not in ending:
4961 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4962 last_pos)
4963 elif first != '{':
4964 return (
4965 ('Invalid ICU format. Extra characters at the start of a complex '
4966 'message (go/icu-message-migration): "%s"') %
4967 starting, 0, len(starting))
4968 elif ending != '}':
4969 return (('Invalid ICU format. Extra characters at the end of a complex '
4970 'message (go/icu-message-migration): "%s"')
4971 % ending, last_pos - 1, len(text) - 1)
4972 if kind not in valid_types:
4973 return (('Unknown ICU message type %s. '
4974 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4975 known, required = valid_types[kind]
4976 defined_variants = set()
4977 for variant, variant_range, value, value_range in variants:
4978 start, end = variant_range
4979 if variant in defined_variants:
4980 return ('Variant "%s" is defined more than once' % variant,
4981 start, end)
4982 elif known and variant not in known:
4983 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4984 start, end)
4985 defined_variants.add(variant)
4986 # Check for nested structure
4987 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4988 if res:
4989 return (res[0], res[1] + value_range[0] + 1,
4990 res[2] + value_range[0] + 1)
4991 missing = required - defined_variants
4992 if missing:
4993 return ('Required variants missing: %s' % ', '.join(missing), 0,
4994 len(text))
4995 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:264996
4997
4998 def _ParseIcuVariants(text, offset=0):
4999 """Parse variants part of ICU complex message.
5000
5001 Builds a tuple of variant names and values, as well as
5002 their offsets in the input string.
5003
5004 Args:
5005 text: a string to parse
5006 offset: additional offset to add to positions in the text to get correct
5007 position in the complete ICU string.
5008
5009 Returns:
5010 List of tuples, each tuple consist of four fields: variant name,
5011 variant name span (tuple of two integers), variant value, value
5012 span (tuple of two integers).
5013 """
5014 depth, start, end = 0, -1, -1
5015 variants = []
5016 key = None
5017 for idx, char in enumerate(text):
5018 if char == '{':
5019 if not depth:
5020 start = idx
5021 chunk = text[end + 1:start]
5022 key = chunk.strip()
5023 pos = offset + end + 1 + chunk.find(key)
5024 span = (pos, pos + len(key))
5025 depth += 1
5026 elif char == '}':
5027 if not depth:
5028 return variants, depth, offset + idx
5029 depth -= 1
5030 if not depth:
5031 end = idx
5032 variants.append((key, span, text[start:end + 1], (offset + start,
5033 offset + end + 1)))
5034 return variants, depth, offset + end + 1
5035
meacer8c0d3832019-12-26 21:46:165036 try:
5037 old_sys_path = sys.path
5038 sys.path = sys.path + [input_api.os_path.join(
5039 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5040 from helper import grd_helper
5041 finally:
5042 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145043
5044 for f in affected_grds:
5045 file_path = f.LocalPath()
5046 old_id_to_msg_map = {}
5047 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385048 # Note that this code doesn't check if the file has been deleted. This is
5049 # OK because it only uses the old and new file contents and doesn't load
5050 # the file via its path.
5051 # It's also possible that a file's content refers to a renamed or deleted
5052 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5053 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5054 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145055 if file_path.endswith('.grdp'):
5056 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585057 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595058 '\n'.join(f.OldContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145059 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585060 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595061 '\n'.join(f.NewContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145062 else:
meacerff8a9b62019-12-10 19:43:585063 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145064 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585065 old_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595066 StringIO('\n'.join(f.OldContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145067 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585068 new_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595069 StringIO('\n'.join(f.NewContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145070
Rainhard Findlingd8d04372020-08-13 13:30:095071 grd_name, ext = input_api.os_path.splitext(
5072 input_api.os_path.basename(file_path))
5073 screenshots_dir = input_api.os_path.join(
5074 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5075
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145076 # Compute added, removed and modified message IDs.
5077 old_ids = set(old_id_to_msg_map)
5078 new_ids = set(new_id_to_msg_map)
5079 added_ids = new_ids - old_ids
5080 removed_ids = old_ids - new_ids
5081 modified_ids = set([])
5082 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355083 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095084 != new_id_to_msg_map[key].ContentsAsXml('', True)):
Daniel Chengab582892021-09-30 20:53:195085 # The message content itself changed. Require an updated screenshot.
5086 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355087 elif old_id_to_msg_map[key].attrs['meaning'] != \
5088 new_id_to_msg_map[key].attrs['meaning']:
5089 # The message meaning changed. Ensure there is a screenshot for it.
5090 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5091 if sha1_path not in new_or_added_paths and not \
5092 input_api.os_path.exists(sha1_path):
5093 # There is neither a previous screenshot nor is a new one added now.
5094 # Require a screenshot.
5095 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145096
Rainhard Findlingfc31844c52020-05-15 09:58:265097 if run_screenshot_check:
5098 # Check the screenshot directory for .png files. Warn if there is any.
5099 for png_path in affected_png_paths:
5100 if png_path.startswith(screenshots_dir):
5101 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145102
Rainhard Findlingfc31844c52020-05-15 09:58:265103 for added_id in added_ids:
5104 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145105
Rainhard Findlingfc31844c52020-05-15 09:58:265106 for modified_id in modified_ids:
5107 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145108
Rainhard Findlingfc31844c52020-05-15 09:58:265109 for removed_id in removed_ids:
5110 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5111
5112 # Check new and changed strings for ICU syntax errors.
5113 for key in added_ids.union(modified_ids):
5114 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5115 err = _ValidateIcuSyntax(msg, 0, [])
5116 if err is not None:
5117 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145118
5119 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265120 if run_screenshot_check:
5121 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005122 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265123 'Do not include actual screenshots in the changelist. Run '
5124 'tools/translate/upload_screenshots.py to upload them instead:',
5125 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145126
Rainhard Findlingfc31844c52020-05-15 09:58:265127 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005128 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265129 'You are adding or modifying UI strings.\n'
5130 'To ensure the best translations, take screenshots of the relevant UI '
5131 '(https://g.co/chrome/translation) and add these files to your '
5132 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145133
Rainhard Findlingfc31844c52020-05-15 09:58:265134 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005135 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265136 'You removed strings associated with these files. Remove:',
5137 sorted(unnecessary_sha1_files)))
5138 else:
5139 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5140 'screenshots check.'))
5141
5142 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075143 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265144 'ICU syntax errors were found in the following strings (problems or '
5145 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145146
5147 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125148
5149
Saagar Sanghavifceeaae2020-08-12 16:40:365150def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125151 repo_root=None,
5152 translation_expectations_path=None,
5153 grd_files=None):
5154 import sys
5155 affected_grds = [f for f in input_api.AffectedFiles()
5156 if (f.LocalPath().endswith('.grd') or
5157 f.LocalPath().endswith('.grdp'))]
5158 if not affected_grds:
5159 return []
5160
5161 try:
5162 old_sys_path = sys.path
5163 sys.path = sys.path + [
5164 input_api.os_path.join(
5165 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5166 from helper import git_helper
5167 from helper import translation_helper
5168 finally:
5169 sys.path = old_sys_path
5170
5171 # Check that translation expectations can be parsed and we can get a list of
5172 # translatable grd files. |repo_root| and |translation_expectations_path| are
5173 # only passed by tests.
5174 if not repo_root:
5175 repo_root = input_api.PresubmitLocalPath()
5176 if not translation_expectations_path:
5177 translation_expectations_path = input_api.os_path.join(
5178 repo_root, 'tools', 'gritsettings',
5179 'translation_expectations.pyl')
5180 if not grd_files:
5181 grd_files = git_helper.list_grds_in_repository(repo_root)
5182
dpapad8e21b472020-10-23 17:15:035183 # Ignore bogus grd files used only for testing
5184 # ui/webui/resoucres/tools/generate_grd.py.
5185 ignore_path = input_api.os_path.join(
5186 'ui', 'webui', 'resources', 'tools', 'tests')
Dirk Prankee3c9c62d2021-05-18 18:35:595187 grd_files = [p for p in grd_files if ignore_path not in p]
dpapad8e21b472020-10-23 17:15:035188
Mustafa Emre Acer51f2f742020-03-09 19:41:125189 try:
5190 translation_helper.get_translatable_grds(repo_root, grd_files,
5191 translation_expectations_path)
5192 except Exception as e:
5193 return [output_api.PresubmitNotifyResult(
5194 'Failed to get a list of translatable grd files. This happens when:\n'
5195 ' - One of the modified grd or grdp files cannot be parsed or\n'
5196 ' - %s is not updated.\n'
5197 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5198 return []
Ken Rockotc31f4832020-05-29 18:58:515199
5200
Saagar Sanghavifceeaae2020-08-12 16:40:365201def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515202 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095203 changed_mojoms = input_api.AffectedFiles(
5204 include_deletes=True,
5205 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525206
5207 if not changed_mojoms:
5208 return []
5209
Ken Rockotc31f4832020-05-29 18:58:515210 delta = []
5211 for mojom in changed_mojoms:
5212 old_contents = ''.join(mojom.OldContents()) or None
5213 new_contents = ''.join(mojom.NewContents()) or None
5214 delta.append({
5215 'filename': mojom.LocalPath(),
5216 'old': '\n'.join(mojom.OldContents()) or None,
5217 'new': '\n'.join(mojom.NewContents()) or None,
5218 })
5219
5220 process = input_api.subprocess.Popen(
5221 [input_api.python_executable,
5222 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5223 'public', 'tools', 'mojom',
5224 'check_stable_mojom_compatibility.py'),
5225 '--src-root', input_api.PresubmitLocalPath()],
5226 stdin=input_api.subprocess.PIPE,
5227 stdout=input_api.subprocess.PIPE,
5228 stderr=input_api.subprocess.PIPE,
5229 universal_newlines=True)
5230 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5231 if process.returncode:
5232 return [output_api.PresubmitError(
5233 'One or more [Stable] mojom definitions appears to have been changed '
5234 'in a way that is not backward-compatible.',
5235 long_text=error)]
5236 return []
Dominic Battre645d42342020-12-04 16:14:105237
5238def CheckDeprecationOfPreferences(input_api, output_api):
5239 """Removing a preference should come with a deprecation."""
5240
5241 def FilterFile(affected_file):
5242 """Accept only .cc files and the like."""
5243 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5244 files_to_skip = (_EXCLUDED_PATHS +
5245 _TEST_CODE_EXCLUDED_PATHS +
5246 input_api.DEFAULT_FILES_TO_SKIP)
5247 return input_api.FilterSourceFile(
5248 affected_file,
5249 files_to_check=file_inclusion_pattern,
5250 files_to_skip=files_to_skip)
5251
5252 def ModifiedLines(affected_file):
5253 """Returns a list of tuples (line number, line text) of added and removed
5254 lines.
5255
5256 Deleted lines share the same line number as the previous line.
5257
5258 This relies on the scm diff output describing each changed code section
5259 with a line of the form
5260
5261 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5262 """
5263 line_num = 0
5264 modified_lines = []
5265 for line in affected_file.GenerateScmDiff().splitlines():
5266 # Extract <new line num> of the patch fragment (see format above).
5267 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5268 if m:
5269 line_num = int(m.groups(1)[0])
5270 continue
5271 if ((line.startswith('+') and not line.startswith('++')) or
5272 (line.startswith('-') and not line.startswith('--'))):
5273 modified_lines.append((line_num, line))
5274
5275 if not line.startswith('-'):
5276 line_num += 1
5277 return modified_lines
5278
5279 def FindLineWith(lines, needle):
5280 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5281
5282 If 0 or >1 lines contain `needle`, -1 is returned.
5283 """
5284 matching_line_numbers = [
5285 # + 1 for 1-based counting of line numbers.
5286 i + 1 for i, line
5287 in enumerate(lines)
5288 if needle in line]
5289 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5290
5291 def ModifiedPrefMigration(affected_file):
5292 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5293 # Determine first and last lines of MigrateObsolete.*Pref functions.
5294 new_contents = affected_file.NewContents();
5295 range_1 = (
5296 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5297 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5298 range_2 = (
5299 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5300 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5301 if (-1 in range_1 + range_2):
5302 raise Exception(
5303 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5304
5305 # Check whether any of the modified lines are part of the
5306 # MigrateObsolete.*Pref functions.
5307 for line_nr, line in ModifiedLines(affected_file):
5308 if (range_1[0] <= line_nr <= range_1[1] or
5309 range_2[0] <= line_nr <= range_2[1]):
5310 return True
5311 return False
5312
5313 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5314 browser_prefs_file_pattern = input_api.re.compile(
5315 r'chrome/browser/prefs/browser_prefs.cc')
5316
5317 changes = input_api.AffectedFiles(include_deletes=True,
5318 file_filter=FilterFile)
5319 potential_problems = []
5320 for f in changes:
5321 for line in f.GenerateScmDiff().splitlines():
5322 # Check deleted lines for pref registrations.
5323 if (line.startswith('-') and not line.startswith('--') and
5324 register_pref_pattern.search(line)):
5325 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5326
5327 if browser_prefs_file_pattern.search(f.LocalPath()):
5328 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5329 # assume that they knew that they have to deprecate preferences and don't
5330 # warn.
5331 try:
5332 if ModifiedPrefMigration(f):
5333 return []
5334 except Exception as e:
5335 return [output_api.PresubmitError(str(e))]
5336
5337 if potential_problems:
5338 return [output_api.PresubmitPromptWarning(
5339 'Discovered possible removal of preference registrations.\n\n'
5340 'Please make sure to properly deprecate preferences by clearing their\n'
5341 'value for a couple of milestones before finally removing the code.\n'
5342 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195343 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5344 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105345 'This may be a false positive warning (e.g. if you move preference\n'
5346 'registrations to a different place).\n',
5347 potential_problems
5348 )]
5349 return []
Matt Stark6ef08872021-07-29 01:21:465350
5351def CheckConsistentGrdChanges(input_api, output_api):
5352 """Changes to GRD files must be consistent for tools to read them."""
5353 changed_grds = input_api.AffectedFiles(
5354 include_deletes=False,
5355 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5356 errors = []
Daniel Chengab582892021-09-30 20:53:195357 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5358 for matcher, msg in _INVALID_GRD_FILE_LINE]
Matt Stark6ef08872021-07-29 01:21:465359 for grd in changed_grds:
5360 for i, line in enumerate(grd.NewContents()):
5361 for matcher, msg in invalid_file_regexes:
5362 if matcher.search(line):
Daniel Chengab582892021-09-30 20:53:195363 errors.append(
5364 output_api.PresubmitError('Problem on {grd}:{i} - {msg}'.format(
5365 grd=grd.LocalPath(), i=i + 1, msg=msg)))
Matt Stark6ef08872021-07-29 01:21:465366 return errors
Kevin McNee967dd2d22021-11-15 16:09:295367
5368def CheckMPArchApiUsage(input_api, output_api):
5369 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5370 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5371 """
5372
5373 # Only consider top-level directories that (1) can use content APIs, (2)
5374 # apply to desktop or android chrome, and (3) are known to have a significant
5375 # number of uses of the APIs of concern.
5376 files_to_check = (
5377 r'^(chrome|components|content|extensions)[\\/].+%s' %
5378 _IMPLEMENTATION_EXTENSIONS,
5379 r'^(chrome|components|content|extensions)[\\/].+%s' % _HEADER_EXTENSIONS,
5380 )
5381 files_to_skip=(_EXCLUDED_PATHS +
5382 _TEST_CODE_EXCLUDED_PATHS +
5383 input_api.DEFAULT_FILES_TO_SKIP)
5384 source_file_filter = lambda f: input_api.FilterSourceFile(
5385 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5386
5387 # Note that since these are are just regular expressions and we don't have
5388 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5389 # could have a method named IsInMainFrame).
5390 concerning_class_pattern = input_api.re.compile(
5391 r'WebContentsObserver|WebContentsUserData')
5392 # A subset of WebContentsObserver overrides where there's particular risk for
5393 # confusing tab and page level operations and data (e.g. incorrectly
5394 # resetting page state in DidFinishNavigation).
5395 concerning_wco_methods = [
5396 'DidStartNavigation',
5397 'ReadyToCommitNavigation',
5398 'DidFinishNavigation',
5399 'RenderViewReady',
5400 'RenderViewDeleted',
5401 'RenderViewHostChanged',
5402 'DocumentAvailableInMainFrame',
5403 'DocumentOnLoadCompletedInMainFrame',
5404 'DOMContentLoaded',
5405 'DidFinishLoad',
5406 ]
5407 concerning_nav_handle_methods = [
5408 'IsInMainFrame',
5409 ]
5410 concerning_web_contents_methods = [
5411 'ForEachFrame',
5412 'GetAllFrames',
5413 'FromRenderFrameHost',
5414 'FromRenderViewHost',
5415 'GetMainFrame',
5416 'GetRenderViewHost',
5417 ]
5418 concerning_rfh_methods = [
5419 'GetParent',
5420 'GetMainFrame',
5421 'GetFrameTreeNodeId',
5422 ]
5423 concerning_method_pattern = input_api.re.compile(
5424 r'(' +
5425 r'|'.join(
5426 item
5427 for sublist in [concerning_wco_methods,
5428 concerning_nav_handle_methods,
5429 concerning_web_contents_methods,
5430 concerning_rfh_methods]
5431 for item in sublist) +
5432 r')\(')
5433
5434 uses_concerning_api = False
5435 for f in input_api.AffectedFiles(include_deletes=False,
5436 file_filter=source_file_filter):
5437 for line_num, line in f.ChangedContents():
5438 if (concerning_class_pattern.search(line) or
5439 concerning_method_pattern.search(line)):
5440 uses_concerning_api = True
5441 break
5442 if uses_concerning_api:
5443 break
5444
5445 if uses_concerning_api:
5446 output_api.AppendCC('[email protected]')
5447
5448 return []