blob: 032995cbac95c9d998d5d4f804671500b019b7ac [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,
[email protected]06e6d0ff2012-12-11 01:36:4472 r'.+profile_sync_service_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 (
951 r'/\bScopedObserver',
952 (
953 'ScopedObserver is deprecated.',
954 'Please use base::ScopedObservation for observing a single source,',
955 'or base::ScopedMultiSourceObservation for observing multple sources',
956 ),
957 False,
958 (),
959 ),
Jan Wilken Dörrie60df2362021-04-08 19:44:21960 (
Robert Liao22f66a52021-04-10 00:57:52961 'RoInitialize',
962 (
Robert Liao48018922021-04-16 23:03:02963 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:52964 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
965 'instead. See http://crbug.com/1197722 for more information.'
966 ),
967 True,
Robert Liao48018922021-04-16 23:03:02968 (
969 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$'
970 ),
Robert Liao22f66a52021-04-10 00:57:52971 ),
[email protected]127f18ec2012-06-16 05:05:59972)
973
Mario Sanchez Prada2472cab2019-09-18 10:58:31974# Format: Sequence of tuples containing:
975# * String pattern or, if starting with a slash, a regular expression.
976# * Sequence of strings to show when the pattern matches.
977_DEPRECATED_MOJO_TYPES = (
978 (
979 r'/\bmojo::AssociatedBinding\b',
980 (
981 'mojo::AssociatedBinding<Interface> is deprecated.',
982 'Use mojo::AssociatedReceiver<Interface> instead.',
983 ),
984 ),
985 (
986 r'/\bmojo::AssociatedBindingSet\b',
987 (
988 'mojo::AssociatedBindingSet<Interface> is deprecated.',
989 'Use mojo::AssociatedReceiverSet<Interface> instead.',
990 ),
991 ),
992 (
993 r'/\bmojo::AssociatedInterfacePtr\b',
994 (
995 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
996 'Use mojo::AssociatedRemote<Interface> instead.',
997 ),
998 ),
999 (
1000 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1001 (
1002 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1003 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1004 ),
1005 ),
1006 (
1007 r'/\bmojo::AssociatedInterfaceRequest\b',
1008 (
1009 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1010 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1011 ),
1012 ),
1013 (
1014 r'/\bmojo::Binding\b',
1015 (
1016 'mojo::Binding<Interface> is deprecated.',
1017 'Use mojo::Receiver<Interface> instead.',
1018 ),
1019 ),
1020 (
1021 r'/\bmojo::BindingSet\b',
1022 (
1023 'mojo::BindingSet<Interface> is deprecated.',
1024 'Use mojo::ReceiverSet<Interface> instead.',
1025 ),
1026 ),
1027 (
1028 r'/\bmojo::InterfacePtr\b',
1029 (
1030 'mojo::InterfacePtr<Interface> is deprecated.',
1031 'Use mojo::Remote<Interface> instead.',
1032 ),
1033 ),
1034 (
1035 r'/\bmojo::InterfacePtrInfo\b',
1036 (
1037 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1038 'Use mojo::PendingRemote<Interface> instead.',
1039 ),
1040 ),
1041 (
1042 r'/\bmojo::InterfaceRequest\b',
1043 (
1044 'mojo::InterfaceRequest<Interface> is deprecated.',
1045 'Use mojo::PendingReceiver<Interface> instead.',
1046 ),
1047 ),
1048 (
1049 r'/\bmojo::MakeRequest\b',
1050 (
1051 'mojo::MakeRequest is deprecated.',
1052 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1053 ),
1054 ),
1055 (
1056 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1057 (
1058 'mojo::MakeRequest is deprecated.',
1059 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181060 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311061 ),
1062 ),
1063 (
1064 r'/\bmojo::MakeStrongBinding\b',
1065 (
1066 'mojo::MakeStrongBinding is deprecated.',
1067 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1068 'mojo::MakeSelfOwnedReceiver() instead.',
1069 ),
1070 ),
1071 (
1072 r'/\bmojo::MakeStrongAssociatedBinding\b',
1073 (
1074 'mojo::MakeStrongAssociatedBinding is deprecated.',
1075 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1076 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1077 ),
1078 ),
1079 (
Gyuyoung Kim4952ba62020-07-07 07:33:441080 r'/\bmojo::StrongAssociatedBinding\b',
1081 (
1082 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1083 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1084 ),
1085 ),
1086 (
1087 r'/\bmojo::StrongBinding\b',
1088 (
1089 'mojo::StrongBinding<Interface> is deprecated.',
1090 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1091 ),
1092 ),
1093 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311094 r'/\bmojo::StrongAssociatedBindingSet\b',
1095 (
1096 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1097 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1098 ),
1099 ),
1100 (
1101 r'/\bmojo::StrongBindingSet\b',
1102 (
1103 'mojo::StrongBindingSet<Interface> is deprecated.',
1104 'Use mojo::UniqueReceiverSet<Interface> instead.',
1105 ),
1106 ),
1107)
wnwenbdc444e2016-05-25 13:44:151108
mlamouria82272622014-09-16 18:45:041109_IPC_ENUM_TRAITS_DEPRECATED = (
1110 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501111 'See http://www.chromium.org/Home/chromium-security/education/'
1112 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041113
Stephen Martinis97a394142018-06-07 23:06:051114_LONG_PATH_ERROR = (
1115 'Some files included in this CL have file names that are too long (> 200'
1116 ' characters). If committed, these files will cause issues on Windows. See'
1117 ' https://crbug.com/612667 for more details.'
1118)
1119
Shenghua Zhangbfaa38b82017-11-16 21:58:021120_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041121 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041122 r".*[\\/]BuildHooksAndroidImpl\.java",
1123 r".*[\\/]LicenseContentProvider\.java",
1124 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281125 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021126]
[email protected]127f18ec2012-06-16 05:05:591127
Mohamed Heikald048240a2019-11-12 16:57:371128# List of image extensions that are used as resources in chromium.
1129_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1130
Sean Kau46e29bc2017-08-28 16:31:161131# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401132_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041133 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401134 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041135 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1136 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041137 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431138 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161139]
1140
1141
[email protected]b00342e7f2013-03-26 16:21:541142_VALID_OS_MACROS = (
1143 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081144 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541145 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441146 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121147 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541148 'OS_BSD',
1149 'OS_CAT', # For testing.
1150 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041151 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541152 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371153 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541154 'OS_IOS',
1155 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441156 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541157 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211158 'OS_NACL_NONSFI',
1159 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121160 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541161 'OS_OPENBSD',
1162 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371163 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541164 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541165 'OS_WIN',
1166)
1167
1168
Andrew Grieveb773bad2020-06-05 18:00:381169# These are not checked on the public chromium-presubmit trybot.
1170# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041171# checkouts.
agrievef32bcc72016-04-04 14:57:401172_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381173 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381174]
1175
1176
1177_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041178 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361179 'base/android/jni_generator/jni_generator.pydeps',
1180 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361181 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041182 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361183 'build/android/gyp/aar.pydeps',
1184 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271185 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361186 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381187 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361188 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021189 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221190 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111191 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361192 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361193 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361194 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111195 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041196 'build/android/gyp/create_app_bundle_apks.pydeps',
1197 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361198 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121199 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091200 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221201 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001202 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361203 'build/android/gyp/desugar.pydeps',
1204 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421205 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041206 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361207 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361208 'build/android/gyp/filter_zip.pydeps',
1209 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361210 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361211 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581212 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361213 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141214 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261215 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471216 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011217 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041218 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361219 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361220 'build/android/gyp/merge_manifest.pydeps',
1221 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221222 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361223 'build/android/gyp/proguard.pydeps',
Mohamed Heikala9dd71a2021-04-15 15:39:271224 'build/android/gyp/resources_shrinker/shrinker.pydeps',
Peter Wen578730b2020-03-19 19:55:461225 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241226 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361227 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461228 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561229 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361230 'build/android/incremental_install/generate_android_manifest.pydeps',
1231 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041232 'build/android/resource_sizes.pydeps',
1233 'build/android/test_runner.pydeps',
1234 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361235 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361236 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321237 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271238 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1239 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041240 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001241 'components/cronet/tools/generate_javadoc.pydeps',
1242 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381243 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001244 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381245 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041246 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181247 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041248 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421249 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1250 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131251 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501252 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061253 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221254 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401255]
1256
wnwenbdc444e2016-05-25 13:44:151257
agrievef32bcc72016-04-04 14:57:401258_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1259
1260
Eric Boren6fd2b932018-01-25 15:05:081261# Bypass the AUTHORS check for these accounts.
1262_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591263 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451264 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591265 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521266 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071267 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041268 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271269 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041270 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161271 for s in ('chromium-internal-autoroll',)
1272 ) | set('%[email protected]' % s
1273 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081274
1275
Daniel Bratell65b033262019-04-23 08:17:061276def _IsCPlusPlusFile(input_api, file_path):
1277 """Returns True if this file contains C++-like code (and not Python,
1278 Go, Java, MarkDown, ...)"""
1279
1280 ext = input_api.os_path.splitext(file_path)[1]
1281 # This list is compatible with CppChecker.IsCppFile but we should
1282 # consider adding ".c" to it. If we do that we can use this function
1283 # at more places in the code.
1284 return ext in (
1285 '.h',
1286 '.cc',
1287 '.cpp',
1288 '.m',
1289 '.mm',
1290 )
1291
1292def _IsCPlusPlusHeaderFile(input_api, file_path):
1293 return input_api.os_path.splitext(file_path)[1] == ".h"
1294
1295
1296def _IsJavaFile(input_api, file_path):
1297 return input_api.os_path.splitext(file_path)[1] == ".java"
1298
1299
1300def _IsProtoFile(input_api, file_path):
1301 return input_api.os_path.splitext(file_path)[1] == ".proto"
1302
Mohamed Heikal5e5b7922020-10-29 18:57:591303
1304def CheckNoUpstreamDepsOnClank(input_api, output_api):
1305 """Prevent additions of dependencies from the upstream repo on //clank."""
1306 # clank can depend on clank
1307 if input_api.change.RepositoryRoot().endswith('clank'):
1308 return []
1309 build_file_patterns = [
1310 r'(.+/)?BUILD\.gn',
1311 r'.+\.gni',
1312 ]
1313 excluded_files = [
1314 r'build[/\\]config[/\\]android[/\\]config\.gni'
1315 ]
1316 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1317
1318 error_message = 'Disallowed import on //clank in an upstream build file:'
1319
1320 def FilterFile(affected_file):
1321 return input_api.FilterSourceFile(
1322 affected_file,
1323 files_to_check=build_file_patterns,
1324 files_to_skip=excluded_files)
1325
1326 problems = []
1327 for f in input_api.AffectedSourceFiles(FilterFile):
1328 local_path = f.LocalPath()
1329 for line_number, line in f.ChangedContents():
1330 if (bad_pattern.search(line)):
1331 problems.append(
1332 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1333 if problems:
1334 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1335 else:
1336 return []
1337
1338
Saagar Sanghavifceeaae2020-08-12 16:40:361339def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191340 """Attempts to prevent use of functions intended only for testing in
1341 non-testing code. For now this is just a best-effort implementation
1342 that ignores header files and may have some false positives. A
1343 better implementation would probably need a proper C++ parser.
1344 """
1345 # We only scan .cc files and the like, as the declaration of
1346 # for-testing functions in header files are hard to distinguish from
1347 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491348 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191349
jochenc0d4808c2015-07-27 09:25:421350 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191351 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091352 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131353 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191354 exclusion_pattern = input_api.re.compile(
1355 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1356 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131357 # Avoid a false positive in this case, where the method name, the ::, and
1358 # the closing { are all on different lines due to line wrapping.
1359 # HelperClassForTesting::
1360 # HelperClassForTesting(
1361 # args)
1362 # : member(0) {}
1363 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191364
1365 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441366 files_to_skip = (_EXCLUDED_PATHS +
1367 _TEST_CODE_EXCLUDED_PATHS +
1368 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191369 return input_api.FilterSourceFile(
1370 affected_file,
James Cook24a504192020-07-23 00:08:441371 files_to_check=file_inclusion_pattern,
1372 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191373
1374 problems = []
1375 for f in input_api.AffectedSourceFiles(FilterFile):
1376 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131377 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241378 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031379 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461380 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131381 not exclusion_pattern.search(line) and
1382 not allowlist_pattern.search(line) and
1383 not in_method_defn):
[email protected]55459852011-08-10 15:17:191384 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031385 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131386 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191387
1388 if problems:
[email protected]f7051d52013-04-02 18:31:421389 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031390 else:
1391 return []
[email protected]55459852011-08-10 15:17:191392
1393
Saagar Sanghavifceeaae2020-08-12 16:40:361394def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231395 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591396 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231397 """
1398 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1399 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1400 name_pattern = r'ForTest(s|ing)?'
1401 # Describes an occurrence of "ForTest*" inside a // comment.
1402 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501403 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551404 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231405 # Catch calls.
1406 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1407 # Ignore definitions. (Comments are ignored separately.)
1408 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1409
1410 problems = []
1411 sources = lambda x: input_api.FilterSourceFile(
1412 x,
James Cook24a504192020-07-23 00:08:441413 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1414 + input_api.DEFAULT_FILES_TO_SKIP),
1415 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231416 )
1417 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1418 local_path = f.LocalPath()
1419 is_inside_javadoc = False
1420 for line_number, line in f.ChangedContents():
1421 if is_inside_javadoc and javadoc_end_re.search(line):
1422 is_inside_javadoc = False
1423 if not is_inside_javadoc and javadoc_start_re.search(line):
1424 is_inside_javadoc = True
1425 if is_inside_javadoc:
1426 continue
1427 if (inclusion_re.search(line) and
1428 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501429 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231430 not exclusion_re.search(line)):
1431 problems.append(
1432 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1433
1434 if problems:
1435 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1436 else:
1437 return []
1438
1439
Saagar Sanghavifceeaae2020-08-12 16:40:361440def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541441 """Checks to make sure no .h files include <iostream>."""
1442 files = []
1443 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1444 input_api.re.MULTILINE)
1445 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1446 if not f.LocalPath().endswith('.h'):
1447 continue
1448 contents = input_api.ReadFile(f)
1449 if pattern.search(contents):
1450 files.append(f)
1451
1452 if len(files):
yolandyandaabc6d2016-04-18 18:29:391453 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061454 'Do not #include <iostream> in header files, since it inserts static '
1455 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541456 '#include <ostream>. See http://crbug.com/94794',
1457 files) ]
1458 return []
1459
Danil Chapovalov3518f362018-08-11 16:13:431460def _CheckNoStrCatRedefines(input_api, output_api):
1461 """Checks no windows headers with StrCat redefined are included directly."""
1462 files = []
1463 pattern_deny = input_api.re.compile(
1464 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1465 input_api.re.MULTILINE)
1466 pattern_allow = input_api.re.compile(
1467 r'^#include\s"base/win/windows_defines.inc"',
1468 input_api.re.MULTILINE)
1469 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1470 contents = input_api.ReadFile(f)
1471 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1472 files.append(f.LocalPath())
1473
1474 if len(files):
1475 return [output_api.PresubmitError(
1476 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1477 'directly since they pollute code with StrCat macro. Instead, '
1478 'include matching header from base/win. See http://crbug.com/856536',
1479 files) ]
1480 return []
1481
[email protected]10689ca2011-09-02 02:31:541482
Saagar Sanghavifceeaae2020-08-12 16:40:361483def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521484 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181485 problems = []
1486 for f in input_api.AffectedFiles():
1487 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1488 continue
1489
1490 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041491 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181492 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1493
1494 if not problems:
1495 return []
1496 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1497 '\n'.join(problems))]
1498
Saagar Sanghavifceeaae2020-08-12 16:40:361499def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341500 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1501
1502 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1503 instead of DISABLED_. To filter false positives, reports are only generated
1504 if a corresponding MAYBE_ line exists.
1505 """
1506 problems = []
1507
1508 # The following two patterns are looked for in tandem - is a test labeled
1509 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1510 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1511 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1512
1513 # This is for the case that a test is disabled on all platforms.
1514 full_disable_pattern = input_api.re.compile(
1515 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1516 input_api.re.MULTILINE)
1517
Katie Df13948e2018-09-25 07:33:441518 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341519 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1520 continue
1521
1522 # Search for MABYE_, DISABLE_ pairs.
1523 disable_lines = {} # Maps of test name to line number.
1524 maybe_lines = {}
1525 for line_num, line in f.ChangedContents():
1526 disable_match = disable_pattern.search(line)
1527 if disable_match:
1528 disable_lines[disable_match.group(1)] = line_num
1529 maybe_match = maybe_pattern.search(line)
1530 if maybe_match:
1531 maybe_lines[maybe_match.group(1)] = line_num
1532
1533 # Search for DISABLE_ occurrences within a TEST() macro.
1534 disable_tests = set(disable_lines.keys())
1535 maybe_tests = set(maybe_lines.keys())
1536 for test in disable_tests.intersection(maybe_tests):
1537 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1538
1539 contents = input_api.ReadFile(f)
1540 full_disable_match = full_disable_pattern.search(contents)
1541 if full_disable_match:
1542 problems.append(' %s' % f.LocalPath())
1543
1544 if not problems:
1545 return []
1546 return [
1547 output_api.PresubmitPromptWarning(
1548 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1549 '\n'.join(problems))
1550 ]
1551
[email protected]72df4e782012-06-21 16:28:181552
Saagar Sanghavifceeaae2020-08-12 16:40:361553def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571554 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521555 errors = []
Hans Wennborg944479f2020-06-25 21:39:251556 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521557 input_api.re.MULTILINE)
1558 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1559 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1560 continue
1561 for lnum, line in f.ChangedContents():
1562 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171563 errors.append(output_api.PresubmitError(
1564 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571565 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171566 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521567 return errors
1568
1569
Weilun Shia487fad2020-10-28 00:10:341570# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1571# more reliable way. See
1572# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191573
wnwenbdc444e2016-05-25 13:44:151574
Saagar Sanghavifceeaae2020-08-12 16:40:361575def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391576 """Check that FlakyTest annotation is our own instead of the android one"""
1577 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1578 files = []
1579 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1580 if f.LocalPath().endswith('Test.java'):
1581 if pattern.search(input_api.ReadFile(f)):
1582 files.append(f)
1583 if len(files):
1584 return [output_api.PresubmitError(
1585 'Use org.chromium.base.test.util.FlakyTest instead of '
1586 'android.test.FlakyTest',
1587 files)]
1588 return []
mcasasb7440c282015-02-04 14:52:191589
wnwenbdc444e2016-05-25 13:44:151590
Saagar Sanghavifceeaae2020-08-12 16:40:361591def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441592 """Make sure .DEPS.git is never modified manually."""
1593 if any(f.LocalPath().endswith('.DEPS.git') for f in
1594 input_api.AffectedFiles()):
1595 return [output_api.PresubmitError(
1596 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1597 'automated system based on what\'s in DEPS and your changes will be\n'
1598 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501599 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1600 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441601 'for more information')]
1602 return []
1603
1604
Saagar Sanghavifceeaae2020-08-12 16:40:361605def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471606 """Checks that DEPS file deps are from allowed_hosts."""
1607 # Run only if DEPS file has been modified to annoy fewer bystanders.
1608 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1609 return []
1610 # Outsource work to gclient verify
1611 try:
John Budorickf20c0042019-04-25 23:23:401612 gclient_path = input_api.os_path.join(
1613 input_api.PresubmitLocalPath(),
1614 'third_party', 'depot_tools', 'gclient.py')
1615 input_api.subprocess.check_output(
1616 [input_api.python_executable, gclient_path, 'verify'],
1617 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471618 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201619 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471620 return [output_api.PresubmitError(
1621 'DEPS file must have only git dependencies.',
1622 long_text=error.output)]
1623
1624
Mario Sanchez Prada2472cab2019-09-18 10:58:311625def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1626 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591627 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311628
1629 Returns an string composed of the name of the file, the line number where the
1630 match has been found and the additional text passed as |message| in case the
1631 target type name matches the text inside the line passed as parameter.
1632 """
Peng Huang9c5949a02020-06-11 19:20:541633 result = []
1634
danakjd18e8892020-12-17 17:42:011635 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1636 return result
1637 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541638 return result
1639
Mario Sanchez Prada2472cab2019-09-18 10:58:311640 matched = False
1641 if type_name[0:1] == '/':
1642 regex = type_name[1:]
1643 if input_api.re.search(regex, line):
1644 matched = True
1645 elif type_name in line:
1646 matched = True
1647
Mario Sanchez Prada2472cab2019-09-18 10:58:311648 if matched:
1649 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1650 for message_line in message:
1651 result.append(' %s' % message_line)
1652
1653 return result
1654
1655
Saagar Sanghavifceeaae2020-08-12 16:40:361656def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591657 """Make sure that banned functions are not used."""
1658 warnings = []
1659 errors = []
1660
James Cook24a504192020-07-23 00:08:441661 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151662 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441663 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151664 if input_api.re.match(item, local_path):
1665 return True
1666 return False
1667
Peter K. Lee6c03ccff2019-07-15 14:40:051668 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541669 local_path = affected_file.LocalPath()
1670 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1671 return False
1672 basename = input_api.os_path.basename(local_path)
1673 if 'ios' in basename.split('_'):
1674 return True
1675 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1676 if sep and 'ios' in local_path.split(sep):
1677 return True
1678 return False
1679
wnwenbdc444e2016-05-25 13:44:151680 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311681 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1682 func_name, message)
1683 if problems:
wnwenbdc444e2016-05-25 13:44:151684 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311685 errors.extend(problems)
1686 else:
1687 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151688
Eric Stevensona9a980972017-09-23 00:04:411689 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1690 for f in input_api.AffectedFiles(file_filter=file_filter):
1691 for line_num, line in f.ChangedContents():
1692 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1693 CheckForMatch(f, line_num, line, func_name, message, error)
1694
[email protected]127f18ec2012-06-16 05:05:591695 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1696 for f in input_api.AffectedFiles(file_filter=file_filter):
1697 for line_num, line in f.ChangedContents():
1698 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151699 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591700
Peter K. Lee6c03ccff2019-07-15 14:40:051701 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541702 for line_num, line in f.ChangedContents():
1703 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1704 CheckForMatch(f, line_num, line, func_name, message, error)
1705
Peter K. Lee6c03ccff2019-07-15 14:40:051706 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1707 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1708 for line_num, line in f.ChangedContents():
1709 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1710 CheckForMatch(f, line_num, line, func_name, message, error)
1711
[email protected]127f18ec2012-06-16 05:05:591712 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1713 for f in input_api.AffectedFiles(file_filter=file_filter):
1714 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491715 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441716 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491717 continue
wnwenbdc444e2016-05-25 13:44:151718 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591719
1720 result = []
1721 if (warnings):
1722 result.append(output_api.PresubmitPromptWarning(
1723 'Banned functions were used.\n' + '\n'.join(warnings)))
1724 if (errors):
1725 result.append(output_api.PresubmitError(
1726 'Banned functions were used.\n' + '\n'.join(errors)))
1727 return result
1728
1729
Michael Thiessen44457642020-02-06 00:24:151730def _CheckAndroidNoBannedImports(input_api, output_api):
1731 """Make sure that banned java imports are not used."""
1732 errors = []
1733
1734 def IsException(path, exceptions):
1735 for exception in exceptions:
1736 if (path.startswith(exception)):
1737 return True
1738 return False
1739
1740 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1741 for f in input_api.AffectedFiles(file_filter=file_filter):
1742 for line_num, line in f.ChangedContents():
1743 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1744 if IsException(f.LocalPath(), exceptions):
1745 continue;
1746 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1747 'import ' + import_name, message)
1748 if problems:
1749 errors.extend(problems)
1750 result = []
1751 if (errors):
1752 result.append(output_api.PresubmitError(
1753 'Banned imports were used.\n' + '\n'.join(errors)))
1754 return result
1755
1756
Saagar Sanghavifceeaae2020-08-12 16:40:361757def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311758 """Make sure that old Mojo types are not used."""
1759 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571760 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311761
Mario Sanchez Pradaaab91382019-12-19 08:57:091762 # For any path that is not an "ok" or an "error" path, a warning will be
1763 # raised if deprecated mojo types are found.
1764 ok_paths = ['components/arc']
1765 error_paths = ['third_party/blink', 'content']
1766
Mario Sanchez Prada2472cab2019-09-18 10:58:311767 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1768 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571769 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091770 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311771 continue
1772
1773 for line_num, line in f.ChangedContents():
1774 for func_name, message in _DEPRECATED_MOJO_TYPES:
1775 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1776 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571777
Mario Sanchez Prada2472cab2019-09-18 10:58:311778 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091779 # Raise errors inside |error_paths| and warnings everywhere else.
1780 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571781 errors.extend(problems)
1782 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311783 warnings.extend(problems)
1784
1785 result = []
1786 if (warnings):
1787 result.append(output_api.PresubmitPromptWarning(
1788 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571789 if (errors):
1790 result.append(output_api.PresubmitError(
1791 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311792 return result
1793
1794
Saagar Sanghavifceeaae2020-08-12 16:40:361795def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061796 """Make sure that banned functions are not used."""
1797 files = []
1798 pattern = input_api.re.compile(r'^#pragma\s+once',
1799 input_api.re.MULTILINE)
1800 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1801 if not f.LocalPath().endswith('.h'):
1802 continue
1803 contents = input_api.ReadFile(f)
1804 if pattern.search(contents):
1805 files.append(f)
1806
1807 if files:
1808 return [output_api.PresubmitError(
1809 'Do not use #pragma once in header files.\n'
1810 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1811 files)]
1812 return []
1813
[email protected]127f18ec2012-06-16 05:05:591814
Saagar Sanghavifceeaae2020-08-12 16:40:361815def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121816 """Checks to make sure we don't introduce use of foo ? true : false."""
1817 problems = []
1818 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1819 for f in input_api.AffectedFiles():
1820 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1821 continue
1822
1823 for line_num, line in f.ChangedContents():
1824 if pattern.match(line):
1825 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1826
1827 if not problems:
1828 return []
1829 return [output_api.PresubmitPromptWarning(
1830 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1831 '\n'.join(problems))]
1832
1833
Saagar Sanghavifceeaae2020-08-12 16:40:361834def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281835 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181836 change. Breaking - rules is an error, breaking ! rules is a
1837 warning.
1838 """
mohan.reddyf21db962014-10-16 12:26:471839 import sys
[email protected]55f9f382012-07-31 11:02:181840 # We need to wait until we have an input_api object and use this
1841 # roundabout construct to import checkdeps because this file is
1842 # eval-ed and thus doesn't have __file__.
1843 original_sys_path = sys.path
1844 try:
1845 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471846 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181847 import checkdeps
[email protected]55f9f382012-07-31 11:02:181848 from rules import Rule
1849 finally:
1850 # Restore sys.path to what it was before.
1851 sys.path = original_sys_path
1852
1853 added_includes = []
rhalavati08acd232017-04-03 07:23:281854 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241855 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181856 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061857 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501858 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081859 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061860 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501861 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081862 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061863 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501864 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081865 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181866
[email protected]26385172013-05-09 23:11:351867 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181868
1869 error_descriptions = []
1870 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281871 error_subjects = set()
1872 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361873
[email protected]55f9f382012-07-31 11:02:181874 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1875 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081876 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181877 description_with_path = '%s\n %s' % (path, rule_description)
1878 if rule_type == Rule.DISALLOW:
1879 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281880 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181881 else:
1882 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281883 warning_subjects.add("#includes")
1884
1885 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1886 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081887 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281888 description_with_path = '%s\n %s' % (path, rule_description)
1889 if rule_type == Rule.DISALLOW:
1890 error_descriptions.append(description_with_path)
1891 error_subjects.add("imports")
1892 else:
1893 warning_descriptions.append(description_with_path)
1894 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181895
Jinsuk Kim5a092672017-10-24 22:42:241896 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021897 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081898 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241899 description_with_path = '%s\n %s' % (path, rule_description)
1900 if rule_type == Rule.DISALLOW:
1901 error_descriptions.append(description_with_path)
1902 error_subjects.add("imports")
1903 else:
1904 warning_descriptions.append(description_with_path)
1905 warning_subjects.add("imports")
1906
[email protected]55f9f382012-07-31 11:02:181907 results = []
1908 if error_descriptions:
1909 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281910 'You added one or more %s that violate checkdeps rules.'
1911 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181912 error_descriptions))
1913 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421914 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281915 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181916 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281917 '%s? See relevant DEPS file(s) for details and contacts.' %
1918 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181919 warning_descriptions))
1920 return results
1921
1922
Saagar Sanghavifceeaae2020-08-12 16:40:361923def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:221924 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151925 if input_api.platform == 'win32':
1926 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291927 checkperms_tool = input_api.os_path.join(
1928 input_api.PresubmitLocalPath(),
1929 'tools', 'checkperms', 'checkperms.py')
1930 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471931 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391932 with input_api.CreateTemporaryFile() as file_list:
1933 for f in input_api.AffectedFiles():
1934 # checkperms.py file/directory arguments must be relative to the
1935 # repository.
Dirk Prankee3c9c62d2021-05-18 18:35:591936 file_list.write((f.LocalPath() + '\n').encode('utf8'))
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391937 file_list.close()
1938 args += ['--file-list', file_list.name]
1939 try:
1940 input_api.subprocess.check_output(args)
1941 return []
1942 except input_api.subprocess.CalledProcessError as error:
1943 return [output_api.PresubmitError(
1944 'checkperms.py failed:',
1945 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221946
1947
Saagar Sanghavifceeaae2020-08-12 16:40:361948def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:491949 """Makes sure we don't include ui/aura/window_property.h
1950 in header files.
1951 """
1952 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1953 errors = []
1954 for f in input_api.AffectedFiles():
1955 if not f.LocalPath().endswith('.h'):
1956 continue
1957 for line_num, line in f.ChangedContents():
1958 if pattern.match(line):
1959 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1960
1961 results = []
1962 if errors:
1963 results.append(output_api.PresubmitError(
1964 'Header files should not include ui/aura/window_property.h', errors))
1965 return results
1966
1967
Omer Katzcc77ea92021-04-26 10:23:281968def CheckNoInternalHeapIncludes(input_api, output_api):
1969 """Makes sure we don't include any headers from
1970 third_party/blink/renderer/platform/heap/impl or
1971 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1972 third_party/blink/renderer/platform/heap
1973 """
1974 impl_pattern = input_api.re.compile(
1975 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1976 v8_wrapper_pattern = input_api.re.compile(
1977 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"')
1978 file_filter = lambda f: not input_api.re.match(
1979 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1980 f.LocalPath())
1981 errors = []
1982
1983 for f in input_api.AffectedFiles(file_filter=file_filter):
1984 for line_num, line in f.ChangedContents():
1985 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1986 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1987
1988 results = []
1989 if errors:
1990 results.append(output_api.PresubmitError(
1991 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1992 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1993 'relevant counterparts from third_party/blink/renderer/platform/heap',
1994 errors))
1995 return results
1996
1997
[email protected]70ca77752012-11-20 03:45:031998def _CheckForVersionControlConflictsInFile(input_api, f):
1999 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2000 errors = []
2001 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162002 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232003 # First-level headers in markdown look a lot like version control
2004 # conflict markers. http://daringfireball.net/projects/markdown/basics
2005 continue
[email protected]70ca77752012-11-20 03:45:032006 if pattern.match(line):
2007 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2008 return errors
2009
2010
Saagar Sanghavifceeaae2020-08-12 16:40:362011def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032012 """Usually this is not intentional and will cause a compile failure."""
2013 errors = []
2014 for f in input_api.AffectedFiles():
2015 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2016
2017 results = []
2018 if errors:
2019 results.append(output_api.PresubmitError(
2020 'Version control conflict markers found, please resolve.', errors))
2021 return results
2022
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202023
Saagar Sanghavifceeaae2020-08-12 16:40:362024def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162025 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2026 errors = []
2027 for f in input_api.AffectedFiles():
2028 for line_num, line in f.ChangedContents():
2029 if pattern.search(line):
2030 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2031
2032 results = []
2033 if errors:
2034 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502035 'Found Google support URL addressed by answer number. Please replace '
2036 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162037 return results
2038
[email protected]70ca77752012-11-20 03:45:032039
Saagar Sanghavifceeaae2020-08-12 16:40:362040def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442041 def FilterFile(affected_file):
2042 """Filter function for use with input_api.AffectedSourceFiles,
2043 below. This filters out everything except non-test files from
2044 top-level directories that generally speaking should not hard-code
2045 service URLs (e.g. src/android_webview/, src/content/ and others).
2046 """
2047 return input_api.FilterSourceFile(
2048 affected_file,
James Cook24a504192020-07-23 00:08:442049 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2050 files_to_skip=(_EXCLUDED_PATHS +
2051 _TEST_CODE_EXCLUDED_PATHS +
2052 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442053
reillyi38965732015-11-16 18:27:332054 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2055 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462056 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2057 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442058 problems = [] # items are (filename, line_number, line)
2059 for f in input_api.AffectedSourceFiles(FilterFile):
2060 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462061 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442062 problems.append((f.LocalPath(), line_num, line))
2063
2064 if problems:
[email protected]f7051d52013-04-02 18:31:422065 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442066 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582067 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442068 [' %s:%d: %s' % (
2069 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032070 else:
2071 return []
[email protected]06e6d0ff2012-12-11 01:36:442072
2073
Saagar Sanghavifceeaae2020-08-12 16:40:362074def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292075 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2076 def FileFilter(affected_file):
2077 """Includes directories known to be Chrome OS only."""
2078 return input_api.FilterSourceFile(
2079 affected_file,
James Cook24a504192020-07-23 00:08:442080 files_to_check=('^ash/',
2081 '^chromeos/', # Top-level src/chromeos.
2082 '/chromeos/', # Any path component.
2083 '^components/arc',
2084 '^components/exo'),
2085 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292086
2087 prefs = []
2088 priority_prefs = []
2089 for f in input_api.AffectedFiles(file_filter=FileFilter):
2090 for line_num, line in f.ChangedContents():
2091 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2092 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2093 prefs.append(' %s' % line)
2094 if input_api.re.search(
2095 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2096 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2097 priority_prefs.append(' %s' % line)
2098
2099 results = []
2100 if (prefs):
2101 results.append(output_api.PresubmitPromptWarning(
2102 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2103 'by browser sync settings. If these prefs should be controlled by OS '
2104 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2105 if (priority_prefs):
2106 results.append(output_api.PresubmitPromptWarning(
2107 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2108 'controlled by browser sync settings. If these prefs should be '
2109 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2110 'instead.\n' + '\n'.join(prefs)))
2111 return results
2112
2113
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492114# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362115def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272116 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312117 The native_client_sdk directory is excluded because it has auto-generated PNG
2118 files for documentation.
[email protected]d2530012013-01-25 16:39:272119 """
[email protected]d2530012013-01-25 16:39:272120 errors = []
James Cook24a504192020-07-23 00:08:442121 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2122 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312123 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442124 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312125 for f in input_api.AffectedFiles(include_deletes=False,
2126 file_filter=file_filter):
2127 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272128
2129 results = []
2130 if errors:
2131 results.append(output_api.PresubmitError(
2132 'The name of PNG files should not have abbreviations. \n'
2133 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2134 'Contact [email protected] if you have questions.', errors))
2135 return results
2136
2137
Daniel Cheng4dcdb6b2017-04-13 08:30:172138def _ExtractAddRulesFromParsedDeps(parsed_deps):
2139 """Extract the rules that add dependencies from a parsed DEPS file.
2140
2141 Args:
2142 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2143 add_rules = set()
2144 add_rules.update([
2145 rule[1:] for rule in parsed_deps.get('include_rules', [])
2146 if rule.startswith('+') or rule.startswith('!')
2147 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502148 for _, rules in parsed_deps.get('specific_include_rules',
Dirk Prankee3c9c62d2021-05-18 18:35:592149 {}).items():
Daniel Cheng4dcdb6b2017-04-13 08:30:172150 add_rules.update([
2151 rule[1:] for rule in rules
2152 if rule.startswith('+') or rule.startswith('!')
2153 ])
2154 return add_rules
2155
2156
2157def _ParseDeps(contents):
2158 """Simple helper for parsing DEPS files."""
2159 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172160 class _VarImpl:
2161
2162 def __init__(self, local_scope):
2163 self._local_scope = local_scope
2164
2165 def Lookup(self, var_name):
2166 """Implements the Var syntax."""
2167 try:
2168 return self._local_scope['vars'][var_name]
2169 except KeyError:
2170 raise Exception('Var is not defined: %s' % var_name)
2171
2172 local_scope = {}
2173 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172174 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592175 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172176 }
Dirk Pranke1b9e06382021-05-14 01:16:222177
Dirk Prankee3c9c62d2021-05-18 18:35:592178 exec(contents, global_scope, local_scope)
Daniel Cheng4dcdb6b2017-04-13 08:30:172179 return local_scope
2180
2181
2182def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592183 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412184 a set of DEPS entries that we should look up.
2185
2186 For a directory (rather than a specific filename) we fake a path to
2187 a specific filename by adding /DEPS. This is chosen as a file that
2188 will seldom or never be subject to per-file include_rules.
2189 """
[email protected]2b438d62013-11-14 17:54:142190 # We ignore deps entries on auto-generated directories.
2191 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082192
Daniel Cheng4dcdb6b2017-04-13 08:30:172193 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2194 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2195
2196 added_deps = new_deps.difference(old_deps)
2197
[email protected]2b438d62013-11-14 17:54:142198 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172199 for added_dep in added_deps:
2200 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2201 continue
2202 # Assume that a rule that ends in .h is a rule for a specific file.
2203 if added_dep.endswith('.h'):
2204 results.add(added_dep)
2205 else:
2206 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082207 return results
2208
2209
Saagar Sanghavifceeaae2020-08-12 16:40:362210def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552211 """When a dependency prefixed with + is added to a DEPS file, we
2212 want to make sure that the change is reviewed by an OWNER of the
2213 target file or directory, to avoid layering violations from being
2214 introduced. This check verifies that this happens.
2215 """
Joey Mou57048132021-02-26 22:17:552216 # We rely on Gerrit's code-owners to check approvals.
2217 # input_api.gerrit is always set for Chromium, but other projects
2218 # might not use Gerrit.
2219 if not input_api.gerrit:
2220 return []
Edward Lesmes44feb2332021-03-19 01:27:522221 if (input_api.change.issue and
2222 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232223 # Skip OWNERS check when Owners-Override label is approved. This is intended
2224 # for global owners, trusted bots, and on-call sheriffs. Review is still
2225 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522226 return []
Edward Lesmes6fba51082021-01-20 04:20:232227
Daniel Cheng4dcdb6b2017-04-13 08:30:172228 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242229
2230 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492231 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242232 for f in input_api.AffectedFiles(include_deletes=False,
2233 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552234 filename = input_api.os_path.basename(f.LocalPath())
2235 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172236 virtual_depended_on_files.update(_CalculateAddedDeps(
2237 input_api.os_path,
2238 '\n'.join(f.OldContents()),
2239 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552240
[email protected]e871964c2013-05-13 14:14:552241 if not virtual_depended_on_files:
2242 return []
2243
2244 if input_api.is_committing:
2245 if input_api.tbr:
2246 return [output_api.PresubmitNotifyResult(
2247 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272248 if input_api.dry_run:
2249 return [output_api.PresubmitNotifyResult(
2250 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552251 if not input_api.change.issue:
2252 return [output_api.PresubmitError(
2253 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402254 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552255 output = output_api.PresubmitError
2256 else:
2257 output = output_api.PresubmitNotifyResult
2258
tandriied3b7e12016-05-12 14:38:502259 owner_email, reviewers = (
2260 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2261 input_api,
Edward Lesmesa3846442021-02-08 20:20:032262 None,
tandriied3b7e12016-05-12 14:38:502263 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552264
2265 owner_email = owner_email or input_api.change.author_email
2266
Edward Lesmesa3846442021-02-08 20:20:032267 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2268 virtual_depended_on_files, reviewers.union([owner_email]), [])
2269 missing_files = [
2270 f for f in virtual_depended_on_files
2271 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412272
2273 # We strip the /DEPS part that was added by
2274 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2275 # directory.
2276 def StripDeps(path):
2277 start_deps = path.rfind('/DEPS')
2278 if start_deps != -1:
2279 return path[:start_deps]
2280 else:
2281 return path
2282 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552283 for path in missing_files]
2284
2285 if unapproved_dependencies:
2286 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152287 output('You need LGTM from owners of depends-on paths in DEPS that were '
2288 'modified in this CL:\n %s' %
2289 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032290 suggested_owners = input_api.owners_client.SuggestOwners(
2291 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152292 output_list.append(output(
2293 'Suggested missing target path OWNERS:\n %s' %
2294 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552295 return output_list
2296
2297 return []
2298
2299
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492300# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362301def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492302 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442303 files_to_skip = (_EXCLUDED_PATHS +
2304 _TEST_CODE_EXCLUDED_PATHS +
2305 input_api.DEFAULT_FILES_TO_SKIP +
2306 (r"^base[\\/]logging\.h$",
2307 r"^base[\\/]logging\.cc$",
2308 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2309 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2310 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2311 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2312 r"startup_browser_creator\.cc$",
2313 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2314 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2315 r"diagnostics_writer\.cc$",
2316 r"^chrome[\\/]chrome_cleaner[\\/].*",
2317 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2318 r"dll_hash_main\.cc$",
2319 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2320 r"^chromecast[\\/]",
2321 r"^cloud_print[\\/]",
2322 r"^components[\\/]browser_watcher[\\/]"
2323 r"dump_stability_report_main_win.cc$",
2324 r"^components[\\/]media_control[\\/]renderer[\\/]"
2325 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352326 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2327 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442328 r"^components[\\/]zucchini[\\/].*",
2329 # TODO(peter): Remove exception. https://crbug.com/534537
2330 r"^content[\\/]browser[\\/]notifications[\\/]"
2331 r"notification_event_dispatcher_impl\.cc$",
2332 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2333 r"gl_helper_benchmark\.cc$",
2334 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2335 r"^courgette[\\/]courgette_tool\.cc$",
2336 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2337 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2338 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Sergey Ulanov6db14b4d62021-05-10 07:59:482339 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
James Cook24a504192020-07-23 00:08:442340 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2341 r"^ipc[\\/]ipc_logging\.cc$",
2342 r"^native_client_sdk[\\/]",
2343 r"^remoting[\\/]base[\\/]logging\.h$",
2344 r"^remoting[\\/]host[\\/].*",
2345 r"^sandbox[\\/]linux[\\/].*",
2346 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2347 r"dump_file_system.cc$",
2348 r"^tools[\\/]",
2349 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2350 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2351 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2352 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2353 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402354 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442355 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402356
thomasanderson625d3932017-03-29 07:16:582357 log_info = set([])
2358 printf = set([])
[email protected]85218562013-11-22 07:41:402359
2360 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582361 for _, line in f.ChangedContents():
2362 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2363 log_info.add(f.LocalPath())
2364 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2365 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372366
thomasanderson625d3932017-03-29 07:16:582367 if input_api.re.search(r"\bprintf\(", line):
2368 printf.add(f.LocalPath())
2369 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2370 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402371
2372 if log_info:
2373 return [output_api.PresubmitError(
2374 'These files spam the console log with LOG(INFO):',
2375 items=log_info)]
2376 if printf:
2377 return [output_api.PresubmitError(
2378 'These files spam the console log with printf/fprintf:',
2379 items=printf)]
2380 return []
2381
2382
Saagar Sanghavifceeaae2020-08-12 16:40:362383def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162384 """These types are all expected to hold locks while in scope and
2385 so should never be anonymous (which causes them to be immediately
2386 destroyed)."""
2387 they_who_must_be_named = [
2388 'base::AutoLock',
2389 'base::AutoReset',
2390 'base::AutoUnlock',
2391 'SkAutoAlphaRestore',
2392 'SkAutoBitmapShaderInstall',
2393 'SkAutoBlitterChoose',
2394 'SkAutoBounderCommit',
2395 'SkAutoCallProc',
2396 'SkAutoCanvasRestore',
2397 'SkAutoCommentBlock',
2398 'SkAutoDescriptor',
2399 'SkAutoDisableDirectionCheck',
2400 'SkAutoDisableOvalCheck',
2401 'SkAutoFree',
2402 'SkAutoGlyphCache',
2403 'SkAutoHDC',
2404 'SkAutoLockColors',
2405 'SkAutoLockPixels',
2406 'SkAutoMalloc',
2407 'SkAutoMaskFreeImage',
2408 'SkAutoMutexAcquire',
2409 'SkAutoPathBoundsUpdate',
2410 'SkAutoPDFRelease',
2411 'SkAutoRasterClipValidate',
2412 'SkAutoRef',
2413 'SkAutoTime',
2414 'SkAutoTrace',
2415 'SkAutoUnref',
2416 ]
2417 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2418 # bad: base::AutoLock(lock.get());
2419 # not bad: base::AutoLock lock(lock.get());
2420 bad_pattern = input_api.re.compile(anonymous)
2421 # good: new base::AutoLock(lock.get())
2422 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2423 errors = []
2424
2425 for f in input_api.AffectedFiles():
2426 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2427 continue
2428 for linenum, line in f.ChangedContents():
2429 if bad_pattern.search(line) and not good_pattern.search(line):
2430 errors.append('%s:%d' % (f.LocalPath(), linenum))
2431
2432 if errors:
2433 return [output_api.PresubmitError(
2434 'These lines create anonymous variables that need to be named:',
2435 items=errors)]
2436 return []
2437
2438
Saagar Sanghavifceeaae2020-08-12 16:40:362439def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532440 # Returns whether |template_str| is of the form <T, U...> for some types T
2441 # and U. Assumes that |template_str| is already in the form <...>.
2442 def HasMoreThanOneArg(template_str):
2443 # Level of <...> nesting.
2444 nesting = 0
2445 for c in template_str:
2446 if c == '<':
2447 nesting += 1
2448 elif c == '>':
2449 nesting -= 1
2450 elif c == ',' and nesting == 1:
2451 return True
2452 return False
2453
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492454 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102455 sources = lambda affected_file: input_api.FilterSourceFile(
2456 affected_file,
James Cook24a504192020-07-23 00:08:442457 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2458 input_api.DEFAULT_FILES_TO_SKIP),
2459 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552460
2461 # Pattern to capture a single "<...>" block of template arguments. It can
2462 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2463 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2464 # latter would likely require counting that < and > match, which is not
2465 # expressible in regular languages. Should the need arise, one can introduce
2466 # limited counting (matching up to a total number of nesting depth), which
2467 # should cover all practical cases for already a low nesting limit.
2468 template_arg_pattern = (
2469 r'<[^>]*' # Opening block of <.
2470 r'>([^<]*>)?') # Closing block of >.
2471 # Prefix expressing that whatever follows is not already inside a <...>
2472 # block.
2473 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102474 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552475 not_inside_template_arg_pattern
2476 + r'\bstd::unique_ptr'
2477 + template_arg_pattern
2478 + r'\(\)')
2479
2480 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2481 template_arg_no_array_pattern = (
2482 r'<[^>]*[^]]' # Opening block of <.
2483 r'>([^(<]*[^]]>)?') # Closing block of >.
2484 # Prefix saying that what follows is the start of an expression.
2485 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2486 # Suffix saying that what follows are call parentheses with a non-empty list
2487 # of arguments.
2488 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532489 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552490 return_construct_pattern = input_api.re.compile(
2491 start_of_expr_pattern
2492 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532493 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552494 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532495 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552496 + nonempty_arg_list_pattern)
2497
Vaclav Brozek851d9602018-04-04 16:13:052498 problems_constructor = []
2499 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102500 for f in input_api.AffectedSourceFiles(sources):
2501 for line_number, line in f.ChangedContents():
2502 # Disallow:
2503 # return std::unique_ptr<T>(foo);
2504 # bar = std::unique_ptr<T>(foo);
2505 # But allow:
2506 # return std::unique_ptr<T[]>(foo);
2507 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532508 # And also allow cases when the second template argument is present. Those
2509 # cases cannot be handled by std::make_unique:
2510 # return std::unique_ptr<T, U>(foo);
2511 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052512 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532513 return_construct_result = return_construct_pattern.search(line)
2514 if return_construct_result and not HasMoreThanOneArg(
2515 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052516 problems_constructor.append(
2517 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102518 # Disallow:
2519 # std::unique_ptr<T>()
2520 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052521 problems_nullptr.append(
2522 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2523
2524 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162525 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052526 errors.append(output_api.PresubmitError(
2527 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162528 problems_nullptr))
2529 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052530 errors.append(output_api.PresubmitError(
2531 'The following files use explicit std::unique_ptr constructor.'
2532 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162533 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102534 return errors
2535
2536
Saagar Sanghavifceeaae2020-08-12 16:40:362537def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082538 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522539 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082540 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522541 # If actions.xml is already included in the changelist, the PRESUBMIT
2542 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082543 return []
2544
Alexei Svitkine64505a92021-03-11 22:00:542545 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2546 files_to_skip = (_EXCLUDED_PATHS +
2547 _TEST_CODE_EXCLUDED_PATHS +
2548 input_api.DEFAULT_FILES_TO_SKIP )
2549 file_filter = lambda f: input_api.FilterSourceFile(
2550 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2551
[email protected]999261d2014-03-03 20:08:082552 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522553 current_actions = None
[email protected]999261d2014-03-03 20:08:082554 for f in input_api.AffectedFiles(file_filter=file_filter):
2555 for line_num, line in f.ChangedContents():
2556 match = input_api.re.search(action_re, line)
2557 if match:
[email protected]2f92dec2014-03-07 19:21:522558 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2559 # loaded only once.
2560 if not current_actions:
2561 with open('tools/metrics/actions/actions.xml') as actions_f:
2562 current_actions = actions_f.read()
2563 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082564 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522565 action = 'name="{0}"'.format(action_name)
2566 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082567 return [output_api.PresubmitPromptWarning(
2568 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522569 'tools/metrics/actions/actions.xml. Please run '
2570 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082571 % (f.LocalPath(), line_num, action_name))]
2572 return []
2573
2574
Daniel Cheng13ca61a882017-08-25 15:11:252575def _ImportJSONCommentEater(input_api):
2576 import sys
2577 sys.path = sys.path + [input_api.os_path.join(
2578 input_api.PresubmitLocalPath(),
2579 'tools', 'json_comment_eater')]
2580 import json_comment_eater
2581 return json_comment_eater
2582
2583
[email protected]99171a92014-06-03 08:44:472584def _GetJSONParseError(input_api, filename, eat_comments=True):
2585 try:
2586 contents = input_api.ReadFile(filename)
2587 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252588 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132589 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472590
2591 input_api.json.loads(contents)
2592 except ValueError as e:
2593 return e
2594 return None
2595
2596
2597def _GetIDLParseError(input_api, filename):
2598 try:
2599 contents = input_api.ReadFile(filename)
2600 idl_schema = input_api.os_path.join(
2601 input_api.PresubmitLocalPath(),
2602 'tools', 'json_schema_compiler', 'idl_schema.py')
2603 process = input_api.subprocess.Popen(
2604 [input_api.python_executable, idl_schema],
2605 stdin=input_api.subprocess.PIPE,
2606 stdout=input_api.subprocess.PIPE,
2607 stderr=input_api.subprocess.PIPE,
2608 universal_newlines=True)
2609 (_, error) = process.communicate(input=contents)
2610 return error or None
2611 except ValueError as e:
2612 return e
2613
2614
Saagar Sanghavifceeaae2020-08-12 16:40:362615def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472616 """Check that IDL and JSON files do not contain syntax errors."""
2617 actions = {
2618 '.idl': _GetIDLParseError,
2619 '.json': _GetJSONParseError,
2620 }
[email protected]99171a92014-06-03 08:44:472621 # Most JSON files are preprocessed and support comments, but these do not.
2622 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042623 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472624 ]
2625 # Only run IDL checker on files in these directories.
2626 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042627 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2628 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472629 ]
2630
2631 def get_action(affected_file):
2632 filename = affected_file.LocalPath()
2633 return actions.get(input_api.os_path.splitext(filename)[1])
2634
[email protected]99171a92014-06-03 08:44:472635 def FilterFile(affected_file):
2636 action = get_action(affected_file)
2637 if not action:
2638 return False
2639 path = affected_file.LocalPath()
2640
Erik Staab2dd72b12020-04-16 15:03:402641 if _MatchesFile(input_api,
2642 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2643 path):
[email protected]99171a92014-06-03 08:44:472644 return False
2645
2646 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162647 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472648 return False
2649 return True
2650
2651 results = []
2652 for affected_file in input_api.AffectedFiles(
2653 file_filter=FilterFile, include_deletes=False):
2654 action = get_action(affected_file)
2655 kwargs = {}
2656 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162657 _MatchesFile(input_api, json_no_comments_patterns,
2658 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472659 kwargs['eat_comments'] = False
2660 parse_error = action(input_api,
2661 affected_file.AbsoluteLocalPath(),
2662 **kwargs)
2663 if parse_error:
2664 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2665 (affected_file.LocalPath(), parse_error)))
2666 return results
2667
2668
Saagar Sanghavifceeaae2020-08-12 16:40:362669def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492670 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472671 import sys
[email protected]760deea2013-12-10 19:33:492672 original_sys_path = sys.path
2673 try:
2674 sys.path = sys.path + [input_api.os_path.join(
2675 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2676 import checkstyle
2677 finally:
2678 # Restore sys.path to what it was before.
2679 sys.path = original_sys_path
2680
2681 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092682 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442683 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492684
2685
Saagar Sanghavifceeaae2020-08-12 16:40:362686def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002687 """Checks to make sure devil is initialized correctly in python scripts."""
2688 script_common_initialize_pattern = input_api.re.compile(
2689 r'script_common\.InitializeEnvironment\(')
2690 devil_env_config_initialize = input_api.re.compile(
2691 r'devil_env\.config\.Initialize\(')
2692
2693 errors = []
2694
2695 sources = lambda affected_file: input_api.FilterSourceFile(
2696 affected_file,
James Cook24a504192020-07-23 00:08:442697 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2698 (r'^build[\\/]android[\\/]devil_chromium\.py',
2699 r'^third_party[\\/].*',)),
2700 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002701
2702 for f in input_api.AffectedSourceFiles(sources):
2703 for line_num, line in f.ChangedContents():
2704 if (script_common_initialize_pattern.search(line) or
2705 devil_env_config_initialize.search(line)):
2706 errors.append("%s:%d" % (f.LocalPath(), line_num))
2707
2708 results = []
2709
2710 if errors:
2711 results.append(output_api.PresubmitError(
2712 'Devil initialization should always be done using '
2713 'devil_chromium.Initialize() in the chromium project, to use better '
2714 'defaults for dependencies (ex. up-to-date version of adb).',
2715 errors))
2716
2717 return results
2718
2719
Sean Kau46e29bc2017-08-28 16:31:162720def _MatchesFile(input_api, patterns, path):
2721 for pattern in patterns:
2722 if input_api.re.search(pattern, path):
2723 return True
2724 return False
2725
2726
Daniel Cheng7052cdf2017-11-21 19:23:292727def _GetOwnersFilesToCheckForIpcOwners(input_api):
2728 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172729
Daniel Cheng7052cdf2017-11-21 19:23:292730 Returns:
2731 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2732 contain to cover IPC-related files with noparent reviewer rules.
2733 """
2734 # Whether or not a file affects IPC is (mostly) determined by a simple list
2735 # of filename patterns.
dchenge07de812016-06-20 19:27:172736 file_patterns = [
palmerb19a0932017-01-24 04:00:312737 # Legacy IPC:
dchenge07de812016-06-20 19:27:172738 '*_messages.cc',
2739 '*_messages*.h',
2740 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312741 # Mojo IPC:
dchenge07de812016-06-20 19:27:172742 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472743 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172744 '*_struct_traits*.*',
2745 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312746 '*.typemap',
2747 # Android native IPC:
2748 '*.aidl',
2749 # Blink uses a different file naming convention:
2750 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472751 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172752 '*StructTraits*.*',
2753 '*TypeConverter*.*',
2754 ]
2755
scottmg7a6ed5ba2016-11-04 18:22:042756 # These third_party directories do not contain IPCs, but contain files
2757 # matching the above patterns, which trigger false positives.
2758 exclude_paths = [
2759 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162760 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232761 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292762 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542763 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162764 # These files are just used to communicate between class loaders running
2765 # in the same process.
2766 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572767 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2768
scottmg7a6ed5ba2016-11-04 18:22:042769 ]
2770
dchenge07de812016-06-20 19:27:172771 # Dictionary mapping an OWNERS file path to Patterns.
2772 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2773 # rules ) to a PatternEntry.
2774 # PatternEntry is a dictionary with two keys:
2775 # - 'files': the files that are matched by this pattern
2776 # - 'rules': the per-file rules needed for this pattern
2777 # For example, if we expect OWNERS file to contain rules for *.mojom and
2778 # *_struct_traits*.*, Patterns might look like this:
2779 # {
2780 # '*.mojom': {
2781 # 'files': ...,
2782 # 'rules': [
2783 # 'per-file *.mojom=set noparent',
2784 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2785 # ],
2786 # },
2787 # '*_struct_traits*.*': {
2788 # 'files': ...,
2789 # 'rules': [
2790 # 'per-file *_struct_traits*.*=set noparent',
2791 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2792 # ],
2793 # },
2794 # }
2795 to_check = {}
2796
Daniel Cheng13ca61a882017-08-25 15:11:252797 def AddPatternToCheck(input_file, pattern):
2798 owners_file = input_api.os_path.join(
2799 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2800 if owners_file not in to_check:
2801 to_check[owners_file] = {}
2802 if pattern not in to_check[owners_file]:
2803 to_check[owners_file][pattern] = {
2804 'files': [],
2805 'rules': [
2806 'per-file %s=set noparent' % pattern,
2807 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2808 ]
2809 }
Vaclav Brozekd5de76a2018-03-17 07:57:502810 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252811
dchenge07de812016-06-20 19:27:172812 # Iterate through the affected files to see what we actually need to check
2813 # for. We should only nag patch authors about per-file rules if a file in that
2814 # directory would match that pattern. If a directory only contains *.mojom
2815 # files and no *_messages*.h files, we should only nag about rules for
2816 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252817 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262818 # Manifest files don't have a strong naming convention. Instead, try to find
2819 # affected .cc and .h files which look like they contain a manifest
2820 # definition.
2821 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2822 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2823 if (manifest_pattern.search(f.LocalPath()) and not
2824 test_manifest_pattern.search(f.LocalPath())):
2825 # We expect all actual service manifest files to contain at least one
2826 # qualified reference to service_manager::Manifest.
2827 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252828 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172829 for pattern in file_patterns:
2830 if input_api.fnmatch.fnmatch(
2831 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042832 skip = False
2833 for exclude in exclude_paths:
2834 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2835 skip = True
2836 break
2837 if skip:
2838 continue
Daniel Cheng13ca61a882017-08-25 15:11:252839 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172840 break
2841
Daniel Cheng7052cdf2017-11-21 19:23:292842 return to_check
2843
2844
Wez17c66962020-04-29 15:26:032845def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2846 """Adds OWNERS files to check for correct Fuchsia security owners."""
2847
2848 file_patterns = [
2849 # Component specifications.
2850 '*.cml', # Component Framework v2.
2851 '*.cmx', # Component Framework v1.
2852
2853 # Fuchsia IDL protocol specifications.
2854 '*.fidl',
2855 ]
2856
Joshua Peraza1ca6d392020-12-08 00:14:092857 # Don't check for owners files for changes in these directories.
2858 exclude_paths = [
2859 'third_party/crashpad/*',
2860 ]
2861
Wez17c66962020-04-29 15:26:032862 def AddPatternToCheck(input_file, pattern):
2863 owners_file = input_api.os_path.join(
2864 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2865 if owners_file not in to_check:
2866 to_check[owners_file] = {}
2867 if pattern not in to_check[owners_file]:
2868 to_check[owners_file][pattern] = {
2869 'files': [],
2870 'rules': [
2871 'per-file %s=set noparent' % pattern,
2872 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2873 ]
2874 }
2875 to_check[owners_file][pattern]['files'].append(input_file)
2876
2877 # Iterate through the affected files to see what we actually need to check
2878 # for. We should only nag patch authors about per-file rules if a file in that
2879 # directory would match that pattern.
2880 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092881 skip = False
2882 for exclude in exclude_paths:
2883 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2884 skip = True
2885 if skip:
2886 continue
2887
Wez17c66962020-04-29 15:26:032888 for pattern in file_patterns:
2889 if input_api.fnmatch.fnmatch(
2890 input_api.os_path.basename(f.LocalPath()), pattern):
2891 AddPatternToCheck(f, pattern)
2892 break
2893
2894 return to_check
2895
2896
Saagar Sanghavifceeaae2020-08-12 16:40:362897def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292898 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2899 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032900 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292901
2902 if to_check:
2903 # If there are any OWNERS files to check, there are IPC-related changes in
2904 # this CL. Auto-CC the review list.
2905 output_api.AppendCC('[email protected]')
2906
2907 # Go through the OWNERS files to check, filtering out rules that are already
2908 # present in that OWNERS file.
Dirk Prankee3c9c62d2021-05-18 18:35:592909 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172910 try:
Dirk Prankee3c9c62d2021-05-18 18:35:592911 with open(owners_file) as f:
dchenge07de812016-06-20 19:27:172912 lines = set(f.read().splitlines())
Jeffrey Youngf3a5c8c42021-05-14 21:56:102913 for entry in patterns.values():
dchenge07de812016-06-20 19:27:172914 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2915 ]
2916 except IOError:
2917 # No OWNERS file, so all the rules are definitely missing.
2918 continue
2919
2920 # All the remaining lines weren't found in OWNERS files, so emit an error.
2921 errors = []
Dirk Prankee3c9c62d2021-05-18 18:35:592922 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172923 missing_lines = []
2924 files = []
Dirk Prankee3c9c62d2021-05-18 18:35:592925 for _, entry in patterns.items():
dchenge07de812016-06-20 19:27:172926 missing_lines.extend(entry['rules'])
2927 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2928 if missing_lines:
2929 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052930 'Because of the presence of files:\n%s\n\n'
2931 '%s needs the following %d lines added:\n\n%s' %
2932 ('\n'.join(files), owners_file, len(missing_lines),
2933 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172934
2935 results = []
2936 if errors:
vabrf5ce3bf92016-07-11 14:52:412937 if input_api.is_committing:
2938 output = output_api.PresubmitError
2939 else:
2940 output = output_api.PresubmitPromptWarning
2941 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592942 'Found OWNERS files that need to be updated for IPC security ' +
2943 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172944 long_text='\n\n'.join(errors)))
2945
2946 return results
2947
2948
Robert Sesek2c905332020-05-06 23:17:132949def _GetFilesUsingSecurityCriticalFunctions(input_api):
2950 """Checks affected files for changes to security-critical calls. This
2951 function checks the full change diff, to catch both additions/changes
2952 and removals.
2953
2954 Returns a dict keyed by file name, and the value is a set of detected
2955 functions.
2956 """
2957 # Map of function pretty name (displayed in an error) to the pattern to
2958 # match it with.
2959 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:372960 'content::GetServiceSandboxType<>()':
2961 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:132962 }
2963 _PATTERNS_TO_CHECK = {
2964 k: input_api.re.compile(v)
2965 for k, v in _PATTERNS_TO_CHECK.items()
2966 }
2967
2968 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2969 files_to_functions = {}
2970 for f in input_api.AffectedFiles():
2971 diff = f.GenerateScmDiff()
2972 for line in diff.split('\n'):
2973 # Not using just RightHandSideLines() because removing a
2974 # call to a security-critical function can be just as important
2975 # as adding or changing the arguments.
2976 if line.startswith('-') or (line.startswith('+') and
2977 not line.startswith('++')):
2978 for name, pattern in _PATTERNS_TO_CHECK.items():
2979 if pattern.search(line):
2980 path = f.LocalPath()
2981 if not path in files_to_functions:
2982 files_to_functions[path] = set()
2983 files_to_functions[path].add(name)
2984 return files_to_functions
2985
2986
Saagar Sanghavifceeaae2020-08-12 16:40:362987def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:132988 """Checks that changes involving security-critical functions are reviewed
2989 by the security team.
2990 """
2991 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:122992 if not len(files_to_functions):
2993 return []
Robert Sesek2c905332020-05-06 23:17:132994
Edward Lesmes1e9fade2021-02-08 20:31:122995 owner_email, reviewers = (
2996 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2997 input_api,
2998 None,
2999 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:133000
Edward Lesmes1e9fade2021-02-08 20:31:123001 # Load the OWNERS file for security changes.
3002 owners_file = 'ipc/SECURITY_OWNERS'
3003 security_owners = input_api.owners_client.ListOwners(owners_file)
3004 has_security_owner = any([owner in reviewers for owner in security_owners])
3005 if has_security_owner:
3006 return []
Robert Sesek2c905332020-05-06 23:17:133007
Edward Lesmes1e9fade2021-02-08 20:31:123008 msg = 'The following files change calls to security-sensive functions\n' \
3009 'that need to be reviewed by {}.\n'.format(owners_file)
3010 for path, names in files_to_functions.items():
3011 msg += ' {}\n'.format(path)
3012 for name in names:
3013 msg += ' {}\n'.format(name)
3014 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133015
Edward Lesmes1e9fade2021-02-08 20:31:123016 if input_api.is_committing:
3017 output = output_api.PresubmitError
3018 else:
3019 output = output_api.PresubmitNotifyResult
3020 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133021
3022
Saagar Sanghavifceeaae2020-08-12 16:40:363023def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263024 """Checks that set noparent is only used together with an OWNERS file in
3025 //build/OWNERS.setnoparent (see also
3026 //docs/code_reviews.md#owners-files-details)
3027 """
3028 errors = []
3029
3030 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3031 allowed_owners_files = set()
3032 with open(allowed_owners_files_file, 'r') as f:
3033 for line in f:
3034 line = line.strip()
3035 if not line or line.startswith('#'):
3036 continue
3037 allowed_owners_files.add(line)
3038
3039 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3040
3041 for f in input_api.AffectedFiles(include_deletes=False):
3042 if not f.LocalPath().endswith('OWNERS'):
3043 continue
3044
3045 found_owners_files = set()
3046 found_set_noparent_lines = dict()
3047
3048 # Parse the OWNERS file.
3049 for lineno, line in enumerate(f.NewContents(), 1):
3050 line = line.strip()
3051 if line.startswith('set noparent'):
3052 found_set_noparent_lines[''] = lineno
3053 if line.startswith('file://'):
3054 if line in allowed_owners_files:
3055 found_owners_files.add('')
3056 if line.startswith('per-file'):
3057 match = per_file_pattern.match(line)
3058 if match:
3059 glob = match.group(1).strip()
3060 directive = match.group(2).strip()
3061 if directive == 'set noparent':
3062 found_set_noparent_lines[glob] = lineno
3063 if directive.startswith('file://'):
3064 if directive in allowed_owners_files:
3065 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153066
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263067 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403068 # listed in build/OWNERS.setnoparent. An exception is made for top level
3069 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143070 if (f.LocalPath().count('/') != 1 and
3071 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403072 for set_noparent_line in found_set_noparent_lines:
3073 if set_noparent_line in found_owners_files:
3074 continue
3075 errors.append(' %s:%d' % (f.LocalPath(),
3076 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263077
3078 results = []
3079 if errors:
3080 if input_api.is_committing:
3081 output = output_api.PresubmitError
3082 else:
3083 output = output_api.PresubmitPromptWarning
3084 results.append(output(
3085 'Found the following "set noparent" restrictions in OWNERS files that '
3086 'do not include owners from build/OWNERS.setnoparent:',
3087 long_text='\n\n'.join(errors)))
3088 return results
3089
3090
Saagar Sanghavifceeaae2020-08-12 16:40:363091def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313092 """Checks that added or removed lines in non third party affected
3093 header files do not lead to new useless class or struct forward
3094 declaration.
jbriance9e12f162016-11-25 07:57:503095 """
3096 results = []
3097 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3098 input_api.re.MULTILINE)
3099 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3100 input_api.re.MULTILINE)
3101 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313102 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193103 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493104 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313105 continue
3106
jbriance9e12f162016-11-25 07:57:503107 if not f.LocalPath().endswith('.h'):
3108 continue
3109
3110 contents = input_api.ReadFile(f)
3111 fwd_decls = input_api.re.findall(class_pattern, contents)
3112 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3113
3114 useless_fwd_decls = []
3115 for decl in fwd_decls:
3116 count = sum(1 for _ in input_api.re.finditer(
3117 r'\b%s\b' % input_api.re.escape(decl), contents))
3118 if count == 1:
3119 useless_fwd_decls.append(decl)
3120
3121 if not useless_fwd_decls:
3122 continue
3123
3124 for line in f.GenerateScmDiff().splitlines():
3125 if (line.startswith('-') and not line.startswith('--') or
3126 line.startswith('+') and not line.startswith('++')):
3127 for decl in useless_fwd_decls:
3128 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3129 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243130 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503131 (f.LocalPath(), decl)))
3132 useless_fwd_decls.remove(decl)
3133
3134 return results
3135
Jinsong Fan91ebbbd2019-04-16 14:57:173136def _CheckAndroidDebuggableBuild(input_api, output_api):
3137 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3138 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3139 this is a debuggable build of Android.
3140 """
3141 build_type_check_pattern = input_api.re.compile(
3142 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3143
3144 errors = []
3145
3146 sources = lambda affected_file: input_api.FilterSourceFile(
3147 affected_file,
James Cook24a504192020-07-23 00:08:443148 files_to_skip=(_EXCLUDED_PATHS +
3149 _TEST_CODE_EXCLUDED_PATHS +
3150 input_api.DEFAULT_FILES_TO_SKIP +
3151 (r"^android_webview[\\/]support_library[\\/]"
3152 "boundary_interfaces[\\/]",
3153 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3154 r'^third_party[\\/].*',
3155 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3156 r"webview[\\/]chromium[\\/]License.*",)),
3157 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173158
3159 for f in input_api.AffectedSourceFiles(sources):
3160 for line_num, line in f.ChangedContents():
3161 if build_type_check_pattern.search(line):
3162 errors.append("%s:%d" % (f.LocalPath(), line_num))
3163
3164 results = []
3165
3166 if errors:
3167 results.append(output_api.PresubmitPromptWarning(
3168 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3169 ' Please use BuildInfo.isDebugAndroid() instead.',
3170 errors))
3171
3172 return results
jbriance9e12f162016-11-25 07:57:503173
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493174# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293175def _CheckAndroidToastUsage(input_api, output_api):
3176 """Checks that code uses org.chromium.ui.widget.Toast instead of
3177 android.widget.Toast (Chromium Toast doesn't force hardware
3178 acceleration on low-end devices, saving memory).
3179 """
3180 toast_import_pattern = input_api.re.compile(
3181 r'^import android\.widget\.Toast;$')
3182
3183 errors = []
3184
3185 sources = lambda affected_file: input_api.FilterSourceFile(
3186 affected_file,
James Cook24a504192020-07-23 00:08:443187 files_to_skip=(_EXCLUDED_PATHS +
3188 _TEST_CODE_EXCLUDED_PATHS +
3189 input_api.DEFAULT_FILES_TO_SKIP +
3190 (r'^chromecast[\\/].*',
3191 r'^remoting[\\/].*')),
3192 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293193
3194 for f in input_api.AffectedSourceFiles(sources):
3195 for line_num, line in f.ChangedContents():
3196 if toast_import_pattern.search(line):
3197 errors.append("%s:%d" % (f.LocalPath(), line_num))
3198
3199 results = []
3200
3201 if errors:
3202 results.append(output_api.PresubmitError(
3203 'android.widget.Toast usage is detected. Android toasts use hardware'
3204 ' acceleration, and can be\ncostly on low-end devices. Please use'
3205 ' org.chromium.ui.widget.Toast instead.\n'
3206 'Contact [email protected] if you have any questions.',
3207 errors))
3208
3209 return results
3210
3211
dgnaa68d5e2015-06-10 10:08:223212def _CheckAndroidCrLogUsage(input_api, output_api):
3213 """Checks that new logs using org.chromium.base.Log:
3214 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513215 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223216 """
pkotwicza1dd0b002016-05-16 14:41:043217
torne89540622017-03-24 19:41:303218 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043219 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303220 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043221 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303222 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043223 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3224 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093225 # The customtabs_benchmark is a small app that does not depend on Chromium
3226 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043227 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043228 ]
3229
dgnaa68d5e2015-06-10 10:08:223230 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123231 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3232 class_in_base_pattern = input_api.re.compile(
3233 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3234 has_some_log_import_pattern = input_api.re.compile(
3235 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223236 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553237 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223238 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463239 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553240 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223241
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463242 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443243 sources = lambda x: input_api.FilterSourceFile(x,
3244 files_to_check=[r'.*\.java$'],
3245 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123246
dgnaa68d5e2015-06-10 10:08:223247 tag_decl_errors = []
3248 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123249 tag_errors = []
dgn38736db2015-09-18 19:20:513250 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123251 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223252
3253 for f in input_api.AffectedSourceFiles(sources):
3254 file_content = input_api.ReadFile(f)
3255 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223256 # Per line checks
dgn87d9fb62015-06-12 09:15:123257 if (cr_log_import_pattern.search(file_content) or
3258 (class_in_base_pattern.search(file_content) and
3259 not has_some_log_import_pattern.search(file_content))):
3260 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223261 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553262 if rough_log_decl_pattern.search(line):
3263 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223264
3265 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123266 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223267 if match:
3268 has_modified_logs = True
3269
3270 # Make sure it uses "TAG"
3271 if not match.group('tag') == 'TAG':
3272 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123273 else:
3274 # Report non cr Log function calls in changed lines
3275 for line_num, line in f.ChangedContents():
3276 if log_call_pattern.search(line):
3277 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223278
3279 # Per file checks
3280 if has_modified_logs:
3281 # Make sure the tag is using the "cr" prefix and is not too long
3282 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513283 tag_name = match.group('name') if match else None
3284 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223285 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513286 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223287 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513288 elif '.' in tag_name:
3289 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223290
3291 results = []
3292 if tag_decl_errors:
3293 results.append(output_api.PresubmitPromptWarning(
3294 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513295 '"private static final String TAG = "<package tag>".\n'
3296 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223297 tag_decl_errors))
3298
3299 if tag_length_errors:
3300 results.append(output_api.PresubmitError(
3301 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513302 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223303 tag_length_errors))
3304
3305 if tag_errors:
3306 results.append(output_api.PresubmitPromptWarning(
3307 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3308 tag_errors))
3309
dgn87d9fb62015-06-12 09:15:123310 if util_log_errors:
dgn4401aa52015-04-29 16:26:173311 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123312 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3313 util_log_errors))
3314
dgn38736db2015-09-18 19:20:513315 if tag_with_dot_errors:
3316 results.append(output_api.PresubmitPromptWarning(
3317 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3318 tag_with_dot_errors))
3319
dgn4401aa52015-04-29 16:26:173320 return results
3321
3322
Yoland Yanb92fa522017-08-28 17:37:063323def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3324 """Checks that junit.framework.* is no longer used."""
3325 deprecated_junit_framework_pattern = input_api.re.compile(
3326 r'^import junit\.framework\..*;',
3327 input_api.re.MULTILINE)
3328 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443329 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063330 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133331 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063332 for line_num, line in f.ChangedContents():
3333 if deprecated_junit_framework_pattern.search(line):
3334 errors.append("%s:%d" % (f.LocalPath(), line_num))
3335
3336 results = []
3337 if errors:
3338 results.append(output_api.PresubmitError(
3339 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3340 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3341 ' if you have any question.', errors))
3342 return results
3343
3344
3345def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3346 """Checks that if new Java test classes have inheritance.
3347 Either the new test class is JUnit3 test or it is a JUnit4 test class
3348 with a base class, either case is undesirable.
3349 """
3350 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3351
3352 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443353 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063354 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133355 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063356 if not f.OldContents():
3357 class_declaration_start_flag = False
3358 for line_num, line in f.ChangedContents():
3359 if class_declaration_pattern.search(line):
3360 class_declaration_start_flag = True
3361 if class_declaration_start_flag and ' extends ' in line:
3362 errors.append('%s:%d' % (f.LocalPath(), line_num))
3363 if '{' in line:
3364 class_declaration_start_flag = False
3365
3366 results = []
3367 if errors:
3368 results.append(output_api.PresubmitPromptWarning(
3369 'The newly created files include Test classes that inherits from base'
3370 ' class. Please do not use inheritance in JUnit4 tests or add new'
3371 ' JUnit3 tests. Contact [email protected] if you have any'
3372 ' questions.', errors))
3373 return results
3374
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203375
yolandyan45001472016-12-21 21:12:423376def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3377 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3378 deprecated_annotation_import_pattern = input_api.re.compile(
3379 r'^import android\.test\.suitebuilder\.annotation\..*;',
3380 input_api.re.MULTILINE)
3381 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443382 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423383 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133384 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423385 for line_num, line in f.ChangedContents():
3386 if deprecated_annotation_import_pattern.search(line):
3387 errors.append("%s:%d" % (f.LocalPath(), line_num))
3388
3389 results = []
3390 if errors:
3391 results.append(output_api.PresubmitError(
3392 'Annotations in android.test.suitebuilder.annotation have been'
3393 ' deprecated since API level 24. Please use android.support.test.filters'
3394 ' from //third_party/android_support_test_runner:runner_java instead.'
3395 ' Contact [email protected] if you have any questions.', errors))
3396 return results
3397
3398
agrieve7b6479d82015-10-07 14:24:223399def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3400 """Checks if MDPI assets are placed in a correct directory."""
3401 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3402 ('/res/drawable/' in f.LocalPath() or
3403 '/res/drawable-ldrtl/' in f.LocalPath()))
3404 errors = []
3405 for f in input_api.AffectedFiles(include_deletes=False,
3406 file_filter=file_filter):
3407 errors.append(' %s' % f.LocalPath())
3408
3409 results = []
3410 if errors:
3411 results.append(output_api.PresubmitError(
3412 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3413 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3414 '/res/drawable-ldrtl/.\n'
3415 'Contact [email protected] if you have questions.', errors))
3416 return results
3417
3418
Nate Fischer535972b2017-09-16 01:06:183419def _CheckAndroidWebkitImports(input_api, output_api):
3420 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353421 android.webview.ValueCallback except in the WebView glue layer
3422 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183423 """
3424 valuecallback_import_pattern = input_api.re.compile(
3425 r'^import android\.webkit\.ValueCallback;$')
3426
3427 errors = []
3428
3429 sources = lambda affected_file: input_api.FilterSourceFile(
3430 affected_file,
James Cook24a504192020-07-23 00:08:443431 files_to_skip=(_EXCLUDED_PATHS +
3432 _TEST_CODE_EXCLUDED_PATHS +
3433 input_api.DEFAULT_FILES_TO_SKIP +
3434 (r'^android_webview[\\/]glue[\\/].*',
3435 r'^weblayer[\\/].*',)),
3436 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183437
3438 for f in input_api.AffectedSourceFiles(sources):
3439 for line_num, line in f.ChangedContents():
3440 if valuecallback_import_pattern.search(line):
3441 errors.append("%s:%d" % (f.LocalPath(), line_num))
3442
3443 results = []
3444
3445 if errors:
3446 results.append(output_api.PresubmitError(
3447 'android.webkit.ValueCallback usage is detected outside of the glue'
3448 ' layer. To stay compatible with the support library, android.webkit.*'
3449 ' classes should only be used inside the glue layer and'
3450 ' org.chromium.base.Callback should be used instead.',
3451 errors))
3452
3453 return results
3454
3455
Becky Zhou7c69b50992018-12-10 19:37:573456def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3457 """Checks Android XML styles """
3458 import sys
3459 original_sys_path = sys.path
3460 try:
3461 sys.path = sys.path + [input_api.os_path.join(
3462 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3463 import checkxmlstyle
3464 finally:
3465 # Restore sys.path to what it was before.
3466 sys.path = original_sys_path
3467
3468 if is_check_on_upload:
3469 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3470 else:
3471 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3472
3473
agrievef32bcc72016-04-04 14:57:403474class PydepsChecker(object):
3475 def __init__(self, input_api, pydeps_files):
3476 self._file_cache = {}
3477 self._input_api = input_api
3478 self._pydeps_files = pydeps_files
3479
3480 def _LoadFile(self, path):
3481 """Returns the list of paths within a .pydeps file relative to //."""
3482 if path not in self._file_cache:
3483 with open(path) as f:
3484 self._file_cache[path] = f.read()
3485 return self._file_cache[path]
3486
3487 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3488 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393489 pydeps_data = self._LoadFile(pydeps_path)
3490 uses_gn_paths = '--gn-paths' in pydeps_data
3491 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3492 if uses_gn_paths:
3493 # Paths look like: //foo/bar/baz
3494 return (e[2:] for e in entries)
3495 else:
3496 # Paths look like: path/relative/to/file.pydeps
3497 os_path = self._input_api.os_path
3498 pydeps_dir = os_path.dirname(pydeps_path)
3499 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403500
3501 def _CreateFilesToPydepsMap(self):
3502 """Returns a map of local_path -> list_of_pydeps."""
3503 ret = {}
3504 for pydep_local_path in self._pydeps_files:
3505 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3506 ret.setdefault(path, []).append(pydep_local_path)
3507 return ret
3508
3509 def ComputeAffectedPydeps(self):
3510 """Returns an iterable of .pydeps files that might need regenerating."""
3511 affected_pydeps = set()
3512 file_to_pydeps_map = None
3513 for f in self._input_api.AffectedFiles(include_deletes=True):
3514 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463515 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3516 # subrepositories. We can't figure out which files change, so re-check
3517 # all files.
3518 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383519 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3520 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403521 return self._pydeps_files
3522 elif local_path.endswith('.pydeps'):
3523 if local_path in self._pydeps_files:
3524 affected_pydeps.add(local_path)
3525 elif local_path.endswith('.py'):
3526 if file_to_pydeps_map is None:
3527 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3528 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3529 return affected_pydeps
3530
3531 def DetermineIfStale(self, pydeps_path):
3532 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413533 import difflib
John Budorick47ca3fe2018-02-10 00:53:103534 import os
3535
agrievef32bcc72016-04-04 14:57:403536 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033537 if old_pydeps_data:
3538 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393539 if '--output' not in cmd:
3540 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033541 old_contents = old_pydeps_data[2:]
3542 else:
3543 # A default cmd that should work in most cases (as long as pydeps filename
3544 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3545 # file is empty/new.
3546 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3547 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3548 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103549 env = dict(os.environ)
3550 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403551 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103552 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413553 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033554 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413555 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403556
3557
Tibor Goldschwendt360793f72019-06-25 18:23:493558def _ParseGclientArgs():
3559 args = {}
3560 with open('build/config/gclient_args.gni', 'r') as f:
3561 for line in f:
3562 line = line.strip()
3563 if not line or line.startswith('#'):
3564 continue
3565 attribute, value = line.split('=')
3566 args[attribute.strip()] = value.strip()
3567 return args
3568
3569
Saagar Sanghavifceeaae2020-08-12 16:40:363570def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403571 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403572 # This check is for Python dependency lists (.pydeps files), and involves
3573 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3574 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283575 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003576 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493577 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403578 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403579 results = []
3580 # First, check for new / deleted .pydeps.
3581 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033582 # Check whether we are running the presubmit check for a file in src.
3583 # f.LocalPath is relative to repo (src, or internal repo).
3584 # os_path.exists is relative to src repo.
3585 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3586 # to src and we can conclude that the pydeps is in src.
3587 if input_api.os_path.exists(f.LocalPath()):
3588 if f.LocalPath().endswith('.pydeps'):
3589 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3590 results.append(output_api.PresubmitError(
3591 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3592 'remove %s' % f.LocalPath()))
3593 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3594 results.append(output_api.PresubmitError(
3595 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3596 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403597
3598 if results:
3599 return results
3600
Mohamed Heikal7cd4d8312020-06-16 16:49:403601 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3602 affected_pydeps = set(checker.ComputeAffectedPydeps())
3603 affected_android_pydeps = affected_pydeps.intersection(
3604 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3605 if affected_android_pydeps and not is_android:
3606 results.append(output_api.PresubmitPromptOrNotify(
3607 'You have changed python files that may affect pydeps for android\n'
3608 'specific scripts. However, the relevant presumbit check cannot be\n'
3609 'run because you are not using an Android checkout. To validate that\n'
3610 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3611 'use the android-internal-presubmit optional trybot.\n'
3612 'Possibly stale pydeps files:\n{}'.format(
3613 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403614
Mohamed Heikal7cd4d8312020-06-16 16:49:403615 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3616 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403617 try:
phajdan.jr0d9878552016-11-04 10:49:413618 result = checker.DetermineIfStale(pydep_path)
3619 if result:
3620 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403621 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413622 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3623 'To regenerate, run:\n\n %s' %
3624 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403625 except input_api.subprocess.CalledProcessError as error:
3626 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3627 long_text=error.output)]
3628
3629 return results
3630
3631
Saagar Sanghavifceeaae2020-08-12 16:40:363632def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433633 """Checks to make sure no header files have |Singleton<|."""
3634 def FileFilter(affected_file):
3635 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443636 files_to_skip = (_EXCLUDED_PATHS +
3637 input_api.DEFAULT_FILES_TO_SKIP +
3638 (r"^base[\\/]memory[\\/]singleton\.h$",
3639 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3640 r"quic_singleton_impl\.h$"))
3641 return input_api.FilterSourceFile(affected_file,
3642 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433643
sergeyu34d21222015-09-16 00:11:443644 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433645 files = []
3646 for f in input_api.AffectedSourceFiles(FileFilter):
3647 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3648 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3649 contents = input_api.ReadFile(f)
3650 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243651 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433652 pattern.search(line)):
3653 files.append(f)
3654 break
3655
3656 if files:
yolandyandaabc6d2016-04-18 18:29:393657 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443658 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433659 'Please move them to an appropriate source file so that the ' +
3660 'template gets instantiated in a single compilation unit.',
3661 files) ]
3662 return []
3663
3664
[email protected]fd20b902014-05-09 02:14:533665_DEPRECATED_CSS = [
3666 # Values
3667 ( "-webkit-box", "flex" ),
3668 ( "-webkit-inline-box", "inline-flex" ),
3669 ( "-webkit-flex", "flex" ),
3670 ( "-webkit-inline-flex", "inline-flex" ),
3671 ( "-webkit-min-content", "min-content" ),
3672 ( "-webkit-max-content", "max-content" ),
3673
3674 # Properties
3675 ( "-webkit-background-clip", "background-clip" ),
3676 ( "-webkit-background-origin", "background-origin" ),
3677 ( "-webkit-background-size", "background-size" ),
3678 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443679 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533680
3681 # Functions
3682 ( "-webkit-gradient", "gradient" ),
3683 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3684 ( "-webkit-linear-gradient", "linear-gradient" ),
3685 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3686 ( "-webkit-radial-gradient", "radial-gradient" ),
3687 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3688]
3689
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203690
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493691# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363692def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533693 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253694 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343695 documentation and iOS CSS for dom distiller
3696 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253697 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533698 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493699 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443700 files_to_skip = (_EXCLUDED_PATHS +
3701 _TEST_CODE_EXCLUDED_PATHS +
3702 input_api.DEFAULT_FILES_TO_SKIP +
3703 (r"^chrome/common/extensions/docs",
3704 r"^chrome/docs",
3705 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3706 r"^components/neterror/resources/neterror.css",
3707 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253708 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443709 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533710 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3711 for line_num, line in fpath.ChangedContents():
3712 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023713 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533714 results.append(output_api.PresubmitError(
3715 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3716 (fpath.LocalPath(), line_num, deprecated_value, value)))
3717 return results
3718
mohan.reddyf21db962014-10-16 12:26:473719
Saagar Sanghavifceeaae2020-08-12 16:40:363720def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363721 bad_files = {}
3722 for f in input_api.AffectedFiles(include_deletes=False):
3723 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493724 not f.LocalPath().startswith('third_party/blink') and
3725 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363726 continue
3727
Daniel Bratell65b033262019-04-23 08:17:063728 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363729 continue
3730
Vaclav Brozekd5de76a2018-03-17 07:57:503731 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363732 if "#include" in line and "../" in line]
3733 if not relative_includes:
3734 continue
3735 bad_files[f.LocalPath()] = relative_includes
3736
3737 if not bad_files:
3738 return []
3739
3740 error_descriptions = []
Dirk Prankee3c9c62d2021-05-18 18:35:593741 for file_path, bad_lines in bad_files.items():
rlanday6802cf632017-05-30 17:48:363742 error_description = file_path
3743 for line in bad_lines:
3744 error_description += '\n ' + line
3745 error_descriptions.append(error_description)
3746
3747 results = []
3748 results.append(output_api.PresubmitError(
3749 'You added one or more relative #include paths (including "../").\n'
3750 'These shouldn\'t be used because they can be used to include headers\n'
3751 'from code that\'s not correctly specified as a dependency in the\n'
3752 'relevant BUILD.gn file(s).',
3753 error_descriptions))
3754
3755 return results
3756
Takeshi Yoshinoe387aa32017-08-02 13:16:133757
Saagar Sanghavifceeaae2020-08-12 16:40:363758def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063759 """Check that nobody tries to include a cc file. It's a relatively
3760 common error which results in duplicate symbols in object
3761 files. This may not always break the build until someone later gets
3762 very confusing linking errors."""
3763 results = []
3764 for f in input_api.AffectedFiles(include_deletes=False):
3765 # We let third_party code do whatever it wants
3766 if (f.LocalPath().startswith('third_party') and
3767 not f.LocalPath().startswith('third_party/blink') and
3768 not f.LocalPath().startswith('third_party\\blink')):
3769 continue
3770
3771 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3772 continue
3773
3774 for _, line in f.ChangedContents():
3775 if line.startswith('#include "'):
3776 included_file = line.split('"')[1]
3777 if _IsCPlusPlusFile(input_api, included_file):
3778 # The most common naming for external files with C++ code,
3779 # apart from standard headers, is to call them foo.inc, but
3780 # Chromium sometimes uses foo-inc.cc so allow that as well.
3781 if not included_file.endswith(('.h', '-inc.cc')):
3782 results.append(output_api.PresubmitError(
3783 'Only header files or .inc files should be included in other\n'
3784 'C++ files. Compiling the contents of a cc file more than once\n'
3785 'will cause duplicate information in the build which may later\n'
3786 'result in strange link_errors.\n' +
3787 f.LocalPath() + ':\n ' +
3788 line))
3789
3790 return results
3791
3792
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203793def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3794 if not isinstance(key, ast.Str):
3795 return 'Key at line %d must be a string literal' % key.lineno
3796 if not isinstance(value, ast.Dict):
3797 return 'Value at line %d must be a dict' % value.lineno
3798 if len(value.keys) != 1:
3799 return 'Dict at line %d must have single entry' % value.lineno
3800 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3801 return (
3802 'Entry at line %d must have a string literal \'filepath\' as key' %
3803 value.lineno)
3804 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133805
Takeshi Yoshinoe387aa32017-08-02 13:16:133806
Sergey Ulanov4af16052018-11-08 02:41:463807def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203808 if not isinstance(key, ast.Str):
3809 return 'Key at line %d must be a string literal' % key.lineno
3810 if not isinstance(value, ast.List):
3811 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463812 for element in value.elts:
3813 if not isinstance(element, ast.Str):
3814 return 'Watchlist elements on line %d is not a string' % key.lineno
3815 if not email_regex.match(element.s):
3816 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3817 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203818 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133819
Takeshi Yoshinoe387aa32017-08-02 13:16:133820
Sergey Ulanov4af16052018-11-08 02:41:463821def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203822 mismatch_template = (
3823 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3824 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133825
Sergey Ulanov4af16052018-11-08 02:41:463826 email_regex = input_api.re.compile(
3827 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3828
3829 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203830 i = 0
3831 last_key = ''
3832 while True:
3833 if i >= len(wd_dict.keys):
3834 if i >= len(w_dict.keys):
3835 return None
3836 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3837 elif i >= len(w_dict.keys):
3838 return (
3839 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133840
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203841 wd_key = wd_dict.keys[i]
3842 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133843
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203844 result = _CheckWatchlistDefinitionsEntrySyntax(
3845 wd_key, wd_dict.values[i], ast)
3846 if result is not None:
3847 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133848
Sergey Ulanov4af16052018-11-08 02:41:463849 result = _CheckWatchlistsEntrySyntax(
3850 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203851 if result is not None:
3852 return 'Bad entry in WATCHLISTS dict: %s' % result
3853
3854 if wd_key.s != w_key.s:
3855 return mismatch_template % (
3856 '%s at line %d' % (wd_key.s, wd_key.lineno),
3857 '%s at line %d' % (w_key.s, w_key.lineno))
3858
3859 if wd_key.s < last_key:
3860 return (
3861 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3862 (wd_key.lineno, w_key.lineno))
3863 last_key = wd_key.s
3864
3865 i = i + 1
3866
3867
Sergey Ulanov4af16052018-11-08 02:41:463868def _CheckWATCHLISTSSyntax(expression, input_api):
3869 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203870 if not isinstance(expression, ast.Expression):
3871 return 'WATCHLISTS file must contain a valid expression'
3872 dictionary = expression.body
3873 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3874 return 'WATCHLISTS file must have single dict with exactly two entries'
3875
3876 first_key = dictionary.keys[0]
3877 first_value = dictionary.values[0]
3878 second_key = dictionary.keys[1]
3879 second_value = dictionary.values[1]
3880
3881 if (not isinstance(first_key, ast.Str) or
3882 first_key.s != 'WATCHLIST_DEFINITIONS' or
3883 not isinstance(first_value, ast.Dict)):
3884 return (
3885 'The first entry of the dict in WATCHLISTS file must be '
3886 'WATCHLIST_DEFINITIONS dict')
3887
3888 if (not isinstance(second_key, ast.Str) or
3889 second_key.s != 'WATCHLISTS' or
3890 not isinstance(second_value, ast.Dict)):
3891 return (
3892 'The second entry of the dict in WATCHLISTS file must be '
3893 'WATCHLISTS dict')
3894
Sergey Ulanov4af16052018-11-08 02:41:463895 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133896
3897
Saagar Sanghavifceeaae2020-08-12 16:40:363898def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133899 for f in input_api.AffectedFiles(include_deletes=False):
3900 if f.LocalPath() == 'WATCHLISTS':
3901 contents = input_api.ReadFile(f, 'r')
3902
3903 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203904 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133905 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203906 # Get an AST tree for it and scan the tree for detailed style checking.
3907 expression = input_api.ast.parse(
3908 contents, filename='WATCHLISTS', mode='eval')
3909 except ValueError as e:
3910 return [output_api.PresubmitError(
3911 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3912 except SyntaxError as e:
3913 return [output_api.PresubmitError(
3914 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3915 except TypeError as e:
3916 return [output_api.PresubmitError(
3917 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133918
Sergey Ulanov4af16052018-11-08 02:41:463919 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203920 if result is not None:
3921 return [output_api.PresubmitError(result)]
3922 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133923
3924 return []
3925
3926
Andrew Grieve1b290e4a22020-11-24 20:07:013927def CheckGnGlobForward(input_api, output_api):
3928 """Checks that forward_variables_from(invoker, "*") follows best practices.
3929
3930 As documented at //build/docs/writing_gn_templates.md
3931 """
3932 def gn_files(f):
3933 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3934
3935 problems = []
3936 for f in input_api.AffectedSourceFiles(gn_files):
3937 for line_num, line in f.ChangedContents():
3938 if 'forward_variables_from(invoker, "*")' in line:
3939 problems.append(
3940 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3941 f.LocalPath(), line_num))
3942
3943 if problems:
3944 return [output_api.PresubmitPromptWarning(
3945 'forward_variables_from("*") without exclusions',
3946 items=sorted(problems),
3947 long_text=('The variables "visibilty" and "test_only" should be '
3948 'explicitly listed in forward_variables_from(). For more '
3949 'details, see:\n'
3950 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
3951 'build/docs/writing_gn_templates.md'
3952 '#Using-forward_variables_from'))]
3953 return []
3954
3955
Saagar Sanghavifceeaae2020-08-12 16:40:363956def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193957 """Checks that newly added header files have corresponding GN changes.
3958 Note that this is only a heuristic. To be precise, run script:
3959 build/check_gn_headers.py.
3960 """
3961
3962 def headers(f):
3963 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443964 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193965
3966 new_headers = []
3967 for f in input_api.AffectedSourceFiles(headers):
3968 if f.Action() != 'A':
3969 continue
3970 new_headers.append(f.LocalPath())
3971
3972 def gn_files(f):
James Cook24a504192020-07-23 00:08:443973 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193974
3975 all_gn_changed_contents = ''
3976 for f in input_api.AffectedSourceFiles(gn_files):
3977 for _, line in f.ChangedContents():
3978 all_gn_changed_contents += line
3979
3980 problems = []
3981 for header in new_headers:
3982 basename = input_api.os_path.basename(header)
3983 if basename not in all_gn_changed_contents:
3984 problems.append(header)
3985
3986 if problems:
3987 return [output_api.PresubmitPromptWarning(
3988 'Missing GN changes for new header files', items=sorted(problems),
3989 long_text='Please double check whether newly added header files need '
3990 'corresponding changes in gn or gni files.\nThis checking is only a '
3991 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3992 'Read https://crbug.com/661774 for more info.')]
3993 return []
3994
3995
Saagar Sanghavifceeaae2020-08-12 16:40:363996def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:023997 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3998
3999 This assumes we won't intentionally reference one product from the other
4000 product.
4001 """
4002 all_problems = []
4003 test_cases = [{
4004 "filename_postfix": "google_chrome_strings.grd",
4005 "correct_name": "Chrome",
4006 "incorrect_name": "Chromium",
4007 }, {
4008 "filename_postfix": "chromium_strings.grd",
4009 "correct_name": "Chromium",
4010 "incorrect_name": "Chrome",
4011 }]
4012
4013 for test_case in test_cases:
4014 problems = []
4015 filename_filter = lambda x: x.LocalPath().endswith(
4016 test_case["filename_postfix"])
4017
4018 # Check each new line. Can yield false positives in multiline comments, but
4019 # easier than trying to parse the XML because messages can have nested
4020 # children, and associating message elements with affected lines is hard.
4021 for f in input_api.AffectedSourceFiles(filename_filter):
4022 for line_num, line in f.ChangedContents():
4023 if "<message" in line or "<!--" in line or "-->" in line:
4024 continue
4025 if test_case["incorrect_name"] in line:
4026 problems.append(
4027 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4028
4029 if problems:
4030 message = (
4031 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4032 % (test_case["correct_name"], test_case["correct_name"],
4033 test_case["incorrect_name"]))
4034 all_problems.append(
4035 output_api.PresubmitPromptWarning(message, items=problems))
4036
4037 return all_problems
4038
4039
Saagar Sanghavifceeaae2020-08-12 16:40:364040def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364041 """Avoid large files, especially binary files, in the repository since
4042 git doesn't scale well for those. They will be in everyone's repo
4043 clones forever, forever making Chromium slower to clone and work
4044 with."""
4045
4046 # Uploading files to cloud storage is not trivial so we don't want
4047 # to set the limit too low, but the upper limit for "normal" large
4048 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4049 # anything over 20 MB is exceptional.
4050 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4051
4052 too_large_files = []
4053 for f in input_api.AffectedFiles():
4054 # Check both added and modified files (but not deleted files).
4055 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384056 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364057 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4058 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4059
4060 if too_large_files:
4061 message = (
4062 'Do not commit large files to git since git scales badly for those.\n' +
4063 'Instead put the large files in cloud storage and use DEPS to\n' +
4064 'fetch them.\n' + '\n'.join(too_large_files)
4065 )
4066 return [output_api.PresubmitError(
4067 'Too large files found in commit', long_text=message + '\n')]
4068 else:
4069 return []
4070
Max Morozb47503b2019-08-08 21:03:274071
Saagar Sanghavifceeaae2020-08-12 16:40:364072def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274073 """Checks specific for fuzz target sources."""
4074 EXPORTED_SYMBOLS = [
4075 'LLVMFuzzerInitialize',
4076 'LLVMFuzzerCustomMutator',
4077 'LLVMFuzzerCustomCrossOver',
4078 'LLVMFuzzerMutate',
4079 ]
4080
4081 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4082
4083 def FilterFile(affected_file):
4084 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444085 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4086 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274087
4088 return input_api.FilterSourceFile(
4089 affected_file,
James Cook24a504192020-07-23 00:08:444090 files_to_check=[files_to_check],
4091 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274092
4093 files_with_missing_header = []
4094 for f in input_api.AffectedSourceFiles(FilterFile):
4095 contents = input_api.ReadFile(f, 'r')
4096 if REQUIRED_HEADER in contents:
4097 continue
4098
4099 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4100 files_with_missing_header.append(f.LocalPath())
4101
4102 if not files_with_missing_header:
4103 return []
4104
4105 long_text = (
4106 'If you define any of the libFuzzer optional functions (%s), it is '
4107 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4108 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4109 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4110 'to access command line arguments passed to the fuzzer. Instead, prefer '
4111 'static initialization and shared resources as documented in '
4112 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4113 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4114 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4115 )
4116
4117 return [output_api.PresubmitPromptWarning(
4118 message="Missing '%s' in:" % REQUIRED_HEADER,
4119 items=files_with_missing_header,
4120 long_text=long_text)]
4121
4122
Mohamed Heikald048240a2019-11-12 16:57:374123def _CheckNewImagesWarning(input_api, output_api):
4124 """
4125 Warns authors who add images into the repo to make sure their images are
4126 optimized before committing.
4127 """
4128 images_added = False
4129 image_paths = []
4130 errors = []
4131 filter_lambda = lambda x: input_api.FilterSourceFile(
4132 x,
James Cook24a504192020-07-23 00:08:444133 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4134 + input_api.DEFAULT_FILES_TO_SKIP),
4135 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374136 )
4137 for f in input_api.AffectedFiles(
4138 include_deletes=False, file_filter=filter_lambda):
4139 local_path = f.LocalPath().lower()
4140 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4141 images_added = True
4142 image_paths.append(f)
4143 if images_added:
4144 errors.append(output_api.PresubmitPromptWarning(
4145 'It looks like you are trying to commit some images. If these are '
4146 'non-test-only images, please make sure to read and apply the tips in '
4147 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4148 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4149 'FYI only and will not block your CL on the CQ.', image_paths))
4150 return errors
4151
4152
Saagar Sanghavifceeaae2020-08-12 16:40:364153def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574154 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224155 results = []
dgnaa68d5e2015-06-10 10:08:224156 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174157 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224158 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294159 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064160 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4161 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424162 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184163 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574164 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374165 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154166 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574167 return results
4168
Saagar Sanghavifceeaae2020-08-12 16:40:364169def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574170 """Groups commit checks that target android code."""
4171 results = []
4172 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224173 return results
4174
Chris Hall59f8d0c72020-05-01 07:31:194175# TODO(chrishall): could we additionally match on any path owned by
4176# ui/accessibility/OWNERS ?
4177_ACCESSIBILITY_PATHS = (
4178 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4179 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4180 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4181 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4182 r"^content[\\/]browser[\\/]accessibility[\\/]",
4183 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4184 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4185 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4186 r"^ui[\\/]accessibility[\\/]",
4187 r"^ui[\\/]views[\\/]accessibility[\\/]",
4188)
4189
Saagar Sanghavifceeaae2020-08-12 16:40:364190def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194191 """Checks that commits to accessibility code contain an AX-Relnotes field in
4192 their commit message."""
4193 def FileFilter(affected_file):
4194 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444195 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194196
4197 # Only consider changes affecting accessibility paths.
4198 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4199 return []
4200
Akihiro Ota08108e542020-05-20 15:30:534201 # AX-Relnotes can appear in either the description or the footer.
4202 # When searching the description, require 'AX-Relnotes:' to appear at the
4203 # beginning of a line.
4204 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4205 description_has_relnotes = any(ax_regex.match(line)
4206 for line in input_api.change.DescriptionText().lower().splitlines())
4207
4208 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4209 'AX-Relnotes', [])
4210 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194211 return []
4212
4213 # TODO(chrishall): link to Relnotes documentation in message.
4214 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4215 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4216 "user-facing changes"
4217 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4218 "user-facing effects"
4219 "\n if this is confusing or annoying then please contact members "
4220 "of ui/accessibility/OWNERS.")
4221
4222 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224223
seanmccullough4a9356252021-04-08 19:54:094224# string pattern, sequence of strings to show when pattern matches,
4225# error flag. True if match is a presubmit error, otherwise it's a warning.
4226_NON_INCLUSIVE_TERMS = (
4227 (
4228 # Note that \b pattern in python re is pretty particular. In this
4229 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4230 # ...' will not. This may require some tweaking to catch these cases
4231 # without triggering a lot of false positives. Leaving it naive and
4232 # less matchy for now.
4233 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4234 (
4235 'Please don\'t use blacklist, whitelist, ' # nocheck
4236 'or slave in your', # nocheck
4237 'code and make every effort to use other terms. Using "// nocheck"',
4238 '"# nocheck" or "<!-- nocheck -->"',
4239 'at the end of the offending line will bypass this PRESUBMIT error',
4240 'but avoid using this whenever possible. Reach out to',
4241 '[email protected] if you have questions'),
4242 True),)
4243
Saagar Sanghavifceeaae2020-08-12 16:40:364244def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394245 """Checks common to both upload and commit."""
4246 results = []
4247 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384248 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544249 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084250
4251 author = input_api.change.author_email
4252 if author and author not in _KNOWN_ROBOTS:
4253 results.extend(
4254 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4255
[email protected]9f919cc2013-07-31 03:04:044256 results.extend(
4257 input_api.canned_checks.CheckChangeHasNoTabs(
4258 input_api,
4259 output_api,
4260 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434261 results.extend(input_api.RunTests(
4262 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244263
Edward Lesmesce51df52020-08-04 22:10:174264 dirmd_bin = input_api.os_path.join(
4265 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4266 results.extend(input_api.RunTests(
4267 input_api.canned_checks.CheckDirMetadataFormat(
4268 input_api, output_api, dirmd_bin)))
4269 results.extend(
4270 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4271 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554272 results.extend(
4273 input_api.canned_checks.CheckNoNewMetadataInOwners(
4274 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094275 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4276 input_api, output_api,
4277 excluded_directories_relative_path = [
4278 'infra',
4279 'inclusive_language_presubmit_exempt_dirs.txt'
4280 ],
4281 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174282
Vaclav Brozekcdc7defb2018-03-20 09:54:354283 for f in input_api.AffectedFiles():
4284 path, name = input_api.os_path.split(f.LocalPath())
4285 if name == 'PRESUBMIT.py':
4286 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004287 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4288 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074289 # The PRESUBMIT.py file (and the directory containing it) might
4290 # have been affected by being moved or removed, so only try to
4291 # run the tests if they still exist.
Dirk Prankee3c9c62d2021-05-18 18:35:594292 use_python3 = False
4293 with open(f.LocalPath()) as fp:
4294 use_python3 = any(line.startswith('USE_PYTHON3 = True')
4295 for line in fp.readlines())
4296
Dirk Pranke38557312018-04-18 00:53:074297 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4298 input_api, output_api, full_path,
Dirk Prankee3c9c62d2021-05-18 18:35:594299 files_to_check=[r'^PRESUBMIT_test\.py$'],
4300 run_on_python2=not use_python3,
4301 run_on_python3=use_python3))
[email protected]22c9bd72011-03-27 16:47:394302 return results
[email protected]1f7b4172010-01-28 01:17:344303
[email protected]b337cb5b2011-01-23 21:24:054304
Saagar Sanghavifceeaae2020-08-12 16:40:364305def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494306 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4307 if f.LocalPath().endswith(('.orig', '.rej'))]
4308 if problems:
4309 return [output_api.PresubmitError(
4310 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034311 else:
4312 return []
[email protected]b8079ae4a2012-12-05 19:56:494313
4314
Saagar Sanghavifceeaae2020-08-12 16:40:364315def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214316 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4317 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4318 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074319 include_re = input_api.re.compile(
4320 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4321 extension_re = input_api.re.compile(r'\.[a-z]+$')
4322 errors = []
4323 for f in input_api.AffectedFiles():
4324 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4325 continue
4326 found_line_number = None
4327 found_macro = None
4328 for line_num, line in f.ChangedContents():
4329 match = macro_re.search(line)
4330 if match:
4331 found_line_number = line_num
4332 found_macro = match.group(2)
4333 break
4334 if not found_line_number:
4335 continue
4336
4337 found_include = False
4338 for line in f.NewContents():
4339 if include_re.search(line):
4340 found_include = True
4341 break
4342 if found_include:
4343 continue
4344
4345 if not f.LocalPath().endswith('.h'):
4346 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4347 try:
4348 content = input_api.ReadFile(primary_header_path, 'r')
4349 if include_re.search(content):
4350 continue
4351 except IOError:
4352 pass
4353 errors.append('%s:%d %s macro is used without including build/'
4354 'build_config.h.'
4355 % (f.LocalPath(), found_line_number, found_macro))
4356 if errors:
4357 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4358 return []
4359
4360
Lei Zhang1c12a22f2021-05-12 11:28:454361def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
4362 stl_include_re = input_api.re.compile(
Lei Zhang0643e342021-05-12 18:02:124363 r'^#include\s+<('
Lei Zhang1c12a22f2021-05-12 11:28:454364 r'algorithm|'
4365 r'array|'
4366 r'limits|'
4367 r'list|'
4368 r'map|'
4369 r'memory|'
4370 r'queue|'
4371 r'set|'
4372 r'string|'
4373 r'unordered_map|'
4374 r'unordered_set|'
4375 r'utility|'
Lei Zhang0643e342021-05-12 18:02:124376 r'vector)>')
Lei Zhang1c12a22f2021-05-12 11:28:454377 std_namespace_re = input_api.re.compile(r'std::')
4378 errors = []
4379 for f in input_api.AffectedFiles():
4380 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4381 continue
4382
4383 uses_std_namespace = False
4384 has_stl_include = False
4385 for line in f.NewContents():
4386 if has_stl_include and uses_std_namespace:
4387 break
4388
4389 if not has_stl_include and stl_include_re.search(line):
4390 has_stl_include = True
4391 continue
4392
4393 if not uses_std_namespace and std_namespace_re.search(line):
4394 uses_std_namespace = True
4395 continue
4396
4397 if has_stl_include and not uses_std_namespace:
4398 errors.append('%s: Includes STL header(s) but does not reference std::'
4399 % f.LocalPath())
4400 if errors:
4401 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4402 return []
4403
4404
[email protected]b00342e7f2013-03-26 16:21:544405def _DidYouMeanOSMacro(bad_macro):
4406 try:
4407 return {'A': 'OS_ANDROID',
4408 'B': 'OS_BSD',
4409 'C': 'OS_CHROMEOS',
4410 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444411 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544412 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444413 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544414 'N': 'OS_NACL',
4415 'O': 'OS_OPENBSD',
4416 'P': 'OS_POSIX',
4417 'S': 'OS_SOLARIS',
4418 'W': 'OS_WIN'}[bad_macro[3].upper()]
4419 except KeyError:
4420 return ''
4421
4422
4423def _CheckForInvalidOSMacrosInFile(input_api, f):
4424 """Check for sensible looking, totally invalid OS macros."""
4425 preprocessor_statement = input_api.re.compile(r'^\s*#')
4426 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4427 results = []
4428 for lnum, line in f.ChangedContents():
4429 if preprocessor_statement.search(line):
4430 for match in os_macro.finditer(line):
4431 if not match.group(1) in _VALID_OS_MACROS:
4432 good = _DidYouMeanOSMacro(match.group(1))
4433 did_you_mean = ' (did you mean %s?)' % good if good else ''
4434 results.append(' %s:%d %s%s' % (f.LocalPath(),
4435 lnum,
4436 match.group(1),
4437 did_you_mean))
4438 return results
4439
4440
Saagar Sanghavifceeaae2020-08-12 16:40:364441def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544442 """Check all affected files for invalid OS macros."""
4443 bad_macros = []
tzik3f295992018-12-04 20:32:234444 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474445 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544446 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4447
4448 if not bad_macros:
4449 return []
4450
4451 return [output_api.PresubmitError(
4452 'Possibly invalid OS macro[s] found. Please fix your code\n'
4453 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4454
lliabraa35bab3932014-10-01 12:16:444455
4456def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4457 """Check all affected files for invalid "if defined" macros."""
4458 ALWAYS_DEFINED_MACROS = (
4459 "TARGET_CPU_PPC",
4460 "TARGET_CPU_PPC64",
4461 "TARGET_CPU_68K",
4462 "TARGET_CPU_X86",
4463 "TARGET_CPU_ARM",
4464 "TARGET_CPU_MIPS",
4465 "TARGET_CPU_SPARC",
4466 "TARGET_CPU_ALPHA",
4467 "TARGET_IPHONE_SIMULATOR",
4468 "TARGET_OS_EMBEDDED",
4469 "TARGET_OS_IPHONE",
4470 "TARGET_OS_MAC",
4471 "TARGET_OS_UNIX",
4472 "TARGET_OS_WIN32",
4473 )
4474 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4475 results = []
4476 for lnum, line in f.ChangedContents():
4477 for match in ifdef_macro.finditer(line):
4478 if match.group(1) in ALWAYS_DEFINED_MACROS:
4479 always_defined = ' %s is always defined. ' % match.group(1)
4480 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4481 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4482 lnum,
4483 always_defined,
4484 did_you_mean))
4485 return results
4486
4487
Saagar Sanghavifceeaae2020-08-12 16:40:364488def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444489 """Check all affected files for invalid "if defined" macros."""
4490 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054491 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444492 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054493 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214494 continue
lliabraa35bab3932014-10-01 12:16:444495 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4496 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4497
4498 if not bad_macros:
4499 return []
4500
4501 return [output_api.PresubmitError(
4502 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4503 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4504 bad_macros)]
4505
4506
Saagar Sanghavifceeaae2020-08-12 16:40:364507def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044508 """Check for same IPC rules described in
4509 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4510 """
4511 base_pattern = r'IPC_ENUM_TRAITS\('
4512 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4513 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4514
4515 problems = []
4516 for f in input_api.AffectedSourceFiles(None):
4517 local_path = f.LocalPath()
4518 if not local_path.endswith('.h'):
4519 continue
4520 for line_number, line in f.ChangedContents():
4521 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4522 problems.append(
4523 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4524
4525 if problems:
4526 return [output_api.PresubmitPromptWarning(
4527 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4528 else:
4529 return []
4530
[email protected]b00342e7f2013-03-26 16:21:544531
Saagar Sanghavifceeaae2020-08-12 16:40:364532def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054533 """Check to make sure no files being submitted have long paths.
4534 This causes issues on Windows.
4535 """
4536 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194537 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054538 local_path = f.LocalPath()
4539 # Windows has a path limit of 260 characters. Limit path length to 200 so
4540 # that we have some extra for the prefix on dev machines and the bots.
4541 if len(local_path) > 200:
4542 problems.append(local_path)
4543
4544 if problems:
4545 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4546 else:
4547 return []
4548
4549
Saagar Sanghavifceeaae2020-08-12 16:40:364550def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144551 """Check that header files have proper guards against multiple inclusion.
4552 If a file should not have such guards (and it probably should) then it
4553 should include the string "no-include-guard-because-multiply-included".
4554 """
Daniel Bratell6a75baef62018-06-04 10:04:454555 def is_chromium_header_file(f):
4556 # We only check header files under the control of the Chromium
4557 # project. That is, those outside third_party apart from
4558 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324559 # We also exclude *_message_generator.h headers as they use
4560 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454561 file_with_path = input_api.os_path.normpath(f.LocalPath())
4562 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324563 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454564 (not file_with_path.startswith('third_party') or
4565 file_with_path.startswith(
4566 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144567
4568 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344569 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144570
4571 errors = []
4572
Daniel Bratell6a75baef62018-06-04 10:04:454573 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144574 guard_name = None
4575 guard_line_number = None
4576 seen_guard_end = False
4577
4578 file_with_path = input_api.os_path.normpath(f.LocalPath())
4579 base_file_name = input_api.os_path.splitext(
4580 input_api.os_path.basename(file_with_path))[0]
4581 upper_base_file_name = base_file_name.upper()
4582
4583 expected_guard = replace_special_with_underscore(
4584 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144585
4586 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574587 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4588 # are too many (1000+) files with slight deviations from the
4589 # coding style. The most important part is that the include guard
4590 # is there, and that it's unique, not the name so this check is
4591 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144592 #
4593 # As code becomes more uniform, this could be made stricter.
4594
4595 guard_name_pattern_list = [
4596 # Anything with the right suffix (maybe with an extra _).
4597 r'\w+_H__?',
4598
Daniel Bratell39b5b062018-05-16 18:09:574599 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144600 r'\w+_h',
4601
4602 # Anything including the uppercase name of the file.
4603 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4604 upper_base_file_name)) + r'\w*',
4605 ]
4606 guard_name_pattern = '|'.join(guard_name_pattern_list)
4607 guard_pattern = input_api.re.compile(
4608 r'#ifndef\s+(' + guard_name_pattern + ')')
4609
4610 for line_number, line in enumerate(f.NewContents()):
4611 if 'no-include-guard-because-multiply-included' in line:
4612 guard_name = 'DUMMY' # To not trigger check outside the loop.
4613 break
4614
4615 if guard_name is None:
4616 match = guard_pattern.match(line)
4617 if match:
4618 guard_name = match.group(1)
4619 guard_line_number = line_number
4620
Daniel Bratell39b5b062018-05-16 18:09:574621 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454622 # don't match the chromium style guide, but new files should
4623 # get it right.
4624 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574625 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144626 errors.append(output_api.PresubmitPromptWarning(
4627 'Header using the wrong include guard name %s' % guard_name,
4628 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574629 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144630 else:
4631 # The line after #ifndef should have a #define of the same name.
4632 if line_number == guard_line_number + 1:
4633 expected_line = '#define %s' % guard_name
4634 if line != expected_line:
4635 errors.append(output_api.PresubmitPromptWarning(
4636 'Missing "%s" for include guard' % expected_line,
4637 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4638 'Expected: %r\nGot: %r' % (expected_line, line)))
4639
4640 if not seen_guard_end and line == '#endif // %s' % guard_name:
4641 seen_guard_end = True
4642 elif seen_guard_end:
4643 if line.strip() != '':
4644 errors.append(output_api.PresubmitPromptWarning(
4645 'Include guard %s not covering the whole file' % (
4646 guard_name), [f.LocalPath()]))
4647 break # Nothing else to check and enough to warn once.
4648
4649 if guard_name is None:
4650 errors.append(output_api.PresubmitPromptWarning(
4651 'Missing include guard %s' % expected_guard,
4652 [f.LocalPath()],
4653 'Missing include guard in %s\n'
4654 'Recommended name: %s\n'
4655 'This check can be disabled by having the string\n'
4656 'no-include-guard-because-multiply-included in the header.' %
4657 (f.LocalPath(), expected_guard)))
4658
4659 return errors
4660
4661
Saagar Sanghavifceeaae2020-08-12 16:40:364662def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234663 """Check source code and known ascii text files for Windows style line
4664 endings.
4665 """
Xianzhu Wang58e172f2021-05-17 03:58:384666 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234667
4668 file_inclusion_pattern = (
4669 known_text_files,
4670 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4671 )
4672
mostynbb639aca52015-01-07 20:31:234673 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534674 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444675 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534676 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504677 include_file = False
4678 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234679 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504680 include_file = True
4681 if include_file:
4682 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234683
4684 if problems:
4685 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4686 'these files to contain Windows style line endings?\n' +
4687 '\n'.join(problems))]
4688
4689 return []
4690
Jose Magana2b456f22021-03-09 23:26:404691def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4692 """Check source code for use of Chrome App technologies being
4693 deprecated.
4694 """
4695
4696 def _CheckForDeprecatedTech(input_api, output_api,
4697 detection_list, files_to_check = None, files_to_skip = None):
4698
4699 if (files_to_check or files_to_skip):
4700 source_file_filter = lambda f: input_api.FilterSourceFile(
4701 f, files_to_check=files_to_check,
4702 files_to_skip=files_to_skip)
4703 else:
4704 source_file_filter = None
4705
4706 problems = []
4707
4708 for f in input_api.AffectedSourceFiles(source_file_filter):
4709 if f.Action() == 'D':
4710 continue
4711 for _, line in f.ChangedContents():
4712 if any( detect in line for detect in detection_list ):
4713 problems.append(f.LocalPath())
4714
4715 return problems
4716
4717 # to avoid this presubmit script triggering warnings
4718 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4719
4720 problems =[]
4721
4722 # NMF: any files with extensions .nmf or NMF
4723 _NMF_FILES = r'\.(nmf|NMF)$'
4724 problems += _CheckForDeprecatedTech(input_api, output_api,
4725 detection_list = [''], # any change to the file will trigger warning
4726 files_to_check = [ r'.+%s' % _NMF_FILES ])
4727
4728 # MANIFEST: any manifest.json that in its diff includes "app":
4729 _MANIFEST_FILES = r'(manifest\.json)$'
4730 problems += _CheckForDeprecatedTech(input_api, output_api,
4731 detection_list = ['"app":'],
4732 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4733
4734 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4735 problems += _CheckForDeprecatedTech(input_api, output_api,
4736 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4737 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4738
4739 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4740 problems += _CheckForDeprecatedTech(input_api, output_api,
4741 detection_list = ['#include "ppapi','#include <ppapi'],
4742 files_to_check = (
4743 r'.+%s' % _HEADER_EXTENSIONS,
4744 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4745 files_to_skip = [r"^ppapi[\\/]"] )
4746
Jose Magana2b456f22021-03-09 23:26:404747 if problems:
4748 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4749 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4750 ' PNaCl, PPAPI). See this blog post for more details:\n'
4751 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4752 'and this documentation for options to replace these technologies:\n'
4753 'https://developer.chrome.com/docs/apps/migration/\n'+
4754 '\n'.join(problems))]
4755
4756 return []
4757
mostynbb639aca52015-01-07 20:31:234758
Saagar Sanghavifceeaae2020-08-12 16:40:364759def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134760 """Checks that all source files use SYSLOG properly."""
4761 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364762 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564763 for line_number, line in f.ChangedContents():
4764 if 'SYSLOG' in line:
4765 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4766
pastarmovj89f7ee12016-09-20 14:58:134767 if syslog_files:
4768 return [output_api.PresubmitPromptWarning(
4769 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4770 ' calls.\nFiles to check:\n', items=syslog_files)]
4771 return []
4772
4773
[email protected]1f7b4172010-01-28 01:17:344774def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364775 if input_api.version < [2, 0, 0]:
4776 return [output_api.PresubmitError("Your depot_tools is out of date. "
4777 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4778 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344779 results = []
scottmg39b29952014-12-08 18:31:284780 results.extend(
jam93a6ee792017-02-08 23:59:224781 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544782 return results
[email protected]ca8d1982009-02-19 16:33:124783
4784
4785def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364786 if input_api.version < [2, 0, 0]:
4787 return [output_api.PresubmitError("Your depot_tools is out of date. "
4788 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4789 "but your version is %d.%d.%d" % tuple(input_api.version))]
4790
[email protected]fe5f57c52009-06-05 14:25:544791 results = []
[email protected]fe5f57c52009-06-05 14:25:544792 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274793 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344794 input_api,
4795 output_api,
[email protected]2fdd1f362013-01-16 03:56:034796 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274797
jam93a6ee792017-02-08 23:59:224798 results.extend(
4799 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544800 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4801 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384802 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4803 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414804 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4805 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544806 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144807
4808
Saagar Sanghavifceeaae2020-08-12 16:40:364809def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264810 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024811 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4812 # footer is set to true.
4813 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264814 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024815 footer.lower()
4816 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264817 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024818
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144819 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264820 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144821 import sys
4822 from io import StringIO
4823
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144824 new_or_added_paths = set(f.LocalPath()
4825 for f in input_api.AffectedFiles()
4826 if (f.Action() == 'A' or f.Action() == 'M'))
4827 removed_paths = set(f.LocalPath()
4828 for f in input_api.AffectedFiles(include_deletes=True)
4829 if f.Action() == 'D')
4830
Andrew Grieve0e8790c2020-09-03 17:27:324831 affected_grds = [
4832 f for f in input_api.AffectedFiles()
4833 if f.LocalPath().endswith(('.grd', '.grdp'))
4834 ]
4835 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164836 if not affected_grds:
4837 return []
4838
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144839 affected_png_paths = [f.AbsoluteLocalPath()
4840 for f in input_api.AffectedFiles()
4841 if (f.LocalPath().endswith('.png'))]
4842
4843 # Check for screenshots. Developers can upload screenshots using
4844 # tools/translation/upload_screenshots.py which finds and uploads
4845 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4846 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4847 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4848 #
4849 # The logic here is as follows:
4850 #
4851 # - If the CL has a .png file under the screenshots directory for a grd
4852 # file, warn the developer. Actual images should never be checked into the
4853 # Chrome repo.
4854 #
4855 # - If the CL contains modified or new messages in grd files and doesn't
4856 # contain the corresponding .sha1 files, warn the developer to add images
4857 # and upload them via tools/translation/upload_screenshots.py.
4858 #
4859 # - If the CL contains modified or new messages in grd files and the
4860 # corresponding .sha1 files, everything looks good.
4861 #
4862 # - If the CL contains removed messages in grd files but the corresponding
4863 # .sha1 files aren't removed, warn the developer to remove them.
4864 unnecessary_screenshots = []
4865 missing_sha1 = []
4866 unnecessary_sha1_files = []
4867
Rainhard Findlingfc31844c52020-05-15 09:58:264868 # This checks verifies that the ICU syntax of messages this CL touched is
4869 # valid, and reports any found syntax errors.
4870 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4871 # without developers being aware of them. Later on, such ICU syntax errors
4872 # break message extraction for translation, hence would block Chromium
4873 # translations until they are fixed.
4874 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144875
4876 def _CheckScreenshotAdded(screenshots_dir, message_id):
4877 sha1_path = input_api.os_path.join(
4878 screenshots_dir, message_id + '.png.sha1')
4879 if sha1_path not in new_or_added_paths:
4880 missing_sha1.append(sha1_path)
4881
4882
4883 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4884 sha1_path = input_api.os_path.join(
4885 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034886 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144887 unnecessary_sha1_files.append(sha1_path)
4888
Rainhard Findlingfc31844c52020-05-15 09:58:264889
4890 def _ValidateIcuSyntax(text, level, signatures):
4891 """Validates ICU syntax of a text string.
4892
4893 Check if text looks similar to ICU and checks for ICU syntax correctness
4894 in this case. Reports various issues with ICU syntax and values of
4895 variants. Supports checking of nested messages. Accumulate information of
4896 each ICU messages found in the text for further checking.
4897
4898 Args:
4899 text: a string to check.
4900 level: a number of current nesting level.
4901 signatures: an accumulator, a list of tuple of (level, variable,
4902 kind, variants).
4903
4904 Returns:
4905 None if a string is not ICU or no issue detected.
4906 A tuple of (message, start index, end index) if an issue detected.
4907 """
4908 valid_types = {
4909 'plural': (frozenset(
4910 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4911 frozenset(['=1', 'other'])),
4912 'selectordinal': (frozenset(
4913 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4914 frozenset(['one', 'other'])),
4915 'select': (frozenset(), frozenset(['other'])),
4916 }
4917
4918 # Check if the message looks like an attempt to use ICU
4919 # plural. If yes - check if its syntax strictly matches ICU format.
4920 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4921 if not like:
4922 signatures.append((level, None, None, None))
4923 return
4924
4925 # Check for valid prefix and suffix
4926 m = re.match(
4927 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4928 r'(plural|selectordinal|select),\s*'
4929 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4930 if not m:
4931 return (('This message looks like an ICU plural, '
4932 'but does not follow ICU syntax.'), like.start(), like.end())
4933 starting, variable, kind, variant_pairs = m.groups()
4934 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4935 if depth:
4936 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4937 len(text))
4938 first = text[0]
4939 ending = text[last_pos:]
4940 if not starting:
4941 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4942 last_pos)
4943 if not ending or '}' not in ending:
4944 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4945 last_pos)
4946 elif first != '{':
4947 return (
4948 ('Invalid ICU format. Extra characters at the start of a complex '
4949 'message (go/icu-message-migration): "%s"') %
4950 starting, 0, len(starting))
4951 elif ending != '}':
4952 return (('Invalid ICU format. Extra characters at the end of a complex '
4953 'message (go/icu-message-migration): "%s"')
4954 % ending, last_pos - 1, len(text) - 1)
4955 if kind not in valid_types:
4956 return (('Unknown ICU message type %s. '
4957 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4958 known, required = valid_types[kind]
4959 defined_variants = set()
4960 for variant, variant_range, value, value_range in variants:
4961 start, end = variant_range
4962 if variant in defined_variants:
4963 return ('Variant "%s" is defined more than once' % variant,
4964 start, end)
4965 elif known and variant not in known:
4966 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4967 start, end)
4968 defined_variants.add(variant)
4969 # Check for nested structure
4970 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4971 if res:
4972 return (res[0], res[1] + value_range[0] + 1,
4973 res[2] + value_range[0] + 1)
4974 missing = required - defined_variants
4975 if missing:
4976 return ('Required variants missing: %s' % ', '.join(missing), 0,
4977 len(text))
4978 signatures.append((level, variable, kind, defined_variants))
4979
4980
4981 def _ParseIcuVariants(text, offset=0):
4982 """Parse variants part of ICU complex message.
4983
4984 Builds a tuple of variant names and values, as well as
4985 their offsets in the input string.
4986
4987 Args:
4988 text: a string to parse
4989 offset: additional offset to add to positions in the text to get correct
4990 position in the complete ICU string.
4991
4992 Returns:
4993 List of tuples, each tuple consist of four fields: variant name,
4994 variant name span (tuple of two integers), variant value, value
4995 span (tuple of two integers).
4996 """
4997 depth, start, end = 0, -1, -1
4998 variants = []
4999 key = None
5000 for idx, char in enumerate(text):
5001 if char == '{':
5002 if not depth:
5003 start = idx
5004 chunk = text[end + 1:start]
5005 key = chunk.strip()
5006 pos = offset + end + 1 + chunk.find(key)
5007 span = (pos, pos + len(key))
5008 depth += 1
5009 elif char == '}':
5010 if not depth:
5011 return variants, depth, offset + idx
5012 depth -= 1
5013 if not depth:
5014 end = idx
5015 variants.append((key, span, text[start:end + 1], (offset + start,
5016 offset + end + 1)))
5017 return variants, depth, offset + end + 1
5018
meacer8c0d3832019-12-26 21:46:165019 try:
5020 old_sys_path = sys.path
5021 sys.path = sys.path + [input_api.os_path.join(
5022 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5023 from helper import grd_helper
5024 finally:
5025 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145026
5027 for f in affected_grds:
5028 file_path = f.LocalPath()
5029 old_id_to_msg_map = {}
5030 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385031 # Note that this code doesn't check if the file has been deleted. This is
5032 # OK because it only uses the old and new file contents and doesn't load
5033 # the file via its path.
5034 # It's also possible that a file's content refers to a renamed or deleted
5035 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5036 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5037 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145038 if file_path.endswith('.grdp'):
5039 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585040 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595041 '\n'.join(f.OldContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145042 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585043 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595044 '\n'.join(f.NewContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145045 else:
meacerff8a9b62019-12-10 19:43:585046 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145047 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585048 old_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595049 StringIO('\n'.join(f.OldContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145050 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585051 new_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595052 StringIO('\n'.join(f.NewContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145053
Rainhard Findlingd8d04372020-08-13 13:30:095054 grd_name, ext = input_api.os_path.splitext(
5055 input_api.os_path.basename(file_path))
5056 screenshots_dir = input_api.os_path.join(
5057 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5058
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145059 # Compute added, removed and modified message IDs.
5060 old_ids = set(old_id_to_msg_map)
5061 new_ids = set(new_id_to_msg_map)
5062 added_ids = new_ids - old_ids
5063 removed_ids = old_ids - new_ids
5064 modified_ids = set([])
5065 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355066 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095067 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5068 # The message content itself changed. Require an updated screenshot.
5069 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355070 elif old_id_to_msg_map[key].attrs['meaning'] != \
5071 new_id_to_msg_map[key].attrs['meaning']:
5072 # The message meaning changed. Ensure there is a screenshot for it.
5073 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5074 if sha1_path not in new_or_added_paths and not \
5075 input_api.os_path.exists(sha1_path):
5076 # There is neither a previous screenshot nor is a new one added now.
5077 # Require a screenshot.
5078 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145079
Rainhard Findlingfc31844c52020-05-15 09:58:265080 if run_screenshot_check:
5081 # Check the screenshot directory for .png files. Warn if there is any.
5082 for png_path in affected_png_paths:
5083 if png_path.startswith(screenshots_dir):
5084 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145085
Rainhard Findlingfc31844c52020-05-15 09:58:265086 for added_id in added_ids:
5087 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145088
Rainhard Findlingfc31844c52020-05-15 09:58:265089 for modified_id in modified_ids:
5090 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145091
Rainhard Findlingfc31844c52020-05-15 09:58:265092 for removed_id in removed_ids:
5093 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5094
5095 # Check new and changed strings for ICU syntax errors.
5096 for key in added_ids.union(modified_ids):
5097 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5098 err = _ValidateIcuSyntax(msg, 0, [])
5099 if err is not None:
5100 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145101
5102 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265103 if run_screenshot_check:
5104 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005105 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265106 'Do not include actual screenshots in the changelist. Run '
5107 'tools/translate/upload_screenshots.py to upload them instead:',
5108 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145109
Rainhard Findlingfc31844c52020-05-15 09:58:265110 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005111 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265112 'You are adding or modifying UI strings.\n'
5113 'To ensure the best translations, take screenshots of the relevant UI '
5114 '(https://g.co/chrome/translation) and add these files to your '
5115 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145116
Rainhard Findlingfc31844c52020-05-15 09:58:265117 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005118 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265119 'You removed strings associated with these files. Remove:',
5120 sorted(unnecessary_sha1_files)))
5121 else:
5122 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5123 'screenshots check.'))
5124
5125 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075126 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265127 'ICU syntax errors were found in the following strings (problems or '
5128 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145129
5130 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125131
5132
Saagar Sanghavifceeaae2020-08-12 16:40:365133def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125134 repo_root=None,
5135 translation_expectations_path=None,
5136 grd_files=None):
5137 import sys
5138 affected_grds = [f for f in input_api.AffectedFiles()
5139 if (f.LocalPath().endswith('.grd') or
5140 f.LocalPath().endswith('.grdp'))]
5141 if not affected_grds:
5142 return []
5143
5144 try:
5145 old_sys_path = sys.path
5146 sys.path = sys.path + [
5147 input_api.os_path.join(
5148 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5149 from helper import git_helper
5150 from helper import translation_helper
5151 finally:
5152 sys.path = old_sys_path
5153
5154 # Check that translation expectations can be parsed and we can get a list of
5155 # translatable grd files. |repo_root| and |translation_expectations_path| are
5156 # only passed by tests.
5157 if not repo_root:
5158 repo_root = input_api.PresubmitLocalPath()
5159 if not translation_expectations_path:
5160 translation_expectations_path = input_api.os_path.join(
5161 repo_root, 'tools', 'gritsettings',
5162 'translation_expectations.pyl')
5163 if not grd_files:
5164 grd_files = git_helper.list_grds_in_repository(repo_root)
5165
dpapad8e21b472020-10-23 17:15:035166 # Ignore bogus grd files used only for testing
5167 # ui/webui/resoucres/tools/generate_grd.py.
5168 ignore_path = input_api.os_path.join(
5169 'ui', 'webui', 'resources', 'tools', 'tests')
Dirk Prankee3c9c62d2021-05-18 18:35:595170 grd_files = [p for p in grd_files if ignore_path not in p]
dpapad8e21b472020-10-23 17:15:035171
Mustafa Emre Acer51f2f742020-03-09 19:41:125172 try:
5173 translation_helper.get_translatable_grds(repo_root, grd_files,
5174 translation_expectations_path)
5175 except Exception as e:
5176 return [output_api.PresubmitNotifyResult(
5177 'Failed to get a list of translatable grd files. This happens when:\n'
5178 ' - One of the modified grd or grdp files cannot be parsed or\n'
5179 ' - %s is not updated.\n'
5180 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5181 return []
Ken Rockotc31f4832020-05-29 18:58:515182
5183
Saagar Sanghavifceeaae2020-08-12 16:40:365184def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515185 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095186 changed_mojoms = input_api.AffectedFiles(
5187 include_deletes=True,
5188 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515189 delta = []
5190 for mojom in changed_mojoms:
5191 old_contents = ''.join(mojom.OldContents()) or None
5192 new_contents = ''.join(mojom.NewContents()) or None
5193 delta.append({
5194 'filename': mojom.LocalPath(),
5195 'old': '\n'.join(mojom.OldContents()) or None,
5196 'new': '\n'.join(mojom.NewContents()) or None,
5197 })
5198
5199 process = input_api.subprocess.Popen(
5200 [input_api.python_executable,
5201 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5202 'public', 'tools', 'mojom',
5203 'check_stable_mojom_compatibility.py'),
5204 '--src-root', input_api.PresubmitLocalPath()],
5205 stdin=input_api.subprocess.PIPE,
5206 stdout=input_api.subprocess.PIPE,
5207 stderr=input_api.subprocess.PIPE,
5208 universal_newlines=True)
5209 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5210 if process.returncode:
5211 return [output_api.PresubmitError(
5212 'One or more [Stable] mojom definitions appears to have been changed '
5213 'in a way that is not backward-compatible.',
5214 long_text=error)]
5215 return []
Dominic Battre645d42342020-12-04 16:14:105216
5217def CheckDeprecationOfPreferences(input_api, output_api):
5218 """Removing a preference should come with a deprecation."""
5219
5220 def FilterFile(affected_file):
5221 """Accept only .cc files and the like."""
5222 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5223 files_to_skip = (_EXCLUDED_PATHS +
5224 _TEST_CODE_EXCLUDED_PATHS +
5225 input_api.DEFAULT_FILES_TO_SKIP)
5226 return input_api.FilterSourceFile(
5227 affected_file,
5228 files_to_check=file_inclusion_pattern,
5229 files_to_skip=files_to_skip)
5230
5231 def ModifiedLines(affected_file):
5232 """Returns a list of tuples (line number, line text) of added and removed
5233 lines.
5234
5235 Deleted lines share the same line number as the previous line.
5236
5237 This relies on the scm diff output describing each changed code section
5238 with a line of the form
5239
5240 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5241 """
5242 line_num = 0
5243 modified_lines = []
5244 for line in affected_file.GenerateScmDiff().splitlines():
5245 # Extract <new line num> of the patch fragment (see format above).
5246 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5247 if m:
5248 line_num = int(m.groups(1)[0])
5249 continue
5250 if ((line.startswith('+') and not line.startswith('++')) or
5251 (line.startswith('-') and not line.startswith('--'))):
5252 modified_lines.append((line_num, line))
5253
5254 if not line.startswith('-'):
5255 line_num += 1
5256 return modified_lines
5257
5258 def FindLineWith(lines, needle):
5259 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5260
5261 If 0 or >1 lines contain `needle`, -1 is returned.
5262 """
5263 matching_line_numbers = [
5264 # + 1 for 1-based counting of line numbers.
5265 i + 1 for i, line
5266 in enumerate(lines)
5267 if needle in line]
5268 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5269
5270 def ModifiedPrefMigration(affected_file):
5271 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5272 # Determine first and last lines of MigrateObsolete.*Pref functions.
5273 new_contents = affected_file.NewContents();
5274 range_1 = (
5275 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5276 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5277 range_2 = (
5278 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5279 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5280 if (-1 in range_1 + range_2):
5281 raise Exception(
5282 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5283
5284 # Check whether any of the modified lines are part of the
5285 # MigrateObsolete.*Pref functions.
5286 for line_nr, line in ModifiedLines(affected_file):
5287 if (range_1[0] <= line_nr <= range_1[1] or
5288 range_2[0] <= line_nr <= range_2[1]):
5289 return True
5290 return False
5291
5292 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5293 browser_prefs_file_pattern = input_api.re.compile(
5294 r'chrome/browser/prefs/browser_prefs.cc')
5295
5296 changes = input_api.AffectedFiles(include_deletes=True,
5297 file_filter=FilterFile)
5298 potential_problems = []
5299 for f in changes:
5300 for line in f.GenerateScmDiff().splitlines():
5301 # Check deleted lines for pref registrations.
5302 if (line.startswith('-') and not line.startswith('--') and
5303 register_pref_pattern.search(line)):
5304 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5305
5306 if browser_prefs_file_pattern.search(f.LocalPath()):
5307 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5308 # assume that they knew that they have to deprecate preferences and don't
5309 # warn.
5310 try:
5311 if ModifiedPrefMigration(f):
5312 return []
5313 except Exception as e:
5314 return [output_api.PresubmitError(str(e))]
5315
5316 if potential_problems:
5317 return [output_api.PresubmitPromptWarning(
5318 'Discovered possible removal of preference registrations.\n\n'
5319 'Please make sure to properly deprecate preferences by clearing their\n'
5320 'value for a couple of milestones before finally removing the code.\n'
5321 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195322 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5323 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105324 'This may be a false positive warning (e.g. if you move preference\n'
5325 'registrations to a different place).\n',
5326 potential_problems
5327 )]
5328 return []