blob: e001e539e2bbe252c33eed931751c0af9709231e [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 = (
Ilya Shermane8a7d2d2020-07-25 04:33:4717 # Generated file.
18 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2619 r"client_variations.js"),
Egor Paskoce145c42018-09-28 19:31:0420 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
21 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
22 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
23 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
24 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4925 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0426 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4627 # sqlite is an imported third party dependency.
28 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0429 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5430 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5331 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1232 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0433 r".+[\\/]pnacl_shim\.c$",
34 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0435 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1436 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0437 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5438 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0439 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4040)
[email protected]ca8d1982009-02-19 16:33:1241
John Abd-El-Malek759fea62021-03-13 03:41:1442_EXCLUDED_SET_NO_PARENT_PATHS = (
43 # It's for historical reasons that blink isn't a top level directory, where
44 # it would be allowed to have "set noparent" to avoid top level owners
45 # accidentally +1ing changes.
46 'third_party/blink/OWNERS',
47)
48
wnwenbdc444e2016-05-25 13:44:1549
[email protected]06e6d0ff2012-12-11 01:36:4450# Fragment of a regular expression that matches C++ and Objective-C++
51# implementation files.
52_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
53
wnwenbdc444e2016-05-25 13:44:1554
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1955# Fragment of a regular expression that matches C++ and Objective-C++
56# header files.
57_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
58
59
[email protected]06e6d0ff2012-12-11 01:36:4460# Regular expression that matches code only used for test binaries
61# (best effort).
62_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0463 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4464 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1365 # Test suite files, like:
66 # foo_browsertest.cc
67 # bar_unittest_mac.cc (suffix)
68 # baz_unittests.cc (plural)
69 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1270 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1871 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2172 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0473 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4374 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0475 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4376 # Web test harness.
77 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4778 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0479 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0880 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0481 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4182 # EarlGrey app side code for tests.
83 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1784 # Views Examples code
85 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4186 # Chromium Codelab
87 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4488)
[email protected]ca8d1982009-02-19 16:33:1289
Daniel Bratell609102be2019-03-27 20:53:2190_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1591
[email protected]eea609a2011-11-18 13:10:1292_TEST_ONLY_WARNING = (
93 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5594 'production code. If you are doing this from inside another method\n'
95 'named as *ForTesting(), then consider exposing things to have tests\n'
96 'make that same call directly.\n'
97 'If that is not possible, you may put a comment on the same line with\n'
98 ' // IN-TEST \n'
99 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
100 'method and can be ignored. Do not do this inside production code.\n'
101 'The android-binary-size trybot will block if the method exists in the\n'
102 'release apk.')
[email protected]eea609a2011-11-18 13:10:12103
104
[email protected]cf9b78f2012-11-14 11:40:28105_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:40106 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:21107 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
108 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:28109
Michael Thiessen44457642020-02-06 00:24:15110# Format: Sequence of tuples containing:
111# * Full import path.
112# * Sequence of strings to show when the pattern matches.
113# * Sequence of path or filename exceptions to this rule
114_BANNED_JAVA_IMPORTS = (
115 (
Colin Blundell170d78c82020-03-12 13:56:04116 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15117 (
118 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
119 ),
120 (
121 'net/android/javatests/src/org/chromium/net/'
122 'AndroidProxySelectorTest.java',
123 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04124 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15125 ),
126 ),
Michael Thiessened631912020-08-07 19:01:31127 (
128 'android.support.test.rule.UiThreadTestRule;',
129 (
130 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43131 '@org.chromium.base.test.UiThreadTest on test methods that should run '
132 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31133 ),
134 (),
135 ),
136 (
137 'android.support.test.annotation.UiThreadTest;',
138 (
139 'Do not use android.support.test.annotation.UiThreadTest, use '
140 'org.chromium.base.test.UiThreadTest instead. See '
141 'https://crbug.com/1111893.',
142 ),
143 ()
Michael Thiessenfd6919b2020-12-08 20:44:01144 ),
145 (
146 'android.support.test.rule.ActivityTestRule;',
147 (
148 'Do not use ActivityTestRule, use '
149 'org.chromium.base.test.BaseActivityTestRule instead.',
150 ),
151 (
152 'components/cronet/',
153 )
Michael Thiessened631912020-08-07 19:01:31154 )
Michael Thiessen44457642020-02-06 00:24:15155)
wnwenbdc444e2016-05-25 13:44:15156
Daniel Bratell609102be2019-03-27 20:53:21157# Format: Sequence of tuples containing:
158# * String pattern or, if starting with a slash, a regular expression.
159# * Sequence of strings to show when the pattern matches.
160# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41161_BANNED_JAVA_FUNCTIONS = (
162 (
163 'StrictMode.allowThreadDiskReads()',
164 (
165 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
166 'directly.',
167 ),
168 False,
169 ),
170 (
171 'StrictMode.allowThreadDiskWrites()',
172 (
173 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
174 'directly.',
175 ),
176 False,
177 ),
Michael Thiessen0f2547e2020-07-27 21:55:36178 (
179 '.waitForIdleSync()',
180 (
181 'Do not use waitForIdleSync as it masks underlying issues. There is '
182 'almost always something else you should wait on instead.',
183 ),
184 False,
185 ),
Eric Stevensona9a980972017-09-23 00:04:41186)
187
Daniel Bratell609102be2019-03-27 20:53:21188# Format: Sequence of tuples containing:
189# * String pattern or, if starting with a slash, a regular expression.
190# * Sequence of strings to show when the pattern matches.
191# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59192_BANNED_OBJC_FUNCTIONS = (
193 (
194 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20195 (
196 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59197 'prohibited. Please use CrTrackingArea instead.',
198 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
199 ),
200 False,
201 ),
202 (
[email protected]eaae1972014-04-16 04:17:26203 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20204 (
205 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59206 'instead.',
207 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
208 ),
209 False,
210 ),
211 (
212 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20213 (
214 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59215 'Please use |convertPoint:(point) fromView:nil| instead.',
216 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
217 ),
218 True,
219 ),
220 (
221 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20222 (
223 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59224 'Please use |convertPoint:(point) toView:nil| instead.',
225 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
226 ),
227 True,
228 ),
229 (
230 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20231 (
232 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59233 'Please use |convertRect:(point) fromView:nil| instead.',
234 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
235 ),
236 True,
237 ),
238 (
239 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20240 (
241 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59242 'Please use |convertRect:(point) toView:nil| instead.',
243 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
244 ),
245 True,
246 ),
247 (
248 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20249 (
250 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59251 'Please use |convertSize:(point) fromView:nil| instead.',
252 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
253 ),
254 True,
255 ),
256 (
257 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20258 (
259 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59260 'Please use |convertSize:(point) toView:nil| instead.',
261 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
262 ),
263 True,
264 ),
jif65398702016-10-27 10:19:48265 (
266 r"/\s+UTF8String\s*]",
267 (
268 'The use of -[NSString UTF8String] is dangerous as it can return null',
269 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
270 'Please use |SysNSStringToUTF8| instead.',
271 ),
272 True,
273 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34274 (
275 r'__unsafe_unretained',
276 (
277 'The use of __unsafe_unretained is almost certainly wrong, unless',
278 'when interacting with NSFastEnumeration or NSInvocation.',
279 'Please use __weak in files build with ARC, nothing otherwise.',
280 ),
281 False,
282 ),
Avi Drissman7382afa02019-04-29 23:27:13283 (
284 'freeWhenDone:NO',
285 (
286 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
287 'Foundation types is prohibited.',
288 ),
289 True,
290 ),
[email protected]127f18ec2012-06-16 05:05:59291)
292
Daniel Bratell609102be2019-03-27 20:53:21293# Format: Sequence of tuples containing:
294# * String pattern or, if starting with a slash, a regular expression.
295# * Sequence of strings to show when the pattern matches.
296# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54297_BANNED_IOS_OBJC_FUNCTIONS = (
298 (
299 r'/\bTEST[(]',
300 (
301 'TEST() macro should not be used in Objective-C++ code as it does not ',
302 'drain the autorelease pool at the end of the test. Use TEST_F() ',
303 'macro instead with a fixture inheriting from PlatformTest (or a ',
304 'typedef).'
305 ),
306 True,
307 ),
308 (
309 r'/\btesting::Test\b',
310 (
311 'testing::Test should not be used in Objective-C++ code as it does ',
312 'not drain the autorelease pool at the end of the test. Use ',
313 'PlatformTest instead.'
314 ),
315 True,
316 ),
317)
318
Peter K. Lee6c03ccff2019-07-15 14:40:05319# Format: Sequence of tuples containing:
320# * String pattern or, if starting with a slash, a regular expression.
321# * Sequence of strings to show when the pattern matches.
322# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
323_BANNED_IOS_EGTEST_FUNCTIONS = (
324 (
325 r'/\bEXPECT_OCMOCK_VERIFY\b',
326 (
327 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
328 'it is meant for GTests. Use [mock verify] instead.'
329 ),
330 True,
331 ),
332)
333
Daniel Bratell609102be2019-03-27 20:53:21334# Format: Sequence of tuples containing:
335# * String pattern or, if starting with a slash, a regular expression.
336# * Sequence of strings to show when the pattern matches.
337# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
338# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59339_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20340 (
Peter Kasting94a56c42019-10-25 21:54:04341 r'/\busing namespace ',
342 (
343 'Using directives ("using namespace x") are banned by the Google Style',
344 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
345 'Explicitly qualify symbols or use using declarations ("using x::foo").',
346 ),
347 True,
348 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
349 ),
Antonio Gomes07300d02019-03-13 20:59:57350 # Make sure that gtest's FRIEND_TEST() macro is not used; the
351 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
352 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53353 (
[email protected]23e6cbc2012-06-16 18:51:20354 'FRIEND_TEST(',
355 (
[email protected]e3c945502012-06-26 20:01:49356 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20357 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
358 ),
359 False,
[email protected]7345da02012-11-27 14:31:49360 (),
[email protected]23e6cbc2012-06-16 18:51:20361 ),
362 (
tomhudsone2c14d552016-05-26 17:07:46363 'setMatrixClip',
364 (
365 'Overriding setMatrixClip() is prohibited; ',
366 'the base function is deprecated. ',
367 ),
368 True,
369 (),
370 ),
371 (
[email protected]52657f62013-05-20 05:30:31372 'SkRefPtr',
373 (
374 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22375 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31376 ),
377 True,
378 (),
379 ),
380 (
381 'SkAutoRef',
382 (
383 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22384 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31385 ),
386 True,
387 (),
388 ),
389 (
390 'SkAutoTUnref',
391 (
392 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22393 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31394 ),
395 True,
396 (),
397 ),
398 (
399 'SkAutoUnref',
400 (
401 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
402 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22403 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31404 ),
405 True,
406 (),
407 ),
[email protected]d89eec82013-12-03 14:10:59408 (
409 r'/HANDLE_EINTR\(.*close',
410 (
411 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
412 'descriptor will be closed, and it is incorrect to retry the close.',
413 'Either call close directly and ignore its return value, or wrap close',
414 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
415 ),
416 True,
417 (),
418 ),
419 (
420 r'/IGNORE_EINTR\((?!.*close)',
421 (
422 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
423 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
424 ),
425 True,
426 (
427 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04428 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
429 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59430 ),
431 ),
[email protected]ec5b3f02014-04-04 18:43:43432 (
433 r'/v8::Extension\(',
434 (
435 'Do not introduce new v8::Extensions into the code base, use',
436 'gin::Wrappable instead. See http://crbug.com/334679',
437 ),
438 True,
[email protected]f55c90ee62014-04-12 00:50:03439 (
Egor Paskoce145c42018-09-28 19:31:04440 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03441 ),
[email protected]ec5b3f02014-04-04 18:43:43442 ),
skyostilf9469f72015-04-20 10:38:52443 (
jame2d1a952016-04-02 00:27:10444 '#pragma comment(lib,',
445 (
446 'Specify libraries to link with in build files and not in the source.',
447 ),
448 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41449 (
tzik3f295992018-12-04 20:32:23450 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04451 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41452 ),
jame2d1a952016-04-02 00:27:10453 ),
fdorayc4ac18d2017-05-01 21:39:59454 (
Gabriel Charette7cc6c432018-04-25 20:52:02455 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59456 (
457 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
458 ),
459 False,
460 (),
461 ),
462 (
Gabriel Charette7cc6c432018-04-25 20:52:02463 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59464 (
465 'Consider using THREAD_CHECKER macros instead of the class directly.',
466 ),
467 False,
468 (),
469 ),
dbeamb6f4fde2017-06-15 04:03:06470 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06471 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
472 (
473 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
474 'deprecated (http://crbug.com/634507). Please avoid converting away',
475 'from the Time types in Chromium code, especially if any math is',
476 'being done on time values. For interfacing with platform/library',
477 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
478 'type converter methods instead. For faking TimeXXX values (for unit',
479 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
480 'other use cases, please contact base/time/OWNERS.',
481 ),
482 False,
483 (),
484 ),
485 (
dbeamb6f4fde2017-06-15 04:03:06486 'CallJavascriptFunctionUnsafe',
487 (
488 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
489 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
490 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
491 ),
492 False,
493 (
Egor Paskoce145c42018-09-28 19:31:04494 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
495 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
496 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06497 ),
498 ),
dskiba1474c2bfd62017-07-20 02:19:24499 (
500 'leveldb::DB::Open',
501 (
502 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
503 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
504 "Chrome's tracing, making their memory usage visible.",
505 ),
506 True,
507 (
508 r'^third_party/leveldatabase/.*\.(cc|h)$',
509 ),
Gabriel Charette0592c3a2017-07-26 12:02:04510 ),
511 (
Chris Mumfordc38afb62017-10-09 17:55:08512 'leveldb::NewMemEnv',
513 (
514 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58515 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
516 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08517 ),
518 True,
519 (
520 r'^third_party/leveldatabase/.*\.(cc|h)$',
521 ),
522 ),
523 (
Gabriel Charetted9839bc2017-07-29 14:17:47524 'RunLoop::QuitCurrent',
525 (
Robert Liao64b7ab22017-08-04 23:03:43526 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
527 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47528 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41529 False,
Gabriel Charetted9839bc2017-07-29 14:17:47530 (),
Gabriel Charettea44975052017-08-21 23:14:04531 ),
532 (
533 'base::ScopedMockTimeMessageLoopTaskRunner',
534 (
Gabriel Charette87cc1af2018-04-25 20:52:51535 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11536 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51537 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
538 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
539 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04540 ),
Gabriel Charette87cc1af2018-04-25 20:52:51541 False,
Gabriel Charettea44975052017-08-21 23:14:04542 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57543 ),
544 (
Dave Tapuska98199b612019-07-10 13:30:44545 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57546 (
547 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02548 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57549 ),
550 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16551 # Abseil's benchmarks never linked into chrome.
552 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38553 ),
554 (
Peter Kasting991618a62019-06-17 22:00:09555 r'/\bstd::stoi\b',
556 (
557 'std::stoi uses exceptions to communicate results. ',
558 'Use base::StringToInt() instead.',
559 ),
560 True,
561 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
562 ),
563 (
564 r'/\bstd::stol\b',
565 (
566 'std::stol uses exceptions to communicate results. ',
567 'Use base::StringToInt() instead.',
568 ),
569 True,
570 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
571 ),
572 (
573 r'/\bstd::stoul\b',
574 (
575 'std::stoul uses exceptions to communicate results. ',
576 'Use base::StringToUint() instead.',
577 ),
578 True,
579 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
580 ),
581 (
582 r'/\bstd::stoll\b',
583 (
584 'std::stoll uses exceptions to communicate results. ',
585 'Use base::StringToInt64() instead.',
586 ),
587 True,
588 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
589 ),
590 (
591 r'/\bstd::stoull\b',
592 (
593 'std::stoull uses exceptions to communicate results. ',
594 'Use base::StringToUint64() instead.',
595 ),
596 True,
597 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
598 ),
599 (
600 r'/\bstd::stof\b',
601 (
602 'std::stof uses exceptions to communicate results. ',
603 'For locale-independent values, e.g. reading numbers from disk',
604 'profiles, use base::StringToDouble().',
605 'For user-visible values, parse using ICU.',
606 ),
607 True,
608 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
609 ),
610 (
611 r'/\bstd::stod\b',
612 (
613 'std::stod uses exceptions to communicate results. ',
614 'For locale-independent values, e.g. reading numbers from disk',
615 'profiles, use base::StringToDouble().',
616 'For user-visible values, parse using ICU.',
617 ),
618 True,
619 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
620 ),
621 (
622 r'/\bstd::stold\b',
623 (
624 'std::stold uses exceptions to communicate results. ',
625 'For locale-independent values, e.g. reading numbers from disk',
626 'profiles, use base::StringToDouble().',
627 'For user-visible values, parse using ICU.',
628 ),
629 True,
630 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
631 ),
632 (
Daniel Bratell69334cc2019-03-26 11:07:45633 r'/\bstd::to_string\b',
634 (
635 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09636 'For locale-independent strings, e.g. writing numbers to disk',
637 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45638 'For user-visible strings, use base::FormatNumber() and',
639 'the related functions in base/i18n/number_formatting.h.',
640 ),
Peter Kasting991618a62019-06-17 22:00:09641 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21642 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45643 ),
644 (
645 r'/\bstd::shared_ptr\b',
646 (
647 'std::shared_ptr should not be used. Use scoped_refptr instead.',
648 ),
649 True,
Ulan Degenbaev947043882021-02-10 14:02:31650 [
651 # Needed for interop with third-party library.
652 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57653 'array_buffer_contents\.(cc|h)',
Wez5f56be52021-05-04 09:30:58654 '^gin/array_buffer\.(cc|h)',
655 '^chrome/services/sharing/nearby/',
Meilin Wang00efc7c2021-05-13 01:12:42656 # gRPC provides some C++ libraries that use std::shared_ptr<>.
657 '^chromeos/services/libassistant/grpc/',
Wez5f56be52021-05-04 09:30:58658 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
659 '.*fuchsia.*test\.(cc|h)',
Alex Chau9eb03cdd52020-07-13 21:04:57660 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21661 ),
662 (
Peter Kasting991618a62019-06-17 22:00:09663 r'/\bstd::weak_ptr\b',
664 (
665 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
666 ),
667 True,
668 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
669 ),
670 (
Daniel Bratell609102be2019-03-27 20:53:21671 r'/\blong long\b',
672 (
673 'long long is banned. Use stdint.h if you need a 64 bit number.',
674 ),
675 False, # Only a warning since it is already used.
676 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
677 ),
678 (
679 r'/\bstd::bind\b',
680 (
681 'std::bind is banned because of lifetime risks.',
682 'Use base::BindOnce or base::BindRepeating instead.',
683 ),
684 True,
685 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
686 ),
687 (
688 r'/\b#include <chrono>\b',
689 (
690 '<chrono> overlaps with Time APIs in base. Keep using',
691 'base classes.',
692 ),
693 True,
694 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
695 ),
696 (
697 r'/\b#include <exception>\b',
698 (
699 'Exceptions are banned and disabled in Chromium.',
700 ),
701 True,
702 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
703 ),
704 (
705 r'/\bstd::function\b',
706 (
Colin Blundellea615d422021-05-12 09:35:41707 'std::function is banned. Instead use base::OnceCallback or ',
708 'base::RepeatingCallback, which directly support Chromium\'s weak ',
709 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21710 ),
Peter Kasting991618a62019-06-17 22:00:09711 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21712 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
713 ),
714 (
715 r'/\b#include <random>\b',
716 (
717 'Do not use any random number engines from <random>. Instead',
718 'use base::RandomBitGenerator.',
719 ),
720 True,
721 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
722 ),
723 (
Tom Andersona95e12042020-09-09 23:08:00724 r'/\b#include <X11/',
725 (
726 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
727 ),
728 True,
729 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
730 ),
731 (
Daniel Bratell609102be2019-03-27 20:53:21732 r'/\bstd::ratio\b',
733 (
734 'std::ratio is banned by the Google Style Guide.',
735 ),
736 True,
737 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45738 ),
739 (
Francois Doray43670e32017-09-27 12:40:38740 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
741 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
742 (
743 'Use the new API in base/threading/thread_restrictions.h.',
744 ),
Gabriel Charette04b138f2018-08-06 00:03:22745 False,
Francois Doray43670e32017-09-27 12:40:38746 (),
747 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38748 (
Michael Giuffrida7f93d6922019-04-19 14:39:58749 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19750 (
751 'RunMessageLoop is deprecated, use RunLoop instead.',
752 ),
753 False,
754 (),
755 ),
756 (
Dave Tapuska98199b612019-07-10 13:30:44757 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19758 (
759 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
760 ),
761 False,
762 (),
763 ),
764 (
Dave Tapuska98199b612019-07-10 13:30:44765 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19766 (
767 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
768 "if you're convinced you need this.",
769 ),
770 False,
771 (),
772 ),
773 (
Dave Tapuska98199b612019-07-10 13:30:44774 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19775 (
776 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04777 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19778 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
779 'async events instead of flushing threads.',
780 ),
781 False,
782 (),
783 ),
784 (
785 r'MessageLoopRunner',
786 (
787 'MessageLoopRunner is deprecated, use RunLoop instead.',
788 ),
789 False,
790 (),
791 ),
792 (
Dave Tapuska98199b612019-07-10 13:30:44793 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19794 (
795 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
796 "gab@ if you found a use case where this is the only solution.",
797 ),
798 False,
799 (),
800 ),
801 (
Victor Costane48a2e82019-03-15 22:02:34802 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16803 (
Victor Costane48a2e82019-03-15 22:02:34804 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16805 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
806 ),
807 True,
808 (
809 r'^sql/initialization\.(cc|h)$',
810 r'^third_party/sqlite/.*\.(c|cc|h)$',
811 ),
812 ),
Matt Menke7f520a82018-03-28 21:38:37813 (
Dave Tapuska98199b612019-07-10 13:30:44814 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47815 (
816 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
817 'base::RandomShuffle instead.'
818 ),
819 True,
820 (),
821 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24822 (
823 'ios/web/public/test/http_server',
824 (
825 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
826 ),
827 False,
828 (),
829 ),
Robert Liao764c9492019-01-24 18:46:28830 (
831 'GetAddressOf',
832 (
833 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53834 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11835 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53836 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28837 ),
838 True,
839 (),
840 ),
Antonio Gomes07300d02019-03-13 20:59:57841 (
Ben Lewisa9514602019-04-29 17:53:05842 'SHFileOperation',
843 (
844 'SHFileOperation was deprecated in Windows Vista, and there are less ',
845 'complex functions to achieve the same goals. Use IFileOperation for ',
846 'any esoteric actions instead.'
847 ),
848 True,
849 (),
850 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18851 (
Cliff Smolinsky81951642019-04-30 21:39:51852 'StringFromGUID2',
853 (
854 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24855 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51856 ),
857 True,
858 (
859 r'/base/win/win_util_unittest.cc'
860 ),
861 ),
862 (
863 'StringFromCLSID',
864 (
865 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24866 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51867 ),
868 True,
869 (
870 r'/base/win/win_util_unittest.cc'
871 ),
872 ),
873 (
Avi Drissman7382afa02019-04-29 23:27:13874 'kCFAllocatorNull',
875 (
876 'The use of kCFAllocatorNull with the NoCopy creation of ',
877 'CoreFoundation types is prohibited.',
878 ),
879 True,
880 (),
881 ),
Oksana Zhuravlovafd247772019-05-16 16:57:29882 (
883 'mojo::ConvertTo',
884 (
885 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
886 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
887 'StringTraits if you would like to convert between custom types and',
888 'the wire format of mojom types.'
889 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22890 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29891 (
Wezf89dec092019-09-11 19:38:33892 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
893 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29894 r'^third_party/blink/.*\.(cc|h)$',
895 r'^content/renderer/.*\.(cc|h)$',
896 ),
897 ),
Robert Liao1d78df52019-11-11 20:02:01898 (
Oksana Zhuravlovac8222d22019-12-19 19:21:16899 'GetInterfaceProvider',
900 (
901 'InterfaceProvider is deprecated.',
902 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
903 'or Platform::GetBrowserInterfaceBroker.'
904 ),
905 False,
906 (),
907 ),
908 (
Robert Liao1d78df52019-11-11 20:02:01909 'CComPtr',
910 (
911 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
912 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
913 'details.'
914 ),
915 False,
916 (),
917 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:20918 (
919 r'/\b(IFACE|STD)METHOD_?\(',
920 (
921 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
922 'Instead, always use IFACEMETHODIMP in the declaration.'
923 ),
924 False,
925 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
926 ),
Allen Bauer53b43fb12020-03-12 17:21:47927 (
928 'set_owned_by_client',
929 (
930 'set_owned_by_client is deprecated.',
931 'views::View already owns the child views by default. This introduces ',
932 'a competing ownership model which makes the code difficult to reason ',
933 'about. See http://crbug.com/1044687 for more details.'
934 ),
935 False,
936 (),
937 ),
Eric Secklerbe6f48d2020-05-06 18:09:12938 (
939 r'/\bTRACE_EVENT_ASYNC_',
940 (
941 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
942 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
943 ),
944 False,
945 (
946 r'^base/trace_event/.*',
947 r'^base/tracing/.*',
948 ),
949 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:26950 (
Robert Liao22f66a52021-04-10 00:57:52951 'RoInitialize',
952 (
Robert Liao48018922021-04-16 23:03:02953 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:52954 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
955 'instead. See http://crbug.com/1197722 for more information.'
956 ),
957 True,
Robert Liao48018922021-04-16 23:03:02958 (
959 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$'
960 ),
Robert Liao22f66a52021-04-10 00:57:52961 ),
Lei Zhang1ddeadb2021-05-20 22:14:34962 (
963 r'/DISALLOW_(COPY|ASSIGN|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS)\(',
964 (
965 'DISALLOW_xxx macros are deprecated. See base/macros.h for details.',
966 ),
967 False,
968 (),
969 ),
[email protected]127f18ec2012-06-16 05:05:59970)
971
Mario Sanchez Prada2472cab2019-09-18 10:58:31972# Format: Sequence of tuples containing:
973# * String pattern or, if starting with a slash, a regular expression.
974# * Sequence of strings to show when the pattern matches.
975_DEPRECATED_MOJO_TYPES = (
976 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31977 r'/\bmojo::AssociatedInterfacePtrInfo\b',
978 (
979 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
980 'Use mojo::PendingAssociatedRemote<Interface> instead.',
981 ),
982 ),
983 (
984 r'/\bmojo::AssociatedInterfaceRequest\b',
985 (
986 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
987 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
988 ),
989 ),
990 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31991 r'/\bmojo::InterfacePtr\b',
992 (
993 'mojo::InterfacePtr<Interface> is deprecated.',
994 'Use mojo::Remote<Interface> instead.',
995 ),
996 ),
997 (
998 r'/\bmojo::InterfacePtrInfo\b',
999 (
1000 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1001 'Use mojo::PendingRemote<Interface> instead.',
1002 ),
1003 ),
1004 (
1005 r'/\bmojo::InterfaceRequest\b',
1006 (
1007 'mojo::InterfaceRequest<Interface> is deprecated.',
1008 'Use mojo::PendingReceiver<Interface> instead.',
1009 ),
1010 ),
1011 (
1012 r'/\bmojo::MakeRequest\b',
1013 (
1014 'mojo::MakeRequest is deprecated.',
1015 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1016 ),
1017 ),
Mario Sanchez Prada2472cab2019-09-18 10:58:311018)
wnwenbdc444e2016-05-25 13:44:151019
mlamouria82272622014-09-16 18:45:041020_IPC_ENUM_TRAITS_DEPRECATED = (
1021 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501022 'See http://www.chromium.org/Home/chromium-security/education/'
1023 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041024
Stephen Martinis97a394142018-06-07 23:06:051025_LONG_PATH_ERROR = (
1026 'Some files included in this CL have file names that are too long (> 200'
1027 ' characters). If committed, these files will cause issues on Windows. See'
1028 ' https://crbug.com/612667 for more details.'
1029)
1030
Shenghua Zhangbfaa38b82017-11-16 21:58:021031_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041032 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041033 r".*[\\/]BuildHooksAndroidImpl\.java",
1034 r".*[\\/]LicenseContentProvider\.java",
1035 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281036 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021037]
[email protected]127f18ec2012-06-16 05:05:591038
Mohamed Heikald048240a2019-11-12 16:57:371039# List of image extensions that are used as resources in chromium.
1040_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1041
Sean Kau46e29bc2017-08-28 16:31:161042# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401043_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041044 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401045 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041046 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1047 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041048 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431049 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161050]
1051
1052
[email protected]b00342e7f2013-03-26 16:21:541053_VALID_OS_MACROS = (
1054 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081055 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541056 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441057 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121058 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541059 'OS_BSD',
1060 'OS_CAT', # For testing.
1061 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041062 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541063 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371064 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541065 'OS_IOS',
1066 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441067 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541068 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211069 'OS_NACL_NONSFI',
1070 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121071 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541072 'OS_OPENBSD',
1073 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371074 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541075 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541076 'OS_WIN',
1077)
1078
1079
Andrew Grieveb773bad2020-06-05 18:00:381080# These are not checked on the public chromium-presubmit trybot.
1081# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041082# checkouts.
agrievef32bcc72016-04-04 14:57:401083_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381084 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381085]
1086
1087
1088_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041089 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361090 'base/android/jni_generator/jni_generator.pydeps',
1091 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361092 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041093 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361094 'build/android/gyp/aar.pydeps',
1095 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271096 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361097 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381098 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361099 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021100 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221101 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111102 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361103 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361104 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361105 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111106 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041107 'build/android/gyp/create_app_bundle_apks.pydeps',
1108 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361109 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121110 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091111 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221112 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001113 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361114 'build/android/gyp/desugar.pydeps',
1115 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421116 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041117 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361118 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361119 'build/android/gyp/filter_zip.pydeps',
1120 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361121 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361122 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581123 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361124 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141125 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261126 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471127 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011128 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041129 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361130 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361131 'build/android/gyp/merge_manifest.pydeps',
1132 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221133 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361134 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461135 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301136 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241137 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361138 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461139 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561140 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361141 'build/android/incremental_install/generate_android_manifest.pydeps',
1142 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041143 'build/android/resource_sizes.pydeps',
1144 'build/android/test_runner.pydeps',
1145 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361146 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361147 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321148 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271149 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1150 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041151 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001152 'components/cronet/tools/generate_javadoc.pydeps',
1153 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381154 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001155 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381156 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041157 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181158 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041159 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421160 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1161 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131162 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501163 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061164 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221165 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401166]
1167
wnwenbdc444e2016-05-25 13:44:151168
agrievef32bcc72016-04-04 14:57:401169_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1170
1171
Eric Boren6fd2b932018-01-25 15:05:081172# Bypass the AUTHORS check for these accounts.
1173_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591174 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451175 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591176 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521177 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071178 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041179 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271180 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041181 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161182 for s in ('chromium-internal-autoroll',)
1183 ) | set('%[email protected]' % s
1184 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081185
Matt Stark6ef08872021-07-29 01:21:461186_INVALID_GRD_FILE_LINE = [
1187 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1188]
Eric Boren6fd2b932018-01-25 15:05:081189
Daniel Bratell65b033262019-04-23 08:17:061190def _IsCPlusPlusFile(input_api, file_path):
1191 """Returns True if this file contains C++-like code (and not Python,
1192 Go, Java, MarkDown, ...)"""
1193
1194 ext = input_api.os_path.splitext(file_path)[1]
1195 # This list is compatible with CppChecker.IsCppFile but we should
1196 # consider adding ".c" to it. If we do that we can use this function
1197 # at more places in the code.
1198 return ext in (
1199 '.h',
1200 '.cc',
1201 '.cpp',
1202 '.m',
1203 '.mm',
1204 )
1205
1206def _IsCPlusPlusHeaderFile(input_api, file_path):
1207 return input_api.os_path.splitext(file_path)[1] == ".h"
1208
1209
1210def _IsJavaFile(input_api, file_path):
1211 return input_api.os_path.splitext(file_path)[1] == ".java"
1212
1213
1214def _IsProtoFile(input_api, file_path):
1215 return input_api.os_path.splitext(file_path)[1] == ".proto"
1216
Mohamed Heikal5e5b7922020-10-29 18:57:591217
1218def CheckNoUpstreamDepsOnClank(input_api, output_api):
1219 """Prevent additions of dependencies from the upstream repo on //clank."""
1220 # clank can depend on clank
1221 if input_api.change.RepositoryRoot().endswith('clank'):
1222 return []
1223 build_file_patterns = [
1224 r'(.+/)?BUILD\.gn',
1225 r'.+\.gni',
1226 ]
1227 excluded_files = [
1228 r'build[/\\]config[/\\]android[/\\]config\.gni'
1229 ]
1230 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1231
1232 error_message = 'Disallowed import on //clank in an upstream build file:'
1233
1234 def FilterFile(affected_file):
1235 return input_api.FilterSourceFile(
1236 affected_file,
1237 files_to_check=build_file_patterns,
1238 files_to_skip=excluded_files)
1239
1240 problems = []
1241 for f in input_api.AffectedSourceFiles(FilterFile):
1242 local_path = f.LocalPath()
1243 for line_number, line in f.ChangedContents():
1244 if (bad_pattern.search(line)):
1245 problems.append(
1246 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1247 if problems:
1248 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1249 else:
1250 return []
1251
1252
Saagar Sanghavifceeaae2020-08-12 16:40:361253def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191254 """Attempts to prevent use of functions intended only for testing in
1255 non-testing code. For now this is just a best-effort implementation
1256 that ignores header files and may have some false positives. A
1257 better implementation would probably need a proper C++ parser.
1258 """
1259 # We only scan .cc files and the like, as the declaration of
1260 # for-testing functions in header files are hard to distinguish from
1261 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491262 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191263
jochenc0d4808c2015-07-27 09:25:421264 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191265 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091266 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131267 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191268 exclusion_pattern = input_api.re.compile(
1269 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1270 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131271 # Avoid a false positive in this case, where the method name, the ::, and
1272 # the closing { are all on different lines due to line wrapping.
1273 # HelperClassForTesting::
1274 # HelperClassForTesting(
1275 # args)
1276 # : member(0) {}
1277 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191278
1279 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441280 files_to_skip = (_EXCLUDED_PATHS +
1281 _TEST_CODE_EXCLUDED_PATHS +
1282 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191283 return input_api.FilterSourceFile(
1284 affected_file,
James Cook24a504192020-07-23 00:08:441285 files_to_check=file_inclusion_pattern,
1286 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191287
1288 problems = []
1289 for f in input_api.AffectedSourceFiles(FilterFile):
1290 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131291 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241292 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031293 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461294 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131295 not exclusion_pattern.search(line) and
1296 not allowlist_pattern.search(line) and
1297 not in_method_defn):
[email protected]55459852011-08-10 15:17:191298 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031299 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131300 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191301
1302 if problems:
[email protected]f7051d52013-04-02 18:31:421303 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031304 else:
1305 return []
[email protected]55459852011-08-10 15:17:191306
1307
Saagar Sanghavifceeaae2020-08-12 16:40:361308def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231309 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591310 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231311 """
1312 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1313 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1314 name_pattern = r'ForTest(s|ing)?'
1315 # Describes an occurrence of "ForTest*" inside a // comment.
1316 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501317 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551318 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231319 # Catch calls.
1320 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1321 # Ignore definitions. (Comments are ignored separately.)
1322 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1323
1324 problems = []
1325 sources = lambda x: input_api.FilterSourceFile(
1326 x,
James Cook24a504192020-07-23 00:08:441327 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1328 + input_api.DEFAULT_FILES_TO_SKIP),
1329 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231330 )
1331 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1332 local_path = f.LocalPath()
1333 is_inside_javadoc = False
1334 for line_number, line in f.ChangedContents():
1335 if is_inside_javadoc and javadoc_end_re.search(line):
1336 is_inside_javadoc = False
1337 if not is_inside_javadoc and javadoc_start_re.search(line):
1338 is_inside_javadoc = True
1339 if is_inside_javadoc:
1340 continue
1341 if (inclusion_re.search(line) and
1342 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501343 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231344 not exclusion_re.search(line)):
1345 problems.append(
1346 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1347
1348 if problems:
1349 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1350 else:
1351 return []
1352
1353
Saagar Sanghavifceeaae2020-08-12 16:40:361354def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541355 """Checks to make sure no .h files include <iostream>."""
1356 files = []
1357 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1358 input_api.re.MULTILINE)
1359 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1360 if not f.LocalPath().endswith('.h'):
1361 continue
1362 contents = input_api.ReadFile(f)
1363 if pattern.search(contents):
1364 files.append(f)
1365
1366 if len(files):
yolandyandaabc6d2016-04-18 18:29:391367 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061368 'Do not #include <iostream> in header files, since it inserts static '
1369 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541370 '#include <ostream>. See http://crbug.com/94794',
1371 files) ]
1372 return []
1373
Danil Chapovalov3518f362018-08-11 16:13:431374def _CheckNoStrCatRedefines(input_api, output_api):
1375 """Checks no windows headers with StrCat redefined are included directly."""
1376 files = []
1377 pattern_deny = input_api.re.compile(
1378 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1379 input_api.re.MULTILINE)
1380 pattern_allow = input_api.re.compile(
1381 r'^#include\s"base/win/windows_defines.inc"',
1382 input_api.re.MULTILINE)
1383 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1384 contents = input_api.ReadFile(f)
1385 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1386 files.append(f.LocalPath())
1387
1388 if len(files):
1389 return [output_api.PresubmitError(
1390 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1391 'directly since they pollute code with StrCat macro. Instead, '
1392 'include matching header from base/win. See http://crbug.com/856536',
1393 files) ]
1394 return []
1395
[email protected]10689ca2011-09-02 02:31:541396
Saagar Sanghavifceeaae2020-08-12 16:40:361397def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521398 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181399 problems = []
1400 for f in input_api.AffectedFiles():
1401 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1402 continue
1403
1404 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041405 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181406 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1407
1408 if not problems:
1409 return []
1410 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1411 '\n'.join(problems))]
1412
Saagar Sanghavifceeaae2020-08-12 16:40:361413def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341414 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1415
1416 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1417 instead of DISABLED_. To filter false positives, reports are only generated
1418 if a corresponding MAYBE_ line exists.
1419 """
1420 problems = []
1421
1422 # The following two patterns are looked for in tandem - is a test labeled
1423 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1424 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1425 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1426
1427 # This is for the case that a test is disabled on all platforms.
1428 full_disable_pattern = input_api.re.compile(
1429 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1430 input_api.re.MULTILINE)
1431
Katie Df13948e2018-09-25 07:33:441432 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341433 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1434 continue
1435
1436 # Search for MABYE_, DISABLE_ pairs.
1437 disable_lines = {} # Maps of test name to line number.
1438 maybe_lines = {}
1439 for line_num, line in f.ChangedContents():
1440 disable_match = disable_pattern.search(line)
1441 if disable_match:
1442 disable_lines[disable_match.group(1)] = line_num
1443 maybe_match = maybe_pattern.search(line)
1444 if maybe_match:
1445 maybe_lines[maybe_match.group(1)] = line_num
1446
1447 # Search for DISABLE_ occurrences within a TEST() macro.
1448 disable_tests = set(disable_lines.keys())
1449 maybe_tests = set(maybe_lines.keys())
1450 for test in disable_tests.intersection(maybe_tests):
1451 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1452
1453 contents = input_api.ReadFile(f)
1454 full_disable_match = full_disable_pattern.search(contents)
1455 if full_disable_match:
1456 problems.append(' %s' % f.LocalPath())
1457
1458 if not problems:
1459 return []
1460 return [
1461 output_api.PresubmitPromptWarning(
1462 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1463 '\n'.join(problems))
1464 ]
1465
[email protected]72df4e782012-06-21 16:28:181466
Saagar Sanghavifceeaae2020-08-12 16:40:361467def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571468 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521469 errors = []
Hans Wennborg944479f2020-06-25 21:39:251470 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521471 input_api.re.MULTILINE)
1472 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1473 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1474 continue
1475 for lnum, line in f.ChangedContents():
1476 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171477 errors.append(output_api.PresubmitError(
1478 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571479 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171480 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521481 return errors
1482
1483
Weilun Shia487fad2020-10-28 00:10:341484# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1485# more reliable way. See
1486# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191487
wnwenbdc444e2016-05-25 13:44:151488
Saagar Sanghavifceeaae2020-08-12 16:40:361489def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391490 """Check that FlakyTest annotation is our own instead of the android one"""
1491 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1492 files = []
1493 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1494 if f.LocalPath().endswith('Test.java'):
1495 if pattern.search(input_api.ReadFile(f)):
1496 files.append(f)
1497 if len(files):
1498 return [output_api.PresubmitError(
1499 'Use org.chromium.base.test.util.FlakyTest instead of '
1500 'android.test.FlakyTest',
1501 files)]
1502 return []
mcasasb7440c282015-02-04 14:52:191503
wnwenbdc444e2016-05-25 13:44:151504
Saagar Sanghavifceeaae2020-08-12 16:40:361505def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441506 """Make sure .DEPS.git is never modified manually."""
1507 if any(f.LocalPath().endswith('.DEPS.git') for f in
1508 input_api.AffectedFiles()):
1509 return [output_api.PresubmitError(
1510 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1511 'automated system based on what\'s in DEPS and your changes will be\n'
1512 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501513 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1514 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441515 'for more information')]
1516 return []
1517
1518
Saagar Sanghavifceeaae2020-08-12 16:40:361519def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471520 """Checks that DEPS file deps are from allowed_hosts."""
1521 # Run only if DEPS file has been modified to annoy fewer bystanders.
1522 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1523 return []
1524 # Outsource work to gclient verify
1525 try:
John Budorickf20c0042019-04-25 23:23:401526 gclient_path = input_api.os_path.join(
1527 input_api.PresubmitLocalPath(),
1528 'third_party', 'depot_tools', 'gclient.py')
1529 input_api.subprocess.check_output(
1530 [input_api.python_executable, gclient_path, 'verify'],
1531 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471532 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201533 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471534 return [output_api.PresubmitError(
1535 'DEPS file must have only git dependencies.',
1536 long_text=error.output)]
1537
1538
Mario Sanchez Prada2472cab2019-09-18 10:58:311539def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1540 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591541 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311542
1543 Returns an string composed of the name of the file, the line number where the
1544 match has been found and the additional text passed as |message| in case the
1545 target type name matches the text inside the line passed as parameter.
1546 """
Peng Huang9c5949a02020-06-11 19:20:541547 result = []
1548
danakjd18e8892020-12-17 17:42:011549 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1550 return result
1551 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541552 return result
1553
Mario Sanchez Prada2472cab2019-09-18 10:58:311554 matched = False
1555 if type_name[0:1] == '/':
1556 regex = type_name[1:]
1557 if input_api.re.search(regex, line):
1558 matched = True
1559 elif type_name in line:
1560 matched = True
1561
Mario Sanchez Prada2472cab2019-09-18 10:58:311562 if matched:
1563 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1564 for message_line in message:
1565 result.append(' %s' % message_line)
1566
1567 return result
1568
1569
Saagar Sanghavifceeaae2020-08-12 16:40:361570def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591571 """Make sure that banned functions are not used."""
1572 warnings = []
1573 errors = []
1574
James Cook24a504192020-07-23 00:08:441575 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151576 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441577 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151578 if input_api.re.match(item, local_path):
1579 return True
1580 return False
1581
Peter K. Lee6c03ccff2019-07-15 14:40:051582 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541583 local_path = affected_file.LocalPath()
1584 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1585 return False
1586 basename = input_api.os_path.basename(local_path)
1587 if 'ios' in basename.split('_'):
1588 return True
1589 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1590 if sep and 'ios' in local_path.split(sep):
1591 return True
1592 return False
1593
wnwenbdc444e2016-05-25 13:44:151594 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311595 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1596 func_name, message)
1597 if problems:
wnwenbdc444e2016-05-25 13:44:151598 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311599 errors.extend(problems)
1600 else:
1601 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151602
Eric Stevensona9a980972017-09-23 00:04:411603 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1604 for f in input_api.AffectedFiles(file_filter=file_filter):
1605 for line_num, line in f.ChangedContents():
1606 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1607 CheckForMatch(f, line_num, line, func_name, message, error)
1608
[email protected]127f18ec2012-06-16 05:05:591609 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1610 for f in input_api.AffectedFiles(file_filter=file_filter):
1611 for line_num, line in f.ChangedContents():
1612 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151613 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591614
Peter K. Lee6c03ccff2019-07-15 14:40:051615 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541616 for line_num, line in f.ChangedContents():
1617 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1618 CheckForMatch(f, line_num, line, func_name, message, error)
1619
Peter K. Lee6c03ccff2019-07-15 14:40:051620 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1621 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1622 for line_num, line in f.ChangedContents():
1623 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1624 CheckForMatch(f, line_num, line, func_name, message, error)
1625
[email protected]127f18ec2012-06-16 05:05:591626 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1627 for f in input_api.AffectedFiles(file_filter=file_filter):
1628 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491629 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441630 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491631 continue
wnwenbdc444e2016-05-25 13:44:151632 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591633
1634 result = []
1635 if (warnings):
1636 result.append(output_api.PresubmitPromptWarning(
1637 'Banned functions were used.\n' + '\n'.join(warnings)))
1638 if (errors):
1639 result.append(output_api.PresubmitError(
1640 'Banned functions were used.\n' + '\n'.join(errors)))
1641 return result
1642
1643
Michael Thiessen44457642020-02-06 00:24:151644def _CheckAndroidNoBannedImports(input_api, output_api):
1645 """Make sure that banned java imports are not used."""
1646 errors = []
1647
1648 def IsException(path, exceptions):
1649 for exception in exceptions:
1650 if (path.startswith(exception)):
1651 return True
1652 return False
1653
1654 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1655 for f in input_api.AffectedFiles(file_filter=file_filter):
1656 for line_num, line in f.ChangedContents():
1657 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1658 if IsException(f.LocalPath(), exceptions):
1659 continue;
1660 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1661 'import ' + import_name, message)
1662 if problems:
1663 errors.extend(problems)
1664 result = []
1665 if (errors):
1666 result.append(output_api.PresubmitError(
1667 'Banned imports were used.\n' + '\n'.join(errors)))
1668 return result
1669
1670
Saagar Sanghavifceeaae2020-08-12 16:40:361671def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311672 """Make sure that old Mojo types are not used."""
1673 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571674 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311675
Mario Sanchez Pradaaab91382019-12-19 08:57:091676 # For any path that is not an "ok" or an "error" path, a warning will be
1677 # raised if deprecated mojo types are found.
1678 ok_paths = ['components/arc']
1679 error_paths = ['third_party/blink', 'content']
1680
Mario Sanchez Prada2472cab2019-09-18 10:58:311681 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1682 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571683 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091684 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311685 continue
1686
1687 for line_num, line in f.ChangedContents():
1688 for func_name, message in _DEPRECATED_MOJO_TYPES:
1689 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1690 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571691
Mario Sanchez Prada2472cab2019-09-18 10:58:311692 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091693 # Raise errors inside |error_paths| and warnings everywhere else.
1694 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571695 errors.extend(problems)
1696 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311697 warnings.extend(problems)
1698
1699 result = []
1700 if (warnings):
1701 result.append(output_api.PresubmitPromptWarning(
1702 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571703 if (errors):
1704 result.append(output_api.PresubmitError(
1705 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311706 return result
1707
1708
Saagar Sanghavifceeaae2020-08-12 16:40:361709def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061710 """Make sure that banned functions are not used."""
1711 files = []
1712 pattern = input_api.re.compile(r'^#pragma\s+once',
1713 input_api.re.MULTILINE)
1714 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1715 if not f.LocalPath().endswith('.h'):
1716 continue
1717 contents = input_api.ReadFile(f)
1718 if pattern.search(contents):
1719 files.append(f)
1720
1721 if files:
1722 return [output_api.PresubmitError(
1723 'Do not use #pragma once in header files.\n'
1724 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1725 files)]
1726 return []
1727
[email protected]127f18ec2012-06-16 05:05:591728
Saagar Sanghavifceeaae2020-08-12 16:40:361729def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121730 """Checks to make sure we don't introduce use of foo ? true : false."""
1731 problems = []
1732 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1733 for f in input_api.AffectedFiles():
1734 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1735 continue
1736
1737 for line_num, line in f.ChangedContents():
1738 if pattern.match(line):
1739 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1740
1741 if not problems:
1742 return []
1743 return [output_api.PresubmitPromptWarning(
1744 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1745 '\n'.join(problems))]
1746
1747
Saagar Sanghavifceeaae2020-08-12 16:40:361748def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281749 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181750 change. Breaking - rules is an error, breaking ! rules is a
1751 warning.
1752 """
mohan.reddyf21db962014-10-16 12:26:471753 import sys
[email protected]55f9f382012-07-31 11:02:181754 # We need to wait until we have an input_api object and use this
1755 # roundabout construct to import checkdeps because this file is
1756 # eval-ed and thus doesn't have __file__.
1757 original_sys_path = sys.path
1758 try:
1759 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471760 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181761 import checkdeps
[email protected]55f9f382012-07-31 11:02:181762 from rules import Rule
1763 finally:
1764 # Restore sys.path to what it was before.
1765 sys.path = original_sys_path
1766
1767 added_includes = []
rhalavati08acd232017-04-03 07:23:281768 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241769 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181770 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061771 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501772 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081773 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061774 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501775 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081776 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061777 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501778 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081779 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181780
[email protected]26385172013-05-09 23:11:351781 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181782
1783 error_descriptions = []
1784 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281785 error_subjects = set()
1786 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361787
[email protected]55f9f382012-07-31 11:02:181788 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1789 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081790 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181791 description_with_path = '%s\n %s' % (path, rule_description)
1792 if rule_type == Rule.DISALLOW:
1793 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281794 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181795 else:
1796 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281797 warning_subjects.add("#includes")
1798
1799 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1800 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081801 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281802 description_with_path = '%s\n %s' % (path, rule_description)
1803 if rule_type == Rule.DISALLOW:
1804 error_descriptions.append(description_with_path)
1805 error_subjects.add("imports")
1806 else:
1807 warning_descriptions.append(description_with_path)
1808 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181809
Jinsuk Kim5a092672017-10-24 22:42:241810 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021811 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081812 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241813 description_with_path = '%s\n %s' % (path, rule_description)
1814 if rule_type == Rule.DISALLOW:
1815 error_descriptions.append(description_with_path)
1816 error_subjects.add("imports")
1817 else:
1818 warning_descriptions.append(description_with_path)
1819 warning_subjects.add("imports")
1820
[email protected]55f9f382012-07-31 11:02:181821 results = []
1822 if error_descriptions:
1823 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281824 'You added one or more %s that violate checkdeps rules.'
1825 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181826 error_descriptions))
1827 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421828 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281829 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181830 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281831 '%s? See relevant DEPS file(s) for details and contacts.' %
1832 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181833 warning_descriptions))
1834 return results
1835
1836
Saagar Sanghavifceeaae2020-08-12 16:40:361837def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:221838 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151839 if input_api.platform == 'win32':
1840 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291841 checkperms_tool = input_api.os_path.join(
1842 input_api.PresubmitLocalPath(),
1843 'tools', 'checkperms', 'checkperms.py')
1844 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471845 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391846 with input_api.CreateTemporaryFile() as file_list:
1847 for f in input_api.AffectedFiles():
1848 # checkperms.py file/directory arguments must be relative to the
1849 # repository.
Dirk Prankee3c9c62d2021-05-18 18:35:591850 file_list.write((f.LocalPath() + '\n').encode('utf8'))
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391851 file_list.close()
1852 args += ['--file-list', file_list.name]
1853 try:
1854 input_api.subprocess.check_output(args)
1855 return []
1856 except input_api.subprocess.CalledProcessError as error:
1857 return [output_api.PresubmitError(
1858 'checkperms.py failed:',
Ari Chivukula45f58dd52021-06-18 04:23:041859 long_text=error.output.decode('utf-8', 'ignore'))]
[email protected]fbcafe5a2012-08-08 15:31:221860
1861
Saagar Sanghavifceeaae2020-08-12 16:40:361862def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:491863 """Makes sure we don't include ui/aura/window_property.h
1864 in header files.
1865 """
1866 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1867 errors = []
1868 for f in input_api.AffectedFiles():
1869 if not f.LocalPath().endswith('.h'):
1870 continue
1871 for line_num, line in f.ChangedContents():
1872 if pattern.match(line):
1873 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1874
1875 results = []
1876 if errors:
1877 results.append(output_api.PresubmitError(
1878 'Header files should not include ui/aura/window_property.h', errors))
1879 return results
1880
1881
Omer Katzcc77ea92021-04-26 10:23:281882def CheckNoInternalHeapIncludes(input_api, output_api):
1883 """Makes sure we don't include any headers from
1884 third_party/blink/renderer/platform/heap/impl or
1885 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1886 third_party/blink/renderer/platform/heap
1887 """
1888 impl_pattern = input_api.re.compile(
1889 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1890 v8_wrapper_pattern = input_api.re.compile(
1891 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"')
1892 file_filter = lambda f: not input_api.re.match(
1893 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1894 f.LocalPath())
1895 errors = []
1896
1897 for f in input_api.AffectedFiles(file_filter=file_filter):
1898 for line_num, line in f.ChangedContents():
1899 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1900 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1901
1902 results = []
1903 if errors:
1904 results.append(output_api.PresubmitError(
1905 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1906 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1907 'relevant counterparts from third_party/blink/renderer/platform/heap',
1908 errors))
1909 return results
1910
1911
[email protected]70ca77752012-11-20 03:45:031912def _CheckForVersionControlConflictsInFile(input_api, f):
1913 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1914 errors = []
1915 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161916 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231917 # First-level headers in markdown look a lot like version control
1918 # conflict markers. http://daringfireball.net/projects/markdown/basics
1919 continue
[email protected]70ca77752012-11-20 03:45:031920 if pattern.match(line):
1921 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1922 return errors
1923
1924
Saagar Sanghavifceeaae2020-08-12 16:40:361925def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:031926 """Usually this is not intentional and will cause a compile failure."""
1927 errors = []
1928 for f in input_api.AffectedFiles():
1929 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1930
1931 results = []
1932 if errors:
1933 results.append(output_api.PresubmitError(
1934 'Version control conflict markers found, please resolve.', errors))
1935 return results
1936
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201937
Saagar Sanghavifceeaae2020-08-12 16:40:361938def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:161939 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1940 errors = []
1941 for f in input_api.AffectedFiles():
1942 for line_num, line in f.ChangedContents():
1943 if pattern.search(line):
1944 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1945
1946 results = []
1947 if errors:
1948 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501949 'Found Google support URL addressed by answer number. Please replace '
1950 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161951 return results
1952
[email protected]70ca77752012-11-20 03:45:031953
Saagar Sanghavifceeaae2020-08-12 16:40:361954def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:441955 def FilterFile(affected_file):
1956 """Filter function for use with input_api.AffectedSourceFiles,
1957 below. This filters out everything except non-test files from
1958 top-level directories that generally speaking should not hard-code
1959 service URLs (e.g. src/android_webview/, src/content/ and others).
1960 """
1961 return input_api.FilterSourceFile(
1962 affected_file,
James Cook24a504192020-07-23 00:08:441963 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
1964 files_to_skip=(_EXCLUDED_PATHS +
1965 _TEST_CODE_EXCLUDED_PATHS +
1966 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:441967
reillyi38965732015-11-16 18:27:331968 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1969 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461970 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1971 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441972 problems = [] # items are (filename, line_number, line)
1973 for f in input_api.AffectedSourceFiles(FilterFile):
1974 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461975 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441976 problems.append((f.LocalPath(), line_num, line))
1977
1978 if problems:
[email protected]f7051d52013-04-02 18:31:421979 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441980 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581981 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441982 [' %s:%d: %s' % (
1983 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031984 else:
1985 return []
[email protected]06e6d0ff2012-12-11 01:36:441986
1987
Saagar Sanghavifceeaae2020-08-12 16:40:361988def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:291989 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
1990 def FileFilter(affected_file):
1991 """Includes directories known to be Chrome OS only."""
1992 return input_api.FilterSourceFile(
1993 affected_file,
James Cook24a504192020-07-23 00:08:441994 files_to_check=('^ash/',
1995 '^chromeos/', # Top-level src/chromeos.
1996 '/chromeos/', # Any path component.
1997 '^components/arc',
1998 '^components/exo'),
1999 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292000
2001 prefs = []
2002 priority_prefs = []
2003 for f in input_api.AffectedFiles(file_filter=FileFilter):
2004 for line_num, line in f.ChangedContents():
2005 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2006 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2007 prefs.append(' %s' % line)
2008 if input_api.re.search(
2009 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2010 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2011 priority_prefs.append(' %s' % line)
2012
2013 results = []
2014 if (prefs):
2015 results.append(output_api.PresubmitPromptWarning(
2016 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2017 'by browser sync settings. If these prefs should be controlled by OS '
2018 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2019 if (priority_prefs):
2020 results.append(output_api.PresubmitPromptWarning(
2021 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2022 'controlled by browser sync settings. If these prefs should be '
2023 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2024 'instead.\n' + '\n'.join(prefs)))
2025 return results
2026
2027
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492028# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362029def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272030 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312031 The native_client_sdk directory is excluded because it has auto-generated PNG
2032 files for documentation.
[email protected]d2530012013-01-25 16:39:272033 """
[email protected]d2530012013-01-25 16:39:272034 errors = []
James Cook24a504192020-07-23 00:08:442035 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2036 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312037 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442038 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312039 for f in input_api.AffectedFiles(include_deletes=False,
2040 file_filter=file_filter):
2041 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272042
2043 results = []
2044 if errors:
2045 results.append(output_api.PresubmitError(
2046 'The name of PNG files should not have abbreviations. \n'
2047 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2048 'Contact [email protected] if you have questions.', errors))
2049 return results
2050
2051
Daniel Cheng4dcdb6b2017-04-13 08:30:172052def _ExtractAddRulesFromParsedDeps(parsed_deps):
2053 """Extract the rules that add dependencies from a parsed DEPS file.
2054
2055 Args:
2056 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2057 add_rules = set()
2058 add_rules.update([
2059 rule[1:] for rule in parsed_deps.get('include_rules', [])
2060 if rule.startswith('+') or rule.startswith('!')
2061 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502062 for _, rules in parsed_deps.get('specific_include_rules',
Dirk Prankee3c9c62d2021-05-18 18:35:592063 {}).items():
Daniel Cheng4dcdb6b2017-04-13 08:30:172064 add_rules.update([
2065 rule[1:] for rule in rules
2066 if rule.startswith('+') or rule.startswith('!')
2067 ])
2068 return add_rules
2069
2070
2071def _ParseDeps(contents):
2072 """Simple helper for parsing DEPS files."""
2073 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172074 class _VarImpl:
2075
2076 def __init__(self, local_scope):
2077 self._local_scope = local_scope
2078
2079 def Lookup(self, var_name):
2080 """Implements the Var syntax."""
2081 try:
2082 return self._local_scope['vars'][var_name]
2083 except KeyError:
2084 raise Exception('Var is not defined: %s' % var_name)
2085
2086 local_scope = {}
2087 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172088 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592089 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172090 }
Dirk Pranke1b9e06382021-05-14 01:16:222091
Dirk Prankee3c9c62d2021-05-18 18:35:592092 exec(contents, global_scope, local_scope)
Daniel Cheng4dcdb6b2017-04-13 08:30:172093 return local_scope
2094
2095
2096def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592097 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412098 a set of DEPS entries that we should look up.
2099
2100 For a directory (rather than a specific filename) we fake a path to
2101 a specific filename by adding /DEPS. This is chosen as a file that
2102 will seldom or never be subject to per-file include_rules.
2103 """
[email protected]2b438d62013-11-14 17:54:142104 # We ignore deps entries on auto-generated directories.
2105 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082106
Daniel Cheng4dcdb6b2017-04-13 08:30:172107 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2108 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2109
2110 added_deps = new_deps.difference(old_deps)
2111
[email protected]2b438d62013-11-14 17:54:142112 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172113 for added_dep in added_deps:
2114 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2115 continue
2116 # Assume that a rule that ends in .h is a rule for a specific file.
2117 if added_dep.endswith('.h'):
2118 results.add(added_dep)
2119 else:
2120 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082121 return results
2122
2123
Saagar Sanghavifceeaae2020-08-12 16:40:362124def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552125 """When a dependency prefixed with + is added to a DEPS file, we
2126 want to make sure that the change is reviewed by an OWNER of the
2127 target file or directory, to avoid layering violations from being
2128 introduced. This check verifies that this happens.
2129 """
Joey Mou57048132021-02-26 22:17:552130 # We rely on Gerrit's code-owners to check approvals.
2131 # input_api.gerrit is always set for Chromium, but other projects
2132 # might not use Gerrit.
2133 if not input_api.gerrit:
2134 return []
Edward Lesmes44feb2332021-03-19 01:27:522135 if (input_api.change.issue and
2136 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232137 # Skip OWNERS check when Owners-Override label is approved. This is intended
2138 # for global owners, trusted bots, and on-call sheriffs. Review is still
2139 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522140 return []
Edward Lesmes6fba51082021-01-20 04:20:232141
Daniel Cheng4dcdb6b2017-04-13 08:30:172142 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242143
2144 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492145 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242146 for f in input_api.AffectedFiles(include_deletes=False,
2147 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552148 filename = input_api.os_path.basename(f.LocalPath())
2149 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172150 virtual_depended_on_files.update(_CalculateAddedDeps(
2151 input_api.os_path,
2152 '\n'.join(f.OldContents()),
2153 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552154
[email protected]e871964c2013-05-13 14:14:552155 if not virtual_depended_on_files:
2156 return []
2157
2158 if input_api.is_committing:
2159 if input_api.tbr:
2160 return [output_api.PresubmitNotifyResult(
2161 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272162 if input_api.dry_run:
2163 return [output_api.PresubmitNotifyResult(
2164 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552165 if not input_api.change.issue:
2166 return [output_api.PresubmitError(
2167 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402168 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552169 output = output_api.PresubmitError
2170 else:
2171 output = output_api.PresubmitNotifyResult
2172
tandriied3b7e12016-05-12 14:38:502173 owner_email, reviewers = (
2174 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2175 input_api,
Edward Lesmesa3846442021-02-08 20:20:032176 None,
tandriied3b7e12016-05-12 14:38:502177 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552178
2179 owner_email = owner_email or input_api.change.author_email
2180
Edward Lesmesa3846442021-02-08 20:20:032181 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2182 virtual_depended_on_files, reviewers.union([owner_email]), [])
2183 missing_files = [
2184 f for f in virtual_depended_on_files
2185 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412186
2187 # We strip the /DEPS part that was added by
2188 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2189 # directory.
2190 def StripDeps(path):
2191 start_deps = path.rfind('/DEPS')
2192 if start_deps != -1:
2193 return path[:start_deps]
2194 else:
2195 return path
2196 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552197 for path in missing_files]
2198
2199 if unapproved_dependencies:
2200 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152201 output('You need LGTM from owners of depends-on paths in DEPS that were '
2202 'modified in this CL:\n %s' %
2203 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032204 suggested_owners = input_api.owners_client.SuggestOwners(
2205 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152206 output_list.append(output(
2207 'Suggested missing target path OWNERS:\n %s' %
2208 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552209 return output_list
2210
2211 return []
2212
2213
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492214# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362215def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492216 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442217 files_to_skip = (_EXCLUDED_PATHS +
2218 _TEST_CODE_EXCLUDED_PATHS +
2219 input_api.DEFAULT_FILES_TO_SKIP +
2220 (r"^base[\\/]logging\.h$",
2221 r"^base[\\/]logging\.cc$",
2222 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2223 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2224 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2225 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2226 r"startup_browser_creator\.cc$",
2227 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2228 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2229 r"diagnostics_writer\.cc$",
2230 r"^chrome[\\/]chrome_cleaner[\\/].*",
2231 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2232 r"dll_hash_main\.cc$",
2233 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2234 r"^chromecast[\\/]",
2235 r"^cloud_print[\\/]",
2236 r"^components[\\/]browser_watcher[\\/]"
2237 r"dump_stability_report_main_win.cc$",
2238 r"^components[\\/]media_control[\\/]renderer[\\/]"
2239 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352240 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2241 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442242 r"^components[\\/]zucchini[\\/].*",
2243 # TODO(peter): Remove exception. https://crbug.com/534537
2244 r"^content[\\/]browser[\\/]notifications[\\/]"
2245 r"notification_event_dispatcher_impl\.cc$",
2246 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2247 r"gl_helper_benchmark\.cc$",
2248 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2249 r"^courgette[\\/]courgette_tool\.cc$",
2250 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2251 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2252 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Sergey Ulanov6db14b4d62021-05-10 07:59:482253 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
James Cook24a504192020-07-23 00:08:442254 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2255 r"^ipc[\\/]ipc_logging\.cc$",
2256 r"^native_client_sdk[\\/]",
2257 r"^remoting[\\/]base[\\/]logging\.h$",
2258 r"^remoting[\\/]host[\\/].*",
2259 r"^sandbox[\\/]linux[\\/].*",
2260 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2261 r"dump_file_system.cc$",
2262 r"^tools[\\/]",
2263 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2264 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2265 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2266 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2267 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402268 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442269 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402270
thomasanderson625d3932017-03-29 07:16:582271 log_info = set([])
2272 printf = set([])
[email protected]85218562013-11-22 07:41:402273
2274 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582275 for _, line in f.ChangedContents():
2276 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2277 log_info.add(f.LocalPath())
2278 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2279 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372280
thomasanderson625d3932017-03-29 07:16:582281 if input_api.re.search(r"\bprintf\(", line):
2282 printf.add(f.LocalPath())
2283 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2284 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402285
2286 if log_info:
2287 return [output_api.PresubmitError(
2288 'These files spam the console log with LOG(INFO):',
2289 items=log_info)]
2290 if printf:
2291 return [output_api.PresubmitError(
2292 'These files spam the console log with printf/fprintf:',
2293 items=printf)]
2294 return []
2295
2296
Saagar Sanghavifceeaae2020-08-12 16:40:362297def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162298 """These types are all expected to hold locks while in scope and
2299 so should never be anonymous (which causes them to be immediately
2300 destroyed)."""
2301 they_who_must_be_named = [
2302 'base::AutoLock',
2303 'base::AutoReset',
2304 'base::AutoUnlock',
2305 'SkAutoAlphaRestore',
2306 'SkAutoBitmapShaderInstall',
2307 'SkAutoBlitterChoose',
2308 'SkAutoBounderCommit',
2309 'SkAutoCallProc',
2310 'SkAutoCanvasRestore',
2311 'SkAutoCommentBlock',
2312 'SkAutoDescriptor',
2313 'SkAutoDisableDirectionCheck',
2314 'SkAutoDisableOvalCheck',
2315 'SkAutoFree',
2316 'SkAutoGlyphCache',
2317 'SkAutoHDC',
2318 'SkAutoLockColors',
2319 'SkAutoLockPixels',
2320 'SkAutoMalloc',
2321 'SkAutoMaskFreeImage',
2322 'SkAutoMutexAcquire',
2323 'SkAutoPathBoundsUpdate',
2324 'SkAutoPDFRelease',
2325 'SkAutoRasterClipValidate',
2326 'SkAutoRef',
2327 'SkAutoTime',
2328 'SkAutoTrace',
2329 'SkAutoUnref',
2330 ]
2331 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2332 # bad: base::AutoLock(lock.get());
2333 # not bad: base::AutoLock lock(lock.get());
2334 bad_pattern = input_api.re.compile(anonymous)
2335 # good: new base::AutoLock(lock.get())
2336 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2337 errors = []
2338
2339 for f in input_api.AffectedFiles():
2340 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2341 continue
2342 for linenum, line in f.ChangedContents():
2343 if bad_pattern.search(line) and not good_pattern.search(line):
2344 errors.append('%s:%d' % (f.LocalPath(), linenum))
2345
2346 if errors:
2347 return [output_api.PresubmitError(
2348 'These lines create anonymous variables that need to be named:',
2349 items=errors)]
2350 return []
2351
2352
Saagar Sanghavifceeaae2020-08-12 16:40:362353def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532354 # Returns whether |template_str| is of the form <T, U...> for some types T
2355 # and U. Assumes that |template_str| is already in the form <...>.
2356 def HasMoreThanOneArg(template_str):
2357 # Level of <...> nesting.
2358 nesting = 0
2359 for c in template_str:
2360 if c == '<':
2361 nesting += 1
2362 elif c == '>':
2363 nesting -= 1
2364 elif c == ',' and nesting == 1:
2365 return True
2366 return False
2367
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492368 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102369 sources = lambda affected_file: input_api.FilterSourceFile(
2370 affected_file,
James Cook24a504192020-07-23 00:08:442371 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2372 input_api.DEFAULT_FILES_TO_SKIP),
2373 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552374
2375 # Pattern to capture a single "<...>" block of template arguments. It can
2376 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2377 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2378 # latter would likely require counting that < and > match, which is not
2379 # expressible in regular languages. Should the need arise, one can introduce
2380 # limited counting (matching up to a total number of nesting depth), which
2381 # should cover all practical cases for already a low nesting limit.
2382 template_arg_pattern = (
2383 r'<[^>]*' # Opening block of <.
2384 r'>([^<]*>)?') # Closing block of >.
2385 # Prefix expressing that whatever follows is not already inside a <...>
2386 # block.
2387 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102388 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552389 not_inside_template_arg_pattern
2390 + r'\bstd::unique_ptr'
2391 + template_arg_pattern
2392 + r'\(\)')
2393
2394 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2395 template_arg_no_array_pattern = (
2396 r'<[^>]*[^]]' # Opening block of <.
2397 r'>([^(<]*[^]]>)?') # Closing block of >.
2398 # Prefix saying that what follows is the start of an expression.
2399 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2400 # Suffix saying that what follows are call parentheses with a non-empty list
2401 # of arguments.
2402 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532403 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552404 return_construct_pattern = input_api.re.compile(
2405 start_of_expr_pattern
2406 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532407 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552408 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532409 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552410 + nonempty_arg_list_pattern)
2411
Vaclav Brozek851d9602018-04-04 16:13:052412 problems_constructor = []
2413 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102414 for f in input_api.AffectedSourceFiles(sources):
2415 for line_number, line in f.ChangedContents():
2416 # Disallow:
2417 # return std::unique_ptr<T>(foo);
2418 # bar = std::unique_ptr<T>(foo);
2419 # But allow:
2420 # return std::unique_ptr<T[]>(foo);
2421 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532422 # And also allow cases when the second template argument is present. Those
2423 # cases cannot be handled by std::make_unique:
2424 # return std::unique_ptr<T, U>(foo);
2425 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052426 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532427 return_construct_result = return_construct_pattern.search(line)
2428 if return_construct_result and not HasMoreThanOneArg(
2429 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052430 problems_constructor.append(
2431 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102432 # Disallow:
2433 # std::unique_ptr<T>()
2434 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052435 problems_nullptr.append(
2436 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2437
2438 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162439 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052440 errors.append(output_api.PresubmitError(
2441 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162442 problems_nullptr))
2443 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052444 errors.append(output_api.PresubmitError(
2445 'The following files use explicit std::unique_ptr constructor.'
2446 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162447 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102448 return errors
2449
2450
Saagar Sanghavifceeaae2020-08-12 16:40:362451def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082452 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522453 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082454 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522455 # If actions.xml is already included in the changelist, the PRESUBMIT
2456 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082457 return []
2458
Alexei Svitkine64505a92021-03-11 22:00:542459 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2460 files_to_skip = (_EXCLUDED_PATHS +
2461 _TEST_CODE_EXCLUDED_PATHS +
2462 input_api.DEFAULT_FILES_TO_SKIP )
2463 file_filter = lambda f: input_api.FilterSourceFile(
2464 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2465
[email protected]999261d2014-03-03 20:08:082466 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522467 current_actions = None
[email protected]999261d2014-03-03 20:08:082468 for f in input_api.AffectedFiles(file_filter=file_filter):
2469 for line_num, line in f.ChangedContents():
2470 match = input_api.re.search(action_re, line)
2471 if match:
[email protected]2f92dec2014-03-07 19:21:522472 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2473 # loaded only once.
2474 if not current_actions:
2475 with open('tools/metrics/actions/actions.xml') as actions_f:
2476 current_actions = actions_f.read()
2477 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082478 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522479 action = 'name="{0}"'.format(action_name)
2480 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082481 return [output_api.PresubmitPromptWarning(
2482 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522483 'tools/metrics/actions/actions.xml. Please run '
2484 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082485 % (f.LocalPath(), line_num, action_name))]
2486 return []
2487
2488
Daniel Cheng13ca61a882017-08-25 15:11:252489def _ImportJSONCommentEater(input_api):
2490 import sys
2491 sys.path = sys.path + [input_api.os_path.join(
2492 input_api.PresubmitLocalPath(),
2493 'tools', 'json_comment_eater')]
2494 import json_comment_eater
2495 return json_comment_eater
2496
2497
[email protected]99171a92014-06-03 08:44:472498def _GetJSONParseError(input_api, filename, eat_comments=True):
2499 try:
2500 contents = input_api.ReadFile(filename)
2501 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252502 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132503 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472504
2505 input_api.json.loads(contents)
2506 except ValueError as e:
2507 return e
2508 return None
2509
2510
2511def _GetIDLParseError(input_api, filename):
2512 try:
2513 contents = input_api.ReadFile(filename)
2514 idl_schema = input_api.os_path.join(
2515 input_api.PresubmitLocalPath(),
2516 'tools', 'json_schema_compiler', 'idl_schema.py')
2517 process = input_api.subprocess.Popen(
2518 [input_api.python_executable, idl_schema],
2519 stdin=input_api.subprocess.PIPE,
2520 stdout=input_api.subprocess.PIPE,
2521 stderr=input_api.subprocess.PIPE,
2522 universal_newlines=True)
2523 (_, error) = process.communicate(input=contents)
2524 return error or None
2525 except ValueError as e:
2526 return e
2527
2528
Saagar Sanghavifceeaae2020-08-12 16:40:362529def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472530 """Check that IDL and JSON files do not contain syntax errors."""
2531 actions = {
2532 '.idl': _GetIDLParseError,
2533 '.json': _GetJSONParseError,
2534 }
[email protected]99171a92014-06-03 08:44:472535 # Most JSON files are preprocessed and support comments, but these do not.
2536 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042537 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472538 ]
2539 # Only run IDL checker on files in these directories.
2540 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042541 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2542 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472543 ]
2544
2545 def get_action(affected_file):
2546 filename = affected_file.LocalPath()
2547 return actions.get(input_api.os_path.splitext(filename)[1])
2548
[email protected]99171a92014-06-03 08:44:472549 def FilterFile(affected_file):
2550 action = get_action(affected_file)
2551 if not action:
2552 return False
2553 path = affected_file.LocalPath()
2554
Erik Staab2dd72b12020-04-16 15:03:402555 if _MatchesFile(input_api,
2556 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2557 path):
[email protected]99171a92014-06-03 08:44:472558 return False
2559
2560 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162561 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472562 return False
2563 return True
2564
2565 results = []
2566 for affected_file in input_api.AffectedFiles(
2567 file_filter=FilterFile, include_deletes=False):
2568 action = get_action(affected_file)
2569 kwargs = {}
2570 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162571 _MatchesFile(input_api, json_no_comments_patterns,
2572 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472573 kwargs['eat_comments'] = False
2574 parse_error = action(input_api,
2575 affected_file.AbsoluteLocalPath(),
2576 **kwargs)
2577 if parse_error:
2578 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2579 (affected_file.LocalPath(), parse_error)))
2580 return results
2581
2582
Saagar Sanghavifceeaae2020-08-12 16:40:362583def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492584 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472585 import sys
[email protected]760deea2013-12-10 19:33:492586 original_sys_path = sys.path
2587 try:
2588 sys.path = sys.path + [input_api.os_path.join(
2589 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2590 import checkstyle
2591 finally:
2592 # Restore sys.path to what it was before.
2593 sys.path = original_sys_path
2594
2595 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092596 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442597 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492598
2599
Saagar Sanghavifceeaae2020-08-12 16:40:362600def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002601 """Checks to make sure devil is initialized correctly in python scripts."""
2602 script_common_initialize_pattern = input_api.re.compile(
2603 r'script_common\.InitializeEnvironment\(')
2604 devil_env_config_initialize = input_api.re.compile(
2605 r'devil_env\.config\.Initialize\(')
2606
2607 errors = []
2608
2609 sources = lambda affected_file: input_api.FilterSourceFile(
2610 affected_file,
James Cook24a504192020-07-23 00:08:442611 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2612 (r'^build[\\/]android[\\/]devil_chromium\.py',
2613 r'^third_party[\\/].*',)),
2614 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002615
2616 for f in input_api.AffectedSourceFiles(sources):
2617 for line_num, line in f.ChangedContents():
2618 if (script_common_initialize_pattern.search(line) or
2619 devil_env_config_initialize.search(line)):
2620 errors.append("%s:%d" % (f.LocalPath(), line_num))
2621
2622 results = []
2623
2624 if errors:
2625 results.append(output_api.PresubmitError(
2626 'Devil initialization should always be done using '
2627 'devil_chromium.Initialize() in the chromium project, to use better '
2628 'defaults for dependencies (ex. up-to-date version of adb).',
2629 errors))
2630
2631 return results
2632
2633
Sean Kau46e29bc2017-08-28 16:31:162634def _MatchesFile(input_api, patterns, path):
2635 for pattern in patterns:
2636 if input_api.re.search(pattern, path):
2637 return True
2638 return False
2639
2640
Daniel Cheng7052cdf2017-11-21 19:23:292641def _GetOwnersFilesToCheckForIpcOwners(input_api):
2642 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172643
Daniel Cheng7052cdf2017-11-21 19:23:292644 Returns:
2645 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2646 contain to cover IPC-related files with noparent reviewer rules.
2647 """
2648 # Whether or not a file affects IPC is (mostly) determined by a simple list
2649 # of filename patterns.
dchenge07de812016-06-20 19:27:172650 file_patterns = [
palmerb19a0932017-01-24 04:00:312651 # Legacy IPC:
dchenge07de812016-06-20 19:27:172652 '*_messages.cc',
2653 '*_messages*.h',
2654 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312655 # Mojo IPC:
dchenge07de812016-06-20 19:27:172656 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472657 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172658 '*_struct_traits*.*',
2659 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312660 '*.typemap',
2661 # Android native IPC:
2662 '*.aidl',
2663 # Blink uses a different file naming convention:
2664 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472665 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172666 '*StructTraits*.*',
2667 '*TypeConverter*.*',
2668 ]
2669
scottmg7a6ed5ba2016-11-04 18:22:042670 # These third_party directories do not contain IPCs, but contain files
2671 # matching the above patterns, which trigger false positives.
2672 exclude_paths = [
2673 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162674 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232675 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292676 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542677 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162678 # These files are just used to communicate between class loaders running
2679 # in the same process.
2680 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572681 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2682
scottmg7a6ed5ba2016-11-04 18:22:042683 ]
2684
dchenge07de812016-06-20 19:27:172685 # Dictionary mapping an OWNERS file path to Patterns.
2686 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2687 # rules ) to a PatternEntry.
2688 # PatternEntry is a dictionary with two keys:
2689 # - 'files': the files that are matched by this pattern
2690 # - 'rules': the per-file rules needed for this pattern
2691 # For example, if we expect OWNERS file to contain rules for *.mojom and
2692 # *_struct_traits*.*, Patterns might look like this:
2693 # {
2694 # '*.mojom': {
2695 # 'files': ...,
2696 # 'rules': [
2697 # 'per-file *.mojom=set noparent',
2698 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2699 # ],
2700 # },
2701 # '*_struct_traits*.*': {
2702 # 'files': ...,
2703 # 'rules': [
2704 # 'per-file *_struct_traits*.*=set noparent',
2705 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2706 # ],
2707 # },
2708 # }
2709 to_check = {}
2710
Daniel Cheng13ca61a882017-08-25 15:11:252711 def AddPatternToCheck(input_file, pattern):
2712 owners_file = input_api.os_path.join(
2713 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2714 if owners_file not in to_check:
2715 to_check[owners_file] = {}
2716 if pattern not in to_check[owners_file]:
2717 to_check[owners_file][pattern] = {
2718 'files': [],
2719 'rules': [
2720 'per-file %s=set noparent' % pattern,
2721 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2722 ]
2723 }
Vaclav Brozekd5de76a2018-03-17 07:57:502724 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252725
dchenge07de812016-06-20 19:27:172726 # Iterate through the affected files to see what we actually need to check
2727 # for. We should only nag patch authors about per-file rules if a file in that
2728 # directory would match that pattern. If a directory only contains *.mojom
2729 # files and no *_messages*.h files, we should only nag about rules for
2730 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252731 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262732 # Manifest files don't have a strong naming convention. Instead, try to find
2733 # affected .cc and .h files which look like they contain a manifest
2734 # definition.
2735 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2736 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2737 if (manifest_pattern.search(f.LocalPath()) and not
2738 test_manifest_pattern.search(f.LocalPath())):
2739 # We expect all actual service manifest files to contain at least one
2740 # qualified reference to service_manager::Manifest.
2741 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252742 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172743 for pattern in file_patterns:
2744 if input_api.fnmatch.fnmatch(
2745 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042746 skip = False
2747 for exclude in exclude_paths:
2748 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2749 skip = True
2750 break
2751 if skip:
2752 continue
Daniel Cheng13ca61a882017-08-25 15:11:252753 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172754 break
2755
Daniel Cheng7052cdf2017-11-21 19:23:292756 return to_check
2757
2758
Wez17c66962020-04-29 15:26:032759def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2760 """Adds OWNERS files to check for correct Fuchsia security owners."""
2761
2762 file_patterns = [
2763 # Component specifications.
2764 '*.cml', # Component Framework v2.
2765 '*.cmx', # Component Framework v1.
2766
2767 # Fuchsia IDL protocol specifications.
2768 '*.fidl',
2769 ]
2770
Joshua Peraza1ca6d392020-12-08 00:14:092771 # Don't check for owners files for changes in these directories.
2772 exclude_paths = [
2773 'third_party/crashpad/*',
2774 ]
2775
Wez17c66962020-04-29 15:26:032776 def AddPatternToCheck(input_file, pattern):
2777 owners_file = input_api.os_path.join(
2778 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2779 if owners_file not in to_check:
2780 to_check[owners_file] = {}
2781 if pattern not in to_check[owners_file]:
2782 to_check[owners_file][pattern] = {
2783 'files': [],
2784 'rules': [
2785 'per-file %s=set noparent' % pattern,
2786 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2787 ]
2788 }
2789 to_check[owners_file][pattern]['files'].append(input_file)
2790
2791 # Iterate through the affected files to see what we actually need to check
2792 # for. We should only nag patch authors about per-file rules if a file in that
2793 # directory would match that pattern.
2794 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092795 skip = False
2796 for exclude in exclude_paths:
2797 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2798 skip = True
2799 if skip:
2800 continue
2801
Wez17c66962020-04-29 15:26:032802 for pattern in file_patterns:
2803 if input_api.fnmatch.fnmatch(
2804 input_api.os_path.basename(f.LocalPath()), pattern):
2805 AddPatternToCheck(f, pattern)
2806 break
2807
2808 return to_check
2809
2810
Saagar Sanghavifceeaae2020-08-12 16:40:362811def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292812 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2813 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032814 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292815
2816 if to_check:
2817 # If there are any OWNERS files to check, there are IPC-related changes in
2818 # this CL. Auto-CC the review list.
2819 output_api.AppendCC('[email protected]')
2820
2821 # Go through the OWNERS files to check, filtering out rules that are already
2822 # present in that OWNERS file.
Dirk Prankee3c9c62d2021-05-18 18:35:592823 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172824 try:
Dirk Prankee3c9c62d2021-05-18 18:35:592825 with open(owners_file) as f:
dchenge07de812016-06-20 19:27:172826 lines = set(f.read().splitlines())
Jeffrey Youngf3a5c8c42021-05-14 21:56:102827 for entry in patterns.values():
dchenge07de812016-06-20 19:27:172828 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2829 ]
2830 except IOError:
2831 # No OWNERS file, so all the rules are definitely missing.
2832 continue
2833
2834 # All the remaining lines weren't found in OWNERS files, so emit an error.
2835 errors = []
Dirk Prankee3c9c62d2021-05-18 18:35:592836 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172837 missing_lines = []
2838 files = []
Dirk Prankee3c9c62d2021-05-18 18:35:592839 for _, entry in patterns.items():
dchenge07de812016-06-20 19:27:172840 missing_lines.extend(entry['rules'])
2841 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2842 if missing_lines:
2843 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052844 'Because of the presence of files:\n%s\n\n'
2845 '%s needs the following %d lines added:\n\n%s' %
2846 ('\n'.join(files), owners_file, len(missing_lines),
2847 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172848
2849 results = []
2850 if errors:
vabrf5ce3bf92016-07-11 14:52:412851 if input_api.is_committing:
2852 output = output_api.PresubmitError
2853 else:
2854 output = output_api.PresubmitPromptWarning
2855 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592856 'Found OWNERS files that need to be updated for IPC security ' +
2857 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172858 long_text='\n\n'.join(errors)))
2859
2860 return results
2861
2862
Robert Sesek2c905332020-05-06 23:17:132863def _GetFilesUsingSecurityCriticalFunctions(input_api):
2864 """Checks affected files for changes to security-critical calls. This
2865 function checks the full change diff, to catch both additions/changes
2866 and removals.
2867
2868 Returns a dict keyed by file name, and the value is a set of detected
2869 functions.
2870 """
2871 # Map of function pretty name (displayed in an error) to the pattern to
2872 # match it with.
2873 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:372874 'content::GetServiceSandboxType<>()':
2875 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:132876 }
2877 _PATTERNS_TO_CHECK = {
2878 k: input_api.re.compile(v)
2879 for k, v in _PATTERNS_TO_CHECK.items()
2880 }
2881
2882 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2883 files_to_functions = {}
2884 for f in input_api.AffectedFiles():
2885 diff = f.GenerateScmDiff()
2886 for line in diff.split('\n'):
2887 # Not using just RightHandSideLines() because removing a
2888 # call to a security-critical function can be just as important
2889 # as adding or changing the arguments.
2890 if line.startswith('-') or (line.startswith('+') and
2891 not line.startswith('++')):
2892 for name, pattern in _PATTERNS_TO_CHECK.items():
2893 if pattern.search(line):
2894 path = f.LocalPath()
2895 if not path in files_to_functions:
2896 files_to_functions[path] = set()
2897 files_to_functions[path].add(name)
2898 return files_to_functions
2899
2900
Saagar Sanghavifceeaae2020-08-12 16:40:362901def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:132902 """Checks that changes involving security-critical functions are reviewed
2903 by the security team.
2904 """
2905 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:122906 if not len(files_to_functions):
2907 return []
Robert Sesek2c905332020-05-06 23:17:132908
Edward Lesmes1e9fade2021-02-08 20:31:122909 owner_email, reviewers = (
2910 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2911 input_api,
2912 None,
2913 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:132914
Edward Lesmes1e9fade2021-02-08 20:31:122915 # Load the OWNERS file for security changes.
2916 owners_file = 'ipc/SECURITY_OWNERS'
2917 security_owners = input_api.owners_client.ListOwners(owners_file)
2918 has_security_owner = any([owner in reviewers for owner in security_owners])
2919 if has_security_owner:
2920 return []
Robert Sesek2c905332020-05-06 23:17:132921
Edward Lesmes1e9fade2021-02-08 20:31:122922 msg = 'The following files change calls to security-sensive functions\n' \
2923 'that need to be reviewed by {}.\n'.format(owners_file)
2924 for path, names in files_to_functions.items():
2925 msg += ' {}\n'.format(path)
2926 for name in names:
2927 msg += ' {}\n'.format(name)
2928 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:132929
Edward Lesmes1e9fade2021-02-08 20:31:122930 if input_api.is_committing:
2931 output = output_api.PresubmitError
2932 else:
2933 output = output_api.PresubmitNotifyResult
2934 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:132935
2936
Saagar Sanghavifceeaae2020-08-12 16:40:362937def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:262938 """Checks that set noparent is only used together with an OWNERS file in
2939 //build/OWNERS.setnoparent (see also
2940 //docs/code_reviews.md#owners-files-details)
2941 """
2942 errors = []
2943
2944 allowed_owners_files_file = 'build/OWNERS.setnoparent'
2945 allowed_owners_files = set()
2946 with open(allowed_owners_files_file, 'r') as f:
2947 for line in f:
2948 line = line.strip()
2949 if not line or line.startswith('#'):
2950 continue
2951 allowed_owners_files.add(line)
2952
2953 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
2954
2955 for f in input_api.AffectedFiles(include_deletes=False):
2956 if not f.LocalPath().endswith('OWNERS'):
2957 continue
2958
2959 found_owners_files = set()
2960 found_set_noparent_lines = dict()
2961
2962 # Parse the OWNERS file.
2963 for lineno, line in enumerate(f.NewContents(), 1):
2964 line = line.strip()
2965 if line.startswith('set noparent'):
2966 found_set_noparent_lines[''] = lineno
2967 if line.startswith('file://'):
2968 if line in allowed_owners_files:
2969 found_owners_files.add('')
2970 if line.startswith('per-file'):
2971 match = per_file_pattern.match(line)
2972 if match:
2973 glob = match.group(1).strip()
2974 directive = match.group(2).strip()
2975 if directive == 'set noparent':
2976 found_set_noparent_lines[glob] = lineno
2977 if directive.startswith('file://'):
2978 if directive in allowed_owners_files:
2979 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:152980
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:262981 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:402982 # listed in build/OWNERS.setnoparent. An exception is made for top level
2983 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:142984 if (f.LocalPath().count('/') != 1 and
2985 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:402986 for set_noparent_line in found_set_noparent_lines:
2987 if set_noparent_line in found_owners_files:
2988 continue
2989 errors.append(' %s:%d' % (f.LocalPath(),
2990 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:262991
2992 results = []
2993 if errors:
2994 if input_api.is_committing:
2995 output = output_api.PresubmitError
2996 else:
2997 output = output_api.PresubmitPromptWarning
2998 results.append(output(
2999 'Found the following "set noparent" restrictions in OWNERS files that '
3000 'do not include owners from build/OWNERS.setnoparent:',
3001 long_text='\n\n'.join(errors)))
3002 return results
3003
3004
Saagar Sanghavifceeaae2020-08-12 16:40:363005def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313006 """Checks that added or removed lines in non third party affected
3007 header files do not lead to new useless class or struct forward
3008 declaration.
jbriance9e12f162016-11-25 07:57:503009 """
3010 results = []
3011 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3012 input_api.re.MULTILINE)
3013 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3014 input_api.re.MULTILINE)
3015 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313016 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193017 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493018 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313019 continue
3020
jbriance9e12f162016-11-25 07:57:503021 if not f.LocalPath().endswith('.h'):
3022 continue
3023
3024 contents = input_api.ReadFile(f)
3025 fwd_decls = input_api.re.findall(class_pattern, contents)
3026 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3027
3028 useless_fwd_decls = []
3029 for decl in fwd_decls:
3030 count = sum(1 for _ in input_api.re.finditer(
3031 r'\b%s\b' % input_api.re.escape(decl), contents))
3032 if count == 1:
3033 useless_fwd_decls.append(decl)
3034
3035 if not useless_fwd_decls:
3036 continue
3037
3038 for line in f.GenerateScmDiff().splitlines():
3039 if (line.startswith('-') and not line.startswith('--') or
3040 line.startswith('+') and not line.startswith('++')):
3041 for decl in useless_fwd_decls:
3042 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3043 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243044 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503045 (f.LocalPath(), decl)))
3046 useless_fwd_decls.remove(decl)
3047
3048 return results
3049
Jinsong Fan91ebbbd2019-04-16 14:57:173050def _CheckAndroidDebuggableBuild(input_api, output_api):
3051 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3052 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3053 this is a debuggable build of Android.
3054 """
3055 build_type_check_pattern = input_api.re.compile(
3056 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3057
3058 errors = []
3059
3060 sources = lambda affected_file: input_api.FilterSourceFile(
3061 affected_file,
James Cook24a504192020-07-23 00:08:443062 files_to_skip=(_EXCLUDED_PATHS +
3063 _TEST_CODE_EXCLUDED_PATHS +
3064 input_api.DEFAULT_FILES_TO_SKIP +
3065 (r"^android_webview[\\/]support_library[\\/]"
3066 "boundary_interfaces[\\/]",
3067 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3068 r'^third_party[\\/].*',
3069 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3070 r"webview[\\/]chromium[\\/]License.*",)),
3071 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173072
3073 for f in input_api.AffectedSourceFiles(sources):
3074 for line_num, line in f.ChangedContents():
3075 if build_type_check_pattern.search(line):
3076 errors.append("%s:%d" % (f.LocalPath(), line_num))
3077
3078 results = []
3079
3080 if errors:
3081 results.append(output_api.PresubmitPromptWarning(
3082 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3083 ' Please use BuildInfo.isDebugAndroid() instead.',
3084 errors))
3085
3086 return results
jbriance9e12f162016-11-25 07:57:503087
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493088# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293089def _CheckAndroidToastUsage(input_api, output_api):
3090 """Checks that code uses org.chromium.ui.widget.Toast instead of
3091 android.widget.Toast (Chromium Toast doesn't force hardware
3092 acceleration on low-end devices, saving memory).
3093 """
3094 toast_import_pattern = input_api.re.compile(
3095 r'^import android\.widget\.Toast;$')
3096
3097 errors = []
3098
3099 sources = lambda affected_file: input_api.FilterSourceFile(
3100 affected_file,
James Cook24a504192020-07-23 00:08:443101 files_to_skip=(_EXCLUDED_PATHS +
3102 _TEST_CODE_EXCLUDED_PATHS +
3103 input_api.DEFAULT_FILES_TO_SKIP +
3104 (r'^chromecast[\\/].*',
3105 r'^remoting[\\/].*')),
3106 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293107
3108 for f in input_api.AffectedSourceFiles(sources):
3109 for line_num, line in f.ChangedContents():
3110 if toast_import_pattern.search(line):
3111 errors.append("%s:%d" % (f.LocalPath(), line_num))
3112
3113 results = []
3114
3115 if errors:
3116 results.append(output_api.PresubmitError(
3117 'android.widget.Toast usage is detected. Android toasts use hardware'
3118 ' acceleration, and can be\ncostly on low-end devices. Please use'
3119 ' org.chromium.ui.widget.Toast instead.\n'
3120 'Contact [email protected] if you have any questions.',
3121 errors))
3122
3123 return results
3124
3125
dgnaa68d5e2015-06-10 10:08:223126def _CheckAndroidCrLogUsage(input_api, output_api):
3127 """Checks that new logs using org.chromium.base.Log:
3128 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513129 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223130 """
pkotwicza1dd0b002016-05-16 14:41:043131
torne89540622017-03-24 19:41:303132 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043133 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303134 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043135 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303136 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043137 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3138 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093139 # The customtabs_benchmark is a small app that does not depend on Chromium
3140 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043141 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043142 ]
3143
dgnaa68d5e2015-06-10 10:08:223144 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123145 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3146 class_in_base_pattern = input_api.re.compile(
3147 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3148 has_some_log_import_pattern = input_api.re.compile(
3149 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223150 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553151 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223152 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463153 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553154 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223155
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463156 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443157 sources = lambda x: input_api.FilterSourceFile(x,
3158 files_to_check=[r'.*\.java$'],
3159 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123160
dgnaa68d5e2015-06-10 10:08:223161 tag_decl_errors = []
3162 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123163 tag_errors = []
dgn38736db2015-09-18 19:20:513164 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123165 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223166
3167 for f in input_api.AffectedSourceFiles(sources):
3168 file_content = input_api.ReadFile(f)
3169 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223170 # Per line checks
dgn87d9fb62015-06-12 09:15:123171 if (cr_log_import_pattern.search(file_content) or
3172 (class_in_base_pattern.search(file_content) and
3173 not has_some_log_import_pattern.search(file_content))):
3174 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223175 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553176 if rough_log_decl_pattern.search(line):
3177 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223178
3179 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123180 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223181 if match:
3182 has_modified_logs = True
3183
3184 # Make sure it uses "TAG"
3185 if not match.group('tag') == 'TAG':
3186 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123187 else:
3188 # Report non cr Log function calls in changed lines
3189 for line_num, line in f.ChangedContents():
3190 if log_call_pattern.search(line):
3191 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223192
3193 # Per file checks
3194 if has_modified_logs:
3195 # Make sure the tag is using the "cr" prefix and is not too long
3196 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513197 tag_name = match.group('name') if match else None
3198 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223199 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513200 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223201 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513202 elif '.' in tag_name:
3203 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223204
3205 results = []
3206 if tag_decl_errors:
3207 results.append(output_api.PresubmitPromptWarning(
3208 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513209 '"private static final String TAG = "<package tag>".\n'
3210 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223211 tag_decl_errors))
3212
3213 if tag_length_errors:
3214 results.append(output_api.PresubmitError(
3215 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513216 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223217 tag_length_errors))
3218
3219 if tag_errors:
3220 results.append(output_api.PresubmitPromptWarning(
3221 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3222 tag_errors))
3223
dgn87d9fb62015-06-12 09:15:123224 if util_log_errors:
dgn4401aa52015-04-29 16:26:173225 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123226 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3227 util_log_errors))
3228
dgn38736db2015-09-18 19:20:513229 if tag_with_dot_errors:
3230 results.append(output_api.PresubmitPromptWarning(
3231 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3232 tag_with_dot_errors))
3233
dgn4401aa52015-04-29 16:26:173234 return results
3235
3236
Yoland Yanb92fa522017-08-28 17:37:063237def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3238 """Checks that junit.framework.* is no longer used."""
3239 deprecated_junit_framework_pattern = input_api.re.compile(
3240 r'^import junit\.framework\..*;',
3241 input_api.re.MULTILINE)
3242 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443243 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063244 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133245 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063246 for line_num, line in f.ChangedContents():
3247 if deprecated_junit_framework_pattern.search(line):
3248 errors.append("%s:%d" % (f.LocalPath(), line_num))
3249
3250 results = []
3251 if errors:
3252 results.append(output_api.PresubmitError(
3253 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3254 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3255 ' if you have any question.', errors))
3256 return results
3257
3258
3259def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3260 """Checks that if new Java test classes have inheritance.
3261 Either the new test class is JUnit3 test or it is a JUnit4 test class
3262 with a base class, either case is undesirable.
3263 """
3264 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3265
3266 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443267 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063268 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133269 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063270 if not f.OldContents():
3271 class_declaration_start_flag = False
3272 for line_num, line in f.ChangedContents():
3273 if class_declaration_pattern.search(line):
3274 class_declaration_start_flag = True
3275 if class_declaration_start_flag and ' extends ' in line:
3276 errors.append('%s:%d' % (f.LocalPath(), line_num))
3277 if '{' in line:
3278 class_declaration_start_flag = False
3279
3280 results = []
3281 if errors:
3282 results.append(output_api.PresubmitPromptWarning(
3283 'The newly created files include Test classes that inherits from base'
3284 ' class. Please do not use inheritance in JUnit4 tests or add new'
3285 ' JUnit3 tests. Contact [email protected] if you have any'
3286 ' questions.', errors))
3287 return results
3288
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203289
yolandyan45001472016-12-21 21:12:423290def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3291 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3292 deprecated_annotation_import_pattern = input_api.re.compile(
3293 r'^import android\.test\.suitebuilder\.annotation\..*;',
3294 input_api.re.MULTILINE)
3295 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443296 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423297 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133298 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423299 for line_num, line in f.ChangedContents():
3300 if deprecated_annotation_import_pattern.search(line):
3301 errors.append("%s:%d" % (f.LocalPath(), line_num))
3302
3303 results = []
3304 if errors:
3305 results.append(output_api.PresubmitError(
3306 'Annotations in android.test.suitebuilder.annotation have been'
3307 ' deprecated since API level 24. Please use android.support.test.filters'
3308 ' from //third_party/android_support_test_runner:runner_java instead.'
3309 ' Contact [email protected] if you have any questions.', errors))
3310 return results
3311
3312
agrieve7b6479d82015-10-07 14:24:223313def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3314 """Checks if MDPI assets are placed in a correct directory."""
3315 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3316 ('/res/drawable/' in f.LocalPath() or
3317 '/res/drawable-ldrtl/' in f.LocalPath()))
3318 errors = []
3319 for f in input_api.AffectedFiles(include_deletes=False,
3320 file_filter=file_filter):
3321 errors.append(' %s' % f.LocalPath())
3322
3323 results = []
3324 if errors:
3325 results.append(output_api.PresubmitError(
3326 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3327 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3328 '/res/drawable-ldrtl/.\n'
3329 'Contact [email protected] if you have questions.', errors))
3330 return results
3331
3332
Nate Fischer535972b2017-09-16 01:06:183333def _CheckAndroidWebkitImports(input_api, output_api):
3334 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353335 android.webview.ValueCallback except in the WebView glue layer
3336 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183337 """
3338 valuecallback_import_pattern = input_api.re.compile(
3339 r'^import android\.webkit\.ValueCallback;$')
3340
3341 errors = []
3342
3343 sources = lambda affected_file: input_api.FilterSourceFile(
3344 affected_file,
James Cook24a504192020-07-23 00:08:443345 files_to_skip=(_EXCLUDED_PATHS +
3346 _TEST_CODE_EXCLUDED_PATHS +
3347 input_api.DEFAULT_FILES_TO_SKIP +
3348 (r'^android_webview[\\/]glue[\\/].*',
3349 r'^weblayer[\\/].*',)),
3350 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183351
3352 for f in input_api.AffectedSourceFiles(sources):
3353 for line_num, line in f.ChangedContents():
3354 if valuecallback_import_pattern.search(line):
3355 errors.append("%s:%d" % (f.LocalPath(), line_num))
3356
3357 results = []
3358
3359 if errors:
3360 results.append(output_api.PresubmitError(
3361 'android.webkit.ValueCallback usage is detected outside of the glue'
3362 ' layer. To stay compatible with the support library, android.webkit.*'
3363 ' classes should only be used inside the glue layer and'
3364 ' org.chromium.base.Callback should be used instead.',
3365 errors))
3366
3367 return results
3368
3369
Becky Zhou7c69b50992018-12-10 19:37:573370def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3371 """Checks Android XML styles """
3372 import sys
3373 original_sys_path = sys.path
3374 try:
3375 sys.path = sys.path + [input_api.os_path.join(
3376 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3377 import checkxmlstyle
3378 finally:
3379 # Restore sys.path to what it was before.
3380 sys.path = original_sys_path
3381
3382 if is_check_on_upload:
3383 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3384 else:
3385 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3386
3387
agrievef32bcc72016-04-04 14:57:403388class PydepsChecker(object):
3389 def __init__(self, input_api, pydeps_files):
3390 self._file_cache = {}
3391 self._input_api = input_api
3392 self._pydeps_files = pydeps_files
3393
3394 def _LoadFile(self, path):
3395 """Returns the list of paths within a .pydeps file relative to //."""
3396 if path not in self._file_cache:
3397 with open(path) as f:
3398 self._file_cache[path] = f.read()
3399 return self._file_cache[path]
3400
3401 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3402 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393403 pydeps_data = self._LoadFile(pydeps_path)
3404 uses_gn_paths = '--gn-paths' in pydeps_data
3405 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3406 if uses_gn_paths:
3407 # Paths look like: //foo/bar/baz
3408 return (e[2:] for e in entries)
3409 else:
3410 # Paths look like: path/relative/to/file.pydeps
3411 os_path = self._input_api.os_path
3412 pydeps_dir = os_path.dirname(pydeps_path)
3413 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403414
3415 def _CreateFilesToPydepsMap(self):
3416 """Returns a map of local_path -> list_of_pydeps."""
3417 ret = {}
3418 for pydep_local_path in self._pydeps_files:
3419 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3420 ret.setdefault(path, []).append(pydep_local_path)
3421 return ret
3422
3423 def ComputeAffectedPydeps(self):
3424 """Returns an iterable of .pydeps files that might need regenerating."""
3425 affected_pydeps = set()
3426 file_to_pydeps_map = None
3427 for f in self._input_api.AffectedFiles(include_deletes=True):
3428 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463429 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3430 # subrepositories. We can't figure out which files change, so re-check
3431 # all files.
3432 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383433 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3434 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403435 return self._pydeps_files
3436 elif local_path.endswith('.pydeps'):
3437 if local_path in self._pydeps_files:
3438 affected_pydeps.add(local_path)
3439 elif local_path.endswith('.py'):
3440 if file_to_pydeps_map is None:
3441 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3442 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3443 return affected_pydeps
3444
3445 def DetermineIfStale(self, pydeps_path):
3446 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413447 import difflib
John Budorick47ca3fe2018-02-10 00:53:103448 import os
3449
agrievef32bcc72016-04-04 14:57:403450 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033451 if old_pydeps_data:
3452 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393453 if '--output' not in cmd:
3454 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033455 old_contents = old_pydeps_data[2:]
3456 else:
3457 # A default cmd that should work in most cases (as long as pydeps filename
3458 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3459 # file is empty/new.
3460 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3461 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3462 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103463 env = dict(os.environ)
3464 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403465 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103466 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413467 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033468 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413469 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403470
3471
Tibor Goldschwendt360793f72019-06-25 18:23:493472def _ParseGclientArgs():
3473 args = {}
3474 with open('build/config/gclient_args.gni', 'r') as f:
3475 for line in f:
3476 line = line.strip()
3477 if not line or line.startswith('#'):
3478 continue
3479 attribute, value = line.split('=')
3480 args[attribute.strip()] = value.strip()
3481 return args
3482
3483
Saagar Sanghavifceeaae2020-08-12 16:40:363484def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403485 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403486 # This check is for Python dependency lists (.pydeps files), and involves
3487 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3488 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283489 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003490 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493491 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403492 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403493 results = []
3494 # First, check for new / deleted .pydeps.
3495 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033496 # Check whether we are running the presubmit check for a file in src.
3497 # f.LocalPath is relative to repo (src, or internal repo).
3498 # os_path.exists is relative to src repo.
3499 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3500 # to src and we can conclude that the pydeps is in src.
3501 if input_api.os_path.exists(f.LocalPath()):
3502 if f.LocalPath().endswith('.pydeps'):
3503 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3504 results.append(output_api.PresubmitError(
3505 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3506 'remove %s' % f.LocalPath()))
3507 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3508 results.append(output_api.PresubmitError(
3509 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3510 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403511
3512 if results:
3513 return results
3514
Mohamed Heikal7cd4d8312020-06-16 16:49:403515 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3516 affected_pydeps = set(checker.ComputeAffectedPydeps())
3517 affected_android_pydeps = affected_pydeps.intersection(
3518 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3519 if affected_android_pydeps and not is_android:
3520 results.append(output_api.PresubmitPromptOrNotify(
3521 'You have changed python files that may affect pydeps for android\n'
3522 'specific scripts. However, the relevant presumbit check cannot be\n'
3523 'run because you are not using an Android checkout. To validate that\n'
3524 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3525 'use the android-internal-presubmit optional trybot.\n'
3526 'Possibly stale pydeps files:\n{}'.format(
3527 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403528
Mohamed Heikal7cd4d8312020-06-16 16:49:403529 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3530 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403531 try:
phajdan.jr0d9878552016-11-04 10:49:413532 result = checker.DetermineIfStale(pydep_path)
3533 if result:
3534 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403535 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413536 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3537 'To regenerate, run:\n\n %s' %
3538 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403539 except input_api.subprocess.CalledProcessError as error:
3540 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3541 long_text=error.output)]
3542
3543 return results
3544
3545
Saagar Sanghavifceeaae2020-08-12 16:40:363546def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433547 """Checks to make sure no header files have |Singleton<|."""
3548 def FileFilter(affected_file):
3549 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443550 files_to_skip = (_EXCLUDED_PATHS +
3551 input_api.DEFAULT_FILES_TO_SKIP +
3552 (r"^base[\\/]memory[\\/]singleton\.h$",
3553 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3554 r"quic_singleton_impl\.h$"))
3555 return input_api.FilterSourceFile(affected_file,
3556 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433557
sergeyu34d21222015-09-16 00:11:443558 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433559 files = []
3560 for f in input_api.AffectedSourceFiles(FileFilter):
3561 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3562 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3563 contents = input_api.ReadFile(f)
3564 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243565 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433566 pattern.search(line)):
3567 files.append(f)
3568 break
3569
3570 if files:
yolandyandaabc6d2016-04-18 18:29:393571 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443572 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433573 'Please move them to an appropriate source file so that the ' +
3574 'template gets instantiated in a single compilation unit.',
3575 files) ]
3576 return []
3577
3578
[email protected]fd20b902014-05-09 02:14:533579_DEPRECATED_CSS = [
3580 # Values
3581 ( "-webkit-box", "flex" ),
3582 ( "-webkit-inline-box", "inline-flex" ),
3583 ( "-webkit-flex", "flex" ),
3584 ( "-webkit-inline-flex", "inline-flex" ),
3585 ( "-webkit-min-content", "min-content" ),
3586 ( "-webkit-max-content", "max-content" ),
3587
3588 # Properties
3589 ( "-webkit-background-clip", "background-clip" ),
3590 ( "-webkit-background-origin", "background-origin" ),
3591 ( "-webkit-background-size", "background-size" ),
3592 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443593 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533594
3595 # Functions
3596 ( "-webkit-gradient", "gradient" ),
3597 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3598 ( "-webkit-linear-gradient", "linear-gradient" ),
3599 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3600 ( "-webkit-radial-gradient", "radial-gradient" ),
3601 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3602]
3603
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203604
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493605# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363606def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533607 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253608 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343609 documentation and iOS CSS for dom distiller
3610 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253611 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533612 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493613 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443614 files_to_skip = (_EXCLUDED_PATHS +
3615 _TEST_CODE_EXCLUDED_PATHS +
3616 input_api.DEFAULT_FILES_TO_SKIP +
3617 (r"^chrome/common/extensions/docs",
3618 r"^chrome/docs",
3619 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3620 r"^components/neterror/resources/neterror.css",
3621 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253622 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443623 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533624 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3625 for line_num, line in fpath.ChangedContents():
3626 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023627 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533628 results.append(output_api.PresubmitError(
3629 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3630 (fpath.LocalPath(), line_num, deprecated_value, value)))
3631 return results
3632
mohan.reddyf21db962014-10-16 12:26:473633
Saagar Sanghavifceeaae2020-08-12 16:40:363634def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363635 bad_files = {}
3636 for f in input_api.AffectedFiles(include_deletes=False):
3637 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493638 not f.LocalPath().startswith('third_party/blink') and
3639 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363640 continue
3641
Daniel Bratell65b033262019-04-23 08:17:063642 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363643 continue
3644
Vaclav Brozekd5de76a2018-03-17 07:57:503645 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363646 if "#include" in line and "../" in line]
3647 if not relative_includes:
3648 continue
3649 bad_files[f.LocalPath()] = relative_includes
3650
3651 if not bad_files:
3652 return []
3653
3654 error_descriptions = []
Dirk Prankee3c9c62d2021-05-18 18:35:593655 for file_path, bad_lines in bad_files.items():
rlanday6802cf632017-05-30 17:48:363656 error_description = file_path
3657 for line in bad_lines:
3658 error_description += '\n ' + line
3659 error_descriptions.append(error_description)
3660
3661 results = []
3662 results.append(output_api.PresubmitError(
3663 'You added one or more relative #include paths (including "../").\n'
3664 'These shouldn\'t be used because they can be used to include headers\n'
3665 'from code that\'s not correctly specified as a dependency in the\n'
3666 'relevant BUILD.gn file(s).',
3667 error_descriptions))
3668
3669 return results
3670
Takeshi Yoshinoe387aa32017-08-02 13:16:133671
Saagar Sanghavifceeaae2020-08-12 16:40:363672def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063673 """Check that nobody tries to include a cc file. It's a relatively
3674 common error which results in duplicate symbols in object
3675 files. This may not always break the build until someone later gets
3676 very confusing linking errors."""
3677 results = []
3678 for f in input_api.AffectedFiles(include_deletes=False):
3679 # We let third_party code do whatever it wants
3680 if (f.LocalPath().startswith('third_party') and
3681 not f.LocalPath().startswith('third_party/blink') and
3682 not f.LocalPath().startswith('third_party\\blink')):
3683 continue
3684
3685 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3686 continue
3687
3688 for _, line in f.ChangedContents():
3689 if line.startswith('#include "'):
3690 included_file = line.split('"')[1]
3691 if _IsCPlusPlusFile(input_api, included_file):
3692 # The most common naming for external files with C++ code,
3693 # apart from standard headers, is to call them foo.inc, but
3694 # Chromium sometimes uses foo-inc.cc so allow that as well.
3695 if not included_file.endswith(('.h', '-inc.cc')):
3696 results.append(output_api.PresubmitError(
3697 'Only header files or .inc files should be included in other\n'
3698 'C++ files. Compiling the contents of a cc file more than once\n'
3699 'will cause duplicate information in the build which may later\n'
3700 'result in strange link_errors.\n' +
3701 f.LocalPath() + ':\n ' +
3702 line))
3703
3704 return results
3705
3706
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203707def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3708 if not isinstance(key, ast.Str):
3709 return 'Key at line %d must be a string literal' % key.lineno
3710 if not isinstance(value, ast.Dict):
3711 return 'Value at line %d must be a dict' % value.lineno
3712 if len(value.keys) != 1:
3713 return 'Dict at line %d must have single entry' % value.lineno
3714 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3715 return (
3716 'Entry at line %d must have a string literal \'filepath\' as key' %
3717 value.lineno)
3718 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133719
Takeshi Yoshinoe387aa32017-08-02 13:16:133720
Sergey Ulanov4af16052018-11-08 02:41:463721def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203722 if not isinstance(key, ast.Str):
3723 return 'Key at line %d must be a string literal' % key.lineno
3724 if not isinstance(value, ast.List):
3725 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463726 for element in value.elts:
3727 if not isinstance(element, ast.Str):
3728 return 'Watchlist elements on line %d is not a string' % key.lineno
3729 if not email_regex.match(element.s):
3730 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3731 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203732 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133733
Takeshi Yoshinoe387aa32017-08-02 13:16:133734
Sergey Ulanov4af16052018-11-08 02:41:463735def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203736 mismatch_template = (
3737 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3738 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133739
Sergey Ulanov4af16052018-11-08 02:41:463740 email_regex = input_api.re.compile(
3741 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3742
3743 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203744 i = 0
3745 last_key = ''
3746 while True:
3747 if i >= len(wd_dict.keys):
3748 if i >= len(w_dict.keys):
3749 return None
3750 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3751 elif i >= len(w_dict.keys):
3752 return (
3753 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133754
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203755 wd_key = wd_dict.keys[i]
3756 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133757
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203758 result = _CheckWatchlistDefinitionsEntrySyntax(
3759 wd_key, wd_dict.values[i], ast)
3760 if result is not None:
3761 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133762
Sergey Ulanov4af16052018-11-08 02:41:463763 result = _CheckWatchlistsEntrySyntax(
3764 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203765 if result is not None:
3766 return 'Bad entry in WATCHLISTS dict: %s' % result
3767
3768 if wd_key.s != w_key.s:
3769 return mismatch_template % (
3770 '%s at line %d' % (wd_key.s, wd_key.lineno),
3771 '%s at line %d' % (w_key.s, w_key.lineno))
3772
3773 if wd_key.s < last_key:
3774 return (
3775 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3776 (wd_key.lineno, w_key.lineno))
3777 last_key = wd_key.s
3778
3779 i = i + 1
3780
3781
Sergey Ulanov4af16052018-11-08 02:41:463782def _CheckWATCHLISTSSyntax(expression, input_api):
3783 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203784 if not isinstance(expression, ast.Expression):
3785 return 'WATCHLISTS file must contain a valid expression'
3786 dictionary = expression.body
3787 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3788 return 'WATCHLISTS file must have single dict with exactly two entries'
3789
3790 first_key = dictionary.keys[0]
3791 first_value = dictionary.values[0]
3792 second_key = dictionary.keys[1]
3793 second_value = dictionary.values[1]
3794
3795 if (not isinstance(first_key, ast.Str) or
3796 first_key.s != 'WATCHLIST_DEFINITIONS' or
3797 not isinstance(first_value, ast.Dict)):
3798 return (
3799 'The first entry of the dict in WATCHLISTS file must be '
3800 'WATCHLIST_DEFINITIONS dict')
3801
3802 if (not isinstance(second_key, ast.Str) or
3803 second_key.s != 'WATCHLISTS' or
3804 not isinstance(second_value, ast.Dict)):
3805 return (
3806 'The second entry of the dict in WATCHLISTS file must be '
3807 'WATCHLISTS dict')
3808
Sergey Ulanov4af16052018-11-08 02:41:463809 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133810
3811
Saagar Sanghavifceeaae2020-08-12 16:40:363812def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133813 for f in input_api.AffectedFiles(include_deletes=False):
3814 if f.LocalPath() == 'WATCHLISTS':
3815 contents = input_api.ReadFile(f, 'r')
3816
3817 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203818 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133819 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203820 # Get an AST tree for it and scan the tree for detailed style checking.
3821 expression = input_api.ast.parse(
3822 contents, filename='WATCHLISTS', mode='eval')
3823 except ValueError as e:
3824 return [output_api.PresubmitError(
3825 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3826 except SyntaxError as e:
3827 return [output_api.PresubmitError(
3828 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3829 except TypeError as e:
3830 return [output_api.PresubmitError(
3831 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133832
Sergey Ulanov4af16052018-11-08 02:41:463833 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203834 if result is not None:
3835 return [output_api.PresubmitError(result)]
3836 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133837
3838 return []
3839
3840
Andrew Grieve1b290e4a22020-11-24 20:07:013841def CheckGnGlobForward(input_api, output_api):
3842 """Checks that forward_variables_from(invoker, "*") follows best practices.
3843
3844 As documented at //build/docs/writing_gn_templates.md
3845 """
3846 def gn_files(f):
3847 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3848
3849 problems = []
3850 for f in input_api.AffectedSourceFiles(gn_files):
3851 for line_num, line in f.ChangedContents():
3852 if 'forward_variables_from(invoker, "*")' in line:
3853 problems.append(
3854 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3855 f.LocalPath(), line_num))
3856
3857 if problems:
3858 return [output_api.PresubmitPromptWarning(
3859 'forward_variables_from("*") without exclusions',
3860 items=sorted(problems),
3861 long_text=('The variables "visibilty" and "test_only" should be '
3862 'explicitly listed in forward_variables_from(). For more '
3863 'details, see:\n'
3864 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
3865 'build/docs/writing_gn_templates.md'
3866 '#Using-forward_variables_from'))]
3867 return []
3868
3869
Saagar Sanghavifceeaae2020-08-12 16:40:363870def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193871 """Checks that newly added header files have corresponding GN changes.
3872 Note that this is only a heuristic. To be precise, run script:
3873 build/check_gn_headers.py.
3874 """
3875
3876 def headers(f):
3877 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443878 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193879
3880 new_headers = []
3881 for f in input_api.AffectedSourceFiles(headers):
3882 if f.Action() != 'A':
3883 continue
3884 new_headers.append(f.LocalPath())
3885
3886 def gn_files(f):
James Cook24a504192020-07-23 00:08:443887 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193888
3889 all_gn_changed_contents = ''
3890 for f in input_api.AffectedSourceFiles(gn_files):
3891 for _, line in f.ChangedContents():
3892 all_gn_changed_contents += line
3893
3894 problems = []
3895 for header in new_headers:
3896 basename = input_api.os_path.basename(header)
3897 if basename not in all_gn_changed_contents:
3898 problems.append(header)
3899
3900 if problems:
3901 return [output_api.PresubmitPromptWarning(
3902 'Missing GN changes for new header files', items=sorted(problems),
3903 long_text='Please double check whether newly added header files need '
3904 'corresponding changes in gn or gni files.\nThis checking is only a '
3905 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3906 'Read https://crbug.com/661774 for more info.')]
3907 return []
3908
3909
Saagar Sanghavifceeaae2020-08-12 16:40:363910def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:023911 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3912
3913 This assumes we won't intentionally reference one product from the other
3914 product.
3915 """
3916 all_problems = []
3917 test_cases = [{
3918 "filename_postfix": "google_chrome_strings.grd",
3919 "correct_name": "Chrome",
3920 "incorrect_name": "Chromium",
3921 }, {
3922 "filename_postfix": "chromium_strings.grd",
3923 "correct_name": "Chromium",
3924 "incorrect_name": "Chrome",
3925 }]
3926
3927 for test_case in test_cases:
3928 problems = []
3929 filename_filter = lambda x: x.LocalPath().endswith(
3930 test_case["filename_postfix"])
3931
3932 # Check each new line. Can yield false positives in multiline comments, but
3933 # easier than trying to parse the XML because messages can have nested
3934 # children, and associating message elements with affected lines is hard.
3935 for f in input_api.AffectedSourceFiles(filename_filter):
3936 for line_num, line in f.ChangedContents():
3937 if "<message" in line or "<!--" in line or "-->" in line:
3938 continue
3939 if test_case["incorrect_name"] in line:
3940 problems.append(
3941 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3942
3943 if problems:
3944 message = (
3945 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3946 % (test_case["correct_name"], test_case["correct_name"],
3947 test_case["incorrect_name"]))
3948 all_problems.append(
3949 output_api.PresubmitPromptWarning(message, items=problems))
3950
3951 return all_problems
3952
3953
Saagar Sanghavifceeaae2020-08-12 16:40:363954def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:363955 """Avoid large files, especially binary files, in the repository since
3956 git doesn't scale well for those. They will be in everyone's repo
3957 clones forever, forever making Chromium slower to clone and work
3958 with."""
3959
3960 # Uploading files to cloud storage is not trivial so we don't want
3961 # to set the limit too low, but the upper limit for "normal" large
3962 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
3963 # anything over 20 MB is exceptional.
3964 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
3965
3966 too_large_files = []
3967 for f in input_api.AffectedFiles():
3968 # Check both added and modified files (but not deleted files).
3969 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:383970 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:363971 if size > TOO_LARGE_FILE_SIZE_LIMIT:
3972 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
3973
3974 if too_large_files:
3975 message = (
3976 'Do not commit large files to git since git scales badly for those.\n' +
3977 'Instead put the large files in cloud storage and use DEPS to\n' +
3978 'fetch them.\n' + '\n'.join(too_large_files)
3979 )
3980 return [output_api.PresubmitError(
3981 'Too large files found in commit', long_text=message + '\n')]
3982 else:
3983 return []
3984
Max Morozb47503b2019-08-08 21:03:273985
Saagar Sanghavifceeaae2020-08-12 16:40:363986def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:273987 """Checks specific for fuzz target sources."""
3988 EXPORTED_SYMBOLS = [
3989 'LLVMFuzzerInitialize',
3990 'LLVMFuzzerCustomMutator',
3991 'LLVMFuzzerCustomCrossOver',
3992 'LLVMFuzzerMutate',
3993 ]
3994
3995 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
3996
3997 def FilterFile(affected_file):
3998 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:443999 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4000 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274001
4002 return input_api.FilterSourceFile(
4003 affected_file,
James Cook24a504192020-07-23 00:08:444004 files_to_check=[files_to_check],
4005 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274006
4007 files_with_missing_header = []
4008 for f in input_api.AffectedSourceFiles(FilterFile):
4009 contents = input_api.ReadFile(f, 'r')
4010 if REQUIRED_HEADER in contents:
4011 continue
4012
4013 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4014 files_with_missing_header.append(f.LocalPath())
4015
4016 if not files_with_missing_header:
4017 return []
4018
4019 long_text = (
4020 'If you define any of the libFuzzer optional functions (%s), it is '
4021 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4022 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4023 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4024 'to access command line arguments passed to the fuzzer. Instead, prefer '
4025 'static initialization and shared resources as documented in '
John Palmer0e0f72bf2021-06-07 09:10:204026 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
Max Morozb47503b2019-08-08 21:03:274027 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4028 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4029 )
4030
4031 return [output_api.PresubmitPromptWarning(
4032 message="Missing '%s' in:" % REQUIRED_HEADER,
4033 items=files_with_missing_header,
4034 long_text=long_text)]
4035
4036
Mohamed Heikald048240a2019-11-12 16:57:374037def _CheckNewImagesWarning(input_api, output_api):
4038 """
4039 Warns authors who add images into the repo to make sure their images are
4040 optimized before committing.
4041 """
4042 images_added = False
4043 image_paths = []
4044 errors = []
4045 filter_lambda = lambda x: input_api.FilterSourceFile(
4046 x,
James Cook24a504192020-07-23 00:08:444047 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4048 + input_api.DEFAULT_FILES_TO_SKIP),
4049 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374050 )
4051 for f in input_api.AffectedFiles(
4052 include_deletes=False, file_filter=filter_lambda):
4053 local_path = f.LocalPath().lower()
4054 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4055 images_added = True
4056 image_paths.append(f)
4057 if images_added:
4058 errors.append(output_api.PresubmitPromptWarning(
4059 'It looks like you are trying to commit some images. If these are '
4060 'non-test-only images, please make sure to read and apply the tips in '
4061 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4062 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4063 'FYI only and will not block your CL on the CQ.', image_paths))
4064 return errors
4065
4066
Saagar Sanghavifceeaae2020-08-12 16:40:364067def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574068 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224069 results = []
dgnaa68d5e2015-06-10 10:08:224070 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174071 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224072 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294073 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064074 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4075 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424076 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184077 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574078 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374079 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154080 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574081 return results
4082
Saagar Sanghavifceeaae2020-08-12 16:40:364083def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574084 """Groups commit checks that target android code."""
4085 results = []
4086 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224087 return results
4088
Chris Hall59f8d0c72020-05-01 07:31:194089# TODO(chrishall): could we additionally match on any path owned by
4090# ui/accessibility/OWNERS ?
4091_ACCESSIBILITY_PATHS = (
4092 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4093 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4094 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4095 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4096 r"^content[\\/]browser[\\/]accessibility[\\/]",
4097 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4098 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4099 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4100 r"^ui[\\/]accessibility[\\/]",
4101 r"^ui[\\/]views[\\/]accessibility[\\/]",
4102)
4103
Saagar Sanghavifceeaae2020-08-12 16:40:364104def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194105 """Checks that commits to accessibility code contain an AX-Relnotes field in
4106 their commit message."""
4107 def FileFilter(affected_file):
4108 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444109 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194110
4111 # Only consider changes affecting accessibility paths.
4112 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4113 return []
4114
Akihiro Ota08108e542020-05-20 15:30:534115 # AX-Relnotes can appear in either the description or the footer.
4116 # When searching the description, require 'AX-Relnotes:' to appear at the
4117 # beginning of a line.
4118 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4119 description_has_relnotes = any(ax_regex.match(line)
4120 for line in input_api.change.DescriptionText().lower().splitlines())
4121
4122 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4123 'AX-Relnotes', [])
4124 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194125 return []
4126
4127 # TODO(chrishall): link to Relnotes documentation in message.
4128 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4129 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4130 "user-facing changes"
4131 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4132 "user-facing effects"
4133 "\n if this is confusing or annoying then please contact members "
4134 "of ui/accessibility/OWNERS.")
4135
4136 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224137
seanmccullough4a9356252021-04-08 19:54:094138# string pattern, sequence of strings to show when pattern matches,
4139# error flag. True if match is a presubmit error, otherwise it's a warning.
4140_NON_INCLUSIVE_TERMS = (
4141 (
4142 # Note that \b pattern in python re is pretty particular. In this
4143 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4144 # ...' will not. This may require some tweaking to catch these cases
4145 # without triggering a lot of false positives. Leaving it naive and
4146 # less matchy for now.
4147 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4148 (
4149 'Please don\'t use blacklist, whitelist, ' # nocheck
4150 'or slave in your', # nocheck
4151 'code and make every effort to use other terms. Using "// nocheck"',
4152 '"# nocheck" or "<!-- nocheck -->"',
4153 'at the end of the offending line will bypass this PRESUBMIT error',
4154 'but avoid using this whenever possible. Reach out to',
4155 '[email protected] if you have questions'),
4156 True),)
4157
Saagar Sanghavifceeaae2020-08-12 16:40:364158def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394159 """Checks common to both upload and commit."""
4160 results = []
4161 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384162 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544163 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084164
4165 author = input_api.change.author_email
4166 if author and author not in _KNOWN_ROBOTS:
4167 results.extend(
4168 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4169
[email protected]9f919cc2013-07-31 03:04:044170 results.extend(
4171 input_api.canned_checks.CheckChangeHasNoTabs(
4172 input_api,
4173 output_api,
4174 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434175 results.extend(input_api.RunTests(
4176 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244177
Edward Lesmesce51df52020-08-04 22:10:174178 dirmd_bin = input_api.os_path.join(
4179 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4180 results.extend(input_api.RunTests(
4181 input_api.canned_checks.CheckDirMetadataFormat(
4182 input_api, output_api, dirmd_bin)))
4183 results.extend(
4184 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4185 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554186 results.extend(
4187 input_api.canned_checks.CheckNoNewMetadataInOwners(
4188 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094189 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4190 input_api, output_api,
4191 excluded_directories_relative_path = [
4192 'infra',
4193 'inclusive_language_presubmit_exempt_dirs.txt'
4194 ],
4195 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174196
Vaclav Brozekcdc7defb2018-03-20 09:54:354197 for f in input_api.AffectedFiles():
4198 path, name = input_api.os_path.split(f.LocalPath())
4199 if name == 'PRESUBMIT.py':
4200 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004201 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4202 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074203 # The PRESUBMIT.py file (and the directory containing it) might
4204 # have been affected by being moved or removed, so only try to
4205 # run the tests if they still exist.
Dirk Prankee3c9c62d2021-05-18 18:35:594206 use_python3 = False
4207 with open(f.LocalPath()) as fp:
4208 use_python3 = any(line.startswith('USE_PYTHON3 = True')
4209 for line in fp.readlines())
4210
Dirk Pranke38557312018-04-18 00:53:074211 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4212 input_api, output_api, full_path,
Dirk Prankee3c9c62d2021-05-18 18:35:594213 files_to_check=[r'^PRESUBMIT_test\.py$'],
4214 run_on_python2=not use_python3,
4215 run_on_python3=use_python3))
[email protected]22c9bd72011-03-27 16:47:394216 return results
[email protected]1f7b4172010-01-28 01:17:344217
[email protected]b337cb5b2011-01-23 21:24:054218
Saagar Sanghavifceeaae2020-08-12 16:40:364219def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494220 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4221 if f.LocalPath().endswith(('.orig', '.rej'))]
4222 if problems:
4223 return [output_api.PresubmitError(
4224 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034225 else:
4226 return []
[email protected]b8079ae4a2012-12-05 19:56:494227
4228
Saagar Sanghavifceeaae2020-08-12 16:40:364229def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214230 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4231 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4232 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074233 include_re = input_api.re.compile(
4234 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4235 extension_re = input_api.re.compile(r'\.[a-z]+$')
4236 errors = []
Bruce Dawsonaae5e652021-06-24 15:05:394237 for f in input_api.AffectedFiles(include_deletes=False):
Kent Tamura5a8755d2017-06-29 23:37:074238 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4239 continue
4240 found_line_number = None
4241 found_macro = None
Bruce Dawsonaae5e652021-06-24 15:05:394242 all_lines = input_api.ReadFile(f, 'r').splitlines()
4243 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074244 match = macro_re.search(line)
4245 if match:
4246 found_line_number = line_num
4247 found_macro = match.group(2)
4248 break
4249 if not found_line_number:
4250 continue
4251
Bruce Dawsonaae5e652021-06-24 15:05:394252 found_include_line = -1
4253 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074254 if include_re.search(line):
Bruce Dawsonaae5e652021-06-24 15:05:394255 found_include_line = line_num
Kent Tamura5a8755d2017-06-29 23:37:074256 break
Bruce Dawsonaae5e652021-06-24 15:05:394257 if found_include_line >= 0 and found_include_line < found_line_number:
Kent Tamura5a8755d2017-06-29 23:37:074258 continue
4259
4260 if not f.LocalPath().endswith('.h'):
4261 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4262 try:
4263 content = input_api.ReadFile(primary_header_path, 'r')
4264 if include_re.search(content):
4265 continue
4266 except IOError:
4267 pass
Bruce Dawsonaae5e652021-06-24 15:05:394268 errors.append('%s:%d %s macro is used without first including build/'
Kent Tamura5a8755d2017-06-29 23:37:074269 'build_config.h.'
4270 % (f.LocalPath(), found_line_number, found_macro))
4271 if errors:
4272 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4273 return []
4274
4275
Lei Zhang1c12a22f2021-05-12 11:28:454276def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
4277 stl_include_re = input_api.re.compile(
Lei Zhang0643e342021-05-12 18:02:124278 r'^#include\s+<('
Lei Zhang1c12a22f2021-05-12 11:28:454279 r'algorithm|'
4280 r'array|'
4281 r'limits|'
4282 r'list|'
4283 r'map|'
4284 r'memory|'
4285 r'queue|'
4286 r'set|'
4287 r'string|'
4288 r'unordered_map|'
4289 r'unordered_set|'
4290 r'utility|'
Lei Zhang0643e342021-05-12 18:02:124291 r'vector)>')
Lei Zhang1c12a22f2021-05-12 11:28:454292 std_namespace_re = input_api.re.compile(r'std::')
4293 errors = []
4294 for f in input_api.AffectedFiles():
4295 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4296 continue
4297
4298 uses_std_namespace = False
4299 has_stl_include = False
4300 for line in f.NewContents():
4301 if has_stl_include and uses_std_namespace:
4302 break
4303
4304 if not has_stl_include and stl_include_re.search(line):
4305 has_stl_include = True
4306 continue
4307
4308 if not uses_std_namespace and std_namespace_re.search(line):
4309 uses_std_namespace = True
4310 continue
4311
4312 if has_stl_include and not uses_std_namespace:
4313 errors.append('%s: Includes STL header(s) but does not reference std::'
4314 % f.LocalPath())
4315 if errors:
4316 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4317 return []
4318
4319
[email protected]b00342e7f2013-03-26 16:21:544320def _DidYouMeanOSMacro(bad_macro):
4321 try:
4322 return {'A': 'OS_ANDROID',
4323 'B': 'OS_BSD',
4324 'C': 'OS_CHROMEOS',
4325 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444326 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544327 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444328 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544329 'N': 'OS_NACL',
4330 'O': 'OS_OPENBSD',
4331 'P': 'OS_POSIX',
4332 'S': 'OS_SOLARIS',
4333 'W': 'OS_WIN'}[bad_macro[3].upper()]
4334 except KeyError:
4335 return ''
4336
4337
4338def _CheckForInvalidOSMacrosInFile(input_api, f):
4339 """Check for sensible looking, totally invalid OS macros."""
4340 preprocessor_statement = input_api.re.compile(r'^\s*#')
4341 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4342 results = []
4343 for lnum, line in f.ChangedContents():
4344 if preprocessor_statement.search(line):
4345 for match in os_macro.finditer(line):
4346 if not match.group(1) in _VALID_OS_MACROS:
4347 good = _DidYouMeanOSMacro(match.group(1))
4348 did_you_mean = ' (did you mean %s?)' % good if good else ''
4349 results.append(' %s:%d %s%s' % (f.LocalPath(),
4350 lnum,
4351 match.group(1),
4352 did_you_mean))
4353 return results
4354
4355
Saagar Sanghavifceeaae2020-08-12 16:40:364356def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544357 """Check all affected files for invalid OS macros."""
4358 bad_macros = []
tzik3f295992018-12-04 20:32:234359 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474360 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544361 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4362
4363 if not bad_macros:
4364 return []
4365
4366 return [output_api.PresubmitError(
4367 'Possibly invalid OS macro[s] found. Please fix your code\n'
4368 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4369
lliabraa35bab3932014-10-01 12:16:444370
4371def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4372 """Check all affected files for invalid "if defined" macros."""
4373 ALWAYS_DEFINED_MACROS = (
4374 "TARGET_CPU_PPC",
4375 "TARGET_CPU_PPC64",
4376 "TARGET_CPU_68K",
4377 "TARGET_CPU_X86",
4378 "TARGET_CPU_ARM",
4379 "TARGET_CPU_MIPS",
4380 "TARGET_CPU_SPARC",
4381 "TARGET_CPU_ALPHA",
4382 "TARGET_IPHONE_SIMULATOR",
4383 "TARGET_OS_EMBEDDED",
4384 "TARGET_OS_IPHONE",
4385 "TARGET_OS_MAC",
4386 "TARGET_OS_UNIX",
4387 "TARGET_OS_WIN32",
4388 )
4389 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4390 results = []
4391 for lnum, line in f.ChangedContents():
4392 for match in ifdef_macro.finditer(line):
4393 if match.group(1) in ALWAYS_DEFINED_MACROS:
4394 always_defined = ' %s is always defined. ' % match.group(1)
4395 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4396 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4397 lnum,
4398 always_defined,
4399 did_you_mean))
4400 return results
4401
4402
Saagar Sanghavifceeaae2020-08-12 16:40:364403def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444404 """Check all affected files for invalid "if defined" macros."""
4405 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054406 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444407 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054408 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214409 continue
lliabraa35bab3932014-10-01 12:16:444410 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4411 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4412
4413 if not bad_macros:
4414 return []
4415
4416 return [output_api.PresubmitError(
4417 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4418 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4419 bad_macros)]
4420
4421
Saagar Sanghavifceeaae2020-08-12 16:40:364422def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044423 """Check for same IPC rules described in
4424 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4425 """
4426 base_pattern = r'IPC_ENUM_TRAITS\('
4427 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4428 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4429
4430 problems = []
4431 for f in input_api.AffectedSourceFiles(None):
4432 local_path = f.LocalPath()
4433 if not local_path.endswith('.h'):
4434 continue
4435 for line_number, line in f.ChangedContents():
4436 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4437 problems.append(
4438 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4439
4440 if problems:
4441 return [output_api.PresubmitPromptWarning(
4442 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4443 else:
4444 return []
4445
[email protected]b00342e7f2013-03-26 16:21:544446
Saagar Sanghavifceeaae2020-08-12 16:40:364447def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054448 """Check to make sure no files being submitted have long paths.
4449 This causes issues on Windows.
4450 """
4451 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194452 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054453 local_path = f.LocalPath()
4454 # Windows has a path limit of 260 characters. Limit path length to 200 so
4455 # that we have some extra for the prefix on dev machines and the bots.
4456 if len(local_path) > 200:
4457 problems.append(local_path)
4458
4459 if problems:
4460 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4461 else:
4462 return []
4463
4464
Saagar Sanghavifceeaae2020-08-12 16:40:364465def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144466 """Check that header files have proper guards against multiple inclusion.
4467 If a file should not have such guards (and it probably should) then it
4468 should include the string "no-include-guard-because-multiply-included".
4469 """
Daniel Bratell6a75baef62018-06-04 10:04:454470 def is_chromium_header_file(f):
4471 # We only check header files under the control of the Chromium
4472 # project. That is, those outside third_party apart from
4473 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324474 # We also exclude *_message_generator.h headers as they use
4475 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454476 file_with_path = input_api.os_path.normpath(f.LocalPath())
4477 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324478 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454479 (not file_with_path.startswith('third_party') or
4480 file_with_path.startswith(
4481 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144482
4483 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344484 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144485
4486 errors = []
4487
Daniel Bratell6a75baef62018-06-04 10:04:454488 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144489 guard_name = None
4490 guard_line_number = None
4491 seen_guard_end = False
4492
4493 file_with_path = input_api.os_path.normpath(f.LocalPath())
4494 base_file_name = input_api.os_path.splitext(
4495 input_api.os_path.basename(file_with_path))[0]
4496 upper_base_file_name = base_file_name.upper()
4497
4498 expected_guard = replace_special_with_underscore(
4499 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144500
4501 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574502 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4503 # are too many (1000+) files with slight deviations from the
4504 # coding style. The most important part is that the include guard
4505 # is there, and that it's unique, not the name so this check is
4506 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144507 #
4508 # As code becomes more uniform, this could be made stricter.
4509
4510 guard_name_pattern_list = [
4511 # Anything with the right suffix (maybe with an extra _).
4512 r'\w+_H__?',
4513
Daniel Bratell39b5b062018-05-16 18:09:574514 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144515 r'\w+_h',
4516
4517 # Anything including the uppercase name of the file.
4518 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4519 upper_base_file_name)) + r'\w*',
4520 ]
4521 guard_name_pattern = '|'.join(guard_name_pattern_list)
4522 guard_pattern = input_api.re.compile(
4523 r'#ifndef\s+(' + guard_name_pattern + ')')
4524
4525 for line_number, line in enumerate(f.NewContents()):
4526 if 'no-include-guard-because-multiply-included' in line:
4527 guard_name = 'DUMMY' # To not trigger check outside the loop.
4528 break
4529
4530 if guard_name is None:
4531 match = guard_pattern.match(line)
4532 if match:
4533 guard_name = match.group(1)
4534 guard_line_number = line_number
4535
Daniel Bratell39b5b062018-05-16 18:09:574536 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454537 # don't match the chromium style guide, but new files should
4538 # get it right.
4539 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574540 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144541 errors.append(output_api.PresubmitPromptWarning(
4542 'Header using the wrong include guard name %s' % guard_name,
4543 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574544 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144545 else:
4546 # The line after #ifndef should have a #define of the same name.
4547 if line_number == guard_line_number + 1:
4548 expected_line = '#define %s' % guard_name
4549 if line != expected_line:
4550 errors.append(output_api.PresubmitPromptWarning(
4551 'Missing "%s" for include guard' % expected_line,
4552 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4553 'Expected: %r\nGot: %r' % (expected_line, line)))
4554
4555 if not seen_guard_end and line == '#endif // %s' % guard_name:
4556 seen_guard_end = True
4557 elif seen_guard_end:
4558 if line.strip() != '':
4559 errors.append(output_api.PresubmitPromptWarning(
4560 'Include guard %s not covering the whole file' % (
4561 guard_name), [f.LocalPath()]))
4562 break # Nothing else to check and enough to warn once.
4563
4564 if guard_name is None:
4565 errors.append(output_api.PresubmitPromptWarning(
4566 'Missing include guard %s' % expected_guard,
4567 [f.LocalPath()],
4568 'Missing include guard in %s\n'
4569 'Recommended name: %s\n'
4570 'This check can be disabled by having the string\n'
4571 'no-include-guard-because-multiply-included in the header.' %
4572 (f.LocalPath(), expected_guard)))
4573
4574 return errors
4575
4576
Saagar Sanghavifceeaae2020-08-12 16:40:364577def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234578 """Check source code and known ascii text files for Windows style line
4579 endings.
4580 """
Evan Stade6cfc964c12021-05-18 20:21:164581 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234582
4583 file_inclusion_pattern = (
4584 known_text_files,
Bruce Dawson6141d4a2021-06-08 15:56:114585 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4586 r'.+%s' % _HEADER_EXTENSIONS
mostynbb639aca52015-01-07 20:31:234587 )
4588
mostynbb639aca52015-01-07 20:31:234589 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534590 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444591 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534592 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504593 include_file = False
Bruce Dawsonb2cfdfe2021-06-10 19:01:204594 for line in input_api.ReadFile(f, 'r').splitlines(True):
mostynbb639aca52015-01-07 20:31:234595 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504596 include_file = True
4597 if include_file:
4598 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234599
4600 if problems:
4601 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4602 'these files to contain Windows style line endings?\n' +
4603 '\n'.join(problems))]
4604
4605 return []
4606
Evan Stade6cfc964c12021-05-18 20:21:164607def CheckIconFilesForLicenseHeaders(input_api, output_api):
4608 """Check that .icon files (which are fragments of C++) have license headers.
4609 """
4610
4611 icon_files = (r'.*\.icon$',)
4612
4613 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4614 return input_api.canned_checks.CheckLicense(
4615 input_api, output_api, source_file_filter=icons)
4616
Jose Magana2b456f22021-03-09 23:26:404617def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4618 """Check source code for use of Chrome App technologies being
4619 deprecated.
4620 """
4621
4622 def _CheckForDeprecatedTech(input_api, output_api,
4623 detection_list, files_to_check = None, files_to_skip = None):
4624
4625 if (files_to_check or files_to_skip):
4626 source_file_filter = lambda f: input_api.FilterSourceFile(
4627 f, files_to_check=files_to_check,
4628 files_to_skip=files_to_skip)
4629 else:
4630 source_file_filter = None
4631
4632 problems = []
4633
4634 for f in input_api.AffectedSourceFiles(source_file_filter):
4635 if f.Action() == 'D':
4636 continue
4637 for _, line in f.ChangedContents():
4638 if any( detect in line for detect in detection_list ):
4639 problems.append(f.LocalPath())
4640
4641 return problems
4642
4643 # to avoid this presubmit script triggering warnings
4644 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4645
4646 problems =[]
4647
4648 # NMF: any files with extensions .nmf or NMF
4649 _NMF_FILES = r'\.(nmf|NMF)$'
4650 problems += _CheckForDeprecatedTech(input_api, output_api,
4651 detection_list = [''], # any change to the file will trigger warning
4652 files_to_check = [ r'.+%s' % _NMF_FILES ])
4653
4654 # MANIFEST: any manifest.json that in its diff includes "app":
4655 _MANIFEST_FILES = r'(manifest\.json)$'
4656 problems += _CheckForDeprecatedTech(input_api, output_api,
4657 detection_list = ['"app":'],
4658 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4659
4660 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4661 problems += _CheckForDeprecatedTech(input_api, output_api,
4662 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4663 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4664
4665 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4666 problems += _CheckForDeprecatedTech(input_api, output_api,
4667 detection_list = ['#include "ppapi','#include <ppapi'],
4668 files_to_check = (
4669 r'.+%s' % _HEADER_EXTENSIONS,
4670 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4671 files_to_skip = [r"^ppapi[\\/]"] )
4672
Jose Magana2b456f22021-03-09 23:26:404673 if problems:
4674 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4675 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4676 ' PNaCl, PPAPI). See this blog post for more details:\n'
4677 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4678 'and this documentation for options to replace these technologies:\n'
4679 'https://developer.chrome.com/docs/apps/migration/\n'+
4680 '\n'.join(problems))]
4681
4682 return []
4683
mostynbb639aca52015-01-07 20:31:234684
Saagar Sanghavifceeaae2020-08-12 16:40:364685def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134686 """Checks that all source files use SYSLOG properly."""
4687 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364688 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564689 for line_number, line in f.ChangedContents():
4690 if 'SYSLOG' in line:
4691 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4692
pastarmovj89f7ee12016-09-20 14:58:134693 if syslog_files:
4694 return [output_api.PresubmitPromptWarning(
4695 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4696 ' calls.\nFiles to check:\n', items=syslog_files)]
4697 return []
4698
4699
[email protected]1f7b4172010-01-28 01:17:344700def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364701 if input_api.version < [2, 0, 0]:
4702 return [output_api.PresubmitError("Your depot_tools is out of date. "
4703 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4704 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344705 results = []
scottmg39b29952014-12-08 18:31:284706 results.extend(
jam93a6ee792017-02-08 23:59:224707 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544708 return results
[email protected]ca8d1982009-02-19 16:33:124709
4710
4711def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364712 if input_api.version < [2, 0, 0]:
4713 return [output_api.PresubmitError("Your depot_tools is out of date. "
4714 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4715 "but your version is %d.%d.%d" % tuple(input_api.version))]
4716
[email protected]fe5f57c52009-06-05 14:25:544717 results = []
[email protected]fe5f57c52009-06-05 14:25:544718 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274719 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344720 input_api,
4721 output_api,
[email protected]2fdd1f362013-01-16 03:56:034722 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274723
jam93a6ee792017-02-08 23:59:224724 results.extend(
4725 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544726 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4727 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384728 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4729 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414730 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4731 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544732 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144733
4734
Saagar Sanghavifceeaae2020-08-12 16:40:364735def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264736 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024737 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4738 # footer is set to true.
4739 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264740 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024741 footer.lower()
4742 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264743 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024744
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144745 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264746 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144747 import sys
4748 from io import StringIO
4749
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144750 new_or_added_paths = set(f.LocalPath()
4751 for f in input_api.AffectedFiles()
4752 if (f.Action() == 'A' or f.Action() == 'M'))
4753 removed_paths = set(f.LocalPath()
4754 for f in input_api.AffectedFiles(include_deletes=True)
4755 if f.Action() == 'D')
4756
Andrew Grieve0e8790c2020-09-03 17:27:324757 affected_grds = [
4758 f for f in input_api.AffectedFiles()
4759 if f.LocalPath().endswith(('.grd', '.grdp'))
4760 ]
4761 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164762 if not affected_grds:
4763 return []
4764
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144765 affected_png_paths = [f.AbsoluteLocalPath()
4766 for f in input_api.AffectedFiles()
4767 if (f.LocalPath().endswith('.png'))]
4768
4769 # Check for screenshots. Developers can upload screenshots using
4770 # tools/translation/upload_screenshots.py which finds and uploads
4771 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4772 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4773 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4774 #
4775 # The logic here is as follows:
4776 #
4777 # - If the CL has a .png file under the screenshots directory for a grd
4778 # file, warn the developer. Actual images should never be checked into the
4779 # Chrome repo.
4780 #
4781 # - If the CL contains modified or new messages in grd files and doesn't
4782 # contain the corresponding .sha1 files, warn the developer to add images
4783 # and upload them via tools/translation/upload_screenshots.py.
4784 #
4785 # - If the CL contains modified or new messages in grd files and the
4786 # corresponding .sha1 files, everything looks good.
4787 #
4788 # - If the CL contains removed messages in grd files but the corresponding
4789 # .sha1 files aren't removed, warn the developer to remove them.
4790 unnecessary_screenshots = []
4791 missing_sha1 = []
4792 unnecessary_sha1_files = []
4793
Rainhard Findlingfc31844c52020-05-15 09:58:264794 # This checks verifies that the ICU syntax of messages this CL touched is
4795 # valid, and reports any found syntax errors.
4796 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4797 # without developers being aware of them. Later on, such ICU syntax errors
4798 # break message extraction for translation, hence would block Chromium
4799 # translations until they are fixed.
4800 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144801
4802 def _CheckScreenshotAdded(screenshots_dir, message_id):
4803 sha1_path = input_api.os_path.join(
4804 screenshots_dir, message_id + '.png.sha1')
4805 if sha1_path not in new_or_added_paths:
4806 missing_sha1.append(sha1_path)
4807
4808
4809 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4810 sha1_path = input_api.os_path.join(
4811 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034812 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144813 unnecessary_sha1_files.append(sha1_path)
4814
Rainhard Findlingfc31844c52020-05-15 09:58:264815
4816 def _ValidateIcuSyntax(text, level, signatures):
4817 """Validates ICU syntax of a text string.
4818
4819 Check if text looks similar to ICU and checks for ICU syntax correctness
4820 in this case. Reports various issues with ICU syntax and values of
4821 variants. Supports checking of nested messages. Accumulate information of
4822 each ICU messages found in the text for further checking.
4823
4824 Args:
4825 text: a string to check.
4826 level: a number of current nesting level.
4827 signatures: an accumulator, a list of tuple of (level, variable,
4828 kind, variants).
4829
4830 Returns:
4831 None if a string is not ICU or no issue detected.
4832 A tuple of (message, start index, end index) if an issue detected.
4833 """
4834 valid_types = {
4835 'plural': (frozenset(
4836 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4837 frozenset(['=1', 'other'])),
4838 'selectordinal': (frozenset(
4839 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4840 frozenset(['one', 'other'])),
4841 'select': (frozenset(), frozenset(['other'])),
4842 }
4843
4844 # Check if the message looks like an attempt to use ICU
4845 # plural. If yes - check if its syntax strictly matches ICU format.
4846 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4847 if not like:
4848 signatures.append((level, None, None, None))
4849 return
4850
4851 # Check for valid prefix and suffix
4852 m = re.match(
4853 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4854 r'(plural|selectordinal|select),\s*'
4855 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4856 if not m:
4857 return (('This message looks like an ICU plural, '
4858 'but does not follow ICU syntax.'), like.start(), like.end())
4859 starting, variable, kind, variant_pairs = m.groups()
4860 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4861 if depth:
4862 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4863 len(text))
4864 first = text[0]
4865 ending = text[last_pos:]
4866 if not starting:
4867 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4868 last_pos)
4869 if not ending or '}' not in ending:
4870 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4871 last_pos)
4872 elif first != '{':
4873 return (
4874 ('Invalid ICU format. Extra characters at the start of a complex '
4875 'message (go/icu-message-migration): "%s"') %
4876 starting, 0, len(starting))
4877 elif ending != '}':
4878 return (('Invalid ICU format. Extra characters at the end of a complex '
4879 'message (go/icu-message-migration): "%s"')
4880 % ending, last_pos - 1, len(text) - 1)
4881 if kind not in valid_types:
4882 return (('Unknown ICU message type %s. '
4883 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4884 known, required = valid_types[kind]
4885 defined_variants = set()
4886 for variant, variant_range, value, value_range in variants:
4887 start, end = variant_range
4888 if variant in defined_variants:
4889 return ('Variant "%s" is defined more than once' % variant,
4890 start, end)
4891 elif known and variant not in known:
4892 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4893 start, end)
4894 defined_variants.add(variant)
4895 # Check for nested structure
4896 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4897 if res:
4898 return (res[0], res[1] + value_range[0] + 1,
4899 res[2] + value_range[0] + 1)
4900 missing = required - defined_variants
4901 if missing:
4902 return ('Required variants missing: %s' % ', '.join(missing), 0,
4903 len(text))
4904 signatures.append((level, variable, kind, defined_variants))
4905
4906
4907 def _ParseIcuVariants(text, offset=0):
4908 """Parse variants part of ICU complex message.
4909
4910 Builds a tuple of variant names and values, as well as
4911 their offsets in the input string.
4912
4913 Args:
4914 text: a string to parse
4915 offset: additional offset to add to positions in the text to get correct
4916 position in the complete ICU string.
4917
4918 Returns:
4919 List of tuples, each tuple consist of four fields: variant name,
4920 variant name span (tuple of two integers), variant value, value
4921 span (tuple of two integers).
4922 """
4923 depth, start, end = 0, -1, -1
4924 variants = []
4925 key = None
4926 for idx, char in enumerate(text):
4927 if char == '{':
4928 if not depth:
4929 start = idx
4930 chunk = text[end + 1:start]
4931 key = chunk.strip()
4932 pos = offset + end + 1 + chunk.find(key)
4933 span = (pos, pos + len(key))
4934 depth += 1
4935 elif char == '}':
4936 if not depth:
4937 return variants, depth, offset + idx
4938 depth -= 1
4939 if not depth:
4940 end = idx
4941 variants.append((key, span, text[start:end + 1], (offset + start,
4942 offset + end + 1)))
4943 return variants, depth, offset + end + 1
4944
meacer8c0d3832019-12-26 21:46:164945 try:
4946 old_sys_path = sys.path
4947 sys.path = sys.path + [input_api.os_path.join(
4948 input_api.PresubmitLocalPath(), 'tools', 'translation')]
4949 from helper import grd_helper
4950 finally:
4951 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144952
4953 for f in affected_grds:
4954 file_path = f.LocalPath()
4955 old_id_to_msg_map = {}
4956 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:384957 # Note that this code doesn't check if the file has been deleted. This is
4958 # OK because it only uses the old and new file contents and doesn't load
4959 # the file via its path.
4960 # It's also possible that a file's content refers to a renamed or deleted
4961 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
4962 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
4963 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144964 if file_path.endswith('.grdp'):
4965 if f.OldContents():
meacerff8a9b62019-12-10 19:43:584966 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:594967 '\n'.join(f.OldContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144968 if f.NewContents():
meacerff8a9b62019-12-10 19:43:584969 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:594970 '\n'.join(f.NewContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144971 else:
meacerff8a9b62019-12-10 19:43:584972 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144973 if f.OldContents():
meacerff8a9b62019-12-10 19:43:584974 old_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:594975 StringIO('\n'.join(f.OldContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144976 if f.NewContents():
meacerff8a9b62019-12-10 19:43:584977 new_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:594978 StringIO('\n'.join(f.NewContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144979
Rainhard Findlingd8d04372020-08-13 13:30:094980 grd_name, ext = input_api.os_path.splitext(
4981 input_api.os_path.basename(file_path))
4982 screenshots_dir = input_api.os_path.join(
4983 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
4984
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144985 # Compute added, removed and modified message IDs.
4986 old_ids = set(old_id_to_msg_map)
4987 new_ids = set(new_id_to_msg_map)
4988 added_ids = new_ids - old_ids
4989 removed_ids = old_ids - new_ids
4990 modified_ids = set([])
4991 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:354992 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:094993 != new_id_to_msg_map[key].ContentsAsXml('', True)):
4994 # The message content itself changed. Require an updated screenshot.
4995 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:354996 elif old_id_to_msg_map[key].attrs['meaning'] != \
4997 new_id_to_msg_map[key].attrs['meaning']:
4998 # The message meaning changed. Ensure there is a screenshot for it.
4999 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5000 if sha1_path not in new_or_added_paths and not \
5001 input_api.os_path.exists(sha1_path):
5002 # There is neither a previous screenshot nor is a new one added now.
5003 # Require a screenshot.
5004 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145005
Rainhard Findlingfc31844c52020-05-15 09:58:265006 if run_screenshot_check:
5007 # Check the screenshot directory for .png files. Warn if there is any.
5008 for png_path in affected_png_paths:
5009 if png_path.startswith(screenshots_dir):
5010 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145011
Rainhard Findlingfc31844c52020-05-15 09:58:265012 for added_id in added_ids:
5013 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145014
Rainhard Findlingfc31844c52020-05-15 09:58:265015 for modified_id in modified_ids:
5016 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145017
Rainhard Findlingfc31844c52020-05-15 09:58:265018 for removed_id in removed_ids:
5019 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5020
5021 # Check new and changed strings for ICU syntax errors.
5022 for key in added_ids.union(modified_ids):
5023 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5024 err = _ValidateIcuSyntax(msg, 0, [])
5025 if err is not None:
5026 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145027
5028 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265029 if run_screenshot_check:
5030 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005031 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265032 'Do not include actual screenshots in the changelist. Run '
5033 'tools/translate/upload_screenshots.py to upload them instead:',
5034 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145035
Rainhard Findlingfc31844c52020-05-15 09:58:265036 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005037 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265038 'You are adding or modifying UI strings.\n'
5039 'To ensure the best translations, take screenshots of the relevant UI '
5040 '(https://g.co/chrome/translation) and add these files to your '
5041 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145042
Rainhard Findlingfc31844c52020-05-15 09:58:265043 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005044 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265045 'You removed strings associated with these files. Remove:',
5046 sorted(unnecessary_sha1_files)))
5047 else:
5048 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5049 'screenshots check.'))
5050
5051 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075052 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265053 'ICU syntax errors were found in the following strings (problems or '
5054 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145055
5056 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125057
5058
Saagar Sanghavifceeaae2020-08-12 16:40:365059def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125060 repo_root=None,
5061 translation_expectations_path=None,
5062 grd_files=None):
5063 import sys
5064 affected_grds = [f for f in input_api.AffectedFiles()
5065 if (f.LocalPath().endswith('.grd') or
5066 f.LocalPath().endswith('.grdp'))]
5067 if not affected_grds:
5068 return []
5069
5070 try:
5071 old_sys_path = sys.path
5072 sys.path = sys.path + [
5073 input_api.os_path.join(
5074 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5075 from helper import git_helper
5076 from helper import translation_helper
5077 finally:
5078 sys.path = old_sys_path
5079
5080 # Check that translation expectations can be parsed and we can get a list of
5081 # translatable grd files. |repo_root| and |translation_expectations_path| are
5082 # only passed by tests.
5083 if not repo_root:
5084 repo_root = input_api.PresubmitLocalPath()
5085 if not translation_expectations_path:
5086 translation_expectations_path = input_api.os_path.join(
5087 repo_root, 'tools', 'gritsettings',
5088 'translation_expectations.pyl')
5089 if not grd_files:
5090 grd_files = git_helper.list_grds_in_repository(repo_root)
5091
dpapad8e21b472020-10-23 17:15:035092 # Ignore bogus grd files used only for testing
5093 # ui/webui/resoucres/tools/generate_grd.py.
5094 ignore_path = input_api.os_path.join(
5095 'ui', 'webui', 'resources', 'tools', 'tests')
Dirk Prankee3c9c62d2021-05-18 18:35:595096 grd_files = [p for p in grd_files if ignore_path not in p]
dpapad8e21b472020-10-23 17:15:035097
Mustafa Emre Acer51f2f742020-03-09 19:41:125098 try:
5099 translation_helper.get_translatable_grds(repo_root, grd_files,
5100 translation_expectations_path)
5101 except Exception as e:
5102 return [output_api.PresubmitNotifyResult(
5103 'Failed to get a list of translatable grd files. This happens when:\n'
5104 ' - One of the modified grd or grdp files cannot be parsed or\n'
5105 ' - %s is not updated.\n'
5106 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5107 return []
Ken Rockotc31f4832020-05-29 18:58:515108
5109
Saagar Sanghavifceeaae2020-08-12 16:40:365110def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515111 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095112 changed_mojoms = input_api.AffectedFiles(
5113 include_deletes=True,
5114 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515115 delta = []
5116 for mojom in changed_mojoms:
5117 old_contents = ''.join(mojom.OldContents()) or None
5118 new_contents = ''.join(mojom.NewContents()) or None
5119 delta.append({
5120 'filename': mojom.LocalPath(),
5121 'old': '\n'.join(mojom.OldContents()) or None,
5122 'new': '\n'.join(mojom.NewContents()) or None,
5123 })
5124
5125 process = input_api.subprocess.Popen(
5126 [input_api.python_executable,
5127 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5128 'public', 'tools', 'mojom',
5129 'check_stable_mojom_compatibility.py'),
5130 '--src-root', input_api.PresubmitLocalPath()],
5131 stdin=input_api.subprocess.PIPE,
5132 stdout=input_api.subprocess.PIPE,
5133 stderr=input_api.subprocess.PIPE,
5134 universal_newlines=True)
5135 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5136 if process.returncode:
5137 return [output_api.PresubmitError(
5138 'One or more [Stable] mojom definitions appears to have been changed '
5139 'in a way that is not backward-compatible.',
5140 long_text=error)]
5141 return []
Dominic Battre645d42342020-12-04 16:14:105142
5143def CheckDeprecationOfPreferences(input_api, output_api):
5144 """Removing a preference should come with a deprecation."""
5145
5146 def FilterFile(affected_file):
5147 """Accept only .cc files and the like."""
5148 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5149 files_to_skip = (_EXCLUDED_PATHS +
5150 _TEST_CODE_EXCLUDED_PATHS +
5151 input_api.DEFAULT_FILES_TO_SKIP)
5152 return input_api.FilterSourceFile(
5153 affected_file,
5154 files_to_check=file_inclusion_pattern,
5155 files_to_skip=files_to_skip)
5156
5157 def ModifiedLines(affected_file):
5158 """Returns a list of tuples (line number, line text) of added and removed
5159 lines.
5160
5161 Deleted lines share the same line number as the previous line.
5162
5163 This relies on the scm diff output describing each changed code section
5164 with a line of the form
5165
5166 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5167 """
5168 line_num = 0
5169 modified_lines = []
5170 for line in affected_file.GenerateScmDiff().splitlines():
5171 # Extract <new line num> of the patch fragment (see format above).
5172 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5173 if m:
5174 line_num = int(m.groups(1)[0])
5175 continue
5176 if ((line.startswith('+') and not line.startswith('++')) or
5177 (line.startswith('-') and not line.startswith('--'))):
5178 modified_lines.append((line_num, line))
5179
5180 if not line.startswith('-'):
5181 line_num += 1
5182 return modified_lines
5183
5184 def FindLineWith(lines, needle):
5185 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5186
5187 If 0 or >1 lines contain `needle`, -1 is returned.
5188 """
5189 matching_line_numbers = [
5190 # + 1 for 1-based counting of line numbers.
5191 i + 1 for i, line
5192 in enumerate(lines)
5193 if needle in line]
5194 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5195
5196 def ModifiedPrefMigration(affected_file):
5197 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5198 # Determine first and last lines of MigrateObsolete.*Pref functions.
5199 new_contents = affected_file.NewContents();
5200 range_1 = (
5201 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5202 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5203 range_2 = (
5204 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5205 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5206 if (-1 in range_1 + range_2):
5207 raise Exception(
5208 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5209
5210 # Check whether any of the modified lines are part of the
5211 # MigrateObsolete.*Pref functions.
5212 for line_nr, line in ModifiedLines(affected_file):
5213 if (range_1[0] <= line_nr <= range_1[1] or
5214 range_2[0] <= line_nr <= range_2[1]):
5215 return True
5216 return False
5217
5218 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5219 browser_prefs_file_pattern = input_api.re.compile(
5220 r'chrome/browser/prefs/browser_prefs.cc')
5221
5222 changes = input_api.AffectedFiles(include_deletes=True,
5223 file_filter=FilterFile)
5224 potential_problems = []
5225 for f in changes:
5226 for line in f.GenerateScmDiff().splitlines():
5227 # Check deleted lines for pref registrations.
5228 if (line.startswith('-') and not line.startswith('--') and
5229 register_pref_pattern.search(line)):
5230 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5231
5232 if browser_prefs_file_pattern.search(f.LocalPath()):
5233 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5234 # assume that they knew that they have to deprecate preferences and don't
5235 # warn.
5236 try:
5237 if ModifiedPrefMigration(f):
5238 return []
5239 except Exception as e:
5240 return [output_api.PresubmitError(str(e))]
5241
5242 if potential_problems:
5243 return [output_api.PresubmitPromptWarning(
5244 'Discovered possible removal of preference registrations.\n\n'
5245 'Please make sure to properly deprecate preferences by clearing their\n'
5246 'value for a couple of milestones before finally removing the code.\n'
5247 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195248 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5249 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105250 'This may be a false positive warning (e.g. if you move preference\n'
5251 'registrations to a different place).\n',
5252 potential_problems
5253 )]
5254 return []
Matt Stark6ef08872021-07-29 01:21:465255
5256def CheckConsistentGrdChanges(input_api, output_api):
5257 """Changes to GRD files must be consistent for tools to read them."""
5258 changed_grds = input_api.AffectedFiles(
5259 include_deletes=False,
5260 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5261 errors = []
5262 invalid_file_regexes = [(input_api.re.compile(matcher), msg) for matcher, msg in _INVALID_GRD_FILE_LINE]
5263 for grd in changed_grds:
5264 for i, line in enumerate(grd.NewContents()):
5265 for matcher, msg in invalid_file_regexes:
5266 if matcher.search(line):
5267 errors.append(output_api.PresubmitError('Problem on {grd}:{i} - {msg}'.format(grd=grd.LocalPath(), i=i + 1, msg=msg)))
5268 return errors
5269
5270