blob: 62be05c587bdeaac9fac256281f04a8bd019b1d6 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Saagar Sanghavifceeaae2020-08-12 16:40:3610PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1211
Dirk Prankee3c9c62d2021-05-18 18:35:5912# This line is 'magic' in that git-cl looks for it to decide whether to
13# use Python3 instead of Python2 when running the code in this file.
14USE_PYTHON3 = True
15
[email protected]379e7dd2010-01-28 17:39:2116_EXCLUDED_PATHS = (
Mila Greene3aa7222021-09-07 16:34:0817 # File needs to write to stdout to emulate a tool it's replacing.
Mila Greend3fc6a42021-09-10 17:38:2318 r"chrome[\\/]updater[\\/]mac[\\/]keystone[\\/]ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4719 # Generated file.
20 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2621 r"client_variations.js"),
Mila Greene3aa7222021-09-07 16:34:0822 r"^native_client_sdksrc[\\/]build_tools[\\/]make_rules.py",
Egor Paskoce145c42018-09-28 19:31:0423 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
24 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
25 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
26 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4927 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0428 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4629 # sqlite is an imported third party dependency.
30 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0431 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5432 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5333 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1234 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0435 r".+[\\/]pnacl_shim\.c$",
36 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0437 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1438 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0439 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5440 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0441 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4042)
[email protected]ca8d1982009-02-19 16:33:1243
John Abd-El-Malek759fea62021-03-13 03:41:1444_EXCLUDED_SET_NO_PARENT_PATHS = (
45 # It's for historical reasons that blink isn't a top level directory, where
46 # it would be allowed to have "set noparent" to avoid top level owners
47 # accidentally +1ing changes.
48 'third_party/blink/OWNERS',
49)
50
wnwenbdc444e2016-05-25 13:44:1551
[email protected]06e6d0ff2012-12-11 01:36:4452# Fragment of a regular expression that matches C++ and Objective-C++
53# implementation files.
54_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
55
wnwenbdc444e2016-05-25 13:44:1556
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1957# Fragment of a regular expression that matches C++ and Objective-C++
58# header files.
59_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
60
61
[email protected]06e6d0ff2012-12-11 01:36:4462# Regular expression that matches code only used for test binaries
63# (best effort).
64_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0465 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4466 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1367 # Test suite files, like:
68 # foo_browsertest.cc
69 # bar_unittest_mac.cc (suffix)
70 # baz_unittests.cc (plural)
71 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1272 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1873 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2174 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0475 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4376 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0477 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4378 # Web test harness.
79 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4780 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0481 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0882 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0483 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4184 # EarlGrey app side code for tests.
85 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1786 # Views Examples code
87 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4188 # Chromium Codelab
89 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4490)
[email protected]ca8d1982009-02-19 16:33:1291
Daniel Bratell609102be2019-03-27 20:53:2192_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1593
[email protected]eea609a2011-11-18 13:10:1294_TEST_ONLY_WARNING = (
95 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5596 'production code. If you are doing this from inside another method\n'
97 'named as *ForTesting(), then consider exposing things to have tests\n'
98 'make that same call directly.\n'
99 'If that is not possible, you may put a comment on the same line with\n'
100 ' // IN-TEST \n'
101 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
102 'method and can be ignored. Do not do this inside production code.\n'
103 'The android-binary-size trybot will block if the method exists in the\n'
104 'release apk.')
[email protected]eea609a2011-11-18 13:10:12105
106
[email protected]cf9b78f2012-11-14 11:40:28107_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:40108 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:21109 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
110 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:28111
Michael Thiessen44457642020-02-06 00:24:15112# Format: Sequence of tuples containing:
113# * Full import path.
114# * Sequence of strings to show when the pattern matches.
115# * Sequence of path or filename exceptions to this rule
116_BANNED_JAVA_IMPORTS = (
117 (
Colin Blundell170d78c82020-03-12 13:56:04118 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15119 (
120 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
121 ),
122 (
123 'net/android/javatests/src/org/chromium/net/'
124 'AndroidProxySelectorTest.java',
125 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04126 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15127 ),
128 ),
Michael Thiessened631912020-08-07 19:01:31129 (
130 'android.support.test.rule.UiThreadTestRule;',
131 (
132 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43133 '@org.chromium.base.test.UiThreadTest on test methods that should run '
134 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31135 ),
136 (),
137 ),
138 (
139 'android.support.test.annotation.UiThreadTest;',
140 (
141 'Do not use android.support.test.annotation.UiThreadTest, use '
142 'org.chromium.base.test.UiThreadTest instead. See '
143 'https://crbug.com/1111893.',
144 ),
145 ()
Michael Thiessenfd6919b2020-12-08 20:44:01146 ),
147 (
148 'android.support.test.rule.ActivityTestRule;',
149 (
150 'Do not use ActivityTestRule, use '
151 'org.chromium.base.test.BaseActivityTestRule instead.',
152 ),
153 (
154 'components/cronet/',
155 )
Michael Thiessened631912020-08-07 19:01:31156 )
Michael Thiessen44457642020-02-06 00:24:15157)
wnwenbdc444e2016-05-25 13:44:15158
Daniel Bratell609102be2019-03-27 20:53:21159# Format: Sequence of tuples containing:
160# * String pattern or, if starting with a slash, a regular expression.
161# * Sequence of strings to show when the pattern matches.
162# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41163_BANNED_JAVA_FUNCTIONS = (
164 (
165 'StrictMode.allowThreadDiskReads()',
166 (
167 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
168 'directly.',
169 ),
170 False,
171 ),
172 (
173 'StrictMode.allowThreadDiskWrites()',
174 (
175 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
176 'directly.',
177 ),
178 False,
179 ),
Michael Thiessen0f2547e2020-07-27 21:55:36180 (
181 '.waitForIdleSync()',
182 (
183 'Do not use waitForIdleSync as it masks underlying issues. There is '
184 'almost always something else you should wait on instead.',
185 ),
186 False,
187 ),
Eric Stevensona9a980972017-09-23 00:04:41188)
189
Daniel Bratell609102be2019-03-27 20:53:21190# Format: Sequence of tuples containing:
191# * String pattern or, if starting with a slash, a regular expression.
192# * Sequence of strings to show when the pattern matches.
193# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59194_BANNED_OBJC_FUNCTIONS = (
195 (
196 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20197 (
198 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59199 'prohibited. Please use CrTrackingArea instead.',
200 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
201 ),
202 False,
203 ),
204 (
[email protected]eaae1972014-04-16 04:17:26205 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20206 (
207 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59208 'instead.',
209 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
210 ),
211 False,
212 ),
213 (
214 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20215 (
216 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59217 'Please use |convertPoint:(point) fromView:nil| instead.',
218 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
219 ),
220 True,
221 ),
222 (
223 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20224 (
225 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59226 'Please use |convertPoint:(point) toView:nil| instead.',
227 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
228 ),
229 True,
230 ),
231 (
232 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20233 (
234 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59235 'Please use |convertRect:(point) fromView:nil| instead.',
236 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
237 ),
238 True,
239 ),
240 (
241 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20242 (
243 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59244 'Please use |convertRect:(point) toView:nil| instead.',
245 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
246 ),
247 True,
248 ),
249 (
250 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20251 (
252 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59253 'Please use |convertSize:(point) fromView:nil| instead.',
254 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
255 ),
256 True,
257 ),
258 (
259 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20260 (
261 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59262 'Please use |convertSize:(point) toView:nil| instead.',
263 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
264 ),
265 True,
266 ),
jif65398702016-10-27 10:19:48267 (
268 r"/\s+UTF8String\s*]",
269 (
270 'The use of -[NSString UTF8String] is dangerous as it can return null',
271 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
272 'Please use |SysNSStringToUTF8| instead.',
273 ),
274 True,
275 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34276 (
277 r'__unsafe_unretained',
278 (
279 'The use of __unsafe_unretained is almost certainly wrong, unless',
280 'when interacting with NSFastEnumeration or NSInvocation.',
281 'Please use __weak in files build with ARC, nothing otherwise.',
282 ),
283 False,
284 ),
Avi Drissman7382afa02019-04-29 23:27:13285 (
286 'freeWhenDone:NO',
287 (
288 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
289 'Foundation types is prohibited.',
290 ),
291 True,
292 ),
[email protected]127f18ec2012-06-16 05:05:59293)
294
Daniel Bratell609102be2019-03-27 20:53:21295# Format: Sequence of tuples containing:
296# * String pattern or, if starting with a slash, a regular expression.
297# * Sequence of strings to show when the pattern matches.
298# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54299_BANNED_IOS_OBJC_FUNCTIONS = (
300 (
301 r'/\bTEST[(]',
302 (
303 'TEST() macro should not be used in Objective-C++ code as it does not ',
304 'drain the autorelease pool at the end of the test. Use TEST_F() ',
305 'macro instead with a fixture inheriting from PlatformTest (or a ',
306 'typedef).'
307 ),
308 True,
309 ),
310 (
311 r'/\btesting::Test\b',
312 (
313 'testing::Test should not be used in Objective-C++ code as it does ',
314 'not drain the autorelease pool at the end of the test. Use ',
315 'PlatformTest instead.'
316 ),
317 True,
318 ),
319)
320
Peter K. Lee6c03ccff2019-07-15 14:40:05321# Format: Sequence of tuples containing:
322# * String pattern or, if starting with a slash, a regular expression.
323# * Sequence of strings to show when the pattern matches.
324# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
325_BANNED_IOS_EGTEST_FUNCTIONS = (
326 (
327 r'/\bEXPECT_OCMOCK_VERIFY\b',
328 (
329 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
330 'it is meant for GTests. Use [mock verify] instead.'
331 ),
332 True,
333 ),
334)
335
Daniel Bratell609102be2019-03-27 20:53:21336# Format: Sequence of tuples containing:
337# * String pattern or, if starting with a slash, a regular expression.
338# * Sequence of strings to show when the pattern matches.
339# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
340# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59341_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20342 (
Peter Kasting94a56c42019-10-25 21:54:04343 r'/\busing namespace ',
344 (
345 'Using directives ("using namespace x") are banned by the Google Style',
346 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
347 'Explicitly qualify symbols or use using declarations ("using x::foo").',
348 ),
349 True,
350 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
351 ),
Antonio Gomes07300d02019-03-13 20:59:57352 # Make sure that gtest's FRIEND_TEST() macro is not used; the
353 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
354 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53355 (
[email protected]23e6cbc2012-06-16 18:51:20356 'FRIEND_TEST(',
357 (
[email protected]e3c945502012-06-26 20:01:49358 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20359 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
360 ),
361 False,
[email protected]7345da02012-11-27 14:31:49362 (),
[email protected]23e6cbc2012-06-16 18:51:20363 ),
364 (
tomhudsone2c14d552016-05-26 17:07:46365 'setMatrixClip',
366 (
367 'Overriding setMatrixClip() is prohibited; ',
368 'the base function is deprecated. ',
369 ),
370 True,
371 (),
372 ),
373 (
[email protected]52657f62013-05-20 05:30:31374 'SkRefPtr',
375 (
376 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22377 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31378 ),
379 True,
380 (),
381 ),
382 (
383 'SkAutoRef',
384 (
385 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22386 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31387 ),
388 True,
389 (),
390 ),
391 (
392 'SkAutoTUnref',
393 (
394 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22395 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31396 ),
397 True,
398 (),
399 ),
400 (
401 'SkAutoUnref',
402 (
403 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
404 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22405 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31406 ),
407 True,
408 (),
409 ),
[email protected]d89eec82013-12-03 14:10:59410 (
411 r'/HANDLE_EINTR\(.*close',
412 (
413 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
414 'descriptor will be closed, and it is incorrect to retry the close.',
415 'Either call close directly and ignore its return value, or wrap close',
416 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
417 ),
418 True,
419 (),
420 ),
421 (
422 r'/IGNORE_EINTR\((?!.*close)',
423 (
424 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
425 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
426 ),
427 True,
428 (
429 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04430 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
431 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59432 ),
433 ),
[email protected]ec5b3f02014-04-04 18:43:43434 (
435 r'/v8::Extension\(',
436 (
437 'Do not introduce new v8::Extensions into the code base, use',
438 'gin::Wrappable instead. See http://crbug.com/334679',
439 ),
440 True,
[email protected]f55c90ee62014-04-12 00:50:03441 (
Egor Paskoce145c42018-09-28 19:31:04442 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03443 ),
[email protected]ec5b3f02014-04-04 18:43:43444 ),
skyostilf9469f72015-04-20 10:38:52445 (
jame2d1a952016-04-02 00:27:10446 '#pragma comment(lib,',
447 (
448 'Specify libraries to link with in build files and not in the source.',
449 ),
450 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41451 (
tzik3f295992018-12-04 20:32:23452 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04453 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41454 ),
jame2d1a952016-04-02 00:27:10455 ),
fdorayc4ac18d2017-05-01 21:39:59456 (
Gabriel Charette7cc6c432018-04-25 20:52:02457 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59458 (
459 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
460 ),
461 False,
462 (),
463 ),
464 (
Gabriel Charette7cc6c432018-04-25 20:52:02465 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59466 (
467 'Consider using THREAD_CHECKER macros instead of the class directly.',
468 ),
469 False,
470 (),
471 ),
dbeamb6f4fde2017-06-15 04:03:06472 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06473 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
474 (
475 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
476 'deprecated (http://crbug.com/634507). Please avoid converting away',
477 'from the Time types in Chromium code, especially if any math is',
478 'being done on time values. For interfacing with platform/library',
479 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
480 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48481 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06482 'other use cases, please contact base/time/OWNERS.',
483 ),
484 False,
485 (),
486 ),
487 (
dbeamb6f4fde2017-06-15 04:03:06488 'CallJavascriptFunctionUnsafe',
489 (
490 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
491 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
492 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
493 ),
494 False,
495 (
Egor Paskoce145c42018-09-28 19:31:04496 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
497 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
498 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06499 ),
500 ),
dskiba1474c2bfd62017-07-20 02:19:24501 (
502 'leveldb::DB::Open',
503 (
504 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
505 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
506 "Chrome's tracing, making their memory usage visible.",
507 ),
508 True,
509 (
510 r'^third_party/leveldatabase/.*\.(cc|h)$',
511 ),
Gabriel Charette0592c3a2017-07-26 12:02:04512 ),
513 (
Chris Mumfordc38afb62017-10-09 17:55:08514 'leveldb::NewMemEnv',
515 (
516 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58517 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
518 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08519 ),
520 True,
521 (
522 r'^third_party/leveldatabase/.*\.(cc|h)$',
523 ),
524 ),
525 (
Gabriel Charetted9839bc2017-07-29 14:17:47526 'RunLoop::QuitCurrent',
527 (
Robert Liao64b7ab22017-08-04 23:03:43528 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
529 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47530 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41531 False,
Gabriel Charetted9839bc2017-07-29 14:17:47532 (),
Gabriel Charettea44975052017-08-21 23:14:04533 ),
534 (
535 'base::ScopedMockTimeMessageLoopTaskRunner',
536 (
Gabriel Charette87cc1af2018-04-25 20:52:51537 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11538 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51539 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
540 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
541 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04542 ),
Gabriel Charette87cc1af2018-04-25 20:52:51543 False,
Gabriel Charettea44975052017-08-21 23:14:04544 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57545 ),
546 (
Dave Tapuska98199b612019-07-10 13:30:44547 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57548 (
549 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02550 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57551 ),
552 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16553 # Abseil's benchmarks never linked into chrome.
554 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38555 ),
556 (
Peter Kasting991618a62019-06-17 22:00:09557 r'/\bstd::stoi\b',
558 (
559 'std::stoi uses exceptions to communicate results. ',
560 'Use base::StringToInt() instead.',
561 ),
562 True,
563 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
564 ),
565 (
566 r'/\bstd::stol\b',
567 (
568 'std::stol uses exceptions to communicate results. ',
569 'Use base::StringToInt() instead.',
570 ),
571 True,
572 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
573 ),
574 (
575 r'/\bstd::stoul\b',
576 (
577 'std::stoul uses exceptions to communicate results. ',
578 'Use base::StringToUint() instead.',
579 ),
580 True,
581 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
582 ),
583 (
584 r'/\bstd::stoll\b',
585 (
586 'std::stoll uses exceptions to communicate results. ',
587 'Use base::StringToInt64() instead.',
588 ),
589 True,
590 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
591 ),
592 (
593 r'/\bstd::stoull\b',
594 (
595 'std::stoull uses exceptions to communicate results. ',
596 'Use base::StringToUint64() instead.',
597 ),
598 True,
599 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
600 ),
601 (
602 r'/\bstd::stof\b',
603 (
604 'std::stof uses exceptions to communicate results. ',
605 'For locale-independent values, e.g. reading numbers from disk',
606 'profiles, use base::StringToDouble().',
607 'For user-visible values, parse using ICU.',
608 ),
609 True,
610 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
611 ),
612 (
613 r'/\bstd::stod\b',
614 (
615 'std::stod uses exceptions to communicate results. ',
616 'For locale-independent values, e.g. reading numbers from disk',
617 'profiles, use base::StringToDouble().',
618 'For user-visible values, parse using ICU.',
619 ),
620 True,
621 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
622 ),
623 (
624 r'/\bstd::stold\b',
625 (
626 'std::stold uses exceptions to communicate results. ',
627 'For locale-independent values, e.g. reading numbers from disk',
628 'profiles, use base::StringToDouble().',
629 'For user-visible values, parse using ICU.',
630 ),
631 True,
632 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
633 ),
634 (
Daniel Bratell69334cc2019-03-26 11:07:45635 r'/\bstd::to_string\b',
636 (
637 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09638 'For locale-independent strings, e.g. writing numbers to disk',
639 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45640 'For user-visible strings, use base::FormatNumber() and',
641 'the related functions in base/i18n/number_formatting.h.',
642 ),
Peter Kasting991618a62019-06-17 22:00:09643 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21644 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45645 ),
646 (
647 r'/\bstd::shared_ptr\b',
648 (
649 'std::shared_ptr should not be used. Use scoped_refptr instead.',
650 ),
651 True,
Ulan Degenbaev947043882021-02-10 14:02:31652 [
653 # Needed for interop with third-party library.
654 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57655 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58656 '^third_party/blink/renderer/bindings/core/v8/' +
657 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58658 '^gin/array_buffer\.(cc|h)',
659 '^chrome/services/sharing/nearby/',
Meilin Wang00efc7c2021-05-13 01:12:42660 # gRPC provides some C++ libraries that use std::shared_ptr<>.
661 '^chromeos/services/libassistant/grpc/',
Wez5f56be52021-05-04 09:30:58662 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
663 '.*fuchsia.*test\.(cc|h)',
Alex Chau9eb03cdd52020-07-13 21:04:57664 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21665 ),
666 (
Peter Kasting991618a62019-06-17 22:00:09667 r'/\bstd::weak_ptr\b',
668 (
669 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
670 ),
671 True,
672 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
673 ),
674 (
Daniel Bratell609102be2019-03-27 20:53:21675 r'/\blong long\b',
676 (
677 'long long is banned. Use stdint.h if you need a 64 bit number.',
678 ),
679 False, # Only a warning since it is already used.
680 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
681 ),
682 (
683 r'/\bstd::bind\b',
684 (
685 'std::bind is banned because of lifetime risks.',
686 'Use base::BindOnce or base::BindRepeating instead.',
687 ),
688 True,
689 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
690 ),
691 (
692 r'/\b#include <chrono>\b',
693 (
694 '<chrono> overlaps with Time APIs in base. Keep using',
695 'base classes.',
696 ),
697 True,
698 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
699 ),
700 (
701 r'/\b#include <exception>\b',
702 (
703 'Exceptions are banned and disabled in Chromium.',
704 ),
705 True,
706 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
707 ),
708 (
709 r'/\bstd::function\b',
710 (
Colin Blundellea615d422021-05-12 09:35:41711 'std::function is banned. Instead use base::OnceCallback or ',
712 'base::RepeatingCallback, which directly support Chromium\'s weak ',
713 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21714 ),
Peter Kasting991618a62019-06-17 22:00:09715 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21716 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
717 ),
718 (
719 r'/\b#include <random>\b',
720 (
721 'Do not use any random number engines from <random>. Instead',
722 'use base::RandomBitGenerator.',
723 ),
724 True,
725 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
726 ),
727 (
Tom Andersona95e12042020-09-09 23:08:00728 r'/\b#include <X11/',
729 (
730 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
731 ),
732 True,
733 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
734 ),
735 (
Daniel Bratell609102be2019-03-27 20:53:21736 r'/\bstd::ratio\b',
737 (
738 'std::ratio is banned by the Google Style Guide.',
739 ),
740 True,
741 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45742 ),
743 (
Gabriel Charetted90bcc92021-09-21 00:23:10744 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:38745 (
Gabriel Charetted90bcc92021-09-21 00:23:10746 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:38747 ),
Gabriel Charette04b138f2018-08-06 00:03:22748 False,
Francois Doray43670e32017-09-27 12:40:38749 (),
750 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38751 (
Michael Giuffrida7f93d6922019-04-19 14:39:58752 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19753 (
754 'RunMessageLoop is deprecated, use RunLoop instead.',
755 ),
756 False,
757 (),
758 ),
759 (
Dave Tapuska98199b612019-07-10 13:30:44760 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19761 (
762 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
763 ),
764 False,
765 (),
766 ),
767 (
Dave Tapuska98199b612019-07-10 13:30:44768 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19769 (
770 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
771 "if you're convinced you need this.",
772 ),
773 False,
774 (),
775 ),
776 (
Dave Tapuska98199b612019-07-10 13:30:44777 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19778 (
779 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04780 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19781 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
782 'async events instead of flushing threads.',
783 ),
784 False,
785 (),
786 ),
787 (
788 r'MessageLoopRunner',
789 (
790 'MessageLoopRunner is deprecated, use RunLoop instead.',
791 ),
792 False,
793 (),
794 ),
795 (
Dave Tapuska98199b612019-07-10 13:30:44796 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19797 (
798 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
799 "gab@ if you found a use case where this is the only solution.",
800 ),
801 False,
802 (),
803 ),
804 (
Victor Costane48a2e82019-03-15 22:02:34805 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16806 (
Victor Costane48a2e82019-03-15 22:02:34807 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16808 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
809 ),
810 True,
811 (
812 r'^sql/initialization\.(cc|h)$',
813 r'^third_party/sqlite/.*\.(c|cc|h)$',
814 ),
815 ),
Matt Menke7f520a82018-03-28 21:38:37816 (
Dave Tapuska98199b612019-07-10 13:30:44817 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47818 (
819 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
820 'base::RandomShuffle instead.'
821 ),
822 True,
823 (),
824 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24825 (
826 'ios/web/public/test/http_server',
827 (
828 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
829 ),
830 False,
831 (),
832 ),
Robert Liao764c9492019-01-24 18:46:28833 (
834 'GetAddressOf',
835 (
836 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53837 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11838 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53839 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28840 ),
841 True,
842 (),
843 ),
Antonio Gomes07300d02019-03-13 20:59:57844 (
Ben Lewisa9514602019-04-29 17:53:05845 'SHFileOperation',
846 (
847 'SHFileOperation was deprecated in Windows Vista, and there are less ',
848 'complex functions to achieve the same goals. Use IFileOperation for ',
849 'any esoteric actions instead.'
850 ),
851 True,
852 (),
853 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18854 (
Cliff Smolinsky81951642019-04-30 21:39:51855 'StringFromGUID2',
856 (
857 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24858 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51859 ),
860 True,
861 (
862 r'/base/win/win_util_unittest.cc'
863 ),
864 ),
865 (
866 'StringFromCLSID',
867 (
868 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24869 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51870 ),
871 True,
872 (
873 r'/base/win/win_util_unittest.cc'
874 ),
875 ),
876 (
Avi Drissman7382afa02019-04-29 23:27:13877 'kCFAllocatorNull',
878 (
879 'The use of kCFAllocatorNull with the NoCopy creation of ',
880 'CoreFoundation types is prohibited.',
881 ),
882 True,
883 (),
884 ),
Oksana Zhuravlovafd247772019-05-16 16:57:29885 (
886 'mojo::ConvertTo',
887 (
888 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
889 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
890 'StringTraits if you would like to convert between custom types and',
891 'the wire format of mojom types.'
892 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22893 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29894 (
Wezf89dec092019-09-11 19:38:33895 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
896 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29897 r'^third_party/blink/.*\.(cc|h)$',
898 r'^content/renderer/.*\.(cc|h)$',
899 ),
900 ),
Robert Liao1d78df52019-11-11 20:02:01901 (
Oksana Zhuravlovac8222d22019-12-19 19:21:16902 'GetInterfaceProvider',
903 (
904 'InterfaceProvider is deprecated.',
905 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
906 'or Platform::GetBrowserInterfaceBroker.'
907 ),
908 False,
909 (),
910 ),
911 (
Robert Liao1d78df52019-11-11 20:02:01912 'CComPtr',
913 (
914 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
915 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
916 'details.'
917 ),
918 False,
919 (),
920 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:20921 (
922 r'/\b(IFACE|STD)METHOD_?\(',
923 (
924 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
925 'Instead, always use IFACEMETHODIMP in the declaration.'
926 ),
927 False,
928 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
929 ),
Allen Bauer53b43fb12020-03-12 17:21:47930 (
931 'set_owned_by_client',
932 (
933 'set_owned_by_client is deprecated.',
934 'views::View already owns the child views by default. This introduces ',
935 'a competing ownership model which makes the code difficult to reason ',
936 'about. See http://crbug.com/1044687 for more details.'
937 ),
938 False,
939 (),
940 ),
Eric Secklerbe6f48d2020-05-06 18:09:12941 (
Peter Boström7ff41522021-07-29 03:43:27942 'RemoveAllChildViewsWithoutDeleting',
943 (
944 'RemoveAllChildViewsWithoutDeleting is deprecated.',
945 'This method is deemed dangerous as, unless raw pointers are re-added,',
946 'calls to this method introduce memory leaks.'
947 ),
948 False,
949 (),
950 ),
951 (
Eric Secklerbe6f48d2020-05-06 18:09:12952 r'/\bTRACE_EVENT_ASYNC_',
953 (
954 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
955 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
956 ),
957 False,
958 (
959 r'^base/trace_event/.*',
960 r'^base/tracing/.*',
961 ),
962 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:26963 (
Robert Liao22f66a52021-04-10 00:57:52964 'RoInitialize',
965 (
Robert Liao48018922021-04-16 23:03:02966 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:52967 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
968 'instead. See http://crbug.com/1197722 for more information.'
969 ),
970 True,
Robert Liao48018922021-04-16 23:03:02971 (
972 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$'
973 ),
Robert Liao22f66a52021-04-10 00:57:52974 ),
[email protected]127f18ec2012-06-16 05:05:59975)
976
Mario Sanchez Prada2472cab2019-09-18 10:58:31977# Format: Sequence of tuples containing:
978# * String pattern or, if starting with a slash, a regular expression.
979# * Sequence of strings to show when the pattern matches.
980_DEPRECATED_MOJO_TYPES = (
981 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31982 r'/\bmojo::AssociatedInterfacePtrInfo\b',
983 (
984 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
985 'Use mojo::PendingAssociatedRemote<Interface> instead.',
986 ),
987 ),
988 (
989 r'/\bmojo::AssociatedInterfaceRequest\b',
990 (
991 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
992 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
993 ),
994 ),
995 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31996 r'/\bmojo::InterfacePtr\b',
997 (
998 'mojo::InterfacePtr<Interface> is deprecated.',
999 'Use mojo::Remote<Interface> instead.',
1000 ),
1001 ),
1002 (
1003 r'/\bmojo::InterfacePtrInfo\b',
1004 (
1005 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1006 'Use mojo::PendingRemote<Interface> instead.',
1007 ),
1008 ),
1009 (
1010 r'/\bmojo::InterfaceRequest\b',
1011 (
1012 'mojo::InterfaceRequest<Interface> is deprecated.',
1013 'Use mojo::PendingReceiver<Interface> instead.',
1014 ),
1015 ),
1016 (
1017 r'/\bmojo::MakeRequest\b',
1018 (
1019 'mojo::MakeRequest is deprecated.',
1020 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1021 ),
1022 ),
Mario Sanchez Prada2472cab2019-09-18 10:58:311023)
wnwenbdc444e2016-05-25 13:44:151024
mlamouria82272622014-09-16 18:45:041025_IPC_ENUM_TRAITS_DEPRECATED = (
1026 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501027 'See http://www.chromium.org/Home/chromium-security/education/'
1028 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041029
Stephen Martinis97a394142018-06-07 23:06:051030_LONG_PATH_ERROR = (
1031 'Some files included in this CL have file names that are too long (> 200'
1032 ' characters). If committed, these files will cause issues on Windows. See'
1033 ' https://crbug.com/612667 for more details.'
1034)
1035
Shenghua Zhangbfaa38b82017-11-16 21:58:021036_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041037 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041038 r".*[\\/]BuildHooksAndroidImpl\.java",
1039 r".*[\\/]LicenseContentProvider\.java",
1040 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281041 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021042]
[email protected]127f18ec2012-06-16 05:05:591043
Mohamed Heikald048240a2019-11-12 16:57:371044# List of image extensions that are used as resources in chromium.
1045_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1046
Sean Kau46e29bc2017-08-28 16:31:161047# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401048_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041049 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401050 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041051 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1052 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041053 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431054 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161055]
1056
1057
[email protected]b00342e7f2013-03-26 16:21:541058_VALID_OS_MACROS = (
1059 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081060 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541061 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441062 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121063 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541064 'OS_BSD',
1065 'OS_CAT', # For testing.
1066 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041067 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541068 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371069 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541070 'OS_IOS',
1071 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441072 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541073 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211074 'OS_NACL_NONSFI',
1075 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121076 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541077 'OS_OPENBSD',
1078 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371079 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541080 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541081 'OS_WIN',
1082)
1083
1084
Andrew Grieveb773bad2020-06-05 18:00:381085# These are not checked on the public chromium-presubmit trybot.
1086# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041087# checkouts.
agrievef32bcc72016-04-04 14:57:401088_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381089 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381090]
1091
1092
1093_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041094 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361095 'base/android/jni_generator/jni_generator.pydeps',
1096 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361097 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041098 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361099 'build/android/gyp/aar.pydeps',
1100 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271101 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361102 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381103 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361104 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021105 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221106 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111107 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361108 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361109 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361110 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111111 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041112 'build/android/gyp/create_app_bundle_apks.pydeps',
1113 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361114 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121115 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091116 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221117 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001118 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361119 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421120 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041121 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361122 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361123 'build/android/gyp/filter_zip.pydeps',
1124 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361125 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361126 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581127 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361128 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141129 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261130 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471131 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011132 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041133 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361134 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361135 'build/android/gyp/merge_manifest.pydeps',
1136 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221137 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361138 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461139 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301140 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241141 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361142 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461143 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561144 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361145 'build/android/incremental_install/generate_android_manifest.pydeps',
1146 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041147 'build/android/resource_sizes.pydeps',
1148 'build/android/test_runner.pydeps',
1149 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361150 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361151 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321152 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271153 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1154 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041155 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001156 'components/cronet/tools/generate_javadoc.pydeps',
1157 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381158 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001159 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381160 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041161 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181162 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041163 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421164 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1165 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131166 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501167 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061168 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221169 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401170]
1171
wnwenbdc444e2016-05-25 13:44:151172
agrievef32bcc72016-04-04 14:57:401173_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1174
1175
Eric Boren6fd2b932018-01-25 15:05:081176# Bypass the AUTHORS check for these accounts.
1177_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591178 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451179 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591180 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521181 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231182 'wpt-autoroller', 'chrome-weblayer-builder',
1183 'lacros-version-skew-roller', 'skylab-test-cros-roller')
Eric Boren835d71f2018-09-07 21:09:041184 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271185 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041186 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161187 for s in ('chromium-internal-autoroll',)
1188 ) | set('%[email protected]' % s
1189 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081190
Matt Stark6ef08872021-07-29 01:21:461191_INVALID_GRD_FILE_LINE = [
1192 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1193]
Eric Boren6fd2b932018-01-25 15:05:081194
Daniel Bratell65b033262019-04-23 08:17:061195def _IsCPlusPlusFile(input_api, file_path):
1196 """Returns True if this file contains C++-like code (and not Python,
1197 Go, Java, MarkDown, ...)"""
1198
1199 ext = input_api.os_path.splitext(file_path)[1]
1200 # This list is compatible with CppChecker.IsCppFile but we should
1201 # consider adding ".c" to it. If we do that we can use this function
1202 # at more places in the code.
1203 return ext in (
1204 '.h',
1205 '.cc',
1206 '.cpp',
1207 '.m',
1208 '.mm',
1209 )
1210
1211def _IsCPlusPlusHeaderFile(input_api, file_path):
1212 return input_api.os_path.splitext(file_path)[1] == ".h"
1213
1214
1215def _IsJavaFile(input_api, file_path):
1216 return input_api.os_path.splitext(file_path)[1] == ".java"
1217
1218
1219def _IsProtoFile(input_api, file_path):
1220 return input_api.os_path.splitext(file_path)[1] == ".proto"
1221
Mohamed Heikal5e5b7922020-10-29 18:57:591222
1223def CheckNoUpstreamDepsOnClank(input_api, output_api):
1224 """Prevent additions of dependencies from the upstream repo on //clank."""
1225 # clank can depend on clank
1226 if input_api.change.RepositoryRoot().endswith('clank'):
1227 return []
1228 build_file_patterns = [
1229 r'(.+/)?BUILD\.gn',
1230 r'.+\.gni',
1231 ]
1232 excluded_files = [
1233 r'build[/\\]config[/\\]android[/\\]config\.gni'
1234 ]
1235 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1236
1237 error_message = 'Disallowed import on //clank in an upstream build file:'
1238
1239 def FilterFile(affected_file):
1240 return input_api.FilterSourceFile(
1241 affected_file,
1242 files_to_check=build_file_patterns,
1243 files_to_skip=excluded_files)
1244
1245 problems = []
1246 for f in input_api.AffectedSourceFiles(FilterFile):
1247 local_path = f.LocalPath()
1248 for line_number, line in f.ChangedContents():
1249 if (bad_pattern.search(line)):
1250 problems.append(
1251 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1252 if problems:
1253 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1254 else:
1255 return []
1256
1257
Saagar Sanghavifceeaae2020-08-12 16:40:361258def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191259 """Attempts to prevent use of functions intended only for testing in
1260 non-testing code. For now this is just a best-effort implementation
1261 that ignores header files and may have some false positives. A
1262 better implementation would probably need a proper C++ parser.
1263 """
1264 # We only scan .cc files and the like, as the declaration of
1265 # for-testing functions in header files are hard to distinguish from
1266 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491267 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191268
jochenc0d4808c2015-07-27 09:25:421269 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191270 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091271 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131272 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191273 exclusion_pattern = input_api.re.compile(
1274 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1275 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131276 # Avoid a false positive in this case, where the method name, the ::, and
1277 # the closing { are all on different lines due to line wrapping.
1278 # HelperClassForTesting::
1279 # HelperClassForTesting(
1280 # args)
1281 # : member(0) {}
1282 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191283
1284 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441285 files_to_skip = (_EXCLUDED_PATHS +
1286 _TEST_CODE_EXCLUDED_PATHS +
1287 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191288 return input_api.FilterSourceFile(
1289 affected_file,
James Cook24a504192020-07-23 00:08:441290 files_to_check=file_inclusion_pattern,
1291 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191292
1293 problems = []
1294 for f in input_api.AffectedSourceFiles(FilterFile):
1295 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131296 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241297 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031298 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461299 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131300 not exclusion_pattern.search(line) and
1301 not allowlist_pattern.search(line) and
1302 not in_method_defn):
[email protected]55459852011-08-10 15:17:191303 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031304 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131305 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191306
1307 if problems:
[email protected]f7051d52013-04-02 18:31:421308 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031309 else:
1310 return []
[email protected]55459852011-08-10 15:17:191311
1312
Saagar Sanghavifceeaae2020-08-12 16:40:361313def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231314 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591315 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231316 """
1317 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1318 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1319 name_pattern = r'ForTest(s|ing)?'
1320 # Describes an occurrence of "ForTest*" inside a // comment.
1321 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501322 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551323 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231324 # Catch calls.
1325 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1326 # Ignore definitions. (Comments are ignored separately.)
1327 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1328
1329 problems = []
1330 sources = lambda x: input_api.FilterSourceFile(
1331 x,
James Cook24a504192020-07-23 00:08:441332 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1333 + input_api.DEFAULT_FILES_TO_SKIP),
1334 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231335 )
1336 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1337 local_path = f.LocalPath()
1338 is_inside_javadoc = False
1339 for line_number, line in f.ChangedContents():
1340 if is_inside_javadoc and javadoc_end_re.search(line):
1341 is_inside_javadoc = False
1342 if not is_inside_javadoc and javadoc_start_re.search(line):
1343 is_inside_javadoc = True
1344 if is_inside_javadoc:
1345 continue
1346 if (inclusion_re.search(line) and
1347 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501348 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231349 not exclusion_re.search(line)):
1350 problems.append(
1351 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1352
1353 if problems:
1354 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1355 else:
1356 return []
1357
1358
Saagar Sanghavifceeaae2020-08-12 16:40:361359def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541360 """Checks to make sure no .h files include <iostream>."""
1361 files = []
1362 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1363 input_api.re.MULTILINE)
1364 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1365 if not f.LocalPath().endswith('.h'):
1366 continue
1367 contents = input_api.ReadFile(f)
1368 if pattern.search(contents):
1369 files.append(f)
1370
1371 if len(files):
yolandyandaabc6d2016-04-18 18:29:391372 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061373 'Do not #include <iostream> in header files, since it inserts static '
1374 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541375 '#include <ostream>. See http://crbug.com/94794',
1376 files) ]
1377 return []
1378
Danil Chapovalov3518f362018-08-11 16:13:431379def _CheckNoStrCatRedefines(input_api, output_api):
1380 """Checks no windows headers with StrCat redefined are included directly."""
1381 files = []
1382 pattern_deny = input_api.re.compile(
1383 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1384 input_api.re.MULTILINE)
1385 pattern_allow = input_api.re.compile(
1386 r'^#include\s"base/win/windows_defines.inc"',
1387 input_api.re.MULTILINE)
1388 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1389 contents = input_api.ReadFile(f)
1390 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1391 files.append(f.LocalPath())
1392
1393 if len(files):
1394 return [output_api.PresubmitError(
1395 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1396 'directly since they pollute code with StrCat macro. Instead, '
1397 'include matching header from base/win. See http://crbug.com/856536',
1398 files) ]
1399 return []
1400
[email protected]10689ca2011-09-02 02:31:541401
Saagar Sanghavifceeaae2020-08-12 16:40:361402def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521403 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181404 problems = []
1405 for f in input_api.AffectedFiles():
1406 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1407 continue
1408
1409 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041410 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181411 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1412
1413 if not problems:
1414 return []
1415 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1416 '\n'.join(problems))]
1417
Saagar Sanghavifceeaae2020-08-12 16:40:361418def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341419 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1420
1421 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1422 instead of DISABLED_. To filter false positives, reports are only generated
1423 if a corresponding MAYBE_ line exists.
1424 """
1425 problems = []
1426
1427 # The following two patterns are looked for in tandem - is a test labeled
1428 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1429 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1430 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1431
1432 # This is for the case that a test is disabled on all platforms.
1433 full_disable_pattern = input_api.re.compile(
1434 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1435 input_api.re.MULTILINE)
1436
Katie Df13948e2018-09-25 07:33:441437 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341438 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1439 continue
1440
1441 # Search for MABYE_, DISABLE_ pairs.
1442 disable_lines = {} # Maps of test name to line number.
1443 maybe_lines = {}
1444 for line_num, line in f.ChangedContents():
1445 disable_match = disable_pattern.search(line)
1446 if disable_match:
1447 disable_lines[disable_match.group(1)] = line_num
1448 maybe_match = maybe_pattern.search(line)
1449 if maybe_match:
1450 maybe_lines[maybe_match.group(1)] = line_num
1451
1452 # Search for DISABLE_ occurrences within a TEST() macro.
1453 disable_tests = set(disable_lines.keys())
1454 maybe_tests = set(maybe_lines.keys())
1455 for test in disable_tests.intersection(maybe_tests):
1456 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1457
1458 contents = input_api.ReadFile(f)
1459 full_disable_match = full_disable_pattern.search(contents)
1460 if full_disable_match:
1461 problems.append(' %s' % f.LocalPath())
1462
1463 if not problems:
1464 return []
1465 return [
1466 output_api.PresubmitPromptWarning(
1467 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1468 '\n'.join(problems))
1469 ]
1470
Nina Satragnof7660532021-09-20 18:03:351471def CheckForgettingMAYBEInTests(input_api, output_api):
1472 """Checks to make sure tests disabled conditionally are not missing a
1473 corresponding MAYBE_ prefix.
1474 """
1475 # Expect at least a lowercase character in the test name. This helps rule out
1476 # false positives with macros wrapping the actual tests name.
1477 define_maybe_pattern = input_api.re.compile(
1478 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
1479 test_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*\w+,\s*MAYBE_{test_name}\)'
1480 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1481 warnings = []
1482
1483 # Read the entire files. We can't just read the affected lines, forgetting to
1484 # add MAYBE_ on a change would not show up otherwise.
1485 for f in input_api.AffectedFiles(False):
1486 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1487 continue
1488 contents = input_api.ReadFile(f)
1489 lines = contents.splitlines(True)
1490 current_position = 0
1491 warning_test_names = set()
1492 for line_num, line in enumerate(lines, start=1):
1493 current_position += len(line)
1494 maybe_match = define_maybe_pattern.search(line)
1495 if maybe_match:
1496 test_name = maybe_match.group('test_name')
1497 # Do not warn twice for the same test.
1498 if (test_name in warning_test_names):
1499 continue
1500 warning_test_names.add(test_name)
1501
1502 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1503 # the current position.
1504 test_match = input_api.re.compile(
1505 test_maybe_pattern.format(test_name=test_name),
1506 input_api.re.MULTILINE).search(contents, current_position)
1507 suite_match = input_api.re.compile(
1508 suite_maybe_pattern.format(test_name=test_name),
1509 input_api.re.MULTILINE).search(contents, current_position)
1510 if not test_match and not suite_match:
1511 warnings.append(
1512 output_api.PresubmitPromptWarning(
1513 '%s:%d found MAYBE_ defined without corresponding test %s' %
1514 (f.LocalPath(), line_num, test_name)))
1515 return warnings
[email protected]72df4e782012-06-21 16:28:181516
Saagar Sanghavifceeaae2020-08-12 16:40:361517def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571518 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521519 errors = []
Hans Wennborg944479f2020-06-25 21:39:251520 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521521 input_api.re.MULTILINE)
1522 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1523 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1524 continue
1525 for lnum, line in f.ChangedContents():
1526 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171527 errors.append(output_api.PresubmitError(
1528 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571529 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171530 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521531 return errors
1532
1533
Weilun Shia487fad2020-10-28 00:10:341534# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1535# more reliable way. See
1536# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191537
wnwenbdc444e2016-05-25 13:44:151538
Saagar Sanghavifceeaae2020-08-12 16:40:361539def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391540 """Check that FlakyTest annotation is our own instead of the android one"""
1541 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1542 files = []
1543 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1544 if f.LocalPath().endswith('Test.java'):
1545 if pattern.search(input_api.ReadFile(f)):
1546 files.append(f)
1547 if len(files):
1548 return [output_api.PresubmitError(
1549 'Use org.chromium.base.test.util.FlakyTest instead of '
1550 'android.test.FlakyTest',
1551 files)]
1552 return []
mcasasb7440c282015-02-04 14:52:191553
wnwenbdc444e2016-05-25 13:44:151554
Saagar Sanghavifceeaae2020-08-12 16:40:361555def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441556 """Make sure .DEPS.git is never modified manually."""
1557 if any(f.LocalPath().endswith('.DEPS.git') for f in
1558 input_api.AffectedFiles()):
1559 return [output_api.PresubmitError(
1560 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1561 'automated system based on what\'s in DEPS and your changes will be\n'
1562 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501563 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1564 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441565 'for more information')]
1566 return []
1567
1568
Saagar Sanghavifceeaae2020-08-12 16:40:361569def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471570 """Checks that DEPS file deps are from allowed_hosts."""
1571 # Run only if DEPS file has been modified to annoy fewer bystanders.
1572 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1573 return []
1574 # Outsource work to gclient verify
1575 try:
John Budorickf20c0042019-04-25 23:23:401576 gclient_path = input_api.os_path.join(
1577 input_api.PresubmitLocalPath(),
1578 'third_party', 'depot_tools', 'gclient.py')
1579 input_api.subprocess.check_output(
1580 [input_api.python_executable, gclient_path, 'verify'],
1581 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471582 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201583 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471584 return [output_api.PresubmitError(
1585 'DEPS file must have only git dependencies.',
1586 long_text=error.output)]
1587
1588
Mario Sanchez Prada2472cab2019-09-18 10:58:311589def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1590 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591591 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311592
1593 Returns an string composed of the name of the file, the line number where the
1594 match has been found and the additional text passed as |message| in case the
1595 target type name matches the text inside the line passed as parameter.
1596 """
Peng Huang9c5949a02020-06-11 19:20:541597 result = []
1598
danakjd18e8892020-12-17 17:42:011599 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1600 return result
1601 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541602 return result
1603
Mario Sanchez Prada2472cab2019-09-18 10:58:311604 matched = False
1605 if type_name[0:1] == '/':
1606 regex = type_name[1:]
1607 if input_api.re.search(regex, line):
1608 matched = True
1609 elif type_name in line:
1610 matched = True
1611
Mario Sanchez Prada2472cab2019-09-18 10:58:311612 if matched:
1613 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1614 for message_line in message:
1615 result.append(' %s' % message_line)
1616
1617 return result
1618
1619
Saagar Sanghavifceeaae2020-08-12 16:40:361620def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591621 """Make sure that banned functions are not used."""
1622 warnings = []
1623 errors = []
1624
James Cook24a504192020-07-23 00:08:441625 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151626 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441627 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151628 if input_api.re.match(item, local_path):
1629 return True
1630 return False
1631
Peter K. Lee6c03ccff2019-07-15 14:40:051632 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541633 local_path = affected_file.LocalPath()
1634 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1635 return False
1636 basename = input_api.os_path.basename(local_path)
1637 if 'ios' in basename.split('_'):
1638 return True
1639 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1640 if sep and 'ios' in local_path.split(sep):
1641 return True
1642 return False
1643
wnwenbdc444e2016-05-25 13:44:151644 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311645 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1646 func_name, message)
1647 if problems:
wnwenbdc444e2016-05-25 13:44:151648 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311649 errors.extend(problems)
1650 else:
1651 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151652
Eric Stevensona9a980972017-09-23 00:04:411653 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1654 for f in input_api.AffectedFiles(file_filter=file_filter):
1655 for line_num, line in f.ChangedContents():
1656 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1657 CheckForMatch(f, line_num, line, func_name, message, error)
1658
[email protected]127f18ec2012-06-16 05:05:591659 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1660 for f in input_api.AffectedFiles(file_filter=file_filter):
1661 for line_num, line in f.ChangedContents():
1662 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151663 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591664
Peter K. Lee6c03ccff2019-07-15 14:40:051665 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541666 for line_num, line in f.ChangedContents():
1667 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1668 CheckForMatch(f, line_num, line, func_name, message, error)
1669
Peter K. Lee6c03ccff2019-07-15 14:40:051670 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1671 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1672 for line_num, line in f.ChangedContents():
1673 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1674 CheckForMatch(f, line_num, line, func_name, message, error)
1675
[email protected]127f18ec2012-06-16 05:05:591676 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1677 for f in input_api.AffectedFiles(file_filter=file_filter):
1678 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491679 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441680 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491681 continue
wnwenbdc444e2016-05-25 13:44:151682 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591683
1684 result = []
1685 if (warnings):
1686 result.append(output_api.PresubmitPromptWarning(
1687 'Banned functions were used.\n' + '\n'.join(warnings)))
1688 if (errors):
1689 result.append(output_api.PresubmitError(
1690 'Banned functions were used.\n' + '\n'.join(errors)))
1691 return result
1692
1693
Michael Thiessen44457642020-02-06 00:24:151694def _CheckAndroidNoBannedImports(input_api, output_api):
1695 """Make sure that banned java imports are not used."""
1696 errors = []
1697
1698 def IsException(path, exceptions):
1699 for exception in exceptions:
1700 if (path.startswith(exception)):
1701 return True
1702 return False
1703
1704 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1705 for f in input_api.AffectedFiles(file_filter=file_filter):
1706 for line_num, line in f.ChangedContents():
1707 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1708 if IsException(f.LocalPath(), exceptions):
1709 continue;
1710 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1711 'import ' + import_name, message)
1712 if problems:
1713 errors.extend(problems)
1714 result = []
1715 if (errors):
1716 result.append(output_api.PresubmitError(
1717 'Banned imports were used.\n' + '\n'.join(errors)))
1718 return result
1719
1720
Saagar Sanghavifceeaae2020-08-12 16:40:361721def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311722 """Make sure that old Mojo types are not used."""
1723 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571724 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311725
Mario Sanchez Pradaaab91382019-12-19 08:57:091726 # For any path that is not an "ok" or an "error" path, a warning will be
1727 # raised if deprecated mojo types are found.
1728 ok_paths = ['components/arc']
1729 error_paths = ['third_party/blink', 'content']
1730
Mario Sanchez Prada2472cab2019-09-18 10:58:311731 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1732 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571733 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091734 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311735 continue
1736
1737 for line_num, line in f.ChangedContents():
1738 for func_name, message in _DEPRECATED_MOJO_TYPES:
1739 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1740 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571741
Mario Sanchez Prada2472cab2019-09-18 10:58:311742 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091743 # Raise errors inside |error_paths| and warnings everywhere else.
1744 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571745 errors.extend(problems)
1746 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311747 warnings.extend(problems)
1748
1749 result = []
1750 if (warnings):
1751 result.append(output_api.PresubmitPromptWarning(
1752 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571753 if (errors):
1754 result.append(output_api.PresubmitError(
1755 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311756 return result
1757
1758
Saagar Sanghavifceeaae2020-08-12 16:40:361759def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061760 """Make sure that banned functions are not used."""
1761 files = []
1762 pattern = input_api.re.compile(r'^#pragma\s+once',
1763 input_api.re.MULTILINE)
1764 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1765 if not f.LocalPath().endswith('.h'):
1766 continue
1767 contents = input_api.ReadFile(f)
1768 if pattern.search(contents):
1769 files.append(f)
1770
1771 if files:
1772 return [output_api.PresubmitError(
1773 'Do not use #pragma once in header files.\n'
1774 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1775 files)]
1776 return []
1777
[email protected]127f18ec2012-06-16 05:05:591778
Saagar Sanghavifceeaae2020-08-12 16:40:361779def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121780 """Checks to make sure we don't introduce use of foo ? true : false."""
1781 problems = []
1782 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1783 for f in input_api.AffectedFiles():
1784 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1785 continue
1786
1787 for line_num, line in f.ChangedContents():
1788 if pattern.match(line):
1789 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1790
1791 if not problems:
1792 return []
1793 return [output_api.PresubmitPromptWarning(
1794 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1795 '\n'.join(problems))]
1796
1797
Saagar Sanghavifceeaae2020-08-12 16:40:361798def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281799 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181800 change. Breaking - rules is an error, breaking ! rules is a
1801 warning.
1802 """
mohan.reddyf21db962014-10-16 12:26:471803 import sys
[email protected]55f9f382012-07-31 11:02:181804 # We need to wait until we have an input_api object and use this
1805 # roundabout construct to import checkdeps because this file is
1806 # eval-ed and thus doesn't have __file__.
1807 original_sys_path = sys.path
1808 try:
1809 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471810 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181811 import checkdeps
[email protected]55f9f382012-07-31 11:02:181812 from rules import Rule
1813 finally:
1814 # Restore sys.path to what it was before.
1815 sys.path = original_sys_path
1816
1817 added_includes = []
rhalavati08acd232017-04-03 07:23:281818 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241819 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181820 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061821 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501822 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081823 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061824 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501825 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081826 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061827 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501828 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081829 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181830
[email protected]26385172013-05-09 23:11:351831 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181832
1833 error_descriptions = []
1834 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281835 error_subjects = set()
1836 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361837
[email protected]55f9f382012-07-31 11:02:181838 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1839 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081840 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181841 description_with_path = '%s\n %s' % (path, rule_description)
1842 if rule_type == Rule.DISALLOW:
1843 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281844 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181845 else:
1846 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281847 warning_subjects.add("#includes")
1848
1849 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1850 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081851 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281852 description_with_path = '%s\n %s' % (path, rule_description)
1853 if rule_type == Rule.DISALLOW:
1854 error_descriptions.append(description_with_path)
1855 error_subjects.add("imports")
1856 else:
1857 warning_descriptions.append(description_with_path)
1858 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181859
Jinsuk Kim5a092672017-10-24 22:42:241860 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021861 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081862 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241863 description_with_path = '%s\n %s' % (path, rule_description)
1864 if rule_type == Rule.DISALLOW:
1865 error_descriptions.append(description_with_path)
1866 error_subjects.add("imports")
1867 else:
1868 warning_descriptions.append(description_with_path)
1869 warning_subjects.add("imports")
1870
[email protected]55f9f382012-07-31 11:02:181871 results = []
1872 if error_descriptions:
1873 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281874 'You added one or more %s that violate checkdeps rules.'
1875 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181876 error_descriptions))
1877 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421878 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281879 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181880 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281881 '%s? See relevant DEPS file(s) for details and contacts.' %
1882 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181883 warning_descriptions))
1884 return results
1885
1886
Saagar Sanghavifceeaae2020-08-12 16:40:361887def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:221888 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151889 if input_api.platform == 'win32':
1890 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291891 checkperms_tool = input_api.os_path.join(
1892 input_api.PresubmitLocalPath(),
1893 'tools', 'checkperms', 'checkperms.py')
1894 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471895 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391896 with input_api.CreateTemporaryFile() as file_list:
1897 for f in input_api.AffectedFiles():
1898 # checkperms.py file/directory arguments must be relative to the
1899 # repository.
Dirk Prankee3c9c62d2021-05-18 18:35:591900 file_list.write((f.LocalPath() + '\n').encode('utf8'))
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391901 file_list.close()
1902 args += ['--file-list', file_list.name]
1903 try:
1904 input_api.subprocess.check_output(args)
1905 return []
1906 except input_api.subprocess.CalledProcessError as error:
1907 return [output_api.PresubmitError(
1908 'checkperms.py failed:',
Ari Chivukula45f58dd52021-06-18 04:23:041909 long_text=error.output.decode('utf-8', 'ignore'))]
[email protected]fbcafe5a2012-08-08 15:31:221910
1911
Saagar Sanghavifceeaae2020-08-12 16:40:361912def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:491913 """Makes sure we don't include ui/aura/window_property.h
1914 in header files.
1915 """
1916 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1917 errors = []
1918 for f in input_api.AffectedFiles():
1919 if not f.LocalPath().endswith('.h'):
1920 continue
1921 for line_num, line in f.ChangedContents():
1922 if pattern.match(line):
1923 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1924
1925 results = []
1926 if errors:
1927 results.append(output_api.PresubmitError(
1928 'Header files should not include ui/aura/window_property.h', errors))
1929 return results
1930
1931
Omer Katzcc77ea92021-04-26 10:23:281932def CheckNoInternalHeapIncludes(input_api, output_api):
1933 """Makes sure we don't include any headers from
1934 third_party/blink/renderer/platform/heap/impl or
1935 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1936 third_party/blink/renderer/platform/heap
1937 """
1938 impl_pattern = input_api.re.compile(
1939 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1940 v8_wrapper_pattern = input_api.re.compile(
1941 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"')
1942 file_filter = lambda f: not input_api.re.match(
1943 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1944 f.LocalPath())
1945 errors = []
1946
1947 for f in input_api.AffectedFiles(file_filter=file_filter):
1948 for line_num, line in f.ChangedContents():
1949 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1950 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1951
1952 results = []
1953 if errors:
1954 results.append(output_api.PresubmitError(
1955 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1956 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1957 'relevant counterparts from third_party/blink/renderer/platform/heap',
1958 errors))
1959 return results
1960
1961
[email protected]70ca77752012-11-20 03:45:031962def _CheckForVersionControlConflictsInFile(input_api, f):
1963 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1964 errors = []
1965 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161966 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231967 # First-level headers in markdown look a lot like version control
1968 # conflict markers. http://daringfireball.net/projects/markdown/basics
1969 continue
[email protected]70ca77752012-11-20 03:45:031970 if pattern.match(line):
1971 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1972 return errors
1973
1974
Saagar Sanghavifceeaae2020-08-12 16:40:361975def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:031976 """Usually this is not intentional and will cause a compile failure."""
1977 errors = []
1978 for f in input_api.AffectedFiles():
1979 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1980
1981 results = []
1982 if errors:
1983 results.append(output_api.PresubmitError(
1984 'Version control conflict markers found, please resolve.', errors))
1985 return results
1986
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201987
Saagar Sanghavifceeaae2020-08-12 16:40:361988def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:161989 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1990 errors = []
1991 for f in input_api.AffectedFiles():
1992 for line_num, line in f.ChangedContents():
1993 if pattern.search(line):
1994 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1995
1996 results = []
1997 if errors:
1998 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501999 'Found Google support URL addressed by answer number. Please replace '
2000 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162001 return results
2002
[email protected]70ca77752012-11-20 03:45:032003
Saagar Sanghavifceeaae2020-08-12 16:40:362004def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442005 def FilterFile(affected_file):
2006 """Filter function for use with input_api.AffectedSourceFiles,
2007 below. This filters out everything except non-test files from
2008 top-level directories that generally speaking should not hard-code
2009 service URLs (e.g. src/android_webview/, src/content/ and others).
2010 """
2011 return input_api.FilterSourceFile(
2012 affected_file,
James Cook24a504192020-07-23 00:08:442013 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2014 files_to_skip=(_EXCLUDED_PATHS +
2015 _TEST_CODE_EXCLUDED_PATHS +
2016 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442017
reillyi38965732015-11-16 18:27:332018 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2019 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462020 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2021 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442022 problems = [] # items are (filename, line_number, line)
2023 for f in input_api.AffectedSourceFiles(FilterFile):
2024 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462025 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442026 problems.append((f.LocalPath(), line_num, line))
2027
2028 if problems:
[email protected]f7051d52013-04-02 18:31:422029 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442030 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582031 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442032 [' %s:%d: %s' % (
2033 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032034 else:
2035 return []
[email protected]06e6d0ff2012-12-11 01:36:442036
2037
Saagar Sanghavifceeaae2020-08-12 16:40:362038def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292039 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2040 def FileFilter(affected_file):
2041 """Includes directories known to be Chrome OS only."""
2042 return input_api.FilterSourceFile(
2043 affected_file,
James Cook24a504192020-07-23 00:08:442044 files_to_check=('^ash/',
2045 '^chromeos/', # Top-level src/chromeos.
2046 '/chromeos/', # Any path component.
2047 '^components/arc',
2048 '^components/exo'),
2049 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292050
2051 prefs = []
2052 priority_prefs = []
2053 for f in input_api.AffectedFiles(file_filter=FileFilter):
2054 for line_num, line in f.ChangedContents():
2055 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2056 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2057 prefs.append(' %s' % line)
2058 if input_api.re.search(
2059 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2060 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2061 priority_prefs.append(' %s' % line)
2062
2063 results = []
2064 if (prefs):
2065 results.append(output_api.PresubmitPromptWarning(
2066 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2067 'by browser sync settings. If these prefs should be controlled by OS '
2068 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2069 if (priority_prefs):
2070 results.append(output_api.PresubmitPromptWarning(
2071 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2072 'controlled by browser sync settings. If these prefs should be '
2073 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2074 'instead.\n' + '\n'.join(prefs)))
2075 return results
2076
2077
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492078# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362079def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272080 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312081 The native_client_sdk directory is excluded because it has auto-generated PNG
2082 files for documentation.
[email protected]d2530012013-01-25 16:39:272083 """
[email protected]d2530012013-01-25 16:39:272084 errors = []
James Cook24a504192020-07-23 00:08:442085 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2086 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312087 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442088 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312089 for f in input_api.AffectedFiles(include_deletes=False,
2090 file_filter=file_filter):
2091 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272092
2093 results = []
2094 if errors:
2095 results.append(output_api.PresubmitError(
2096 'The name of PNG files should not have abbreviations. \n'
2097 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2098 'Contact [email protected] if you have questions.', errors))
2099 return results
2100
2101
Daniel Cheng4dcdb6b2017-04-13 08:30:172102def _ExtractAddRulesFromParsedDeps(parsed_deps):
2103 """Extract the rules that add dependencies from a parsed DEPS file.
2104
2105 Args:
2106 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2107 add_rules = set()
2108 add_rules.update([
2109 rule[1:] for rule in parsed_deps.get('include_rules', [])
2110 if rule.startswith('+') or rule.startswith('!')
2111 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502112 for _, rules in parsed_deps.get('specific_include_rules',
Dirk Prankee3c9c62d2021-05-18 18:35:592113 {}).items():
Daniel Cheng4dcdb6b2017-04-13 08:30:172114 add_rules.update([
2115 rule[1:] for rule in rules
2116 if rule.startswith('+') or rule.startswith('!')
2117 ])
2118 return add_rules
2119
2120
2121def _ParseDeps(contents):
2122 """Simple helper for parsing DEPS files."""
2123 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172124 class _VarImpl:
2125
2126 def __init__(self, local_scope):
2127 self._local_scope = local_scope
2128
2129 def Lookup(self, var_name):
2130 """Implements the Var syntax."""
2131 try:
2132 return self._local_scope['vars'][var_name]
2133 except KeyError:
2134 raise Exception('Var is not defined: %s' % var_name)
2135
2136 local_scope = {}
2137 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172138 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592139 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172140 }
Dirk Pranke1b9e06382021-05-14 01:16:222141
Dirk Prankee3c9c62d2021-05-18 18:35:592142 exec(contents, global_scope, local_scope)
Daniel Cheng4dcdb6b2017-04-13 08:30:172143 return local_scope
2144
2145
2146def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592147 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412148 a set of DEPS entries that we should look up.
2149
2150 For a directory (rather than a specific filename) we fake a path to
2151 a specific filename by adding /DEPS. This is chosen as a file that
2152 will seldom or never be subject to per-file include_rules.
2153 """
[email protected]2b438d62013-11-14 17:54:142154 # We ignore deps entries on auto-generated directories.
2155 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082156
Daniel Cheng4dcdb6b2017-04-13 08:30:172157 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2158 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2159
2160 added_deps = new_deps.difference(old_deps)
2161
[email protected]2b438d62013-11-14 17:54:142162 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172163 for added_dep in added_deps:
2164 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2165 continue
2166 # Assume that a rule that ends in .h is a rule for a specific file.
2167 if added_dep.endswith('.h'):
2168 results.add(added_dep)
2169 else:
2170 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082171 return results
2172
2173
Saagar Sanghavifceeaae2020-08-12 16:40:362174def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552175 """When a dependency prefixed with + is added to a DEPS file, we
2176 want to make sure that the change is reviewed by an OWNER of the
2177 target file or directory, to avoid layering violations from being
2178 introduced. This check verifies that this happens.
2179 """
Joey Mou57048132021-02-26 22:17:552180 # We rely on Gerrit's code-owners to check approvals.
2181 # input_api.gerrit is always set for Chromium, but other projects
2182 # might not use Gerrit.
2183 if not input_api.gerrit:
2184 return []
Edward Lesmes44feb2332021-03-19 01:27:522185 if (input_api.change.issue and
2186 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232187 # Skip OWNERS check when Owners-Override label is approved. This is intended
2188 # for global owners, trusted bots, and on-call sheriffs. Review is still
2189 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522190 return []
Edward Lesmes6fba51082021-01-20 04:20:232191
Daniel Cheng4dcdb6b2017-04-13 08:30:172192 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242193
2194 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492195 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242196 for f in input_api.AffectedFiles(include_deletes=False,
2197 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552198 filename = input_api.os_path.basename(f.LocalPath())
2199 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172200 virtual_depended_on_files.update(_CalculateAddedDeps(
2201 input_api.os_path,
2202 '\n'.join(f.OldContents()),
2203 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552204
[email protected]e871964c2013-05-13 14:14:552205 if not virtual_depended_on_files:
2206 return []
2207
2208 if input_api.is_committing:
2209 if input_api.tbr:
2210 return [output_api.PresubmitNotifyResult(
2211 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272212 if input_api.dry_run:
2213 return [output_api.PresubmitNotifyResult(
2214 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552215 if not input_api.change.issue:
2216 return [output_api.PresubmitError(
2217 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402218 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552219 output = output_api.PresubmitError
2220 else:
2221 output = output_api.PresubmitNotifyResult
2222
tandriied3b7e12016-05-12 14:38:502223 owner_email, reviewers = (
2224 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2225 input_api,
Edward Lesmesa3846442021-02-08 20:20:032226 None,
tandriied3b7e12016-05-12 14:38:502227 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552228
2229 owner_email = owner_email or input_api.change.author_email
2230
Edward Lesmesa3846442021-02-08 20:20:032231 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2232 virtual_depended_on_files, reviewers.union([owner_email]), [])
2233 missing_files = [
2234 f for f in virtual_depended_on_files
2235 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412236
2237 # We strip the /DEPS part that was added by
2238 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2239 # directory.
2240 def StripDeps(path):
2241 start_deps = path.rfind('/DEPS')
2242 if start_deps != -1:
2243 return path[:start_deps]
2244 else:
2245 return path
2246 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552247 for path in missing_files]
2248
2249 if unapproved_dependencies:
2250 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152251 output('You need LGTM from owners of depends-on paths in DEPS that were '
2252 'modified in this CL:\n %s' %
2253 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032254 suggested_owners = input_api.owners_client.SuggestOwners(
2255 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152256 output_list.append(output(
2257 'Suggested missing target path OWNERS:\n %s' %
2258 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552259 return output_list
2260
2261 return []
2262
2263
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492264# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362265def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492266 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442267 files_to_skip = (_EXCLUDED_PATHS +
2268 _TEST_CODE_EXCLUDED_PATHS +
2269 input_api.DEFAULT_FILES_TO_SKIP +
2270 (r"^base[\\/]logging\.h$",
2271 r"^base[\\/]logging\.cc$",
2272 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2273 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2274 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2275 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2276 r"startup_browser_creator\.cc$",
2277 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2278 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2279 r"diagnostics_writer\.cc$",
2280 r"^chrome[\\/]chrome_cleaner[\\/].*",
2281 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2282 r"dll_hash_main\.cc$",
2283 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2284 r"^chromecast[\\/]",
2285 r"^cloud_print[\\/]",
2286 r"^components[\\/]browser_watcher[\\/]"
2287 r"dump_stability_report_main_win.cc$",
2288 r"^components[\\/]media_control[\\/]renderer[\\/]"
2289 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352290 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2291 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442292 r"^components[\\/]zucchini[\\/].*",
2293 # TODO(peter): Remove exception. https://crbug.com/534537
2294 r"^content[\\/]browser[\\/]notifications[\\/]"
2295 r"notification_event_dispatcher_impl\.cc$",
2296 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2297 r"gl_helper_benchmark\.cc$",
2298 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2299 r"^courgette[\\/]courgette_tool\.cc$",
2300 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
David Dorwinfa9aef42021-08-17 06:46:202301 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
James Cook24a504192020-07-23 00:08:442302 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Sergey Ulanov6db14b4d62021-05-10 07:59:482303 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
James Cook24a504192020-07-23 00:08:442304 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2305 r"^ipc[\\/]ipc_logging\.cc$",
2306 r"^native_client_sdk[\\/]",
2307 r"^remoting[\\/]base[\\/]logging\.h$",
2308 r"^remoting[\\/]host[\\/].*",
2309 r"^sandbox[\\/]linux[\\/].*",
2310 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2311 r"dump_file_system.cc$",
2312 r"^tools[\\/]",
2313 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2314 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2315 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2316 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2317 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402318 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442319 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402320
thomasanderson625d3932017-03-29 07:16:582321 log_info = set([])
2322 printf = set([])
[email protected]85218562013-11-22 07:41:402323
2324 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582325 for _, line in f.ChangedContents():
2326 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2327 log_info.add(f.LocalPath())
2328 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2329 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372330
thomasanderson625d3932017-03-29 07:16:582331 if input_api.re.search(r"\bprintf\(", line):
2332 printf.add(f.LocalPath())
2333 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2334 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402335
2336 if log_info:
2337 return [output_api.PresubmitError(
2338 'These files spam the console log with LOG(INFO):',
2339 items=log_info)]
2340 if printf:
2341 return [output_api.PresubmitError(
2342 'These files spam the console log with printf/fprintf:',
2343 items=printf)]
2344 return []
2345
2346
Saagar Sanghavifceeaae2020-08-12 16:40:362347def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162348 """These types are all expected to hold locks while in scope and
2349 so should never be anonymous (which causes them to be immediately
2350 destroyed)."""
2351 they_who_must_be_named = [
2352 'base::AutoLock',
2353 'base::AutoReset',
2354 'base::AutoUnlock',
2355 'SkAutoAlphaRestore',
2356 'SkAutoBitmapShaderInstall',
2357 'SkAutoBlitterChoose',
2358 'SkAutoBounderCommit',
2359 'SkAutoCallProc',
2360 'SkAutoCanvasRestore',
2361 'SkAutoCommentBlock',
2362 'SkAutoDescriptor',
2363 'SkAutoDisableDirectionCheck',
2364 'SkAutoDisableOvalCheck',
2365 'SkAutoFree',
2366 'SkAutoGlyphCache',
2367 'SkAutoHDC',
2368 'SkAutoLockColors',
2369 'SkAutoLockPixels',
2370 'SkAutoMalloc',
2371 'SkAutoMaskFreeImage',
2372 'SkAutoMutexAcquire',
2373 'SkAutoPathBoundsUpdate',
2374 'SkAutoPDFRelease',
2375 'SkAutoRasterClipValidate',
2376 'SkAutoRef',
2377 'SkAutoTime',
2378 'SkAutoTrace',
2379 'SkAutoUnref',
2380 ]
2381 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2382 # bad: base::AutoLock(lock.get());
2383 # not bad: base::AutoLock lock(lock.get());
2384 bad_pattern = input_api.re.compile(anonymous)
2385 # good: new base::AutoLock(lock.get())
2386 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2387 errors = []
2388
2389 for f in input_api.AffectedFiles():
2390 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2391 continue
2392 for linenum, line in f.ChangedContents():
2393 if bad_pattern.search(line) and not good_pattern.search(line):
2394 errors.append('%s:%d' % (f.LocalPath(), linenum))
2395
2396 if errors:
2397 return [output_api.PresubmitError(
2398 'These lines create anonymous variables that need to be named:',
2399 items=errors)]
2400 return []
2401
2402
Saagar Sanghavifceeaae2020-08-12 16:40:362403def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532404 # Returns whether |template_str| is of the form <T, U...> for some types T
2405 # and U. Assumes that |template_str| is already in the form <...>.
2406 def HasMoreThanOneArg(template_str):
2407 # Level of <...> nesting.
2408 nesting = 0
2409 for c in template_str:
2410 if c == '<':
2411 nesting += 1
2412 elif c == '>':
2413 nesting -= 1
2414 elif c == ',' and nesting == 1:
2415 return True
2416 return False
2417
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492418 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102419 sources = lambda affected_file: input_api.FilterSourceFile(
2420 affected_file,
James Cook24a504192020-07-23 00:08:442421 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2422 input_api.DEFAULT_FILES_TO_SKIP),
2423 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552424
2425 # Pattern to capture a single "<...>" block of template arguments. It can
2426 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2427 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2428 # latter would likely require counting that < and > match, which is not
2429 # expressible in regular languages. Should the need arise, one can introduce
2430 # limited counting (matching up to a total number of nesting depth), which
2431 # should cover all practical cases for already a low nesting limit.
2432 template_arg_pattern = (
2433 r'<[^>]*' # Opening block of <.
2434 r'>([^<]*>)?') # Closing block of >.
2435 # Prefix expressing that whatever follows is not already inside a <...>
2436 # block.
2437 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102438 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552439 not_inside_template_arg_pattern
2440 + r'\bstd::unique_ptr'
2441 + template_arg_pattern
2442 + r'\(\)')
2443
2444 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2445 template_arg_no_array_pattern = (
2446 r'<[^>]*[^]]' # Opening block of <.
2447 r'>([^(<]*[^]]>)?') # Closing block of >.
2448 # Prefix saying that what follows is the start of an expression.
2449 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2450 # Suffix saying that what follows are call parentheses with a non-empty list
2451 # of arguments.
2452 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532453 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552454 return_construct_pattern = input_api.re.compile(
2455 start_of_expr_pattern
2456 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532457 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552458 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532459 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552460 + nonempty_arg_list_pattern)
2461
Vaclav Brozek851d9602018-04-04 16:13:052462 problems_constructor = []
2463 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102464 for f in input_api.AffectedSourceFiles(sources):
2465 for line_number, line in f.ChangedContents():
2466 # Disallow:
2467 # return std::unique_ptr<T>(foo);
2468 # bar = std::unique_ptr<T>(foo);
2469 # But allow:
2470 # return std::unique_ptr<T[]>(foo);
2471 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532472 # And also allow cases when the second template argument is present. Those
2473 # cases cannot be handled by std::make_unique:
2474 # return std::unique_ptr<T, U>(foo);
2475 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052476 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532477 return_construct_result = return_construct_pattern.search(line)
2478 if return_construct_result and not HasMoreThanOneArg(
2479 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052480 problems_constructor.append(
2481 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102482 # Disallow:
2483 # std::unique_ptr<T>()
2484 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052485 problems_nullptr.append(
2486 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2487
2488 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162489 if problems_nullptr:
Daniel Cheng2dbf9c42021-10-06 21:26:112490 errors.append(output_api.PresubmitPromptWarning(
Vaclav Brozek851d9602018-04-04 16:13:052491 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162492 problems_nullptr))
2493 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052494 errors.append(output_api.PresubmitError(
2495 'The following files use explicit std::unique_ptr constructor.'
2496 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162497 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102498 return errors
2499
2500
Saagar Sanghavifceeaae2020-08-12 16:40:362501def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082502 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522503 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082504 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522505 # If actions.xml is already included in the changelist, the PRESUBMIT
2506 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082507 return []
2508
Alexei Svitkine64505a92021-03-11 22:00:542509 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2510 files_to_skip = (_EXCLUDED_PATHS +
2511 _TEST_CODE_EXCLUDED_PATHS +
2512 input_api.DEFAULT_FILES_TO_SKIP )
2513 file_filter = lambda f: input_api.FilterSourceFile(
2514 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2515
[email protected]999261d2014-03-03 20:08:082516 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522517 current_actions = None
[email protected]999261d2014-03-03 20:08:082518 for f in input_api.AffectedFiles(file_filter=file_filter):
2519 for line_num, line in f.ChangedContents():
2520 match = input_api.re.search(action_re, line)
2521 if match:
[email protected]2f92dec2014-03-07 19:21:522522 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2523 # loaded only once.
2524 if not current_actions:
2525 with open('tools/metrics/actions/actions.xml') as actions_f:
2526 current_actions = actions_f.read()
2527 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082528 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522529 action = 'name="{0}"'.format(action_name)
2530 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082531 return [output_api.PresubmitPromptWarning(
2532 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522533 'tools/metrics/actions/actions.xml. Please run '
2534 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082535 % (f.LocalPath(), line_num, action_name))]
2536 return []
2537
2538
Daniel Cheng13ca61a882017-08-25 15:11:252539def _ImportJSONCommentEater(input_api):
2540 import sys
2541 sys.path = sys.path + [input_api.os_path.join(
2542 input_api.PresubmitLocalPath(),
2543 'tools', 'json_comment_eater')]
2544 import json_comment_eater
2545 return json_comment_eater
2546
2547
[email protected]99171a92014-06-03 08:44:472548def _GetJSONParseError(input_api, filename, eat_comments=True):
2549 try:
2550 contents = input_api.ReadFile(filename)
2551 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252552 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132553 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472554
2555 input_api.json.loads(contents)
2556 except ValueError as e:
2557 return e
2558 return None
2559
2560
2561def _GetIDLParseError(input_api, filename):
2562 try:
2563 contents = input_api.ReadFile(filename)
2564 idl_schema = input_api.os_path.join(
2565 input_api.PresubmitLocalPath(),
2566 'tools', 'json_schema_compiler', 'idl_schema.py')
2567 process = input_api.subprocess.Popen(
2568 [input_api.python_executable, idl_schema],
2569 stdin=input_api.subprocess.PIPE,
2570 stdout=input_api.subprocess.PIPE,
2571 stderr=input_api.subprocess.PIPE,
2572 universal_newlines=True)
2573 (_, error) = process.communicate(input=contents)
2574 return error or None
2575 except ValueError as e:
2576 return e
2577
2578
Saagar Sanghavifceeaae2020-08-12 16:40:362579def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472580 """Check that IDL and JSON files do not contain syntax errors."""
2581 actions = {
2582 '.idl': _GetIDLParseError,
2583 '.json': _GetJSONParseError,
2584 }
[email protected]99171a92014-06-03 08:44:472585 # Most JSON files are preprocessed and support comments, but these do not.
2586 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042587 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472588 ]
2589 # Only run IDL checker on files in these directories.
2590 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042591 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2592 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472593 ]
2594
2595 def get_action(affected_file):
2596 filename = affected_file.LocalPath()
2597 return actions.get(input_api.os_path.splitext(filename)[1])
2598
[email protected]99171a92014-06-03 08:44:472599 def FilterFile(affected_file):
2600 action = get_action(affected_file)
2601 if not action:
2602 return False
2603 path = affected_file.LocalPath()
2604
Erik Staab2dd72b12020-04-16 15:03:402605 if _MatchesFile(input_api,
2606 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2607 path):
[email protected]99171a92014-06-03 08:44:472608 return False
2609
2610 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162611 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472612 return False
2613 return True
2614
2615 results = []
2616 for affected_file in input_api.AffectedFiles(
2617 file_filter=FilterFile, include_deletes=False):
2618 action = get_action(affected_file)
2619 kwargs = {}
2620 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162621 _MatchesFile(input_api, json_no_comments_patterns,
2622 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472623 kwargs['eat_comments'] = False
2624 parse_error = action(input_api,
2625 affected_file.AbsoluteLocalPath(),
2626 **kwargs)
2627 if parse_error:
2628 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2629 (affected_file.LocalPath(), parse_error)))
2630 return results
2631
2632
Saagar Sanghavifceeaae2020-08-12 16:40:362633def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492634 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472635 import sys
[email protected]760deea2013-12-10 19:33:492636 original_sys_path = sys.path
2637 try:
2638 sys.path = sys.path + [input_api.os_path.join(
2639 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2640 import checkstyle
2641 finally:
2642 # Restore sys.path to what it was before.
2643 sys.path = original_sys_path
2644
2645 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092646 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442647 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492648
2649
Saagar Sanghavifceeaae2020-08-12 16:40:362650def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002651 """Checks to make sure devil is initialized correctly in python scripts."""
2652 script_common_initialize_pattern = input_api.re.compile(
2653 r'script_common\.InitializeEnvironment\(')
2654 devil_env_config_initialize = input_api.re.compile(
2655 r'devil_env\.config\.Initialize\(')
2656
2657 errors = []
2658
2659 sources = lambda affected_file: input_api.FilterSourceFile(
2660 affected_file,
James Cook24a504192020-07-23 00:08:442661 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2662 (r'^build[\\/]android[\\/]devil_chromium\.py',
2663 r'^third_party[\\/].*',)),
2664 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002665
2666 for f in input_api.AffectedSourceFiles(sources):
2667 for line_num, line in f.ChangedContents():
2668 if (script_common_initialize_pattern.search(line) or
2669 devil_env_config_initialize.search(line)):
2670 errors.append("%s:%d" % (f.LocalPath(), line_num))
2671
2672 results = []
2673
2674 if errors:
2675 results.append(output_api.PresubmitError(
2676 'Devil initialization should always be done using '
2677 'devil_chromium.Initialize() in the chromium project, to use better '
2678 'defaults for dependencies (ex. up-to-date version of adb).',
2679 errors))
2680
2681 return results
2682
2683
Sean Kau46e29bc2017-08-28 16:31:162684def _MatchesFile(input_api, patterns, path):
2685 for pattern in patterns:
2686 if input_api.re.search(pattern, path):
2687 return True
2688 return False
2689
2690
Daniel Cheng7052cdf2017-11-21 19:23:292691def _GetOwnersFilesToCheckForIpcOwners(input_api):
2692 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172693
Daniel Cheng7052cdf2017-11-21 19:23:292694 Returns:
2695 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2696 contain to cover IPC-related files with noparent reviewer rules.
2697 """
2698 # Whether or not a file affects IPC is (mostly) determined by a simple list
2699 # of filename patterns.
dchenge07de812016-06-20 19:27:172700 file_patterns = [
palmerb19a0932017-01-24 04:00:312701 # Legacy IPC:
dchenge07de812016-06-20 19:27:172702 '*_messages.cc',
2703 '*_messages*.h',
2704 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312705 # Mojo IPC:
dchenge07de812016-06-20 19:27:172706 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472707 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172708 '*_struct_traits*.*',
2709 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312710 '*.typemap',
2711 # Android native IPC:
2712 '*.aidl',
2713 # Blink uses a different file naming convention:
2714 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472715 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172716 '*StructTraits*.*',
2717 '*TypeConverter*.*',
2718 ]
2719
scottmg7a6ed5ba2016-11-04 18:22:042720 # These third_party directories do not contain IPCs, but contain files
2721 # matching the above patterns, which trigger false positives.
2722 exclude_paths = [
2723 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162724 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232725 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292726 'third_party/win_build_output/*',
Scott Violet9f82d362019-11-06 21:42:162727 # These files are just used to communicate between class loaders running
2728 # in the same process.
2729 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572730 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2731
scottmg7a6ed5ba2016-11-04 18:22:042732 ]
2733
dchenge07de812016-06-20 19:27:172734 # Dictionary mapping an OWNERS file path to Patterns.
2735 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2736 # rules ) to a PatternEntry.
2737 # PatternEntry is a dictionary with two keys:
2738 # - 'files': the files that are matched by this pattern
2739 # - 'rules': the per-file rules needed for this pattern
2740 # For example, if we expect OWNERS file to contain rules for *.mojom and
2741 # *_struct_traits*.*, Patterns might look like this:
2742 # {
2743 # '*.mojom': {
2744 # 'files': ...,
2745 # 'rules': [
2746 # 'per-file *.mojom=set noparent',
2747 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2748 # ],
2749 # },
2750 # '*_struct_traits*.*': {
2751 # 'files': ...,
2752 # 'rules': [
2753 # 'per-file *_struct_traits*.*=set noparent',
2754 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2755 # ],
2756 # },
2757 # }
2758 to_check = {}
2759
Daniel Cheng13ca61a882017-08-25 15:11:252760 def AddPatternToCheck(input_file, pattern):
2761 owners_file = input_api.os_path.join(
2762 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2763 if owners_file not in to_check:
2764 to_check[owners_file] = {}
2765 if pattern not in to_check[owners_file]:
2766 to_check[owners_file][pattern] = {
2767 'files': [],
2768 'rules': [
2769 'per-file %s=set noparent' % pattern,
2770 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2771 ]
2772 }
Vaclav Brozekd5de76a2018-03-17 07:57:502773 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252774
dchenge07de812016-06-20 19:27:172775 # Iterate through the affected files to see what we actually need to check
2776 # for. We should only nag patch authors about per-file rules if a file in that
2777 # directory would match that pattern. If a directory only contains *.mojom
2778 # files and no *_messages*.h files, we should only nag about rules for
2779 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252780 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262781 # Manifest files don't have a strong naming convention. Instead, try to find
2782 # affected .cc and .h files which look like they contain a manifest
2783 # definition.
2784 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2785 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2786 if (manifest_pattern.search(f.LocalPath()) and not
2787 test_manifest_pattern.search(f.LocalPath())):
2788 # We expect all actual service manifest files to contain at least one
2789 # qualified reference to service_manager::Manifest.
2790 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252791 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172792 for pattern in file_patterns:
2793 if input_api.fnmatch.fnmatch(
2794 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042795 skip = False
2796 for exclude in exclude_paths:
2797 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2798 skip = True
2799 break
2800 if skip:
2801 continue
Daniel Cheng13ca61a882017-08-25 15:11:252802 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172803 break
2804
Daniel Cheng7052cdf2017-11-21 19:23:292805 return to_check
2806
2807
Wez17c66962020-04-29 15:26:032808def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2809 """Adds OWNERS files to check for correct Fuchsia security owners."""
2810
2811 file_patterns = [
2812 # Component specifications.
2813 '*.cml', # Component Framework v2.
2814 '*.cmx', # Component Framework v1.
2815
2816 # Fuchsia IDL protocol specifications.
2817 '*.fidl',
2818 ]
2819
Joshua Peraza1ca6d392020-12-08 00:14:092820 # Don't check for owners files for changes in these directories.
2821 exclude_paths = [
2822 'third_party/crashpad/*',
2823 ]
2824
Wez17c66962020-04-29 15:26:032825 def AddPatternToCheck(input_file, pattern):
2826 owners_file = input_api.os_path.join(
2827 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2828 if owners_file not in to_check:
2829 to_check[owners_file] = {}
2830 if pattern not in to_check[owners_file]:
2831 to_check[owners_file][pattern] = {
2832 'files': [],
2833 'rules': [
2834 'per-file %s=set noparent' % pattern,
2835 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2836 ]
2837 }
2838 to_check[owners_file][pattern]['files'].append(input_file)
2839
2840 # Iterate through the affected files to see what we actually need to check
2841 # for. We should only nag patch authors about per-file rules if a file in that
2842 # directory would match that pattern.
2843 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092844 skip = False
2845 for exclude in exclude_paths:
2846 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2847 skip = True
2848 if skip:
2849 continue
2850
Wez17c66962020-04-29 15:26:032851 for pattern in file_patterns:
2852 if input_api.fnmatch.fnmatch(
2853 input_api.os_path.basename(f.LocalPath()), pattern):
2854 AddPatternToCheck(f, pattern)
2855 break
2856
2857 return to_check
2858
2859
Saagar Sanghavifceeaae2020-08-12 16:40:362860def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292861 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2862 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032863 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292864
2865 if to_check:
2866 # If there are any OWNERS files to check, there are IPC-related changes in
2867 # this CL. Auto-CC the review list.
2868 output_api.AppendCC('[email protected]')
2869
2870 # Go through the OWNERS files to check, filtering out rules that are already
2871 # present in that OWNERS file.
Dirk Prankee3c9c62d2021-05-18 18:35:592872 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172873 try:
Dirk Prankee3c9c62d2021-05-18 18:35:592874 with open(owners_file) as f:
dchenge07de812016-06-20 19:27:172875 lines = set(f.read().splitlines())
Jeffrey Youngf3a5c8c42021-05-14 21:56:102876 for entry in patterns.values():
dchenge07de812016-06-20 19:27:172877 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2878 ]
2879 except IOError:
2880 # No OWNERS file, so all the rules are definitely missing.
2881 continue
2882
2883 # All the remaining lines weren't found in OWNERS files, so emit an error.
2884 errors = []
Dirk Prankee3c9c62d2021-05-18 18:35:592885 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172886 missing_lines = []
2887 files = []
Dirk Prankee3c9c62d2021-05-18 18:35:592888 for _, entry in patterns.items():
dchenge07de812016-06-20 19:27:172889 missing_lines.extend(entry['rules'])
2890 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2891 if missing_lines:
2892 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052893 'Because of the presence of files:\n%s\n\n'
2894 '%s needs the following %d lines added:\n\n%s' %
2895 ('\n'.join(files), owners_file, len(missing_lines),
2896 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172897
2898 results = []
2899 if errors:
vabrf5ce3bf92016-07-11 14:52:412900 if input_api.is_committing:
2901 output = output_api.PresubmitError
2902 else:
2903 output = output_api.PresubmitPromptWarning
2904 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592905 'Found OWNERS files that need to be updated for IPC security ' +
2906 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172907 long_text='\n\n'.join(errors)))
2908
2909 return results
2910
2911
Robert Sesek2c905332020-05-06 23:17:132912def _GetFilesUsingSecurityCriticalFunctions(input_api):
2913 """Checks affected files for changes to security-critical calls. This
2914 function checks the full change diff, to catch both additions/changes
2915 and removals.
2916
2917 Returns a dict keyed by file name, and the value is a set of detected
2918 functions.
2919 """
2920 # Map of function pretty name (displayed in an error) to the pattern to
2921 # match it with.
2922 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:372923 'content::GetServiceSandboxType<>()':
2924 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:132925 }
2926 _PATTERNS_TO_CHECK = {
2927 k: input_api.re.compile(v)
2928 for k, v in _PATTERNS_TO_CHECK.items()
2929 }
2930
2931 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2932 files_to_functions = {}
2933 for f in input_api.AffectedFiles():
2934 diff = f.GenerateScmDiff()
2935 for line in diff.split('\n'):
2936 # Not using just RightHandSideLines() because removing a
2937 # call to a security-critical function can be just as important
2938 # as adding or changing the arguments.
2939 if line.startswith('-') or (line.startswith('+') and
2940 not line.startswith('++')):
2941 for name, pattern in _PATTERNS_TO_CHECK.items():
2942 if pattern.search(line):
2943 path = f.LocalPath()
2944 if not path in files_to_functions:
2945 files_to_functions[path] = set()
2946 files_to_functions[path].add(name)
2947 return files_to_functions
2948
2949
Saagar Sanghavifceeaae2020-08-12 16:40:362950def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:132951 """Checks that changes involving security-critical functions are reviewed
2952 by the security team.
2953 """
2954 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:122955 if not len(files_to_functions):
2956 return []
Robert Sesek2c905332020-05-06 23:17:132957
Edward Lesmes1e9fade2021-02-08 20:31:122958 owner_email, reviewers = (
2959 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2960 input_api,
2961 None,
2962 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:132963
Edward Lesmes1e9fade2021-02-08 20:31:122964 # Load the OWNERS file for security changes.
2965 owners_file = 'ipc/SECURITY_OWNERS'
2966 security_owners = input_api.owners_client.ListOwners(owners_file)
2967 has_security_owner = any([owner in reviewers for owner in security_owners])
2968 if has_security_owner:
2969 return []
Robert Sesek2c905332020-05-06 23:17:132970
Edward Lesmes1e9fade2021-02-08 20:31:122971 msg = 'The following files change calls to security-sensive functions\n' \
2972 'that need to be reviewed by {}.\n'.format(owners_file)
2973 for path, names in files_to_functions.items():
2974 msg += ' {}\n'.format(path)
2975 for name in names:
2976 msg += ' {}\n'.format(name)
2977 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:132978
Edward Lesmes1e9fade2021-02-08 20:31:122979 if input_api.is_committing:
2980 output = output_api.PresubmitError
2981 else:
2982 output = output_api.PresubmitNotifyResult
2983 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:132984
2985
Saagar Sanghavifceeaae2020-08-12 16:40:362986def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:262987 """Checks that set noparent is only used together with an OWNERS file in
2988 //build/OWNERS.setnoparent (see also
2989 //docs/code_reviews.md#owners-files-details)
2990 """
2991 errors = []
2992
2993 allowed_owners_files_file = 'build/OWNERS.setnoparent'
2994 allowed_owners_files = set()
2995 with open(allowed_owners_files_file, 'r') as f:
2996 for line in f:
2997 line = line.strip()
2998 if not line or line.startswith('#'):
2999 continue
3000 allowed_owners_files.add(line)
3001
3002 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3003
3004 for f in input_api.AffectedFiles(include_deletes=False):
3005 if not f.LocalPath().endswith('OWNERS'):
3006 continue
3007
3008 found_owners_files = set()
3009 found_set_noparent_lines = dict()
3010
3011 # Parse the OWNERS file.
3012 for lineno, line in enumerate(f.NewContents(), 1):
3013 line = line.strip()
3014 if line.startswith('set noparent'):
3015 found_set_noparent_lines[''] = lineno
3016 if line.startswith('file://'):
3017 if line in allowed_owners_files:
3018 found_owners_files.add('')
3019 if line.startswith('per-file'):
3020 match = per_file_pattern.match(line)
3021 if match:
3022 glob = match.group(1).strip()
3023 directive = match.group(2).strip()
3024 if directive == 'set noparent':
3025 found_set_noparent_lines[glob] = lineno
3026 if directive.startswith('file://'):
3027 if directive in allowed_owners_files:
3028 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153029
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263030 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403031 # listed in build/OWNERS.setnoparent. An exception is made for top level
3032 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143033 if (f.LocalPath().count('/') != 1 and
3034 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403035 for set_noparent_line in found_set_noparent_lines:
3036 if set_noparent_line in found_owners_files:
3037 continue
3038 errors.append(' %s:%d' % (f.LocalPath(),
3039 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263040
3041 results = []
3042 if errors:
3043 if input_api.is_committing:
3044 output = output_api.PresubmitError
3045 else:
3046 output = output_api.PresubmitPromptWarning
3047 results.append(output(
3048 'Found the following "set noparent" restrictions in OWNERS files that '
3049 'do not include owners from build/OWNERS.setnoparent:',
3050 long_text='\n\n'.join(errors)))
3051 return results
3052
3053
Saagar Sanghavifceeaae2020-08-12 16:40:363054def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313055 """Checks that added or removed lines in non third party affected
3056 header files do not lead to new useless class or struct forward
3057 declaration.
jbriance9e12f162016-11-25 07:57:503058 """
3059 results = []
3060 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3061 input_api.re.MULTILINE)
3062 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3063 input_api.re.MULTILINE)
3064 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313065 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193066 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493067 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313068 continue
3069
jbriance9e12f162016-11-25 07:57:503070 if not f.LocalPath().endswith('.h'):
3071 continue
3072
3073 contents = input_api.ReadFile(f)
3074 fwd_decls = input_api.re.findall(class_pattern, contents)
3075 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3076
3077 useless_fwd_decls = []
3078 for decl in fwd_decls:
3079 count = sum(1 for _ in input_api.re.finditer(
3080 r'\b%s\b' % input_api.re.escape(decl), contents))
3081 if count == 1:
3082 useless_fwd_decls.append(decl)
3083
3084 if not useless_fwd_decls:
3085 continue
3086
3087 for line in f.GenerateScmDiff().splitlines():
3088 if (line.startswith('-') and not line.startswith('--') or
3089 line.startswith('+') and not line.startswith('++')):
3090 for decl in useless_fwd_decls:
3091 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3092 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243093 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503094 (f.LocalPath(), decl)))
3095 useless_fwd_decls.remove(decl)
3096
3097 return results
3098
Jinsong Fan91ebbbd2019-04-16 14:57:173099def _CheckAndroidDebuggableBuild(input_api, output_api):
3100 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3101 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3102 this is a debuggable build of Android.
3103 """
3104 build_type_check_pattern = input_api.re.compile(
3105 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3106
3107 errors = []
3108
3109 sources = lambda affected_file: input_api.FilterSourceFile(
3110 affected_file,
James Cook24a504192020-07-23 00:08:443111 files_to_skip=(_EXCLUDED_PATHS +
3112 _TEST_CODE_EXCLUDED_PATHS +
3113 input_api.DEFAULT_FILES_TO_SKIP +
3114 (r"^android_webview[\\/]support_library[\\/]"
3115 "boundary_interfaces[\\/]",
3116 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3117 r'^third_party[\\/].*',
3118 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3119 r"webview[\\/]chromium[\\/]License.*",)),
3120 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173121
3122 for f in input_api.AffectedSourceFiles(sources):
3123 for line_num, line in f.ChangedContents():
3124 if build_type_check_pattern.search(line):
3125 errors.append("%s:%d" % (f.LocalPath(), line_num))
3126
3127 results = []
3128
3129 if errors:
3130 results.append(output_api.PresubmitPromptWarning(
3131 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3132 ' Please use BuildInfo.isDebugAndroid() instead.',
3133 errors))
3134
3135 return results
jbriance9e12f162016-11-25 07:57:503136
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493137# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293138def _CheckAndroidToastUsage(input_api, output_api):
3139 """Checks that code uses org.chromium.ui.widget.Toast instead of
3140 android.widget.Toast (Chromium Toast doesn't force hardware
3141 acceleration on low-end devices, saving memory).
3142 """
3143 toast_import_pattern = input_api.re.compile(
3144 r'^import android\.widget\.Toast;$')
3145
3146 errors = []
3147
3148 sources = lambda affected_file: input_api.FilterSourceFile(
3149 affected_file,
James Cook24a504192020-07-23 00:08:443150 files_to_skip=(_EXCLUDED_PATHS +
3151 _TEST_CODE_EXCLUDED_PATHS +
3152 input_api.DEFAULT_FILES_TO_SKIP +
3153 (r'^chromecast[\\/].*',
3154 r'^remoting[\\/].*')),
3155 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293156
3157 for f in input_api.AffectedSourceFiles(sources):
3158 for line_num, line in f.ChangedContents():
3159 if toast_import_pattern.search(line):
3160 errors.append("%s:%d" % (f.LocalPath(), line_num))
3161
3162 results = []
3163
3164 if errors:
3165 results.append(output_api.PresubmitError(
3166 'android.widget.Toast usage is detected. Android toasts use hardware'
3167 ' acceleration, and can be\ncostly on low-end devices. Please use'
3168 ' org.chromium.ui.widget.Toast instead.\n'
3169 'Contact [email protected] if you have any questions.',
3170 errors))
3171
3172 return results
3173
3174
dgnaa68d5e2015-06-10 10:08:223175def _CheckAndroidCrLogUsage(input_api, output_api):
3176 """Checks that new logs using org.chromium.base.Log:
3177 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513178 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223179 """
pkotwicza1dd0b002016-05-16 14:41:043180
torne89540622017-03-24 19:41:303181 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043182 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303183 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043184 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303185 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043186 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3187 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093188 # The customtabs_benchmark is a small app that does not depend on Chromium
3189 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043190 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043191 ]
3192
dgnaa68d5e2015-06-10 10:08:223193 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123194 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3195 class_in_base_pattern = input_api.re.compile(
3196 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3197 has_some_log_import_pattern = input_api.re.compile(
3198 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223199 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553200 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223201 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463202 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553203 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223204
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463205 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443206 sources = lambda x: input_api.FilterSourceFile(x,
3207 files_to_check=[r'.*\.java$'],
3208 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123209
dgnaa68d5e2015-06-10 10:08:223210 tag_decl_errors = []
3211 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123212 tag_errors = []
dgn38736db2015-09-18 19:20:513213 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123214 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223215
3216 for f in input_api.AffectedSourceFiles(sources):
3217 file_content = input_api.ReadFile(f)
3218 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223219 # Per line checks
dgn87d9fb62015-06-12 09:15:123220 if (cr_log_import_pattern.search(file_content) or
3221 (class_in_base_pattern.search(file_content) and
3222 not has_some_log_import_pattern.search(file_content))):
3223 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223224 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553225 if rough_log_decl_pattern.search(line):
3226 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223227
3228 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123229 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223230 if match:
3231 has_modified_logs = True
3232
3233 # Make sure it uses "TAG"
3234 if not match.group('tag') == 'TAG':
3235 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123236 else:
3237 # Report non cr Log function calls in changed lines
3238 for line_num, line in f.ChangedContents():
3239 if log_call_pattern.search(line):
3240 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223241
3242 # Per file checks
3243 if has_modified_logs:
3244 # Make sure the tag is using the "cr" prefix and is not too long
3245 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513246 tag_name = match.group('name') if match else None
3247 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223248 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513249 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223250 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513251 elif '.' in tag_name:
3252 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223253
3254 results = []
3255 if tag_decl_errors:
3256 results.append(output_api.PresubmitPromptWarning(
3257 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513258 '"private static final String TAG = "<package tag>".\n'
3259 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223260 tag_decl_errors))
3261
3262 if tag_length_errors:
3263 results.append(output_api.PresubmitError(
3264 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513265 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223266 tag_length_errors))
3267
3268 if tag_errors:
3269 results.append(output_api.PresubmitPromptWarning(
3270 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3271 tag_errors))
3272
dgn87d9fb62015-06-12 09:15:123273 if util_log_errors:
dgn4401aa52015-04-29 16:26:173274 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123275 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3276 util_log_errors))
3277
dgn38736db2015-09-18 19:20:513278 if tag_with_dot_errors:
3279 results.append(output_api.PresubmitPromptWarning(
3280 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3281 tag_with_dot_errors))
3282
dgn4401aa52015-04-29 16:26:173283 return results
3284
3285
Yoland Yanb92fa522017-08-28 17:37:063286def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3287 """Checks that junit.framework.* is no longer used."""
3288 deprecated_junit_framework_pattern = input_api.re.compile(
3289 r'^import junit\.framework\..*;',
3290 input_api.re.MULTILINE)
3291 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443292 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063293 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133294 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063295 for line_num, line in f.ChangedContents():
3296 if deprecated_junit_framework_pattern.search(line):
3297 errors.append("%s:%d" % (f.LocalPath(), line_num))
3298
3299 results = []
3300 if errors:
3301 results.append(output_api.PresubmitError(
3302 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3303 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3304 ' if you have any question.', errors))
3305 return results
3306
3307
3308def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3309 """Checks that if new Java test classes have inheritance.
3310 Either the new test class is JUnit3 test or it is a JUnit4 test class
3311 with a base class, either case is undesirable.
3312 """
3313 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3314
3315 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443316 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063317 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133318 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063319 if not f.OldContents():
3320 class_declaration_start_flag = False
3321 for line_num, line in f.ChangedContents():
3322 if class_declaration_pattern.search(line):
3323 class_declaration_start_flag = True
3324 if class_declaration_start_flag and ' extends ' in line:
3325 errors.append('%s:%d' % (f.LocalPath(), line_num))
3326 if '{' in line:
3327 class_declaration_start_flag = False
3328
3329 results = []
3330 if errors:
3331 results.append(output_api.PresubmitPromptWarning(
3332 'The newly created files include Test classes that inherits from base'
3333 ' class. Please do not use inheritance in JUnit4 tests or add new'
3334 ' JUnit3 tests. Contact [email protected] if you have any'
3335 ' questions.', errors))
3336 return results
3337
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203338
yolandyan45001472016-12-21 21:12:423339def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3340 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3341 deprecated_annotation_import_pattern = input_api.re.compile(
3342 r'^import android\.test\.suitebuilder\.annotation\..*;',
3343 input_api.re.MULTILINE)
3344 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443345 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423346 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133347 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423348 for line_num, line in f.ChangedContents():
3349 if deprecated_annotation_import_pattern.search(line):
3350 errors.append("%s:%d" % (f.LocalPath(), line_num))
3351
3352 results = []
3353 if errors:
3354 results.append(output_api.PresubmitError(
3355 'Annotations in android.test.suitebuilder.annotation have been'
3356 ' deprecated since API level 24. Please use android.support.test.filters'
3357 ' from //third_party/android_support_test_runner:runner_java instead.'
3358 ' Contact [email protected] if you have any questions.', errors))
3359 return results
3360
3361
agrieve7b6479d82015-10-07 14:24:223362def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3363 """Checks if MDPI assets are placed in a correct directory."""
3364 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3365 ('/res/drawable/' in f.LocalPath() or
3366 '/res/drawable-ldrtl/' in f.LocalPath()))
3367 errors = []
3368 for f in input_api.AffectedFiles(include_deletes=False,
3369 file_filter=file_filter):
3370 errors.append(' %s' % f.LocalPath())
3371
3372 results = []
3373 if errors:
3374 results.append(output_api.PresubmitError(
3375 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3376 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3377 '/res/drawable-ldrtl/.\n'
3378 'Contact [email protected] if you have questions.', errors))
3379 return results
3380
3381
Nate Fischer535972b2017-09-16 01:06:183382def _CheckAndroidWebkitImports(input_api, output_api):
3383 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353384 android.webview.ValueCallback except in the WebView glue layer
3385 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183386 """
3387 valuecallback_import_pattern = input_api.re.compile(
3388 r'^import android\.webkit\.ValueCallback;$')
3389
3390 errors = []
3391
3392 sources = lambda affected_file: input_api.FilterSourceFile(
3393 affected_file,
James Cook24a504192020-07-23 00:08:443394 files_to_skip=(_EXCLUDED_PATHS +
3395 _TEST_CODE_EXCLUDED_PATHS +
3396 input_api.DEFAULT_FILES_TO_SKIP +
3397 (r'^android_webview[\\/]glue[\\/].*',
3398 r'^weblayer[\\/].*',)),
3399 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183400
3401 for f in input_api.AffectedSourceFiles(sources):
3402 for line_num, line in f.ChangedContents():
3403 if valuecallback_import_pattern.search(line):
3404 errors.append("%s:%d" % (f.LocalPath(), line_num))
3405
3406 results = []
3407
3408 if errors:
3409 results.append(output_api.PresubmitError(
3410 'android.webkit.ValueCallback usage is detected outside of the glue'
3411 ' layer. To stay compatible with the support library, android.webkit.*'
3412 ' classes should only be used inside the glue layer and'
3413 ' org.chromium.base.Callback should be used instead.',
3414 errors))
3415
3416 return results
3417
3418
Becky Zhou7c69b50992018-12-10 19:37:573419def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3420 """Checks Android XML styles """
3421 import sys
3422 original_sys_path = sys.path
3423 try:
3424 sys.path = sys.path + [input_api.os_path.join(
3425 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3426 import checkxmlstyle
3427 finally:
3428 # Restore sys.path to what it was before.
3429 sys.path = original_sys_path
3430
3431 if is_check_on_upload:
3432 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3433 else:
3434 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3435
3436
agrievef32bcc72016-04-04 14:57:403437class PydepsChecker(object):
3438 def __init__(self, input_api, pydeps_files):
3439 self._file_cache = {}
3440 self._input_api = input_api
3441 self._pydeps_files = pydeps_files
3442
3443 def _LoadFile(self, path):
3444 """Returns the list of paths within a .pydeps file relative to //."""
3445 if path not in self._file_cache:
3446 with open(path) as f:
3447 self._file_cache[path] = f.read()
3448 return self._file_cache[path]
3449
3450 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3451 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393452 pydeps_data = self._LoadFile(pydeps_path)
3453 uses_gn_paths = '--gn-paths' in pydeps_data
3454 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3455 if uses_gn_paths:
3456 # Paths look like: //foo/bar/baz
3457 return (e[2:] for e in entries)
3458 else:
3459 # Paths look like: path/relative/to/file.pydeps
3460 os_path = self._input_api.os_path
3461 pydeps_dir = os_path.dirname(pydeps_path)
3462 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403463
3464 def _CreateFilesToPydepsMap(self):
3465 """Returns a map of local_path -> list_of_pydeps."""
3466 ret = {}
3467 for pydep_local_path in self._pydeps_files:
3468 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3469 ret.setdefault(path, []).append(pydep_local_path)
3470 return ret
3471
3472 def ComputeAffectedPydeps(self):
3473 """Returns an iterable of .pydeps files that might need regenerating."""
3474 affected_pydeps = set()
3475 file_to_pydeps_map = None
3476 for f in self._input_api.AffectedFiles(include_deletes=True):
3477 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463478 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3479 # subrepositories. We can't figure out which files change, so re-check
3480 # all files.
3481 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383482 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3483 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403484 return self._pydeps_files
3485 elif local_path.endswith('.pydeps'):
3486 if local_path in self._pydeps_files:
3487 affected_pydeps.add(local_path)
3488 elif local_path.endswith('.py'):
3489 if file_to_pydeps_map is None:
3490 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3491 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3492 return affected_pydeps
3493
3494 def DetermineIfStale(self, pydeps_path):
3495 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413496 import difflib
John Budorick47ca3fe2018-02-10 00:53:103497 import os
3498
agrievef32bcc72016-04-04 14:57:403499 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033500 if old_pydeps_data:
3501 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393502 if '--output' not in cmd:
3503 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033504 old_contents = old_pydeps_data[2:]
3505 else:
3506 # A default cmd that should work in most cases (as long as pydeps filename
3507 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3508 # file is empty/new.
3509 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3510 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3511 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103512 env = dict(os.environ)
3513 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403514 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103515 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413516 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033517 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413518 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403519
3520
Tibor Goldschwendt360793f72019-06-25 18:23:493521def _ParseGclientArgs():
3522 args = {}
3523 with open('build/config/gclient_args.gni', 'r') as f:
3524 for line in f:
3525 line = line.strip()
3526 if not line or line.startswith('#'):
3527 continue
3528 attribute, value = line.split('=')
3529 args[attribute.strip()] = value.strip()
3530 return args
3531
3532
Saagar Sanghavifceeaae2020-08-12 16:40:363533def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403534 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403535 # This check is for Python dependency lists (.pydeps files), and involves
3536 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3537 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283538 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003539 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493540 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403541 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403542 results = []
3543 # First, check for new / deleted .pydeps.
3544 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033545 # Check whether we are running the presubmit check for a file in src.
3546 # f.LocalPath is relative to repo (src, or internal repo).
3547 # os_path.exists is relative to src repo.
3548 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3549 # to src and we can conclude that the pydeps is in src.
3550 if input_api.os_path.exists(f.LocalPath()):
3551 if f.LocalPath().endswith('.pydeps'):
3552 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3553 results.append(output_api.PresubmitError(
3554 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3555 'remove %s' % f.LocalPath()))
3556 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3557 results.append(output_api.PresubmitError(
3558 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3559 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403560
3561 if results:
3562 return results
3563
Mohamed Heikal7cd4d8312020-06-16 16:49:403564 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3565 affected_pydeps = set(checker.ComputeAffectedPydeps())
3566 affected_android_pydeps = affected_pydeps.intersection(
3567 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3568 if affected_android_pydeps and not is_android:
3569 results.append(output_api.PresubmitPromptOrNotify(
3570 'You have changed python files that may affect pydeps for android\n'
3571 'specific scripts. However, the relevant presumbit check cannot be\n'
3572 'run because you are not using an Android checkout. To validate that\n'
3573 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3574 'use the android-internal-presubmit optional trybot.\n'
3575 'Possibly stale pydeps files:\n{}'.format(
3576 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403577
Mohamed Heikal7cd4d8312020-06-16 16:49:403578 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3579 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403580 try:
phajdan.jr0d9878552016-11-04 10:49:413581 result = checker.DetermineIfStale(pydep_path)
3582 if result:
3583 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403584 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413585 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3586 'To regenerate, run:\n\n %s' %
3587 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403588 except input_api.subprocess.CalledProcessError as error:
3589 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3590 long_text=error.output)]
3591
3592 return results
3593
3594
Saagar Sanghavifceeaae2020-08-12 16:40:363595def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433596 """Checks to make sure no header files have |Singleton<|."""
3597 def FileFilter(affected_file):
3598 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443599 files_to_skip = (_EXCLUDED_PATHS +
3600 input_api.DEFAULT_FILES_TO_SKIP +
3601 (r"^base[\\/]memory[\\/]singleton\.h$",
3602 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3603 r"quic_singleton_impl\.h$"))
3604 return input_api.FilterSourceFile(affected_file,
3605 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433606
sergeyu34d21222015-09-16 00:11:443607 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433608 files = []
3609 for f in input_api.AffectedSourceFiles(FileFilter):
3610 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3611 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3612 contents = input_api.ReadFile(f)
3613 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243614 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433615 pattern.search(line)):
3616 files.append(f)
3617 break
3618
3619 if files:
yolandyandaabc6d2016-04-18 18:29:393620 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443621 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433622 'Please move them to an appropriate source file so that the ' +
3623 'template gets instantiated in a single compilation unit.',
3624 files) ]
3625 return []
3626
3627
[email protected]fd20b902014-05-09 02:14:533628_DEPRECATED_CSS = [
3629 # Values
3630 ( "-webkit-box", "flex" ),
3631 ( "-webkit-inline-box", "inline-flex" ),
3632 ( "-webkit-flex", "flex" ),
3633 ( "-webkit-inline-flex", "inline-flex" ),
3634 ( "-webkit-min-content", "min-content" ),
3635 ( "-webkit-max-content", "max-content" ),
3636
3637 # Properties
3638 ( "-webkit-background-clip", "background-clip" ),
3639 ( "-webkit-background-origin", "background-origin" ),
3640 ( "-webkit-background-size", "background-size" ),
3641 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443642 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533643
3644 # Functions
3645 ( "-webkit-gradient", "gradient" ),
3646 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3647 ( "-webkit-linear-gradient", "linear-gradient" ),
3648 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3649 ( "-webkit-radial-gradient", "radial-gradient" ),
3650 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3651]
3652
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203653
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493654# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363655def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533656 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253657 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343658 documentation and iOS CSS for dom distiller
3659 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253660 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533661 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493662 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443663 files_to_skip = (_EXCLUDED_PATHS +
3664 _TEST_CODE_EXCLUDED_PATHS +
3665 input_api.DEFAULT_FILES_TO_SKIP +
3666 (r"^chrome/common/extensions/docs",
3667 r"^chrome/docs",
3668 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3669 r"^components/neterror/resources/neterror.css",
3670 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253671 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443672 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533673 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3674 for line_num, line in fpath.ChangedContents():
3675 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023676 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533677 results.append(output_api.PresubmitError(
3678 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3679 (fpath.LocalPath(), line_num, deprecated_value, value)))
3680 return results
3681
mohan.reddyf21db962014-10-16 12:26:473682
Saagar Sanghavifceeaae2020-08-12 16:40:363683def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363684 bad_files = {}
3685 for f in input_api.AffectedFiles(include_deletes=False):
3686 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493687 not f.LocalPath().startswith('third_party/blink') and
3688 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363689 continue
3690
Daniel Bratell65b033262019-04-23 08:17:063691 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363692 continue
3693
Vaclav Brozekd5de76a2018-03-17 07:57:503694 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363695 if "#include" in line and "../" in line]
3696 if not relative_includes:
3697 continue
3698 bad_files[f.LocalPath()] = relative_includes
3699
3700 if not bad_files:
3701 return []
3702
3703 error_descriptions = []
Dirk Prankee3c9c62d2021-05-18 18:35:593704 for file_path, bad_lines in bad_files.items():
rlanday6802cf632017-05-30 17:48:363705 error_description = file_path
3706 for line in bad_lines:
3707 error_description += '\n ' + line
3708 error_descriptions.append(error_description)
3709
3710 results = []
3711 results.append(output_api.PresubmitError(
3712 'You added one or more relative #include paths (including "../").\n'
3713 'These shouldn\'t be used because they can be used to include headers\n'
3714 'from code that\'s not correctly specified as a dependency in the\n'
3715 'relevant BUILD.gn file(s).',
3716 error_descriptions))
3717
3718 return results
3719
Takeshi Yoshinoe387aa32017-08-02 13:16:133720
Saagar Sanghavifceeaae2020-08-12 16:40:363721def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063722 """Check that nobody tries to include a cc file. It's a relatively
3723 common error which results in duplicate symbols in object
3724 files. This may not always break the build until someone later gets
3725 very confusing linking errors."""
3726 results = []
3727 for f in input_api.AffectedFiles(include_deletes=False):
3728 # We let third_party code do whatever it wants
3729 if (f.LocalPath().startswith('third_party') and
3730 not f.LocalPath().startswith('third_party/blink') and
3731 not f.LocalPath().startswith('third_party\\blink')):
3732 continue
3733
3734 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3735 continue
3736
3737 for _, line in f.ChangedContents():
3738 if line.startswith('#include "'):
3739 included_file = line.split('"')[1]
3740 if _IsCPlusPlusFile(input_api, included_file):
3741 # The most common naming for external files with C++ code,
3742 # apart from standard headers, is to call them foo.inc, but
3743 # Chromium sometimes uses foo-inc.cc so allow that as well.
3744 if not included_file.endswith(('.h', '-inc.cc')):
3745 results.append(output_api.PresubmitError(
3746 'Only header files or .inc files should be included in other\n'
3747 'C++ files. Compiling the contents of a cc file more than once\n'
3748 'will cause duplicate information in the build which may later\n'
3749 'result in strange link_errors.\n' +
3750 f.LocalPath() + ':\n ' +
3751 line))
3752
3753 return results
3754
3755
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203756def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3757 if not isinstance(key, ast.Str):
3758 return 'Key at line %d must be a string literal' % key.lineno
3759 if not isinstance(value, ast.Dict):
3760 return 'Value at line %d must be a dict' % value.lineno
3761 if len(value.keys) != 1:
3762 return 'Dict at line %d must have single entry' % value.lineno
3763 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3764 return (
3765 'Entry at line %d must have a string literal \'filepath\' as key' %
3766 value.lineno)
3767 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133768
Takeshi Yoshinoe387aa32017-08-02 13:16:133769
Sergey Ulanov4af16052018-11-08 02:41:463770def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203771 if not isinstance(key, ast.Str):
3772 return 'Key at line %d must be a string literal' % key.lineno
3773 if not isinstance(value, ast.List):
3774 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463775 for element in value.elts:
3776 if not isinstance(element, ast.Str):
3777 return 'Watchlist elements on line %d is not a string' % key.lineno
3778 if not email_regex.match(element.s):
3779 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3780 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203781 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133782
Takeshi Yoshinoe387aa32017-08-02 13:16:133783
Sergey Ulanov4af16052018-11-08 02:41:463784def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203785 mismatch_template = (
3786 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3787 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133788
Sergey Ulanov4af16052018-11-08 02:41:463789 email_regex = input_api.re.compile(
3790 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3791
3792 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203793 i = 0
3794 last_key = ''
3795 while True:
3796 if i >= len(wd_dict.keys):
3797 if i >= len(w_dict.keys):
3798 return None
3799 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3800 elif i >= len(w_dict.keys):
3801 return (
3802 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133803
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203804 wd_key = wd_dict.keys[i]
3805 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133806
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203807 result = _CheckWatchlistDefinitionsEntrySyntax(
3808 wd_key, wd_dict.values[i], ast)
3809 if result is not None:
3810 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133811
Sergey Ulanov4af16052018-11-08 02:41:463812 result = _CheckWatchlistsEntrySyntax(
3813 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203814 if result is not None:
3815 return 'Bad entry in WATCHLISTS dict: %s' % result
3816
3817 if wd_key.s != w_key.s:
3818 return mismatch_template % (
3819 '%s at line %d' % (wd_key.s, wd_key.lineno),
3820 '%s at line %d' % (w_key.s, w_key.lineno))
3821
3822 if wd_key.s < last_key:
3823 return (
3824 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3825 (wd_key.lineno, w_key.lineno))
3826 last_key = wd_key.s
3827
3828 i = i + 1
3829
3830
Sergey Ulanov4af16052018-11-08 02:41:463831def _CheckWATCHLISTSSyntax(expression, input_api):
3832 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203833 if not isinstance(expression, ast.Expression):
3834 return 'WATCHLISTS file must contain a valid expression'
3835 dictionary = expression.body
3836 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3837 return 'WATCHLISTS file must have single dict with exactly two entries'
3838
3839 first_key = dictionary.keys[0]
3840 first_value = dictionary.values[0]
3841 second_key = dictionary.keys[1]
3842 second_value = dictionary.values[1]
3843
3844 if (not isinstance(first_key, ast.Str) or
3845 first_key.s != 'WATCHLIST_DEFINITIONS' or
3846 not isinstance(first_value, ast.Dict)):
3847 return (
3848 'The first entry of the dict in WATCHLISTS file must be '
3849 'WATCHLIST_DEFINITIONS dict')
3850
3851 if (not isinstance(second_key, ast.Str) or
3852 second_key.s != 'WATCHLISTS' or
3853 not isinstance(second_value, ast.Dict)):
3854 return (
3855 'The second entry of the dict in WATCHLISTS file must be '
3856 'WATCHLISTS dict')
3857
Sergey Ulanov4af16052018-11-08 02:41:463858 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133859
3860
Saagar Sanghavifceeaae2020-08-12 16:40:363861def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133862 for f in input_api.AffectedFiles(include_deletes=False):
3863 if f.LocalPath() == 'WATCHLISTS':
3864 contents = input_api.ReadFile(f, 'r')
3865
3866 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203867 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133868 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203869 # Get an AST tree for it and scan the tree for detailed style checking.
3870 expression = input_api.ast.parse(
3871 contents, filename='WATCHLISTS', mode='eval')
3872 except ValueError as e:
3873 return [output_api.PresubmitError(
3874 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3875 except SyntaxError as e:
3876 return [output_api.PresubmitError(
3877 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3878 except TypeError as e:
3879 return [output_api.PresubmitError(
3880 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133881
Sergey Ulanov4af16052018-11-08 02:41:463882 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203883 if result is not None:
3884 return [output_api.PresubmitError(result)]
3885 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133886
3887 return []
3888
3889
Andrew Grieve1b290e4a22020-11-24 20:07:013890def CheckGnGlobForward(input_api, output_api):
3891 """Checks that forward_variables_from(invoker, "*") follows best practices.
3892
3893 As documented at //build/docs/writing_gn_templates.md
3894 """
3895 def gn_files(f):
3896 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3897
3898 problems = []
3899 for f in input_api.AffectedSourceFiles(gn_files):
3900 for line_num, line in f.ChangedContents():
3901 if 'forward_variables_from(invoker, "*")' in line:
3902 problems.append(
3903 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3904 f.LocalPath(), line_num))
3905
3906 if problems:
3907 return [output_api.PresubmitPromptWarning(
3908 'forward_variables_from("*") without exclusions',
3909 items=sorted(problems),
3910 long_text=('The variables "visibilty" and "test_only" should be '
3911 'explicitly listed in forward_variables_from(). For more '
3912 'details, see:\n'
3913 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
3914 'build/docs/writing_gn_templates.md'
3915 '#Using-forward_variables_from'))]
3916 return []
3917
3918
Saagar Sanghavifceeaae2020-08-12 16:40:363919def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193920 """Checks that newly added header files have corresponding GN changes.
3921 Note that this is only a heuristic. To be precise, run script:
3922 build/check_gn_headers.py.
3923 """
3924
3925 def headers(f):
3926 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443927 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193928
3929 new_headers = []
3930 for f in input_api.AffectedSourceFiles(headers):
3931 if f.Action() != 'A':
3932 continue
3933 new_headers.append(f.LocalPath())
3934
3935 def gn_files(f):
James Cook24a504192020-07-23 00:08:443936 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193937
3938 all_gn_changed_contents = ''
3939 for f in input_api.AffectedSourceFiles(gn_files):
3940 for _, line in f.ChangedContents():
3941 all_gn_changed_contents += line
3942
3943 problems = []
3944 for header in new_headers:
3945 basename = input_api.os_path.basename(header)
3946 if basename not in all_gn_changed_contents:
3947 problems.append(header)
3948
3949 if problems:
3950 return [output_api.PresubmitPromptWarning(
3951 'Missing GN changes for new header files', items=sorted(problems),
3952 long_text='Please double check whether newly added header files need '
3953 'corresponding changes in gn or gni files.\nThis checking is only a '
3954 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3955 'Read https://crbug.com/661774 for more info.')]
3956 return []
3957
3958
Saagar Sanghavifceeaae2020-08-12 16:40:363959def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:023960 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3961
3962 This assumes we won't intentionally reference one product from the other
3963 product.
3964 """
3965 all_problems = []
3966 test_cases = [{
3967 "filename_postfix": "google_chrome_strings.grd",
3968 "correct_name": "Chrome",
3969 "incorrect_name": "Chromium",
3970 }, {
3971 "filename_postfix": "chromium_strings.grd",
3972 "correct_name": "Chromium",
3973 "incorrect_name": "Chrome",
3974 }]
3975
3976 for test_case in test_cases:
3977 problems = []
3978 filename_filter = lambda x: x.LocalPath().endswith(
3979 test_case["filename_postfix"])
3980
3981 # Check each new line. Can yield false positives in multiline comments, but
3982 # easier than trying to parse the XML because messages can have nested
3983 # children, and associating message elements with affected lines is hard.
3984 for f in input_api.AffectedSourceFiles(filename_filter):
3985 for line_num, line in f.ChangedContents():
3986 if "<message" in line or "<!--" in line or "-->" in line:
3987 continue
3988 if test_case["incorrect_name"] in line:
3989 problems.append(
3990 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3991
3992 if problems:
3993 message = (
3994 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3995 % (test_case["correct_name"], test_case["correct_name"],
3996 test_case["incorrect_name"]))
3997 all_problems.append(
3998 output_api.PresubmitPromptWarning(message, items=problems))
3999
4000 return all_problems
4001
4002
Saagar Sanghavifceeaae2020-08-12 16:40:364003def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364004 """Avoid large files, especially binary files, in the repository since
4005 git doesn't scale well for those. They will be in everyone's repo
4006 clones forever, forever making Chromium slower to clone and work
4007 with."""
4008
4009 # Uploading files to cloud storage is not trivial so we don't want
4010 # to set the limit too low, but the upper limit for "normal" large
4011 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4012 # anything over 20 MB is exceptional.
4013 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4014
4015 too_large_files = []
4016 for f in input_api.AffectedFiles():
4017 # Check both added and modified files (but not deleted files).
4018 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384019 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364020 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4021 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4022
4023 if too_large_files:
4024 message = (
4025 'Do not commit large files to git since git scales badly for those.\n' +
4026 'Instead put the large files in cloud storage and use DEPS to\n' +
4027 'fetch them.\n' + '\n'.join(too_large_files)
4028 )
4029 return [output_api.PresubmitError(
4030 'Too large files found in commit', long_text=message + '\n')]
4031 else:
4032 return []
4033
Max Morozb47503b2019-08-08 21:03:274034
Saagar Sanghavifceeaae2020-08-12 16:40:364035def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274036 """Checks specific for fuzz target sources."""
4037 EXPORTED_SYMBOLS = [
4038 'LLVMFuzzerInitialize',
4039 'LLVMFuzzerCustomMutator',
4040 'LLVMFuzzerCustomCrossOver',
4041 'LLVMFuzzerMutate',
4042 ]
4043
4044 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4045
4046 def FilterFile(affected_file):
4047 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444048 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4049 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274050
4051 return input_api.FilterSourceFile(
4052 affected_file,
James Cook24a504192020-07-23 00:08:444053 files_to_check=[files_to_check],
4054 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274055
4056 files_with_missing_header = []
4057 for f in input_api.AffectedSourceFiles(FilterFile):
4058 contents = input_api.ReadFile(f, 'r')
4059 if REQUIRED_HEADER in contents:
4060 continue
4061
4062 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4063 files_with_missing_header.append(f.LocalPath())
4064
4065 if not files_with_missing_header:
4066 return []
4067
4068 long_text = (
4069 'If you define any of the libFuzzer optional functions (%s), it is '
4070 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4071 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4072 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4073 'to access command line arguments passed to the fuzzer. Instead, prefer '
4074 'static initialization and shared resources as documented in '
John Palmer0e0f72bf2021-06-07 09:10:204075 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
Max Morozb47503b2019-08-08 21:03:274076 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4077 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4078 )
4079
4080 return [output_api.PresubmitPromptWarning(
4081 message="Missing '%s' in:" % REQUIRED_HEADER,
4082 items=files_with_missing_header,
4083 long_text=long_text)]
4084
4085
Mohamed Heikald048240a2019-11-12 16:57:374086def _CheckNewImagesWarning(input_api, output_api):
4087 """
4088 Warns authors who add images into the repo to make sure their images are
4089 optimized before committing.
4090 """
4091 images_added = False
4092 image_paths = []
4093 errors = []
4094 filter_lambda = lambda x: input_api.FilterSourceFile(
4095 x,
James Cook24a504192020-07-23 00:08:444096 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4097 + input_api.DEFAULT_FILES_TO_SKIP),
4098 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374099 )
4100 for f in input_api.AffectedFiles(
4101 include_deletes=False, file_filter=filter_lambda):
4102 local_path = f.LocalPath().lower()
4103 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4104 images_added = True
4105 image_paths.append(f)
4106 if images_added:
4107 errors.append(output_api.PresubmitPromptWarning(
4108 'It looks like you are trying to commit some images. If these are '
4109 'non-test-only images, please make sure to read and apply the tips in '
4110 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4111 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4112 'FYI only and will not block your CL on the CQ.', image_paths))
4113 return errors
4114
4115
Saagar Sanghavifceeaae2020-08-12 16:40:364116def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574117 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224118 results = []
dgnaa68d5e2015-06-10 10:08:224119 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174120 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224121 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294122 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064123 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4124 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424125 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184126 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574127 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374128 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154129 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574130 return results
4131
Saagar Sanghavifceeaae2020-08-12 16:40:364132def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574133 """Groups commit checks that target android code."""
4134 results = []
4135 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224136 return results
4137
Chris Hall59f8d0c72020-05-01 07:31:194138# TODO(chrishall): could we additionally match on any path owned by
4139# ui/accessibility/OWNERS ?
4140_ACCESSIBILITY_PATHS = (
4141 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4142 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4143 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4144 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4145 r"^content[\\/]browser[\\/]accessibility[\\/]",
4146 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4147 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4148 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4149 r"^ui[\\/]accessibility[\\/]",
4150 r"^ui[\\/]views[\\/]accessibility[\\/]",
4151)
4152
Saagar Sanghavifceeaae2020-08-12 16:40:364153def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194154 """Checks that commits to accessibility code contain an AX-Relnotes field in
4155 their commit message."""
4156 def FileFilter(affected_file):
4157 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444158 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194159
4160 # Only consider changes affecting accessibility paths.
4161 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4162 return []
4163
Akihiro Ota08108e542020-05-20 15:30:534164 # AX-Relnotes can appear in either the description or the footer.
4165 # When searching the description, require 'AX-Relnotes:' to appear at the
4166 # beginning of a line.
4167 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4168 description_has_relnotes = any(ax_regex.match(line)
4169 for line in input_api.change.DescriptionText().lower().splitlines())
4170
4171 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4172 'AX-Relnotes', [])
4173 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194174 return []
4175
4176 # TODO(chrishall): link to Relnotes documentation in message.
4177 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4178 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4179 "user-facing changes"
4180 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4181 "user-facing effects"
4182 "\n if this is confusing or annoying then please contact members "
4183 "of ui/accessibility/OWNERS.")
4184
4185 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224186
seanmccullough4a9356252021-04-08 19:54:094187# string pattern, sequence of strings to show when pattern matches,
4188# error flag. True if match is a presubmit error, otherwise it's a warning.
4189_NON_INCLUSIVE_TERMS = (
4190 (
4191 # Note that \b pattern in python re is pretty particular. In this
4192 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4193 # ...' will not. This may require some tweaking to catch these cases
4194 # without triggering a lot of false positives. Leaving it naive and
4195 # less matchy for now.
4196 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4197 (
4198 'Please don\'t use blacklist, whitelist, ' # nocheck
4199 'or slave in your', # nocheck
4200 'code and make every effort to use other terms. Using "// nocheck"',
4201 '"# nocheck" or "<!-- nocheck -->"',
4202 'at the end of the offending line will bypass this PRESUBMIT error',
4203 'but avoid using this whenever possible. Reach out to',
4204 '[email protected] if you have questions'),
4205 True),)
4206
Saagar Sanghavifceeaae2020-08-12 16:40:364207def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394208 """Checks common to both upload and commit."""
4209 results = []
4210 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384211 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544212 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084213
4214 author = input_api.change.author_email
4215 if author and author not in _KNOWN_ROBOTS:
4216 results.extend(
4217 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4218
[email protected]9f919cc2013-07-31 03:04:044219 results.extend(
4220 input_api.canned_checks.CheckChangeHasNoTabs(
4221 input_api,
4222 output_api,
4223 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434224 results.extend(input_api.RunTests(
4225 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244226
Edward Lesmesce51df52020-08-04 22:10:174227 dirmd_bin = input_api.os_path.join(
4228 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4229 results.extend(input_api.RunTests(
4230 input_api.canned_checks.CheckDirMetadataFormat(
4231 input_api, output_api, dirmd_bin)))
4232 results.extend(
4233 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4234 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554235 results.extend(
4236 input_api.canned_checks.CheckNoNewMetadataInOwners(
4237 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094238 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4239 input_api, output_api,
4240 excluded_directories_relative_path = [
4241 'infra',
4242 'inclusive_language_presubmit_exempt_dirs.txt'
4243 ],
4244 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174245
Vaclav Brozekcdc7defb2018-03-20 09:54:354246 for f in input_api.AffectedFiles():
4247 path, name = input_api.os_path.split(f.LocalPath())
4248 if name == 'PRESUBMIT.py':
4249 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004250 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4251 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074252 # The PRESUBMIT.py file (and the directory containing it) might
4253 # have been affected by being moved or removed, so only try to
4254 # run the tests if they still exist.
Dirk Prankee3c9c62d2021-05-18 18:35:594255 use_python3 = False
4256 with open(f.LocalPath()) as fp:
Daniel Chengab582892021-09-30 20:53:194257 use_python3 = any(line.startswith('USE_PYTHON3 = True')
4258 for line in fp.readlines())
Dirk Prankee3c9c62d2021-05-18 18:35:594259
Dirk Pranke38557312018-04-18 00:53:074260 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4261 input_api, output_api, full_path,
Dirk Prankee3c9c62d2021-05-18 18:35:594262 files_to_check=[r'^PRESUBMIT_test\.py$'],
4263 run_on_python2=not use_python3,
Jonathan Njeunjee45f2bd2021-10-12 16:21:584264 run_on_python3=use_python3,
4265 skip_shebang_check=True))
[email protected]22c9bd72011-03-27 16:47:394266 return results
[email protected]1f7b4172010-01-28 01:17:344267
[email protected]b337cb5b2011-01-23 21:24:054268
Saagar Sanghavifceeaae2020-08-12 16:40:364269def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494270 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4271 if f.LocalPath().endswith(('.orig', '.rej'))]
danakj30f05352021-11-03 18:58:414272 # Cargo.toml.orig files are part of third-party crates downloaded from
4273 # crates.io and should be included.
4274 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
[email protected]b8079ae4a2012-12-05 19:56:494275 if problems:
4276 return [output_api.PresubmitError(
4277 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034278 else:
4279 return []
[email protected]b8079ae4a2012-12-05 19:56:494280
4281
Saagar Sanghavifceeaae2020-08-12 16:40:364282def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214283 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4284 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4285 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074286 include_re = input_api.re.compile(
4287 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4288 extension_re = input_api.re.compile(r'\.[a-z]+$')
4289 errors = []
Bruce Dawsonaae5e652021-06-24 15:05:394290 for f in input_api.AffectedFiles(include_deletes=False):
Kent Tamura5a8755d2017-06-29 23:37:074291 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4292 continue
4293 found_line_number = None
4294 found_macro = None
Bruce Dawsonaae5e652021-06-24 15:05:394295 all_lines = input_api.ReadFile(f, 'r').splitlines()
4296 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074297 match = macro_re.search(line)
4298 if match:
4299 found_line_number = line_num
4300 found_macro = match.group(2)
4301 break
4302 if not found_line_number:
4303 continue
4304
Bruce Dawsonaae5e652021-06-24 15:05:394305 found_include_line = -1
4306 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074307 if include_re.search(line):
Bruce Dawsonaae5e652021-06-24 15:05:394308 found_include_line = line_num
Kent Tamura5a8755d2017-06-29 23:37:074309 break
Bruce Dawsonaae5e652021-06-24 15:05:394310 if found_include_line >= 0 and found_include_line < found_line_number:
Kent Tamura5a8755d2017-06-29 23:37:074311 continue
4312
4313 if not f.LocalPath().endswith('.h'):
4314 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4315 try:
4316 content = input_api.ReadFile(primary_header_path, 'r')
4317 if include_re.search(content):
4318 continue
4319 except IOError:
4320 pass
Bruce Dawsonaae5e652021-06-24 15:05:394321 errors.append('%s:%d %s macro is used without first including build/'
Kent Tamura5a8755d2017-06-29 23:37:074322 'build_config.h.'
4323 % (f.LocalPath(), found_line_number, found_macro))
4324 if errors:
4325 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4326 return []
4327
4328
Lei Zhang1c12a22f2021-05-12 11:28:454329def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
4330 stl_include_re = input_api.re.compile(
Lei Zhang0643e342021-05-12 18:02:124331 r'^#include\s+<('
Lei Zhang1c12a22f2021-05-12 11:28:454332 r'algorithm|'
4333 r'array|'
4334 r'limits|'
4335 r'list|'
4336 r'map|'
4337 r'memory|'
4338 r'queue|'
4339 r'set|'
4340 r'string|'
4341 r'unordered_map|'
4342 r'unordered_set|'
4343 r'utility|'
Lei Zhang0643e342021-05-12 18:02:124344 r'vector)>')
Lei Zhang1c12a22f2021-05-12 11:28:454345 std_namespace_re = input_api.re.compile(r'std::')
4346 errors = []
4347 for f in input_api.AffectedFiles():
4348 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4349 continue
4350
4351 uses_std_namespace = False
4352 has_stl_include = False
4353 for line in f.NewContents():
4354 if has_stl_include and uses_std_namespace:
4355 break
4356
4357 if not has_stl_include and stl_include_re.search(line):
4358 has_stl_include = True
4359 continue
4360
4361 if not uses_std_namespace and std_namespace_re.search(line):
4362 uses_std_namespace = True
4363 continue
4364
4365 if has_stl_include and not uses_std_namespace:
4366 errors.append('%s: Includes STL header(s) but does not reference std::'
4367 % f.LocalPath())
4368 if errors:
4369 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4370 return []
4371
4372
[email protected]b00342e7f2013-03-26 16:21:544373def _DidYouMeanOSMacro(bad_macro):
4374 try:
4375 return {'A': 'OS_ANDROID',
4376 'B': 'OS_BSD',
4377 'C': 'OS_CHROMEOS',
4378 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444379 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544380 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444381 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544382 'N': 'OS_NACL',
4383 'O': 'OS_OPENBSD',
4384 'P': 'OS_POSIX',
4385 'S': 'OS_SOLARIS',
4386 'W': 'OS_WIN'}[bad_macro[3].upper()]
4387 except KeyError:
4388 return ''
4389
4390
4391def _CheckForInvalidOSMacrosInFile(input_api, f):
4392 """Check for sensible looking, totally invalid OS macros."""
4393 preprocessor_statement = input_api.re.compile(r'^\s*#')
4394 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4395 results = []
4396 for lnum, line in f.ChangedContents():
4397 if preprocessor_statement.search(line):
4398 for match in os_macro.finditer(line):
4399 if not match.group(1) in _VALID_OS_MACROS:
4400 good = _DidYouMeanOSMacro(match.group(1))
4401 did_you_mean = ' (did you mean %s?)' % good if good else ''
4402 results.append(' %s:%d %s%s' % (f.LocalPath(),
4403 lnum,
4404 match.group(1),
4405 did_you_mean))
4406 return results
4407
4408
Saagar Sanghavifceeaae2020-08-12 16:40:364409def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544410 """Check all affected files for invalid OS macros."""
4411 bad_macros = []
tzik3f295992018-12-04 20:32:234412 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474413 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544414 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4415
4416 if not bad_macros:
4417 return []
4418
4419 return [output_api.PresubmitError(
4420 'Possibly invalid OS macro[s] found. Please fix your code\n'
4421 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4422
lliabraa35bab3932014-10-01 12:16:444423
4424def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4425 """Check all affected files for invalid "if defined" macros."""
4426 ALWAYS_DEFINED_MACROS = (
4427 "TARGET_CPU_PPC",
4428 "TARGET_CPU_PPC64",
4429 "TARGET_CPU_68K",
4430 "TARGET_CPU_X86",
4431 "TARGET_CPU_ARM",
4432 "TARGET_CPU_MIPS",
4433 "TARGET_CPU_SPARC",
4434 "TARGET_CPU_ALPHA",
4435 "TARGET_IPHONE_SIMULATOR",
4436 "TARGET_OS_EMBEDDED",
4437 "TARGET_OS_IPHONE",
4438 "TARGET_OS_MAC",
4439 "TARGET_OS_UNIX",
4440 "TARGET_OS_WIN32",
4441 )
4442 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4443 results = []
4444 for lnum, line in f.ChangedContents():
4445 for match in ifdef_macro.finditer(line):
4446 if match.group(1) in ALWAYS_DEFINED_MACROS:
4447 always_defined = ' %s is always defined. ' % match.group(1)
4448 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4449 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4450 lnum,
4451 always_defined,
4452 did_you_mean))
4453 return results
4454
4455
Saagar Sanghavifceeaae2020-08-12 16:40:364456def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444457 """Check all affected files for invalid "if defined" macros."""
4458 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054459 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444460 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054461 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214462 continue
lliabraa35bab3932014-10-01 12:16:444463 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4464 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4465
4466 if not bad_macros:
4467 return []
4468
4469 return [output_api.PresubmitError(
4470 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4471 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4472 bad_macros)]
4473
4474
Saagar Sanghavifceeaae2020-08-12 16:40:364475def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044476 """Check for same IPC rules described in
4477 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4478 """
4479 base_pattern = r'IPC_ENUM_TRAITS\('
4480 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4481 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4482
4483 problems = []
4484 for f in input_api.AffectedSourceFiles(None):
4485 local_path = f.LocalPath()
4486 if not local_path.endswith('.h'):
4487 continue
4488 for line_number, line in f.ChangedContents():
4489 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4490 problems.append(
4491 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4492
4493 if problems:
4494 return [output_api.PresubmitPromptWarning(
4495 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4496 else:
4497 return []
4498
[email protected]b00342e7f2013-03-26 16:21:544499
Saagar Sanghavifceeaae2020-08-12 16:40:364500def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054501 """Check to make sure no files being submitted have long paths.
4502 This causes issues on Windows.
4503 """
4504 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194505 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054506 local_path = f.LocalPath()
4507 # Windows has a path limit of 260 characters. Limit path length to 200 so
4508 # that we have some extra for the prefix on dev machines and the bots.
4509 if len(local_path) > 200:
4510 problems.append(local_path)
4511
4512 if problems:
4513 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4514 else:
4515 return []
4516
4517
Saagar Sanghavifceeaae2020-08-12 16:40:364518def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144519 """Check that header files have proper guards against multiple inclusion.
4520 If a file should not have such guards (and it probably should) then it
4521 should include the string "no-include-guard-because-multiply-included".
4522 """
Daniel Bratell6a75baef62018-06-04 10:04:454523 def is_chromium_header_file(f):
4524 # We only check header files under the control of the Chromium
4525 # project. That is, those outside third_party apart from
4526 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324527 # We also exclude *_message_generator.h headers as they use
4528 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454529 file_with_path = input_api.os_path.normpath(f.LocalPath())
4530 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324531 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454532 (not file_with_path.startswith('third_party') or
4533 file_with_path.startswith(
4534 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144535
4536 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344537 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144538
4539 errors = []
4540
Daniel Bratell6a75baef62018-06-04 10:04:454541 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144542 guard_name = None
4543 guard_line_number = None
4544 seen_guard_end = False
4545
4546 file_with_path = input_api.os_path.normpath(f.LocalPath())
4547 base_file_name = input_api.os_path.splitext(
4548 input_api.os_path.basename(file_with_path))[0]
4549 upper_base_file_name = base_file_name.upper()
4550
4551 expected_guard = replace_special_with_underscore(
4552 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144553
4554 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574555 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4556 # are too many (1000+) files with slight deviations from the
4557 # coding style. The most important part is that the include guard
4558 # is there, and that it's unique, not the name so this check is
4559 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144560 #
4561 # As code becomes more uniform, this could be made stricter.
4562
4563 guard_name_pattern_list = [
4564 # Anything with the right suffix (maybe with an extra _).
4565 r'\w+_H__?',
4566
Daniel Bratell39b5b062018-05-16 18:09:574567 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144568 r'\w+_h',
4569
4570 # Anything including the uppercase name of the file.
4571 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4572 upper_base_file_name)) + r'\w*',
4573 ]
4574 guard_name_pattern = '|'.join(guard_name_pattern_list)
4575 guard_pattern = input_api.re.compile(
4576 r'#ifndef\s+(' + guard_name_pattern + ')')
4577
4578 for line_number, line in enumerate(f.NewContents()):
4579 if 'no-include-guard-because-multiply-included' in line:
4580 guard_name = 'DUMMY' # To not trigger check outside the loop.
4581 break
4582
4583 if guard_name is None:
4584 match = guard_pattern.match(line)
4585 if match:
4586 guard_name = match.group(1)
4587 guard_line_number = line_number
4588
Daniel Bratell39b5b062018-05-16 18:09:574589 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454590 # don't match the chromium style guide, but new files should
4591 # get it right.
4592 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574593 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144594 errors.append(output_api.PresubmitPromptWarning(
4595 'Header using the wrong include guard name %s' % guard_name,
4596 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574597 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144598 else:
4599 # The line after #ifndef should have a #define of the same name.
4600 if line_number == guard_line_number + 1:
4601 expected_line = '#define %s' % guard_name
4602 if line != expected_line:
4603 errors.append(output_api.PresubmitPromptWarning(
4604 'Missing "%s" for include guard' % expected_line,
4605 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4606 'Expected: %r\nGot: %r' % (expected_line, line)))
4607
4608 if not seen_guard_end and line == '#endif // %s' % guard_name:
4609 seen_guard_end = True
4610 elif seen_guard_end:
4611 if line.strip() != '':
4612 errors.append(output_api.PresubmitPromptWarning(
4613 'Include guard %s not covering the whole file' % (
4614 guard_name), [f.LocalPath()]))
4615 break # Nothing else to check and enough to warn once.
4616
4617 if guard_name is None:
4618 errors.append(output_api.PresubmitPromptWarning(
4619 'Missing include guard %s' % expected_guard,
4620 [f.LocalPath()],
4621 'Missing include guard in %s\n'
4622 'Recommended name: %s\n'
4623 'This check can be disabled by having the string\n'
4624 'no-include-guard-because-multiply-included in the header.' %
4625 (f.LocalPath(), expected_guard)))
4626
4627 return errors
4628
4629
Saagar Sanghavifceeaae2020-08-12 16:40:364630def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234631 """Check source code and known ascii text files for Windows style line
4632 endings.
4633 """
Evan Stade6cfc964c12021-05-18 20:21:164634 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234635
4636 file_inclusion_pattern = (
4637 known_text_files,
Bruce Dawson6141d4a2021-06-08 15:56:114638 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4639 r'.+%s' % _HEADER_EXTENSIONS
mostynbb639aca52015-01-07 20:31:234640 )
4641
mostynbb639aca52015-01-07 20:31:234642 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534643 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444644 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534645 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504646 include_file = False
Bruce Dawsonb2cfdfe2021-06-10 19:01:204647 for line in input_api.ReadFile(f, 'r').splitlines(True):
mostynbb639aca52015-01-07 20:31:234648 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504649 include_file = True
4650 if include_file:
4651 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234652
4653 if problems:
4654 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4655 'these files to contain Windows style line endings?\n' +
4656 '\n'.join(problems))]
4657
4658 return []
4659
Evan Stade6cfc964c12021-05-18 20:21:164660def CheckIconFilesForLicenseHeaders(input_api, output_api):
4661 """Check that .icon files (which are fragments of C++) have license headers.
4662 """
4663
4664 icon_files = (r'.*\.icon$',)
4665
4666 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4667 return input_api.canned_checks.CheckLicense(
4668 input_api, output_api, source_file_filter=icons)
4669
Jose Magana2b456f22021-03-09 23:26:404670def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4671 """Check source code for use of Chrome App technologies being
4672 deprecated.
4673 """
4674
4675 def _CheckForDeprecatedTech(input_api, output_api,
4676 detection_list, files_to_check = None, files_to_skip = None):
4677
4678 if (files_to_check or files_to_skip):
4679 source_file_filter = lambda f: input_api.FilterSourceFile(
4680 f, files_to_check=files_to_check,
4681 files_to_skip=files_to_skip)
4682 else:
4683 source_file_filter = None
4684
4685 problems = []
4686
4687 for f in input_api.AffectedSourceFiles(source_file_filter):
4688 if f.Action() == 'D':
4689 continue
4690 for _, line in f.ChangedContents():
4691 if any( detect in line for detect in detection_list ):
4692 problems.append(f.LocalPath())
4693
4694 return problems
4695
4696 # to avoid this presubmit script triggering warnings
4697 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4698
4699 problems =[]
4700
4701 # NMF: any files with extensions .nmf or NMF
4702 _NMF_FILES = r'\.(nmf|NMF)$'
4703 problems += _CheckForDeprecatedTech(input_api, output_api,
4704 detection_list = [''], # any change to the file will trigger warning
4705 files_to_check = [ r'.+%s' % _NMF_FILES ])
4706
4707 # MANIFEST: any manifest.json that in its diff includes "app":
4708 _MANIFEST_FILES = r'(manifest\.json)$'
4709 problems += _CheckForDeprecatedTech(input_api, output_api,
4710 detection_list = ['"app":'],
4711 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4712
4713 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4714 problems += _CheckForDeprecatedTech(input_api, output_api,
4715 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4716 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4717
4718 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4719 problems += _CheckForDeprecatedTech(input_api, output_api,
4720 detection_list = ['#include "ppapi','#include <ppapi'],
4721 files_to_check = (
4722 r'.+%s' % _HEADER_EXTENSIONS,
4723 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4724 files_to_skip = [r"^ppapi[\\/]"] )
4725
Jose Magana2b456f22021-03-09 23:26:404726 if problems:
4727 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4728 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4729 ' PNaCl, PPAPI). See this blog post for more details:\n'
4730 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4731 'and this documentation for options to replace these technologies:\n'
4732 'https://developer.chrome.com/docs/apps/migration/\n'+
4733 '\n'.join(problems))]
4734
4735 return []
4736
mostynbb639aca52015-01-07 20:31:234737
Saagar Sanghavifceeaae2020-08-12 16:40:364738def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134739 """Checks that all source files use SYSLOG properly."""
4740 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364741 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564742 for line_number, line in f.ChangedContents():
4743 if 'SYSLOG' in line:
4744 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4745
pastarmovj89f7ee12016-09-20 14:58:134746 if syslog_files:
4747 return [output_api.PresubmitPromptWarning(
4748 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4749 ' calls.\nFiles to check:\n', items=syslog_files)]
4750 return []
4751
4752
[email protected]1f7b4172010-01-28 01:17:344753def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364754 if input_api.version < [2, 0, 0]:
4755 return [output_api.PresubmitError("Your depot_tools is out of date. "
4756 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4757 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344758 results = []
scottmg39b29952014-12-08 18:31:284759 results.extend(
jam93a6ee792017-02-08 23:59:224760 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544761 return results
[email protected]ca8d1982009-02-19 16:33:124762
4763
4764def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364765 if input_api.version < [2, 0, 0]:
4766 return [output_api.PresubmitError("Your depot_tools is out of date. "
4767 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4768 "but your version is %d.%d.%d" % tuple(input_api.version))]
4769
[email protected]fe5f57c52009-06-05 14:25:544770 results = []
[email protected]fe5f57c52009-06-05 14:25:544771 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274772 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344773 input_api,
4774 output_api,
[email protected]2fdd1f362013-01-16 03:56:034775 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274776
jam93a6ee792017-02-08 23:59:224777 results.extend(
4778 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544779 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4780 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384781 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4782 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414783 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4784 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544785 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144786
4787
Saagar Sanghavifceeaae2020-08-12 16:40:364788def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264789 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024790 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4791 # footer is set to true.
4792 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264793 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024794 footer.lower()
4795 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264796 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024797
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144798 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264799 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144800 import sys
4801 from io import StringIO
4802
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144803 new_or_added_paths = set(f.LocalPath()
4804 for f in input_api.AffectedFiles()
4805 if (f.Action() == 'A' or f.Action() == 'M'))
4806 removed_paths = set(f.LocalPath()
4807 for f in input_api.AffectedFiles(include_deletes=True)
4808 if f.Action() == 'D')
4809
Andrew Grieve0e8790c2020-09-03 17:27:324810 affected_grds = [
4811 f for f in input_api.AffectedFiles()
4812 if f.LocalPath().endswith(('.grd', '.grdp'))
4813 ]
4814 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164815 if not affected_grds:
4816 return []
4817
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144818 affected_png_paths = [f.AbsoluteLocalPath()
4819 for f in input_api.AffectedFiles()
4820 if (f.LocalPath().endswith('.png'))]
4821
4822 # Check for screenshots. Developers can upload screenshots using
4823 # tools/translation/upload_screenshots.py which finds and uploads
4824 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4825 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4826 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4827 #
4828 # The logic here is as follows:
4829 #
4830 # - If the CL has a .png file under the screenshots directory for a grd
4831 # file, warn the developer. Actual images should never be checked into the
4832 # Chrome repo.
4833 #
4834 # - If the CL contains modified or new messages in grd files and doesn't
4835 # contain the corresponding .sha1 files, warn the developer to add images
4836 # and upload them via tools/translation/upload_screenshots.py.
4837 #
4838 # - If the CL contains modified or new messages in grd files and the
4839 # corresponding .sha1 files, everything looks good.
4840 #
4841 # - If the CL contains removed messages in grd files but the corresponding
4842 # .sha1 files aren't removed, warn the developer to remove them.
4843 unnecessary_screenshots = []
4844 missing_sha1 = []
4845 unnecessary_sha1_files = []
4846
Rainhard Findlingfc31844c52020-05-15 09:58:264847 # This checks verifies that the ICU syntax of messages this CL touched is
4848 # valid, and reports any found syntax errors.
4849 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4850 # without developers being aware of them. Later on, such ICU syntax errors
4851 # break message extraction for translation, hence would block Chromium
4852 # translations until they are fixed.
4853 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144854
4855 def _CheckScreenshotAdded(screenshots_dir, message_id):
4856 sha1_path = input_api.os_path.join(
4857 screenshots_dir, message_id + '.png.sha1')
4858 if sha1_path not in new_or_added_paths:
4859 missing_sha1.append(sha1_path)
4860
4861
4862 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4863 sha1_path = input_api.os_path.join(
4864 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034865 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144866 unnecessary_sha1_files.append(sha1_path)
4867
Rainhard Findlingfc31844c52020-05-15 09:58:264868
4869 def _ValidateIcuSyntax(text, level, signatures):
Daniel Chengab582892021-09-30 20:53:194870 """Validates ICU syntax of a text string.
Rainhard Findlingfc31844c52020-05-15 09:58:264871
4872 Check if text looks similar to ICU and checks for ICU syntax correctness
4873 in this case. Reports various issues with ICU syntax and values of
4874 variants. Supports checking of nested messages. Accumulate information of
4875 each ICU messages found in the text for further checking.
4876
4877 Args:
4878 text: a string to check.
4879 level: a number of current nesting level.
4880 signatures: an accumulator, a list of tuple of (level, variable,
4881 kind, variants).
4882
4883 Returns:
4884 None if a string is not ICU or no issue detected.
4885 A tuple of (message, start index, end index) if an issue detected.
4886 """
Daniel Chengab582892021-09-30 20:53:194887 valid_types = {
4888 'plural': (frozenset(
4889 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4890 frozenset(['=1', 'other'])),
4891 'selectordinal': (frozenset(
4892 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4893 frozenset(['one', 'other'])),
4894 'select': (frozenset(), frozenset(['other'])),
4895 }
Rainhard Findlingfc31844c52020-05-15 09:58:264896
Daniel Chengab582892021-09-30 20:53:194897 # Check if the message looks like an attempt to use ICU
4898 # plural. If yes - check if its syntax strictly matches ICU format.
4899 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4900 if not like:
4901 signatures.append((level, None, None, None))
4902 return
Rainhard Findlingfc31844c52020-05-15 09:58:264903
Daniel Chengab582892021-09-30 20:53:194904 # Check for valid prefix and suffix
4905 m = re.match(
4906 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4907 r'(plural|selectordinal|select),\s*'
4908 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4909 if not m:
4910 return (('This message looks like an ICU plural, '
4911 'but does not follow ICU syntax.'), like.start(), like.end())
4912 starting, variable, kind, variant_pairs = m.groups()
4913 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4914 if depth:
4915 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4916 len(text))
4917 first = text[0]
4918 ending = text[last_pos:]
4919 if not starting:
4920 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4921 last_pos)
4922 if not ending or '}' not in ending:
4923 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4924 last_pos)
4925 elif first != '{':
4926 return (
4927 ('Invalid ICU format. Extra characters at the start of a complex '
4928 'message (go/icu-message-migration): "%s"') %
4929 starting, 0, len(starting))
4930 elif ending != '}':
4931 return (('Invalid ICU format. Extra characters at the end of a complex '
4932 'message (go/icu-message-migration): "%s"')
4933 % ending, last_pos - 1, len(text) - 1)
4934 if kind not in valid_types:
4935 return (('Unknown ICU message type %s. '
4936 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4937 known, required = valid_types[kind]
4938 defined_variants = set()
4939 for variant, variant_range, value, value_range in variants:
4940 start, end = variant_range
4941 if variant in defined_variants:
4942 return ('Variant "%s" is defined more than once' % variant,
4943 start, end)
4944 elif known and variant not in known:
4945 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4946 start, end)
4947 defined_variants.add(variant)
4948 # Check for nested structure
4949 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4950 if res:
4951 return (res[0], res[1] + value_range[0] + 1,
4952 res[2] + value_range[0] + 1)
4953 missing = required - defined_variants
4954 if missing:
4955 return ('Required variants missing: %s' % ', '.join(missing), 0,
4956 len(text))
4957 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:264958
4959
4960 def _ParseIcuVariants(text, offset=0):
4961 """Parse variants part of ICU complex message.
4962
4963 Builds a tuple of variant names and values, as well as
4964 their offsets in the input string.
4965
4966 Args:
4967 text: a string to parse
4968 offset: additional offset to add to positions in the text to get correct
4969 position in the complete ICU string.
4970
4971 Returns:
4972 List of tuples, each tuple consist of four fields: variant name,
4973 variant name span (tuple of two integers), variant value, value
4974 span (tuple of two integers).
4975 """
4976 depth, start, end = 0, -1, -1
4977 variants = []
4978 key = None
4979 for idx, char in enumerate(text):
4980 if char == '{':
4981 if not depth:
4982 start = idx
4983 chunk = text[end + 1:start]
4984 key = chunk.strip()
4985 pos = offset + end + 1 + chunk.find(key)
4986 span = (pos, pos + len(key))
4987 depth += 1
4988 elif char == '}':
4989 if not depth:
4990 return variants, depth, offset + idx
4991 depth -= 1
4992 if not depth:
4993 end = idx
4994 variants.append((key, span, text[start:end + 1], (offset + start,
4995 offset + end + 1)))
4996 return variants, depth, offset + end + 1
4997
meacer8c0d3832019-12-26 21:46:164998 try:
4999 old_sys_path = sys.path
5000 sys.path = sys.path + [input_api.os_path.join(
5001 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5002 from helper import grd_helper
5003 finally:
5004 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145005
5006 for f in affected_grds:
5007 file_path = f.LocalPath()
5008 old_id_to_msg_map = {}
5009 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385010 # Note that this code doesn't check if the file has been deleted. This is
5011 # OK because it only uses the old and new file contents and doesn't load
5012 # the file via its path.
5013 # It's also possible that a file's content refers to a renamed or deleted
5014 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5015 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5016 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145017 if file_path.endswith('.grdp'):
5018 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585019 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595020 '\n'.join(f.OldContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145021 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585022 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595023 '\n'.join(f.NewContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145024 else:
meacerff8a9b62019-12-10 19:43:585025 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145026 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585027 old_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595028 StringIO('\n'.join(f.OldContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145029 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585030 new_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595031 StringIO('\n'.join(f.NewContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145032
Rainhard Findlingd8d04372020-08-13 13:30:095033 grd_name, ext = input_api.os_path.splitext(
5034 input_api.os_path.basename(file_path))
5035 screenshots_dir = input_api.os_path.join(
5036 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5037
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145038 # Compute added, removed and modified message IDs.
5039 old_ids = set(old_id_to_msg_map)
5040 new_ids = set(new_id_to_msg_map)
5041 added_ids = new_ids - old_ids
5042 removed_ids = old_ids - new_ids
5043 modified_ids = set([])
5044 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355045 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095046 != new_id_to_msg_map[key].ContentsAsXml('', True)):
Daniel Chengab582892021-09-30 20:53:195047 # The message content itself changed. Require an updated screenshot.
5048 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355049 elif old_id_to_msg_map[key].attrs['meaning'] != \
5050 new_id_to_msg_map[key].attrs['meaning']:
5051 # The message meaning changed. Ensure there is a screenshot for it.
5052 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5053 if sha1_path not in new_or_added_paths and not \
5054 input_api.os_path.exists(sha1_path):
5055 # There is neither a previous screenshot nor is a new one added now.
5056 # Require a screenshot.
5057 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145058
Rainhard Findlingfc31844c52020-05-15 09:58:265059 if run_screenshot_check:
5060 # Check the screenshot directory for .png files. Warn if there is any.
5061 for png_path in affected_png_paths:
5062 if png_path.startswith(screenshots_dir):
5063 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145064
Rainhard Findlingfc31844c52020-05-15 09:58:265065 for added_id in added_ids:
5066 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145067
Rainhard Findlingfc31844c52020-05-15 09:58:265068 for modified_id in modified_ids:
5069 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145070
Rainhard Findlingfc31844c52020-05-15 09:58:265071 for removed_id in removed_ids:
5072 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5073
5074 # Check new and changed strings for ICU syntax errors.
5075 for key in added_ids.union(modified_ids):
5076 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5077 err = _ValidateIcuSyntax(msg, 0, [])
5078 if err is not None:
5079 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145080
5081 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265082 if run_screenshot_check:
5083 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005084 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265085 'Do not include actual screenshots in the changelist. Run '
5086 'tools/translate/upload_screenshots.py to upload them instead:',
5087 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145088
Rainhard Findlingfc31844c52020-05-15 09:58:265089 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005090 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265091 'You are adding or modifying UI strings.\n'
5092 'To ensure the best translations, take screenshots of the relevant UI '
5093 '(https://g.co/chrome/translation) and add these files to your '
5094 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145095
Rainhard Findlingfc31844c52020-05-15 09:58:265096 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005097 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265098 'You removed strings associated with these files. Remove:',
5099 sorted(unnecessary_sha1_files)))
5100 else:
5101 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5102 'screenshots check.'))
5103
5104 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075105 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265106 'ICU syntax errors were found in the following strings (problems or '
5107 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145108
5109 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125110
5111
Saagar Sanghavifceeaae2020-08-12 16:40:365112def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125113 repo_root=None,
5114 translation_expectations_path=None,
5115 grd_files=None):
5116 import sys
5117 affected_grds = [f for f in input_api.AffectedFiles()
5118 if (f.LocalPath().endswith('.grd') or
5119 f.LocalPath().endswith('.grdp'))]
5120 if not affected_grds:
5121 return []
5122
5123 try:
5124 old_sys_path = sys.path
5125 sys.path = sys.path + [
5126 input_api.os_path.join(
5127 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5128 from helper import git_helper
5129 from helper import translation_helper
5130 finally:
5131 sys.path = old_sys_path
5132
5133 # Check that translation expectations can be parsed and we can get a list of
5134 # translatable grd files. |repo_root| and |translation_expectations_path| are
5135 # only passed by tests.
5136 if not repo_root:
5137 repo_root = input_api.PresubmitLocalPath()
5138 if not translation_expectations_path:
5139 translation_expectations_path = input_api.os_path.join(
5140 repo_root, 'tools', 'gritsettings',
5141 'translation_expectations.pyl')
5142 if not grd_files:
5143 grd_files = git_helper.list_grds_in_repository(repo_root)
5144
dpapad8e21b472020-10-23 17:15:035145 # Ignore bogus grd files used only for testing
5146 # ui/webui/resoucres/tools/generate_grd.py.
5147 ignore_path = input_api.os_path.join(
5148 'ui', 'webui', 'resources', 'tools', 'tests')
Dirk Prankee3c9c62d2021-05-18 18:35:595149 grd_files = [p for p in grd_files if ignore_path not in p]
dpapad8e21b472020-10-23 17:15:035150
Mustafa Emre Acer51f2f742020-03-09 19:41:125151 try:
5152 translation_helper.get_translatable_grds(repo_root, grd_files,
5153 translation_expectations_path)
5154 except Exception as e:
5155 return [output_api.PresubmitNotifyResult(
5156 'Failed to get a list of translatable grd files. This happens when:\n'
5157 ' - One of the modified grd or grdp files cannot be parsed or\n'
5158 ' - %s is not updated.\n'
5159 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5160 return []
Ken Rockotc31f4832020-05-29 18:58:515161
5162
Saagar Sanghavifceeaae2020-08-12 16:40:365163def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515164 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095165 changed_mojoms = input_api.AffectedFiles(
5166 include_deletes=True,
5167 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515168 delta = []
5169 for mojom in changed_mojoms:
5170 old_contents = ''.join(mojom.OldContents()) or None
5171 new_contents = ''.join(mojom.NewContents()) or None
5172 delta.append({
5173 'filename': mojom.LocalPath(),
5174 'old': '\n'.join(mojom.OldContents()) or None,
5175 'new': '\n'.join(mojom.NewContents()) or None,
5176 })
5177
5178 process = input_api.subprocess.Popen(
5179 [input_api.python_executable,
5180 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5181 'public', 'tools', 'mojom',
5182 'check_stable_mojom_compatibility.py'),
5183 '--src-root', input_api.PresubmitLocalPath()],
5184 stdin=input_api.subprocess.PIPE,
5185 stdout=input_api.subprocess.PIPE,
5186 stderr=input_api.subprocess.PIPE,
5187 universal_newlines=True)
5188 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5189 if process.returncode:
5190 return [output_api.PresubmitError(
5191 'One or more [Stable] mojom definitions appears to have been changed '
5192 'in a way that is not backward-compatible.',
5193 long_text=error)]
5194 return []
Dominic Battre645d42342020-12-04 16:14:105195
5196def CheckDeprecationOfPreferences(input_api, output_api):
5197 """Removing a preference should come with a deprecation."""
5198
5199 def FilterFile(affected_file):
5200 """Accept only .cc files and the like."""
5201 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5202 files_to_skip = (_EXCLUDED_PATHS +
5203 _TEST_CODE_EXCLUDED_PATHS +
5204 input_api.DEFAULT_FILES_TO_SKIP)
5205 return input_api.FilterSourceFile(
5206 affected_file,
5207 files_to_check=file_inclusion_pattern,
5208 files_to_skip=files_to_skip)
5209
5210 def ModifiedLines(affected_file):
5211 """Returns a list of tuples (line number, line text) of added and removed
5212 lines.
5213
5214 Deleted lines share the same line number as the previous line.
5215
5216 This relies on the scm diff output describing each changed code section
5217 with a line of the form
5218
5219 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5220 """
5221 line_num = 0
5222 modified_lines = []
5223 for line in affected_file.GenerateScmDiff().splitlines():
5224 # Extract <new line num> of the patch fragment (see format above).
5225 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5226 if m:
5227 line_num = int(m.groups(1)[0])
5228 continue
5229 if ((line.startswith('+') and not line.startswith('++')) or
5230 (line.startswith('-') and not line.startswith('--'))):
5231 modified_lines.append((line_num, line))
5232
5233 if not line.startswith('-'):
5234 line_num += 1
5235 return modified_lines
5236
5237 def FindLineWith(lines, needle):
5238 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5239
5240 If 0 or >1 lines contain `needle`, -1 is returned.
5241 """
5242 matching_line_numbers = [
5243 # + 1 for 1-based counting of line numbers.
5244 i + 1 for i, line
5245 in enumerate(lines)
5246 if needle in line]
5247 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5248
5249 def ModifiedPrefMigration(affected_file):
5250 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5251 # Determine first and last lines of MigrateObsolete.*Pref functions.
5252 new_contents = affected_file.NewContents();
5253 range_1 = (
5254 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5255 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5256 range_2 = (
5257 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5258 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5259 if (-1 in range_1 + range_2):
5260 raise Exception(
5261 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5262
5263 # Check whether any of the modified lines are part of the
5264 # MigrateObsolete.*Pref functions.
5265 for line_nr, line in ModifiedLines(affected_file):
5266 if (range_1[0] <= line_nr <= range_1[1] or
5267 range_2[0] <= line_nr <= range_2[1]):
5268 return True
5269 return False
5270
5271 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5272 browser_prefs_file_pattern = input_api.re.compile(
5273 r'chrome/browser/prefs/browser_prefs.cc')
5274
5275 changes = input_api.AffectedFiles(include_deletes=True,
5276 file_filter=FilterFile)
5277 potential_problems = []
5278 for f in changes:
5279 for line in f.GenerateScmDiff().splitlines():
5280 # Check deleted lines for pref registrations.
5281 if (line.startswith('-') and not line.startswith('--') and
5282 register_pref_pattern.search(line)):
5283 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5284
5285 if browser_prefs_file_pattern.search(f.LocalPath()):
5286 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5287 # assume that they knew that they have to deprecate preferences and don't
5288 # warn.
5289 try:
5290 if ModifiedPrefMigration(f):
5291 return []
5292 except Exception as e:
5293 return [output_api.PresubmitError(str(e))]
5294
5295 if potential_problems:
5296 return [output_api.PresubmitPromptWarning(
5297 'Discovered possible removal of preference registrations.\n\n'
5298 'Please make sure to properly deprecate preferences by clearing their\n'
5299 'value for a couple of milestones before finally removing the code.\n'
5300 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195301 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5302 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105303 'This may be a false positive warning (e.g. if you move preference\n'
5304 'registrations to a different place).\n',
5305 potential_problems
5306 )]
5307 return []
Matt Stark6ef08872021-07-29 01:21:465308
5309def CheckConsistentGrdChanges(input_api, output_api):
5310 """Changes to GRD files must be consistent for tools to read them."""
5311 changed_grds = input_api.AffectedFiles(
5312 include_deletes=False,
5313 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5314 errors = []
Daniel Chengab582892021-09-30 20:53:195315 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5316 for matcher, msg in _INVALID_GRD_FILE_LINE]
Matt Stark6ef08872021-07-29 01:21:465317 for grd in changed_grds:
5318 for i, line in enumerate(grd.NewContents()):
5319 for matcher, msg in invalid_file_regexes:
5320 if matcher.search(line):
Daniel Chengab582892021-09-30 20:53:195321 errors.append(
5322 output_api.PresubmitError('Problem on {grd}:{i} - {msg}'.format(
5323 grd=grd.LocalPath(), i=i + 1, msg=msg)))
Matt Stark6ef08872021-07-29 01:21:465324 return errors