blob: 5d14416cf001ea49e9b2d9ef27d7f8617294135f [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',
481 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
482 '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 ),
Lei Zhang1ddeadb2021-05-20 22:14:34975 (
976 r'/DISALLOW_(COPY|ASSIGN|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS)\(',
977 (
978 'DISALLOW_xxx macros are deprecated. See base/macros.h for details.',
979 ),
980 False,
981 (),
982 ),
[email protected]127f18ec2012-06-16 05:05:59983)
984
Mario Sanchez Prada2472cab2019-09-18 10:58:31985# Format: Sequence of tuples containing:
986# * String pattern or, if starting with a slash, a regular expression.
987# * Sequence of strings to show when the pattern matches.
988_DEPRECATED_MOJO_TYPES = (
989 (
Mario Sanchez Prada2472cab2019-09-18 10:58:31990 r'/\bmojo::AssociatedInterfacePtrInfo\b',
991 (
992 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
993 'Use mojo::PendingAssociatedRemote<Interface> instead.',
994 ),
995 ),
996 (
997 r'/\bmojo::AssociatedInterfaceRequest\b',
998 (
999 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1000 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1001 ),
1002 ),
1003 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311004 r'/\bmojo::InterfacePtr\b',
1005 (
1006 'mojo::InterfacePtr<Interface> is deprecated.',
1007 'Use mojo::Remote<Interface> instead.',
1008 ),
1009 ),
1010 (
1011 r'/\bmojo::InterfacePtrInfo\b',
1012 (
1013 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1014 'Use mojo::PendingRemote<Interface> instead.',
1015 ),
1016 ),
1017 (
1018 r'/\bmojo::InterfaceRequest\b',
1019 (
1020 'mojo::InterfaceRequest<Interface> is deprecated.',
1021 'Use mojo::PendingReceiver<Interface> instead.',
1022 ),
1023 ),
1024 (
1025 r'/\bmojo::MakeRequest\b',
1026 (
1027 'mojo::MakeRequest is deprecated.',
1028 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1029 ),
1030 ),
Mario Sanchez Prada2472cab2019-09-18 10:58:311031)
wnwenbdc444e2016-05-25 13:44:151032
mlamouria82272622014-09-16 18:45:041033_IPC_ENUM_TRAITS_DEPRECATED = (
1034 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501035 'See http://www.chromium.org/Home/chromium-security/education/'
1036 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041037
Stephen Martinis97a394142018-06-07 23:06:051038_LONG_PATH_ERROR = (
1039 'Some files included in this CL have file names that are too long (> 200'
1040 ' characters). If committed, these files will cause issues on Windows. See'
1041 ' https://crbug.com/612667 for more details.'
1042)
1043
Shenghua Zhangbfaa38b82017-11-16 21:58:021044_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041045 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041046 r".*[\\/]BuildHooksAndroidImpl\.java",
1047 r".*[\\/]LicenseContentProvider\.java",
1048 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281049 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021050]
[email protected]127f18ec2012-06-16 05:05:591051
Mohamed Heikald048240a2019-11-12 16:57:371052# List of image extensions that are used as resources in chromium.
1053_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1054
Sean Kau46e29bc2017-08-28 16:31:161055# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401056_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041057 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401058 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041059 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1060 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041061 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431062 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161063]
1064
1065
[email protected]b00342e7f2013-03-26 16:21:541066_VALID_OS_MACROS = (
1067 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081068 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541069 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441070 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121071 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541072 'OS_BSD',
1073 'OS_CAT', # For testing.
1074 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041075 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541076 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371077 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541078 'OS_IOS',
1079 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441080 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541081 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211082 'OS_NACL_NONSFI',
1083 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121084 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541085 'OS_OPENBSD',
1086 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371087 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541088 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541089 'OS_WIN',
1090)
1091
1092
Andrew Grieveb773bad2020-06-05 18:00:381093# These are not checked on the public chromium-presubmit trybot.
1094# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041095# checkouts.
agrievef32bcc72016-04-04 14:57:401096_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381097 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381098]
1099
1100
1101_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041102 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361103 'base/android/jni_generator/jni_generator.pydeps',
1104 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361105 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041106 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361107 'build/android/gyp/aar.pydeps',
1108 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271109 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361110 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381111 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361112 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021113 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221114 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111115 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361116 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361117 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361118 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111119 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041120 'build/android/gyp/create_app_bundle_apks.pydeps',
1121 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361122 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121123 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091124 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221125 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001126 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361127 'build/android/gyp/desugar.pydeps',
1128 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421129 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041130 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361131 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361132 'build/android/gyp/filter_zip.pydeps',
1133 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361134 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361135 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581136 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361137 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141138 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261139 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471140 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011141 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041142 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361143 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361144 'build/android/gyp/merge_manifest.pydeps',
1145 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221146 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361147 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461148 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301149 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241150 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361151 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461152 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561153 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361154 'build/android/incremental_install/generate_android_manifest.pydeps',
1155 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041156 'build/android/resource_sizes.pydeps',
1157 'build/android/test_runner.pydeps',
1158 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361159 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361160 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321161 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271162 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1163 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041164 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001165 'components/cronet/tools/generate_javadoc.pydeps',
1166 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381167 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001168 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381169 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041170 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181171 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041172 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421173 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1174 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131175 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501176 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061177 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221178 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401179]
1180
wnwenbdc444e2016-05-25 13:44:151181
agrievef32bcc72016-04-04 14:57:401182_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1183
1184
Eric Boren6fd2b932018-01-25 15:05:081185# Bypass the AUTHORS check for these accounts.
1186_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591187 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451188 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591189 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521190 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231191 'wpt-autoroller', 'chrome-weblayer-builder',
1192 'lacros-version-skew-roller', 'skylab-test-cros-roller')
Eric Boren835d71f2018-09-07 21:09:041193 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271194 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041195 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161196 for s in ('chromium-internal-autoroll',)
1197 ) | set('%[email protected]' % s
1198 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081199
Matt Stark6ef08872021-07-29 01:21:461200_INVALID_GRD_FILE_LINE = [
1201 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1202]
Eric Boren6fd2b932018-01-25 15:05:081203
Daniel Bratell65b033262019-04-23 08:17:061204def _IsCPlusPlusFile(input_api, file_path):
1205 """Returns True if this file contains C++-like code (and not Python,
1206 Go, Java, MarkDown, ...)"""
1207
1208 ext = input_api.os_path.splitext(file_path)[1]
1209 # This list is compatible with CppChecker.IsCppFile but we should
1210 # consider adding ".c" to it. If we do that we can use this function
1211 # at more places in the code.
1212 return ext in (
1213 '.h',
1214 '.cc',
1215 '.cpp',
1216 '.m',
1217 '.mm',
1218 )
1219
1220def _IsCPlusPlusHeaderFile(input_api, file_path):
1221 return input_api.os_path.splitext(file_path)[1] == ".h"
1222
1223
1224def _IsJavaFile(input_api, file_path):
1225 return input_api.os_path.splitext(file_path)[1] == ".java"
1226
1227
1228def _IsProtoFile(input_api, file_path):
1229 return input_api.os_path.splitext(file_path)[1] == ".proto"
1230
Mohamed Heikal5e5b7922020-10-29 18:57:591231
1232def CheckNoUpstreamDepsOnClank(input_api, output_api):
1233 """Prevent additions of dependencies from the upstream repo on //clank."""
1234 # clank can depend on clank
1235 if input_api.change.RepositoryRoot().endswith('clank'):
1236 return []
1237 build_file_patterns = [
1238 r'(.+/)?BUILD\.gn',
1239 r'.+\.gni',
1240 ]
1241 excluded_files = [
1242 r'build[/\\]config[/\\]android[/\\]config\.gni'
1243 ]
1244 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1245
1246 error_message = 'Disallowed import on //clank in an upstream build file:'
1247
1248 def FilterFile(affected_file):
1249 return input_api.FilterSourceFile(
1250 affected_file,
1251 files_to_check=build_file_patterns,
1252 files_to_skip=excluded_files)
1253
1254 problems = []
1255 for f in input_api.AffectedSourceFiles(FilterFile):
1256 local_path = f.LocalPath()
1257 for line_number, line in f.ChangedContents():
1258 if (bad_pattern.search(line)):
1259 problems.append(
1260 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1261 if problems:
1262 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1263 else:
1264 return []
1265
1266
Saagar Sanghavifceeaae2020-08-12 16:40:361267def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191268 """Attempts to prevent use of functions intended only for testing in
1269 non-testing code. For now this is just a best-effort implementation
1270 that ignores header files and may have some false positives. A
1271 better implementation would probably need a proper C++ parser.
1272 """
1273 # We only scan .cc files and the like, as the declaration of
1274 # for-testing functions in header files are hard to distinguish from
1275 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491276 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191277
jochenc0d4808c2015-07-27 09:25:421278 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191279 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091280 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131281 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191282 exclusion_pattern = input_api.re.compile(
1283 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1284 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131285 # Avoid a false positive in this case, where the method name, the ::, and
1286 # the closing { are all on different lines due to line wrapping.
1287 # HelperClassForTesting::
1288 # HelperClassForTesting(
1289 # args)
1290 # : member(0) {}
1291 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191292
1293 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441294 files_to_skip = (_EXCLUDED_PATHS +
1295 _TEST_CODE_EXCLUDED_PATHS +
1296 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191297 return input_api.FilterSourceFile(
1298 affected_file,
James Cook24a504192020-07-23 00:08:441299 files_to_check=file_inclusion_pattern,
1300 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191301
1302 problems = []
1303 for f in input_api.AffectedSourceFiles(FilterFile):
1304 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131305 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241306 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031307 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461308 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131309 not exclusion_pattern.search(line) and
1310 not allowlist_pattern.search(line) and
1311 not in_method_defn):
[email protected]55459852011-08-10 15:17:191312 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031313 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131314 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191315
1316 if problems:
[email protected]f7051d52013-04-02 18:31:421317 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031318 else:
1319 return []
[email protected]55459852011-08-10 15:17:191320
1321
Saagar Sanghavifceeaae2020-08-12 16:40:361322def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231323 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591324 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231325 """
1326 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1327 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1328 name_pattern = r'ForTest(s|ing)?'
1329 # Describes an occurrence of "ForTest*" inside a // comment.
1330 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501331 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551332 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231333 # Catch calls.
1334 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1335 # Ignore definitions. (Comments are ignored separately.)
1336 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1337
1338 problems = []
1339 sources = lambda x: input_api.FilterSourceFile(
1340 x,
James Cook24a504192020-07-23 00:08:441341 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1342 + input_api.DEFAULT_FILES_TO_SKIP),
1343 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231344 )
1345 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1346 local_path = f.LocalPath()
1347 is_inside_javadoc = False
1348 for line_number, line in f.ChangedContents():
1349 if is_inside_javadoc and javadoc_end_re.search(line):
1350 is_inside_javadoc = False
1351 if not is_inside_javadoc and javadoc_start_re.search(line):
1352 is_inside_javadoc = True
1353 if is_inside_javadoc:
1354 continue
1355 if (inclusion_re.search(line) and
1356 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501357 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231358 not exclusion_re.search(line)):
1359 problems.append(
1360 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1361
1362 if problems:
1363 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1364 else:
1365 return []
1366
1367
Saagar Sanghavifceeaae2020-08-12 16:40:361368def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541369 """Checks to make sure no .h files include <iostream>."""
1370 files = []
1371 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1372 input_api.re.MULTILINE)
1373 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1374 if not f.LocalPath().endswith('.h'):
1375 continue
1376 contents = input_api.ReadFile(f)
1377 if pattern.search(contents):
1378 files.append(f)
1379
1380 if len(files):
yolandyandaabc6d2016-04-18 18:29:391381 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061382 'Do not #include <iostream> in header files, since it inserts static '
1383 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541384 '#include <ostream>. See http://crbug.com/94794',
1385 files) ]
1386 return []
1387
Danil Chapovalov3518f362018-08-11 16:13:431388def _CheckNoStrCatRedefines(input_api, output_api):
1389 """Checks no windows headers with StrCat redefined are included directly."""
1390 files = []
1391 pattern_deny = input_api.re.compile(
1392 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1393 input_api.re.MULTILINE)
1394 pattern_allow = input_api.re.compile(
1395 r'^#include\s"base/win/windows_defines.inc"',
1396 input_api.re.MULTILINE)
1397 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1398 contents = input_api.ReadFile(f)
1399 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1400 files.append(f.LocalPath())
1401
1402 if len(files):
1403 return [output_api.PresubmitError(
1404 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1405 'directly since they pollute code with StrCat macro. Instead, '
1406 'include matching header from base/win. See http://crbug.com/856536',
1407 files) ]
1408 return []
1409
[email protected]10689ca2011-09-02 02:31:541410
Saagar Sanghavifceeaae2020-08-12 16:40:361411def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521412 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181413 problems = []
1414 for f in input_api.AffectedFiles():
1415 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1416 continue
1417
1418 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041419 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181420 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1421
1422 if not problems:
1423 return []
1424 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1425 '\n'.join(problems))]
1426
Saagar Sanghavifceeaae2020-08-12 16:40:361427def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341428 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1429
1430 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1431 instead of DISABLED_. To filter false positives, reports are only generated
1432 if a corresponding MAYBE_ line exists.
1433 """
1434 problems = []
1435
1436 # The following two patterns are looked for in tandem - is a test labeled
1437 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1438 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1439 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1440
1441 # This is for the case that a test is disabled on all platforms.
1442 full_disable_pattern = input_api.re.compile(
1443 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1444 input_api.re.MULTILINE)
1445
Katie Df13948e2018-09-25 07:33:441446 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341447 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1448 continue
1449
1450 # Search for MABYE_, DISABLE_ pairs.
1451 disable_lines = {} # Maps of test name to line number.
1452 maybe_lines = {}
1453 for line_num, line in f.ChangedContents():
1454 disable_match = disable_pattern.search(line)
1455 if disable_match:
1456 disable_lines[disable_match.group(1)] = line_num
1457 maybe_match = maybe_pattern.search(line)
1458 if maybe_match:
1459 maybe_lines[maybe_match.group(1)] = line_num
1460
1461 # Search for DISABLE_ occurrences within a TEST() macro.
1462 disable_tests = set(disable_lines.keys())
1463 maybe_tests = set(maybe_lines.keys())
1464 for test in disable_tests.intersection(maybe_tests):
1465 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1466
1467 contents = input_api.ReadFile(f)
1468 full_disable_match = full_disable_pattern.search(contents)
1469 if full_disable_match:
1470 problems.append(' %s' % f.LocalPath())
1471
1472 if not problems:
1473 return []
1474 return [
1475 output_api.PresubmitPromptWarning(
1476 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1477 '\n'.join(problems))
1478 ]
1479
Nina Satragnof7660532021-09-20 18:03:351480def CheckForgettingMAYBEInTests(input_api, output_api):
1481 """Checks to make sure tests disabled conditionally are not missing a
1482 corresponding MAYBE_ prefix.
1483 """
1484 # Expect at least a lowercase character in the test name. This helps rule out
1485 # false positives with macros wrapping the actual tests name.
1486 define_maybe_pattern = input_api.re.compile(
1487 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
1488 test_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*\w+,\s*MAYBE_{test_name}\)'
1489 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1490 warnings = []
1491
1492 # Read the entire files. We can't just read the affected lines, forgetting to
1493 # add MAYBE_ on a change would not show up otherwise.
1494 for f in input_api.AffectedFiles(False):
1495 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1496 continue
1497 contents = input_api.ReadFile(f)
1498 lines = contents.splitlines(True)
1499 current_position = 0
1500 warning_test_names = set()
1501 for line_num, line in enumerate(lines, start=1):
1502 current_position += len(line)
1503 maybe_match = define_maybe_pattern.search(line)
1504 if maybe_match:
1505 test_name = maybe_match.group('test_name')
1506 # Do not warn twice for the same test.
1507 if (test_name in warning_test_names):
1508 continue
1509 warning_test_names.add(test_name)
1510
1511 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1512 # the current position.
1513 test_match = input_api.re.compile(
1514 test_maybe_pattern.format(test_name=test_name),
1515 input_api.re.MULTILINE).search(contents, current_position)
1516 suite_match = input_api.re.compile(
1517 suite_maybe_pattern.format(test_name=test_name),
1518 input_api.re.MULTILINE).search(contents, current_position)
1519 if not test_match and not suite_match:
1520 warnings.append(
1521 output_api.PresubmitPromptWarning(
1522 '%s:%d found MAYBE_ defined without corresponding test %s' %
1523 (f.LocalPath(), line_num, test_name)))
1524 return warnings
[email protected]72df4e782012-06-21 16:28:181525
Saagar Sanghavifceeaae2020-08-12 16:40:361526def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571527 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521528 errors = []
Hans Wennborg944479f2020-06-25 21:39:251529 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521530 input_api.re.MULTILINE)
1531 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1532 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1533 continue
1534 for lnum, line in f.ChangedContents():
1535 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171536 errors.append(output_api.PresubmitError(
1537 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571538 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171539 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521540 return errors
1541
1542
Weilun Shia487fad2020-10-28 00:10:341543# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1544# more reliable way. See
1545# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191546
wnwenbdc444e2016-05-25 13:44:151547
Saagar Sanghavifceeaae2020-08-12 16:40:361548def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391549 """Check that FlakyTest annotation is our own instead of the android one"""
1550 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1551 files = []
1552 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1553 if f.LocalPath().endswith('Test.java'):
1554 if pattern.search(input_api.ReadFile(f)):
1555 files.append(f)
1556 if len(files):
1557 return [output_api.PresubmitError(
1558 'Use org.chromium.base.test.util.FlakyTest instead of '
1559 'android.test.FlakyTest',
1560 files)]
1561 return []
mcasasb7440c282015-02-04 14:52:191562
wnwenbdc444e2016-05-25 13:44:151563
Saagar Sanghavifceeaae2020-08-12 16:40:361564def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441565 """Make sure .DEPS.git is never modified manually."""
1566 if any(f.LocalPath().endswith('.DEPS.git') for f in
1567 input_api.AffectedFiles()):
1568 return [output_api.PresubmitError(
1569 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1570 'automated system based on what\'s in DEPS and your changes will be\n'
1571 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501572 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1573 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441574 'for more information')]
1575 return []
1576
1577
Saagar Sanghavifceeaae2020-08-12 16:40:361578def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471579 """Checks that DEPS file deps are from allowed_hosts."""
1580 # Run only if DEPS file has been modified to annoy fewer bystanders.
1581 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1582 return []
1583 # Outsource work to gclient verify
1584 try:
John Budorickf20c0042019-04-25 23:23:401585 gclient_path = input_api.os_path.join(
1586 input_api.PresubmitLocalPath(),
1587 'third_party', 'depot_tools', 'gclient.py')
1588 input_api.subprocess.check_output(
1589 [input_api.python_executable, gclient_path, 'verify'],
1590 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471591 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201592 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471593 return [output_api.PresubmitError(
1594 'DEPS file must have only git dependencies.',
1595 long_text=error.output)]
1596
1597
Mario Sanchez Prada2472cab2019-09-18 10:58:311598def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1599 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591600 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311601
1602 Returns an string composed of the name of the file, the line number where the
1603 match has been found and the additional text passed as |message| in case the
1604 target type name matches the text inside the line passed as parameter.
1605 """
Peng Huang9c5949a02020-06-11 19:20:541606 result = []
1607
danakjd18e8892020-12-17 17:42:011608 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1609 return result
1610 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541611 return result
1612
Mario Sanchez Prada2472cab2019-09-18 10:58:311613 matched = False
1614 if type_name[0:1] == '/':
1615 regex = type_name[1:]
1616 if input_api.re.search(regex, line):
1617 matched = True
1618 elif type_name in line:
1619 matched = True
1620
Mario Sanchez Prada2472cab2019-09-18 10:58:311621 if matched:
1622 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1623 for message_line in message:
1624 result.append(' %s' % message_line)
1625
1626 return result
1627
1628
Saagar Sanghavifceeaae2020-08-12 16:40:361629def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591630 """Make sure that banned functions are not used."""
1631 warnings = []
1632 errors = []
1633
James Cook24a504192020-07-23 00:08:441634 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151635 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441636 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151637 if input_api.re.match(item, local_path):
1638 return True
1639 return False
1640
Peter K. Lee6c03ccff2019-07-15 14:40:051641 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541642 local_path = affected_file.LocalPath()
1643 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1644 return False
1645 basename = input_api.os_path.basename(local_path)
1646 if 'ios' in basename.split('_'):
1647 return True
1648 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1649 if sep and 'ios' in local_path.split(sep):
1650 return True
1651 return False
1652
wnwenbdc444e2016-05-25 13:44:151653 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311654 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1655 func_name, message)
1656 if problems:
wnwenbdc444e2016-05-25 13:44:151657 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311658 errors.extend(problems)
1659 else:
1660 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151661
Eric Stevensona9a980972017-09-23 00:04:411662 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1663 for f in input_api.AffectedFiles(file_filter=file_filter):
1664 for line_num, line in f.ChangedContents():
1665 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1666 CheckForMatch(f, line_num, line, func_name, message, error)
1667
[email protected]127f18ec2012-06-16 05:05:591668 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1669 for f in input_api.AffectedFiles(file_filter=file_filter):
1670 for line_num, line in f.ChangedContents():
1671 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151672 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591673
Peter K. Lee6c03ccff2019-07-15 14:40:051674 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541675 for line_num, line in f.ChangedContents():
1676 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1677 CheckForMatch(f, line_num, line, func_name, message, error)
1678
Peter K. Lee6c03ccff2019-07-15 14:40:051679 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1680 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1681 for line_num, line in f.ChangedContents():
1682 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1683 CheckForMatch(f, line_num, line, func_name, message, error)
1684
[email protected]127f18ec2012-06-16 05:05:591685 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1686 for f in input_api.AffectedFiles(file_filter=file_filter):
1687 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491688 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441689 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491690 continue
wnwenbdc444e2016-05-25 13:44:151691 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591692
1693 result = []
1694 if (warnings):
1695 result.append(output_api.PresubmitPromptWarning(
1696 'Banned functions were used.\n' + '\n'.join(warnings)))
1697 if (errors):
1698 result.append(output_api.PresubmitError(
1699 'Banned functions were used.\n' + '\n'.join(errors)))
1700 return result
1701
1702
Michael Thiessen44457642020-02-06 00:24:151703def _CheckAndroidNoBannedImports(input_api, output_api):
1704 """Make sure that banned java imports are not used."""
1705 errors = []
1706
1707 def IsException(path, exceptions):
1708 for exception in exceptions:
1709 if (path.startswith(exception)):
1710 return True
1711 return False
1712
1713 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1714 for f in input_api.AffectedFiles(file_filter=file_filter):
1715 for line_num, line in f.ChangedContents():
1716 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1717 if IsException(f.LocalPath(), exceptions):
1718 continue;
1719 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1720 'import ' + import_name, message)
1721 if problems:
1722 errors.extend(problems)
1723 result = []
1724 if (errors):
1725 result.append(output_api.PresubmitError(
1726 'Banned imports were used.\n' + '\n'.join(errors)))
1727 return result
1728
1729
Saagar Sanghavifceeaae2020-08-12 16:40:361730def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311731 """Make sure that old Mojo types are not used."""
1732 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571733 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311734
Mario Sanchez Pradaaab91382019-12-19 08:57:091735 # For any path that is not an "ok" or an "error" path, a warning will be
1736 # raised if deprecated mojo types are found.
1737 ok_paths = ['components/arc']
1738 error_paths = ['third_party/blink', 'content']
1739
Mario Sanchez Prada2472cab2019-09-18 10:58:311740 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1741 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571742 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091743 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311744 continue
1745
1746 for line_num, line in f.ChangedContents():
1747 for func_name, message in _DEPRECATED_MOJO_TYPES:
1748 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1749 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571750
Mario Sanchez Prada2472cab2019-09-18 10:58:311751 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091752 # Raise errors inside |error_paths| and warnings everywhere else.
1753 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571754 errors.extend(problems)
1755 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311756 warnings.extend(problems)
1757
1758 result = []
1759 if (warnings):
1760 result.append(output_api.PresubmitPromptWarning(
1761 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571762 if (errors):
1763 result.append(output_api.PresubmitError(
1764 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311765 return result
1766
1767
Saagar Sanghavifceeaae2020-08-12 16:40:361768def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061769 """Make sure that banned functions are not used."""
1770 files = []
1771 pattern = input_api.re.compile(r'^#pragma\s+once',
1772 input_api.re.MULTILINE)
1773 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1774 if not f.LocalPath().endswith('.h'):
1775 continue
1776 contents = input_api.ReadFile(f)
1777 if pattern.search(contents):
1778 files.append(f)
1779
1780 if files:
1781 return [output_api.PresubmitError(
1782 'Do not use #pragma once in header files.\n'
1783 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1784 files)]
1785 return []
1786
[email protected]127f18ec2012-06-16 05:05:591787
Saagar Sanghavifceeaae2020-08-12 16:40:361788def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121789 """Checks to make sure we don't introduce use of foo ? true : false."""
1790 problems = []
1791 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1792 for f in input_api.AffectedFiles():
1793 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1794 continue
1795
1796 for line_num, line in f.ChangedContents():
1797 if pattern.match(line):
1798 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1799
1800 if not problems:
1801 return []
1802 return [output_api.PresubmitPromptWarning(
1803 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1804 '\n'.join(problems))]
1805
1806
Saagar Sanghavifceeaae2020-08-12 16:40:361807def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281808 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181809 change. Breaking - rules is an error, breaking ! rules is a
1810 warning.
1811 """
mohan.reddyf21db962014-10-16 12:26:471812 import sys
[email protected]55f9f382012-07-31 11:02:181813 # We need to wait until we have an input_api object and use this
1814 # roundabout construct to import checkdeps because this file is
1815 # eval-ed and thus doesn't have __file__.
1816 original_sys_path = sys.path
1817 try:
1818 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471819 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181820 import checkdeps
[email protected]55f9f382012-07-31 11:02:181821 from rules import Rule
1822 finally:
1823 # Restore sys.path to what it was before.
1824 sys.path = original_sys_path
1825
1826 added_includes = []
rhalavati08acd232017-04-03 07:23:281827 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241828 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181829 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061830 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501831 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081832 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061833 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501834 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081835 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061836 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501837 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081838 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181839
[email protected]26385172013-05-09 23:11:351840 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181841
1842 error_descriptions = []
1843 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281844 error_subjects = set()
1845 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361846
[email protected]55f9f382012-07-31 11:02:181847 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1848 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081849 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181850 description_with_path = '%s\n %s' % (path, rule_description)
1851 if rule_type == Rule.DISALLOW:
1852 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281853 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181854 else:
1855 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281856 warning_subjects.add("#includes")
1857
1858 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1859 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081860 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281861 description_with_path = '%s\n %s' % (path, rule_description)
1862 if rule_type == Rule.DISALLOW:
1863 error_descriptions.append(description_with_path)
1864 error_subjects.add("imports")
1865 else:
1866 warning_descriptions.append(description_with_path)
1867 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181868
Jinsuk Kim5a092672017-10-24 22:42:241869 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021870 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081871 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241872 description_with_path = '%s\n %s' % (path, rule_description)
1873 if rule_type == Rule.DISALLOW:
1874 error_descriptions.append(description_with_path)
1875 error_subjects.add("imports")
1876 else:
1877 warning_descriptions.append(description_with_path)
1878 warning_subjects.add("imports")
1879
[email protected]55f9f382012-07-31 11:02:181880 results = []
1881 if error_descriptions:
1882 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281883 'You added one or more %s that violate checkdeps rules.'
1884 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181885 error_descriptions))
1886 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421887 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281888 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181889 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281890 '%s? See relevant DEPS file(s) for details and contacts.' %
1891 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181892 warning_descriptions))
1893 return results
1894
1895
Saagar Sanghavifceeaae2020-08-12 16:40:361896def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:221897 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151898 if input_api.platform == 'win32':
1899 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291900 checkperms_tool = input_api.os_path.join(
1901 input_api.PresubmitLocalPath(),
1902 'tools', 'checkperms', 'checkperms.py')
1903 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471904 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391905 with input_api.CreateTemporaryFile() as file_list:
1906 for f in input_api.AffectedFiles():
1907 # checkperms.py file/directory arguments must be relative to the
1908 # repository.
Dirk Prankee3c9c62d2021-05-18 18:35:591909 file_list.write((f.LocalPath() + '\n').encode('utf8'))
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391910 file_list.close()
1911 args += ['--file-list', file_list.name]
1912 try:
1913 input_api.subprocess.check_output(args)
1914 return []
1915 except input_api.subprocess.CalledProcessError as error:
1916 return [output_api.PresubmitError(
1917 'checkperms.py failed:',
Ari Chivukula45f58dd52021-06-18 04:23:041918 long_text=error.output.decode('utf-8', 'ignore'))]
[email protected]fbcafe5a2012-08-08 15:31:221919
1920
Saagar Sanghavifceeaae2020-08-12 16:40:361921def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:491922 """Makes sure we don't include ui/aura/window_property.h
1923 in header files.
1924 """
1925 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1926 errors = []
1927 for f in input_api.AffectedFiles():
1928 if not f.LocalPath().endswith('.h'):
1929 continue
1930 for line_num, line in f.ChangedContents():
1931 if pattern.match(line):
1932 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1933
1934 results = []
1935 if errors:
1936 results.append(output_api.PresubmitError(
1937 'Header files should not include ui/aura/window_property.h', errors))
1938 return results
1939
1940
Omer Katzcc77ea92021-04-26 10:23:281941def CheckNoInternalHeapIncludes(input_api, output_api):
1942 """Makes sure we don't include any headers from
1943 third_party/blink/renderer/platform/heap/impl or
1944 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1945 third_party/blink/renderer/platform/heap
1946 """
1947 impl_pattern = input_api.re.compile(
1948 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1949 v8_wrapper_pattern = input_api.re.compile(
1950 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"')
1951 file_filter = lambda f: not input_api.re.match(
1952 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1953 f.LocalPath())
1954 errors = []
1955
1956 for f in input_api.AffectedFiles(file_filter=file_filter):
1957 for line_num, line in f.ChangedContents():
1958 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1959 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1960
1961 results = []
1962 if errors:
1963 results.append(output_api.PresubmitError(
1964 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1965 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1966 'relevant counterparts from third_party/blink/renderer/platform/heap',
1967 errors))
1968 return results
1969
1970
[email protected]70ca77752012-11-20 03:45:031971def _CheckForVersionControlConflictsInFile(input_api, f):
1972 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1973 errors = []
1974 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161975 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231976 # First-level headers in markdown look a lot like version control
1977 # conflict markers. http://daringfireball.net/projects/markdown/basics
1978 continue
[email protected]70ca77752012-11-20 03:45:031979 if pattern.match(line):
1980 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1981 return errors
1982
1983
Saagar Sanghavifceeaae2020-08-12 16:40:361984def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:031985 """Usually this is not intentional and will cause a compile failure."""
1986 errors = []
1987 for f in input_api.AffectedFiles():
1988 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1989
1990 results = []
1991 if errors:
1992 results.append(output_api.PresubmitError(
1993 'Version control conflict markers found, please resolve.', errors))
1994 return results
1995
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201996
Saagar Sanghavifceeaae2020-08-12 16:40:361997def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:161998 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1999 errors = []
2000 for f in input_api.AffectedFiles():
2001 for line_num, line in f.ChangedContents():
2002 if pattern.search(line):
2003 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2004
2005 results = []
2006 if errors:
2007 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502008 'Found Google support URL addressed by answer number. Please replace '
2009 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162010 return results
2011
[email protected]70ca77752012-11-20 03:45:032012
Saagar Sanghavifceeaae2020-08-12 16:40:362013def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442014 def FilterFile(affected_file):
2015 """Filter function for use with input_api.AffectedSourceFiles,
2016 below. This filters out everything except non-test files from
2017 top-level directories that generally speaking should not hard-code
2018 service URLs (e.g. src/android_webview/, src/content/ and others).
2019 """
2020 return input_api.FilterSourceFile(
2021 affected_file,
James Cook24a504192020-07-23 00:08:442022 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2023 files_to_skip=(_EXCLUDED_PATHS +
2024 _TEST_CODE_EXCLUDED_PATHS +
2025 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442026
reillyi38965732015-11-16 18:27:332027 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2028 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462029 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2030 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442031 problems = [] # items are (filename, line_number, line)
2032 for f in input_api.AffectedSourceFiles(FilterFile):
2033 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462034 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442035 problems.append((f.LocalPath(), line_num, line))
2036
2037 if problems:
[email protected]f7051d52013-04-02 18:31:422038 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442039 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582040 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442041 [' %s:%d: %s' % (
2042 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032043 else:
2044 return []
[email protected]06e6d0ff2012-12-11 01:36:442045
2046
Saagar Sanghavifceeaae2020-08-12 16:40:362047def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292048 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2049 def FileFilter(affected_file):
2050 """Includes directories known to be Chrome OS only."""
2051 return input_api.FilterSourceFile(
2052 affected_file,
James Cook24a504192020-07-23 00:08:442053 files_to_check=('^ash/',
2054 '^chromeos/', # Top-level src/chromeos.
2055 '/chromeos/', # Any path component.
2056 '^components/arc',
2057 '^components/exo'),
2058 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292059
2060 prefs = []
2061 priority_prefs = []
2062 for f in input_api.AffectedFiles(file_filter=FileFilter):
2063 for line_num, line in f.ChangedContents():
2064 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2065 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2066 prefs.append(' %s' % line)
2067 if input_api.re.search(
2068 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2069 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2070 priority_prefs.append(' %s' % line)
2071
2072 results = []
2073 if (prefs):
2074 results.append(output_api.PresubmitPromptWarning(
2075 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2076 'by browser sync settings. If these prefs should be controlled by OS '
2077 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2078 if (priority_prefs):
2079 results.append(output_api.PresubmitPromptWarning(
2080 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2081 'controlled by browser sync settings. If these prefs should be '
2082 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2083 'instead.\n' + '\n'.join(prefs)))
2084 return results
2085
2086
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492087# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362088def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272089 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312090 The native_client_sdk directory is excluded because it has auto-generated PNG
2091 files for documentation.
[email protected]d2530012013-01-25 16:39:272092 """
[email protected]d2530012013-01-25 16:39:272093 errors = []
James Cook24a504192020-07-23 00:08:442094 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2095 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312096 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442097 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312098 for f in input_api.AffectedFiles(include_deletes=False,
2099 file_filter=file_filter):
2100 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272101
2102 results = []
2103 if errors:
2104 results.append(output_api.PresubmitError(
2105 'The name of PNG files should not have abbreviations. \n'
2106 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2107 'Contact [email protected] if you have questions.', errors))
2108 return results
2109
2110
Daniel Cheng4dcdb6b2017-04-13 08:30:172111def _ExtractAddRulesFromParsedDeps(parsed_deps):
2112 """Extract the rules that add dependencies from a parsed DEPS file.
2113
2114 Args:
2115 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2116 add_rules = set()
2117 add_rules.update([
2118 rule[1:] for rule in parsed_deps.get('include_rules', [])
2119 if rule.startswith('+') or rule.startswith('!')
2120 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502121 for _, rules in parsed_deps.get('specific_include_rules',
Dirk Prankee3c9c62d2021-05-18 18:35:592122 {}).items():
Daniel Cheng4dcdb6b2017-04-13 08:30:172123 add_rules.update([
2124 rule[1:] for rule in rules
2125 if rule.startswith('+') or rule.startswith('!')
2126 ])
2127 return add_rules
2128
2129
2130def _ParseDeps(contents):
2131 """Simple helper for parsing DEPS files."""
2132 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172133 class _VarImpl:
2134
2135 def __init__(self, local_scope):
2136 self._local_scope = local_scope
2137
2138 def Lookup(self, var_name):
2139 """Implements the Var syntax."""
2140 try:
2141 return self._local_scope['vars'][var_name]
2142 except KeyError:
2143 raise Exception('Var is not defined: %s' % var_name)
2144
2145 local_scope = {}
2146 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172147 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592148 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172149 }
Dirk Pranke1b9e06382021-05-14 01:16:222150
Dirk Prankee3c9c62d2021-05-18 18:35:592151 exec(contents, global_scope, local_scope)
Daniel Cheng4dcdb6b2017-04-13 08:30:172152 return local_scope
2153
2154
2155def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592156 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412157 a set of DEPS entries that we should look up.
2158
2159 For a directory (rather than a specific filename) we fake a path to
2160 a specific filename by adding /DEPS. This is chosen as a file that
2161 will seldom or never be subject to per-file include_rules.
2162 """
[email protected]2b438d62013-11-14 17:54:142163 # We ignore deps entries on auto-generated directories.
2164 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082165
Daniel Cheng4dcdb6b2017-04-13 08:30:172166 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2167 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2168
2169 added_deps = new_deps.difference(old_deps)
2170
[email protected]2b438d62013-11-14 17:54:142171 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172172 for added_dep in added_deps:
2173 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2174 continue
2175 # Assume that a rule that ends in .h is a rule for a specific file.
2176 if added_dep.endswith('.h'):
2177 results.add(added_dep)
2178 else:
2179 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082180 return results
2181
2182
Saagar Sanghavifceeaae2020-08-12 16:40:362183def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552184 """When a dependency prefixed with + is added to a DEPS file, we
2185 want to make sure that the change is reviewed by an OWNER of the
2186 target file or directory, to avoid layering violations from being
2187 introduced. This check verifies that this happens.
2188 """
Joey Mou57048132021-02-26 22:17:552189 # We rely on Gerrit's code-owners to check approvals.
2190 # input_api.gerrit is always set for Chromium, but other projects
2191 # might not use Gerrit.
2192 if not input_api.gerrit:
2193 return []
Edward Lesmes44feb2332021-03-19 01:27:522194 if (input_api.change.issue and
2195 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232196 # Skip OWNERS check when Owners-Override label is approved. This is intended
2197 # for global owners, trusted bots, and on-call sheriffs. Review is still
2198 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522199 return []
Edward Lesmes6fba51082021-01-20 04:20:232200
Daniel Cheng4dcdb6b2017-04-13 08:30:172201 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242202
2203 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492204 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242205 for f in input_api.AffectedFiles(include_deletes=False,
2206 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552207 filename = input_api.os_path.basename(f.LocalPath())
2208 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172209 virtual_depended_on_files.update(_CalculateAddedDeps(
2210 input_api.os_path,
2211 '\n'.join(f.OldContents()),
2212 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552213
[email protected]e871964c2013-05-13 14:14:552214 if not virtual_depended_on_files:
2215 return []
2216
2217 if input_api.is_committing:
2218 if input_api.tbr:
2219 return [output_api.PresubmitNotifyResult(
2220 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272221 if input_api.dry_run:
2222 return [output_api.PresubmitNotifyResult(
2223 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552224 if not input_api.change.issue:
2225 return [output_api.PresubmitError(
2226 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402227 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552228 output = output_api.PresubmitError
2229 else:
2230 output = output_api.PresubmitNotifyResult
2231
tandriied3b7e12016-05-12 14:38:502232 owner_email, reviewers = (
2233 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2234 input_api,
Edward Lesmesa3846442021-02-08 20:20:032235 None,
tandriied3b7e12016-05-12 14:38:502236 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552237
2238 owner_email = owner_email or input_api.change.author_email
2239
Edward Lesmesa3846442021-02-08 20:20:032240 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2241 virtual_depended_on_files, reviewers.union([owner_email]), [])
2242 missing_files = [
2243 f for f in virtual_depended_on_files
2244 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412245
2246 # We strip the /DEPS part that was added by
2247 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2248 # directory.
2249 def StripDeps(path):
2250 start_deps = path.rfind('/DEPS')
2251 if start_deps != -1:
2252 return path[:start_deps]
2253 else:
2254 return path
2255 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552256 for path in missing_files]
2257
2258 if unapproved_dependencies:
2259 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152260 output('You need LGTM from owners of depends-on paths in DEPS that were '
2261 'modified in this CL:\n %s' %
2262 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032263 suggested_owners = input_api.owners_client.SuggestOwners(
2264 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152265 output_list.append(output(
2266 'Suggested missing target path OWNERS:\n %s' %
2267 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552268 return output_list
2269
2270 return []
2271
2272
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492273# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362274def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492275 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442276 files_to_skip = (_EXCLUDED_PATHS +
2277 _TEST_CODE_EXCLUDED_PATHS +
2278 input_api.DEFAULT_FILES_TO_SKIP +
2279 (r"^base[\\/]logging\.h$",
2280 r"^base[\\/]logging\.cc$",
2281 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2282 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2283 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2284 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2285 r"startup_browser_creator\.cc$",
2286 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2287 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2288 r"diagnostics_writer\.cc$",
2289 r"^chrome[\\/]chrome_cleaner[\\/].*",
2290 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2291 r"dll_hash_main\.cc$",
2292 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2293 r"^chromecast[\\/]",
2294 r"^cloud_print[\\/]",
2295 r"^components[\\/]browser_watcher[\\/]"
2296 r"dump_stability_report_main_win.cc$",
2297 r"^components[\\/]media_control[\\/]renderer[\\/]"
2298 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352299 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2300 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442301 r"^components[\\/]zucchini[\\/].*",
2302 # TODO(peter): Remove exception. https://crbug.com/534537
2303 r"^content[\\/]browser[\\/]notifications[\\/]"
2304 r"notification_event_dispatcher_impl\.cc$",
2305 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2306 r"gl_helper_benchmark\.cc$",
2307 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2308 r"^courgette[\\/]courgette_tool\.cc$",
2309 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
David Dorwinfa9aef42021-08-17 06:46:202310 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
James Cook24a504192020-07-23 00:08:442311 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Sergey Ulanov6db14b4d62021-05-10 07:59:482312 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
James Cook24a504192020-07-23 00:08:442313 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2314 r"^ipc[\\/]ipc_logging\.cc$",
2315 r"^native_client_sdk[\\/]",
2316 r"^remoting[\\/]base[\\/]logging\.h$",
2317 r"^remoting[\\/]host[\\/].*",
2318 r"^sandbox[\\/]linux[\\/].*",
2319 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2320 r"dump_file_system.cc$",
2321 r"^tools[\\/]",
2322 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2323 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2324 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2325 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2326 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402327 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442328 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402329
thomasanderson625d3932017-03-29 07:16:582330 log_info = set([])
2331 printf = set([])
[email protected]85218562013-11-22 07:41:402332
2333 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582334 for _, line in f.ChangedContents():
2335 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2336 log_info.add(f.LocalPath())
2337 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2338 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372339
thomasanderson625d3932017-03-29 07:16:582340 if input_api.re.search(r"\bprintf\(", line):
2341 printf.add(f.LocalPath())
2342 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2343 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402344
2345 if log_info:
2346 return [output_api.PresubmitError(
2347 'These files spam the console log with LOG(INFO):',
2348 items=log_info)]
2349 if printf:
2350 return [output_api.PresubmitError(
2351 'These files spam the console log with printf/fprintf:',
2352 items=printf)]
2353 return []
2354
2355
Saagar Sanghavifceeaae2020-08-12 16:40:362356def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162357 """These types are all expected to hold locks while in scope and
2358 so should never be anonymous (which causes them to be immediately
2359 destroyed)."""
2360 they_who_must_be_named = [
2361 'base::AutoLock',
2362 'base::AutoReset',
2363 'base::AutoUnlock',
2364 'SkAutoAlphaRestore',
2365 'SkAutoBitmapShaderInstall',
2366 'SkAutoBlitterChoose',
2367 'SkAutoBounderCommit',
2368 'SkAutoCallProc',
2369 'SkAutoCanvasRestore',
2370 'SkAutoCommentBlock',
2371 'SkAutoDescriptor',
2372 'SkAutoDisableDirectionCheck',
2373 'SkAutoDisableOvalCheck',
2374 'SkAutoFree',
2375 'SkAutoGlyphCache',
2376 'SkAutoHDC',
2377 'SkAutoLockColors',
2378 'SkAutoLockPixels',
2379 'SkAutoMalloc',
2380 'SkAutoMaskFreeImage',
2381 'SkAutoMutexAcquire',
2382 'SkAutoPathBoundsUpdate',
2383 'SkAutoPDFRelease',
2384 'SkAutoRasterClipValidate',
2385 'SkAutoRef',
2386 'SkAutoTime',
2387 'SkAutoTrace',
2388 'SkAutoUnref',
2389 ]
2390 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2391 # bad: base::AutoLock(lock.get());
2392 # not bad: base::AutoLock lock(lock.get());
2393 bad_pattern = input_api.re.compile(anonymous)
2394 # good: new base::AutoLock(lock.get())
2395 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2396 errors = []
2397
2398 for f in input_api.AffectedFiles():
2399 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2400 continue
2401 for linenum, line in f.ChangedContents():
2402 if bad_pattern.search(line) and not good_pattern.search(line):
2403 errors.append('%s:%d' % (f.LocalPath(), linenum))
2404
2405 if errors:
2406 return [output_api.PresubmitError(
2407 'These lines create anonymous variables that need to be named:',
2408 items=errors)]
2409 return []
2410
2411
Saagar Sanghavifceeaae2020-08-12 16:40:362412def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532413 # Returns whether |template_str| is of the form <T, U...> for some types T
2414 # and U. Assumes that |template_str| is already in the form <...>.
2415 def HasMoreThanOneArg(template_str):
2416 # Level of <...> nesting.
2417 nesting = 0
2418 for c in template_str:
2419 if c == '<':
2420 nesting += 1
2421 elif c == '>':
2422 nesting -= 1
2423 elif c == ',' and nesting == 1:
2424 return True
2425 return False
2426
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492427 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102428 sources = lambda affected_file: input_api.FilterSourceFile(
2429 affected_file,
James Cook24a504192020-07-23 00:08:442430 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2431 input_api.DEFAULT_FILES_TO_SKIP),
2432 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552433
2434 # Pattern to capture a single "<...>" block of template arguments. It can
2435 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2436 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2437 # latter would likely require counting that < and > match, which is not
2438 # expressible in regular languages. Should the need arise, one can introduce
2439 # limited counting (matching up to a total number of nesting depth), which
2440 # should cover all practical cases for already a low nesting limit.
2441 template_arg_pattern = (
2442 r'<[^>]*' # Opening block of <.
2443 r'>([^<]*>)?') # Closing block of >.
2444 # Prefix expressing that whatever follows is not already inside a <...>
2445 # block.
2446 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102447 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552448 not_inside_template_arg_pattern
2449 + r'\bstd::unique_ptr'
2450 + template_arg_pattern
2451 + r'\(\)')
2452
2453 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2454 template_arg_no_array_pattern = (
2455 r'<[^>]*[^]]' # Opening block of <.
2456 r'>([^(<]*[^]]>)?') # Closing block of >.
2457 # Prefix saying that what follows is the start of an expression.
2458 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2459 # Suffix saying that what follows are call parentheses with a non-empty list
2460 # of arguments.
2461 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532462 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552463 return_construct_pattern = input_api.re.compile(
2464 start_of_expr_pattern
2465 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532466 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552467 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532468 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552469 + nonempty_arg_list_pattern)
2470
Vaclav Brozek851d9602018-04-04 16:13:052471 problems_constructor = []
2472 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102473 for f in input_api.AffectedSourceFiles(sources):
2474 for line_number, line in f.ChangedContents():
2475 # Disallow:
2476 # return std::unique_ptr<T>(foo);
2477 # bar = std::unique_ptr<T>(foo);
2478 # But allow:
2479 # return std::unique_ptr<T[]>(foo);
2480 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532481 # And also allow cases when the second template argument is present. Those
2482 # cases cannot be handled by std::make_unique:
2483 # return std::unique_ptr<T, U>(foo);
2484 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052485 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532486 return_construct_result = return_construct_pattern.search(line)
2487 if return_construct_result and not HasMoreThanOneArg(
2488 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052489 problems_constructor.append(
2490 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102491 # Disallow:
2492 # std::unique_ptr<T>()
2493 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052494 problems_nullptr.append(
2495 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2496
2497 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162498 if problems_nullptr:
Daniel Chengab582892021-09-30 20:53:192499 errors.append(output_api.PresubmitWarning(
Vaclav Brozek851d9602018-04-04 16:13:052500 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162501 problems_nullptr))
2502 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052503 errors.append(output_api.PresubmitError(
2504 'The following files use explicit std::unique_ptr constructor.'
2505 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162506 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102507 return errors
2508
2509
Saagar Sanghavifceeaae2020-08-12 16:40:362510def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082511 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522512 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082513 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522514 # If actions.xml is already included in the changelist, the PRESUBMIT
2515 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082516 return []
2517
Alexei Svitkine64505a92021-03-11 22:00:542518 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2519 files_to_skip = (_EXCLUDED_PATHS +
2520 _TEST_CODE_EXCLUDED_PATHS +
2521 input_api.DEFAULT_FILES_TO_SKIP )
2522 file_filter = lambda f: input_api.FilterSourceFile(
2523 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2524
[email protected]999261d2014-03-03 20:08:082525 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522526 current_actions = None
[email protected]999261d2014-03-03 20:08:082527 for f in input_api.AffectedFiles(file_filter=file_filter):
2528 for line_num, line in f.ChangedContents():
2529 match = input_api.re.search(action_re, line)
2530 if match:
[email protected]2f92dec2014-03-07 19:21:522531 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2532 # loaded only once.
2533 if not current_actions:
2534 with open('tools/metrics/actions/actions.xml') as actions_f:
2535 current_actions = actions_f.read()
2536 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082537 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522538 action = 'name="{0}"'.format(action_name)
2539 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082540 return [output_api.PresubmitPromptWarning(
2541 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522542 'tools/metrics/actions/actions.xml. Please run '
2543 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082544 % (f.LocalPath(), line_num, action_name))]
2545 return []
2546
2547
Daniel Cheng13ca61a882017-08-25 15:11:252548def _ImportJSONCommentEater(input_api):
2549 import sys
2550 sys.path = sys.path + [input_api.os_path.join(
2551 input_api.PresubmitLocalPath(),
2552 'tools', 'json_comment_eater')]
2553 import json_comment_eater
2554 return json_comment_eater
2555
2556
[email protected]99171a92014-06-03 08:44:472557def _GetJSONParseError(input_api, filename, eat_comments=True):
2558 try:
2559 contents = input_api.ReadFile(filename)
2560 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252561 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132562 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472563
2564 input_api.json.loads(contents)
2565 except ValueError as e:
2566 return e
2567 return None
2568
2569
2570def _GetIDLParseError(input_api, filename):
2571 try:
2572 contents = input_api.ReadFile(filename)
2573 idl_schema = input_api.os_path.join(
2574 input_api.PresubmitLocalPath(),
2575 'tools', 'json_schema_compiler', 'idl_schema.py')
2576 process = input_api.subprocess.Popen(
2577 [input_api.python_executable, idl_schema],
2578 stdin=input_api.subprocess.PIPE,
2579 stdout=input_api.subprocess.PIPE,
2580 stderr=input_api.subprocess.PIPE,
2581 universal_newlines=True)
2582 (_, error) = process.communicate(input=contents)
2583 return error or None
2584 except ValueError as e:
2585 return e
2586
2587
Saagar Sanghavifceeaae2020-08-12 16:40:362588def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472589 """Check that IDL and JSON files do not contain syntax errors."""
2590 actions = {
2591 '.idl': _GetIDLParseError,
2592 '.json': _GetJSONParseError,
2593 }
[email protected]99171a92014-06-03 08:44:472594 # Most JSON files are preprocessed and support comments, but these do not.
2595 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042596 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472597 ]
2598 # Only run IDL checker on files in these directories.
2599 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042600 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2601 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472602 ]
2603
2604 def get_action(affected_file):
2605 filename = affected_file.LocalPath()
2606 return actions.get(input_api.os_path.splitext(filename)[1])
2607
[email protected]99171a92014-06-03 08:44:472608 def FilterFile(affected_file):
2609 action = get_action(affected_file)
2610 if not action:
2611 return False
2612 path = affected_file.LocalPath()
2613
Erik Staab2dd72b12020-04-16 15:03:402614 if _MatchesFile(input_api,
2615 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2616 path):
[email protected]99171a92014-06-03 08:44:472617 return False
2618
2619 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162620 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472621 return False
2622 return True
2623
2624 results = []
2625 for affected_file in input_api.AffectedFiles(
2626 file_filter=FilterFile, include_deletes=False):
2627 action = get_action(affected_file)
2628 kwargs = {}
2629 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162630 _MatchesFile(input_api, json_no_comments_patterns,
2631 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472632 kwargs['eat_comments'] = False
2633 parse_error = action(input_api,
2634 affected_file.AbsoluteLocalPath(),
2635 **kwargs)
2636 if parse_error:
2637 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2638 (affected_file.LocalPath(), parse_error)))
2639 return results
2640
2641
Saagar Sanghavifceeaae2020-08-12 16:40:362642def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492643 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472644 import sys
[email protected]760deea2013-12-10 19:33:492645 original_sys_path = sys.path
2646 try:
2647 sys.path = sys.path + [input_api.os_path.join(
2648 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2649 import checkstyle
2650 finally:
2651 # Restore sys.path to what it was before.
2652 sys.path = original_sys_path
2653
2654 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092655 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442656 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492657
2658
Saagar Sanghavifceeaae2020-08-12 16:40:362659def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002660 """Checks to make sure devil is initialized correctly in python scripts."""
2661 script_common_initialize_pattern = input_api.re.compile(
2662 r'script_common\.InitializeEnvironment\(')
2663 devil_env_config_initialize = input_api.re.compile(
2664 r'devil_env\.config\.Initialize\(')
2665
2666 errors = []
2667
2668 sources = lambda affected_file: input_api.FilterSourceFile(
2669 affected_file,
James Cook24a504192020-07-23 00:08:442670 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2671 (r'^build[\\/]android[\\/]devil_chromium\.py',
2672 r'^third_party[\\/].*',)),
2673 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002674
2675 for f in input_api.AffectedSourceFiles(sources):
2676 for line_num, line in f.ChangedContents():
2677 if (script_common_initialize_pattern.search(line) or
2678 devil_env_config_initialize.search(line)):
2679 errors.append("%s:%d" % (f.LocalPath(), line_num))
2680
2681 results = []
2682
2683 if errors:
2684 results.append(output_api.PresubmitError(
2685 'Devil initialization should always be done using '
2686 'devil_chromium.Initialize() in the chromium project, to use better '
2687 'defaults for dependencies (ex. up-to-date version of adb).',
2688 errors))
2689
2690 return results
2691
2692
Sean Kau46e29bc2017-08-28 16:31:162693def _MatchesFile(input_api, patterns, path):
2694 for pattern in patterns:
2695 if input_api.re.search(pattern, path):
2696 return True
2697 return False
2698
2699
Daniel Cheng7052cdf2017-11-21 19:23:292700def _GetOwnersFilesToCheckForIpcOwners(input_api):
2701 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172702
Daniel Cheng7052cdf2017-11-21 19:23:292703 Returns:
2704 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2705 contain to cover IPC-related files with noparent reviewer rules.
2706 """
2707 # Whether or not a file affects IPC is (mostly) determined by a simple list
2708 # of filename patterns.
dchenge07de812016-06-20 19:27:172709 file_patterns = [
palmerb19a0932017-01-24 04:00:312710 # Legacy IPC:
dchenge07de812016-06-20 19:27:172711 '*_messages.cc',
2712 '*_messages*.h',
2713 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312714 # Mojo IPC:
dchenge07de812016-06-20 19:27:172715 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472716 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172717 '*_struct_traits*.*',
2718 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312719 '*.typemap',
2720 # Android native IPC:
2721 '*.aidl',
2722 # Blink uses a different file naming convention:
2723 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472724 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172725 '*StructTraits*.*',
2726 '*TypeConverter*.*',
2727 ]
2728
scottmg7a6ed5ba2016-11-04 18:22:042729 # These third_party directories do not contain IPCs, but contain files
2730 # matching the above patterns, which trigger false positives.
2731 exclude_paths = [
2732 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162733 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232734 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292735 'third_party/win_build_output/*',
Scott Violet9f82d362019-11-06 21:42:162736 # These files are just used to communicate between class loaders running
2737 # in the same process.
2738 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572739 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2740
scottmg7a6ed5ba2016-11-04 18:22:042741 ]
2742
dchenge07de812016-06-20 19:27:172743 # Dictionary mapping an OWNERS file path to Patterns.
2744 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2745 # rules ) to a PatternEntry.
2746 # PatternEntry is a dictionary with two keys:
2747 # - 'files': the files that are matched by this pattern
2748 # - 'rules': the per-file rules needed for this pattern
2749 # For example, if we expect OWNERS file to contain rules for *.mojom and
2750 # *_struct_traits*.*, Patterns might look like this:
2751 # {
2752 # '*.mojom': {
2753 # 'files': ...,
2754 # 'rules': [
2755 # 'per-file *.mojom=set noparent',
2756 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2757 # ],
2758 # },
2759 # '*_struct_traits*.*': {
2760 # 'files': ...,
2761 # 'rules': [
2762 # 'per-file *_struct_traits*.*=set noparent',
2763 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2764 # ],
2765 # },
2766 # }
2767 to_check = {}
2768
Daniel Cheng13ca61a882017-08-25 15:11:252769 def AddPatternToCheck(input_file, pattern):
2770 owners_file = input_api.os_path.join(
2771 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2772 if owners_file not in to_check:
2773 to_check[owners_file] = {}
2774 if pattern not in to_check[owners_file]:
2775 to_check[owners_file][pattern] = {
2776 'files': [],
2777 'rules': [
2778 'per-file %s=set noparent' % pattern,
2779 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2780 ]
2781 }
Vaclav Brozekd5de76a2018-03-17 07:57:502782 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252783
dchenge07de812016-06-20 19:27:172784 # Iterate through the affected files to see what we actually need to check
2785 # for. We should only nag patch authors about per-file rules if a file in that
2786 # directory would match that pattern. If a directory only contains *.mojom
2787 # files and no *_messages*.h files, we should only nag about rules for
2788 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252789 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262790 # Manifest files don't have a strong naming convention. Instead, try to find
2791 # affected .cc and .h files which look like they contain a manifest
2792 # definition.
2793 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2794 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2795 if (manifest_pattern.search(f.LocalPath()) and not
2796 test_manifest_pattern.search(f.LocalPath())):
2797 # We expect all actual service manifest files to contain at least one
2798 # qualified reference to service_manager::Manifest.
2799 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252800 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172801 for pattern in file_patterns:
2802 if input_api.fnmatch.fnmatch(
2803 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042804 skip = False
2805 for exclude in exclude_paths:
2806 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2807 skip = True
2808 break
2809 if skip:
2810 continue
Daniel Cheng13ca61a882017-08-25 15:11:252811 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172812 break
2813
Daniel Cheng7052cdf2017-11-21 19:23:292814 return to_check
2815
2816
Wez17c66962020-04-29 15:26:032817def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2818 """Adds OWNERS files to check for correct Fuchsia security owners."""
2819
2820 file_patterns = [
2821 # Component specifications.
2822 '*.cml', # Component Framework v2.
2823 '*.cmx', # Component Framework v1.
2824
2825 # Fuchsia IDL protocol specifications.
2826 '*.fidl',
2827 ]
2828
Joshua Peraza1ca6d392020-12-08 00:14:092829 # Don't check for owners files for changes in these directories.
2830 exclude_paths = [
2831 'third_party/crashpad/*',
2832 ]
2833
Wez17c66962020-04-29 15:26:032834 def AddPatternToCheck(input_file, pattern):
2835 owners_file = input_api.os_path.join(
2836 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2837 if owners_file not in to_check:
2838 to_check[owners_file] = {}
2839 if pattern not in to_check[owners_file]:
2840 to_check[owners_file][pattern] = {
2841 'files': [],
2842 'rules': [
2843 'per-file %s=set noparent' % pattern,
2844 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2845 ]
2846 }
2847 to_check[owners_file][pattern]['files'].append(input_file)
2848
2849 # Iterate through the affected files to see what we actually need to check
2850 # for. We should only nag patch authors about per-file rules if a file in that
2851 # directory would match that pattern.
2852 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092853 skip = False
2854 for exclude in exclude_paths:
2855 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2856 skip = True
2857 if skip:
2858 continue
2859
Wez17c66962020-04-29 15:26:032860 for pattern in file_patterns:
2861 if input_api.fnmatch.fnmatch(
2862 input_api.os_path.basename(f.LocalPath()), pattern):
2863 AddPatternToCheck(f, pattern)
2864 break
2865
2866 return to_check
2867
2868
Saagar Sanghavifceeaae2020-08-12 16:40:362869def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292870 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2871 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032872 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292873
2874 if to_check:
2875 # If there are any OWNERS files to check, there are IPC-related changes in
2876 # this CL. Auto-CC the review list.
2877 output_api.AppendCC('[email protected]')
2878
2879 # Go through the OWNERS files to check, filtering out rules that are already
2880 # present in that OWNERS file.
Dirk Prankee3c9c62d2021-05-18 18:35:592881 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172882 try:
Dirk Prankee3c9c62d2021-05-18 18:35:592883 with open(owners_file) as f:
dchenge07de812016-06-20 19:27:172884 lines = set(f.read().splitlines())
Jeffrey Youngf3a5c8c42021-05-14 21:56:102885 for entry in patterns.values():
dchenge07de812016-06-20 19:27:172886 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2887 ]
2888 except IOError:
2889 # No OWNERS file, so all the rules are definitely missing.
2890 continue
2891
2892 # All the remaining lines weren't found in OWNERS files, so emit an error.
2893 errors = []
Dirk Prankee3c9c62d2021-05-18 18:35:592894 for owners_file, patterns in to_check.items():
dchenge07de812016-06-20 19:27:172895 missing_lines = []
2896 files = []
Dirk Prankee3c9c62d2021-05-18 18:35:592897 for _, entry in patterns.items():
dchenge07de812016-06-20 19:27:172898 missing_lines.extend(entry['rules'])
2899 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2900 if missing_lines:
2901 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052902 'Because of the presence of files:\n%s\n\n'
2903 '%s needs the following %d lines added:\n\n%s' %
2904 ('\n'.join(files), owners_file, len(missing_lines),
2905 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172906
2907 results = []
2908 if errors:
vabrf5ce3bf92016-07-11 14:52:412909 if input_api.is_committing:
2910 output = output_api.PresubmitError
2911 else:
2912 output = output_api.PresubmitPromptWarning
2913 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592914 'Found OWNERS files that need to be updated for IPC security ' +
2915 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172916 long_text='\n\n'.join(errors)))
2917
2918 return results
2919
2920
Robert Sesek2c905332020-05-06 23:17:132921def _GetFilesUsingSecurityCriticalFunctions(input_api):
2922 """Checks affected files for changes to security-critical calls. This
2923 function checks the full change diff, to catch both additions/changes
2924 and removals.
2925
2926 Returns a dict keyed by file name, and the value is a set of detected
2927 functions.
2928 """
2929 # Map of function pretty name (displayed in an error) to the pattern to
2930 # match it with.
2931 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:372932 'content::GetServiceSandboxType<>()':
2933 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:132934 }
2935 _PATTERNS_TO_CHECK = {
2936 k: input_api.re.compile(v)
2937 for k, v in _PATTERNS_TO_CHECK.items()
2938 }
2939
2940 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2941 files_to_functions = {}
2942 for f in input_api.AffectedFiles():
2943 diff = f.GenerateScmDiff()
2944 for line in diff.split('\n'):
2945 # Not using just RightHandSideLines() because removing a
2946 # call to a security-critical function can be just as important
2947 # as adding or changing the arguments.
2948 if line.startswith('-') or (line.startswith('+') and
2949 not line.startswith('++')):
2950 for name, pattern in _PATTERNS_TO_CHECK.items():
2951 if pattern.search(line):
2952 path = f.LocalPath()
2953 if not path in files_to_functions:
2954 files_to_functions[path] = set()
2955 files_to_functions[path].add(name)
2956 return files_to_functions
2957
2958
Saagar Sanghavifceeaae2020-08-12 16:40:362959def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:132960 """Checks that changes involving security-critical functions are reviewed
2961 by the security team.
2962 """
2963 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:122964 if not len(files_to_functions):
2965 return []
Robert Sesek2c905332020-05-06 23:17:132966
Edward Lesmes1e9fade2021-02-08 20:31:122967 owner_email, reviewers = (
2968 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2969 input_api,
2970 None,
2971 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:132972
Edward Lesmes1e9fade2021-02-08 20:31:122973 # Load the OWNERS file for security changes.
2974 owners_file = 'ipc/SECURITY_OWNERS'
2975 security_owners = input_api.owners_client.ListOwners(owners_file)
2976 has_security_owner = any([owner in reviewers for owner in security_owners])
2977 if has_security_owner:
2978 return []
Robert Sesek2c905332020-05-06 23:17:132979
Edward Lesmes1e9fade2021-02-08 20:31:122980 msg = 'The following files change calls to security-sensive functions\n' \
2981 'that need to be reviewed by {}.\n'.format(owners_file)
2982 for path, names in files_to_functions.items():
2983 msg += ' {}\n'.format(path)
2984 for name in names:
2985 msg += ' {}\n'.format(name)
2986 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:132987
Edward Lesmes1e9fade2021-02-08 20:31:122988 if input_api.is_committing:
2989 output = output_api.PresubmitError
2990 else:
2991 output = output_api.PresubmitNotifyResult
2992 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:132993
2994
Saagar Sanghavifceeaae2020-08-12 16:40:362995def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:262996 """Checks that set noparent is only used together with an OWNERS file in
2997 //build/OWNERS.setnoparent (see also
2998 //docs/code_reviews.md#owners-files-details)
2999 """
3000 errors = []
3001
3002 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3003 allowed_owners_files = set()
3004 with open(allowed_owners_files_file, 'r') as f:
3005 for line in f:
3006 line = line.strip()
3007 if not line or line.startswith('#'):
3008 continue
3009 allowed_owners_files.add(line)
3010
3011 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3012
3013 for f in input_api.AffectedFiles(include_deletes=False):
3014 if not f.LocalPath().endswith('OWNERS'):
3015 continue
3016
3017 found_owners_files = set()
3018 found_set_noparent_lines = dict()
3019
3020 # Parse the OWNERS file.
3021 for lineno, line in enumerate(f.NewContents(), 1):
3022 line = line.strip()
3023 if line.startswith('set noparent'):
3024 found_set_noparent_lines[''] = lineno
3025 if line.startswith('file://'):
3026 if line in allowed_owners_files:
3027 found_owners_files.add('')
3028 if line.startswith('per-file'):
3029 match = per_file_pattern.match(line)
3030 if match:
3031 glob = match.group(1).strip()
3032 directive = match.group(2).strip()
3033 if directive == 'set noparent':
3034 found_set_noparent_lines[glob] = lineno
3035 if directive.startswith('file://'):
3036 if directive in allowed_owners_files:
3037 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153038
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263039 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403040 # listed in build/OWNERS.setnoparent. An exception is made for top level
3041 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143042 if (f.LocalPath().count('/') != 1 and
3043 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403044 for set_noparent_line in found_set_noparent_lines:
3045 if set_noparent_line in found_owners_files:
3046 continue
3047 errors.append(' %s:%d' % (f.LocalPath(),
3048 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263049
3050 results = []
3051 if errors:
3052 if input_api.is_committing:
3053 output = output_api.PresubmitError
3054 else:
3055 output = output_api.PresubmitPromptWarning
3056 results.append(output(
3057 'Found the following "set noparent" restrictions in OWNERS files that '
3058 'do not include owners from build/OWNERS.setnoparent:',
3059 long_text='\n\n'.join(errors)))
3060 return results
3061
3062
Saagar Sanghavifceeaae2020-08-12 16:40:363063def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313064 """Checks that added or removed lines in non third party affected
3065 header files do not lead to new useless class or struct forward
3066 declaration.
jbriance9e12f162016-11-25 07:57:503067 """
3068 results = []
3069 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3070 input_api.re.MULTILINE)
3071 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3072 input_api.re.MULTILINE)
3073 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313074 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193075 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493076 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313077 continue
3078
jbriance9e12f162016-11-25 07:57:503079 if not f.LocalPath().endswith('.h'):
3080 continue
3081
3082 contents = input_api.ReadFile(f)
3083 fwd_decls = input_api.re.findall(class_pattern, contents)
3084 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3085
3086 useless_fwd_decls = []
3087 for decl in fwd_decls:
3088 count = sum(1 for _ in input_api.re.finditer(
3089 r'\b%s\b' % input_api.re.escape(decl), contents))
3090 if count == 1:
3091 useless_fwd_decls.append(decl)
3092
3093 if not useless_fwd_decls:
3094 continue
3095
3096 for line in f.GenerateScmDiff().splitlines():
3097 if (line.startswith('-') and not line.startswith('--') or
3098 line.startswith('+') and not line.startswith('++')):
3099 for decl in useless_fwd_decls:
3100 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3101 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243102 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503103 (f.LocalPath(), decl)))
3104 useless_fwd_decls.remove(decl)
3105
3106 return results
3107
Jinsong Fan91ebbbd2019-04-16 14:57:173108def _CheckAndroidDebuggableBuild(input_api, output_api):
3109 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3110 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3111 this is a debuggable build of Android.
3112 """
3113 build_type_check_pattern = input_api.re.compile(
3114 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3115
3116 errors = []
3117
3118 sources = lambda affected_file: input_api.FilterSourceFile(
3119 affected_file,
James Cook24a504192020-07-23 00:08:443120 files_to_skip=(_EXCLUDED_PATHS +
3121 _TEST_CODE_EXCLUDED_PATHS +
3122 input_api.DEFAULT_FILES_TO_SKIP +
3123 (r"^android_webview[\\/]support_library[\\/]"
3124 "boundary_interfaces[\\/]",
3125 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3126 r'^third_party[\\/].*',
3127 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3128 r"webview[\\/]chromium[\\/]License.*",)),
3129 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173130
3131 for f in input_api.AffectedSourceFiles(sources):
3132 for line_num, line in f.ChangedContents():
3133 if build_type_check_pattern.search(line):
3134 errors.append("%s:%d" % (f.LocalPath(), line_num))
3135
3136 results = []
3137
3138 if errors:
3139 results.append(output_api.PresubmitPromptWarning(
3140 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3141 ' Please use BuildInfo.isDebugAndroid() instead.',
3142 errors))
3143
3144 return results
jbriance9e12f162016-11-25 07:57:503145
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493146# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293147def _CheckAndroidToastUsage(input_api, output_api):
3148 """Checks that code uses org.chromium.ui.widget.Toast instead of
3149 android.widget.Toast (Chromium Toast doesn't force hardware
3150 acceleration on low-end devices, saving memory).
3151 """
3152 toast_import_pattern = input_api.re.compile(
3153 r'^import android\.widget\.Toast;$')
3154
3155 errors = []
3156
3157 sources = lambda affected_file: input_api.FilterSourceFile(
3158 affected_file,
James Cook24a504192020-07-23 00:08:443159 files_to_skip=(_EXCLUDED_PATHS +
3160 _TEST_CODE_EXCLUDED_PATHS +
3161 input_api.DEFAULT_FILES_TO_SKIP +
3162 (r'^chromecast[\\/].*',
3163 r'^remoting[\\/].*')),
3164 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293165
3166 for f in input_api.AffectedSourceFiles(sources):
3167 for line_num, line in f.ChangedContents():
3168 if toast_import_pattern.search(line):
3169 errors.append("%s:%d" % (f.LocalPath(), line_num))
3170
3171 results = []
3172
3173 if errors:
3174 results.append(output_api.PresubmitError(
3175 'android.widget.Toast usage is detected. Android toasts use hardware'
3176 ' acceleration, and can be\ncostly on low-end devices. Please use'
3177 ' org.chromium.ui.widget.Toast instead.\n'
3178 'Contact [email protected] if you have any questions.',
3179 errors))
3180
3181 return results
3182
3183
dgnaa68d5e2015-06-10 10:08:223184def _CheckAndroidCrLogUsage(input_api, output_api):
3185 """Checks that new logs using org.chromium.base.Log:
3186 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513187 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223188 """
pkotwicza1dd0b002016-05-16 14:41:043189
torne89540622017-03-24 19:41:303190 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043191 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303192 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043193 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303194 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043195 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3196 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093197 # The customtabs_benchmark is a small app that does not depend on Chromium
3198 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043199 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043200 ]
3201
dgnaa68d5e2015-06-10 10:08:223202 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123203 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3204 class_in_base_pattern = input_api.re.compile(
3205 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3206 has_some_log_import_pattern = input_api.re.compile(
3207 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223208 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553209 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223210 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463211 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553212 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223213
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463214 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443215 sources = lambda x: input_api.FilterSourceFile(x,
3216 files_to_check=[r'.*\.java$'],
3217 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123218
dgnaa68d5e2015-06-10 10:08:223219 tag_decl_errors = []
3220 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123221 tag_errors = []
dgn38736db2015-09-18 19:20:513222 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123223 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223224
3225 for f in input_api.AffectedSourceFiles(sources):
3226 file_content = input_api.ReadFile(f)
3227 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223228 # Per line checks
dgn87d9fb62015-06-12 09:15:123229 if (cr_log_import_pattern.search(file_content) or
3230 (class_in_base_pattern.search(file_content) and
3231 not has_some_log_import_pattern.search(file_content))):
3232 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223233 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553234 if rough_log_decl_pattern.search(line):
3235 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223236
3237 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123238 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223239 if match:
3240 has_modified_logs = True
3241
3242 # Make sure it uses "TAG"
3243 if not match.group('tag') == 'TAG':
3244 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123245 else:
3246 # Report non cr Log function calls in changed lines
3247 for line_num, line in f.ChangedContents():
3248 if log_call_pattern.search(line):
3249 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223250
3251 # Per file checks
3252 if has_modified_logs:
3253 # Make sure the tag is using the "cr" prefix and is not too long
3254 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513255 tag_name = match.group('name') if match else None
3256 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223257 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513258 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223259 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513260 elif '.' in tag_name:
3261 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223262
3263 results = []
3264 if tag_decl_errors:
3265 results.append(output_api.PresubmitPromptWarning(
3266 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513267 '"private static final String TAG = "<package tag>".\n'
3268 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223269 tag_decl_errors))
3270
3271 if tag_length_errors:
3272 results.append(output_api.PresubmitError(
3273 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513274 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223275 tag_length_errors))
3276
3277 if tag_errors:
3278 results.append(output_api.PresubmitPromptWarning(
3279 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3280 tag_errors))
3281
dgn87d9fb62015-06-12 09:15:123282 if util_log_errors:
dgn4401aa52015-04-29 16:26:173283 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123284 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3285 util_log_errors))
3286
dgn38736db2015-09-18 19:20:513287 if tag_with_dot_errors:
3288 results.append(output_api.PresubmitPromptWarning(
3289 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3290 tag_with_dot_errors))
3291
dgn4401aa52015-04-29 16:26:173292 return results
3293
3294
Yoland Yanb92fa522017-08-28 17:37:063295def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3296 """Checks that junit.framework.* is no longer used."""
3297 deprecated_junit_framework_pattern = input_api.re.compile(
3298 r'^import junit\.framework\..*;',
3299 input_api.re.MULTILINE)
3300 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443301 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063302 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133303 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063304 for line_num, line in f.ChangedContents():
3305 if deprecated_junit_framework_pattern.search(line):
3306 errors.append("%s:%d" % (f.LocalPath(), line_num))
3307
3308 results = []
3309 if errors:
3310 results.append(output_api.PresubmitError(
3311 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3312 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3313 ' if you have any question.', errors))
3314 return results
3315
3316
3317def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3318 """Checks that if new Java test classes have inheritance.
3319 Either the new test class is JUnit3 test or it is a JUnit4 test class
3320 with a base class, either case is undesirable.
3321 """
3322 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3323
3324 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443325 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063326 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133327 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063328 if not f.OldContents():
3329 class_declaration_start_flag = False
3330 for line_num, line in f.ChangedContents():
3331 if class_declaration_pattern.search(line):
3332 class_declaration_start_flag = True
3333 if class_declaration_start_flag and ' extends ' in line:
3334 errors.append('%s:%d' % (f.LocalPath(), line_num))
3335 if '{' in line:
3336 class_declaration_start_flag = False
3337
3338 results = []
3339 if errors:
3340 results.append(output_api.PresubmitPromptWarning(
3341 'The newly created files include Test classes that inherits from base'
3342 ' class. Please do not use inheritance in JUnit4 tests or add new'
3343 ' JUnit3 tests. Contact [email protected] if you have any'
3344 ' questions.', errors))
3345 return results
3346
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203347
yolandyan45001472016-12-21 21:12:423348def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3349 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3350 deprecated_annotation_import_pattern = input_api.re.compile(
3351 r'^import android\.test\.suitebuilder\.annotation\..*;',
3352 input_api.re.MULTILINE)
3353 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443354 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423355 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133356 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423357 for line_num, line in f.ChangedContents():
3358 if deprecated_annotation_import_pattern.search(line):
3359 errors.append("%s:%d" % (f.LocalPath(), line_num))
3360
3361 results = []
3362 if errors:
3363 results.append(output_api.PresubmitError(
3364 'Annotations in android.test.suitebuilder.annotation have been'
3365 ' deprecated since API level 24. Please use android.support.test.filters'
3366 ' from //third_party/android_support_test_runner:runner_java instead.'
3367 ' Contact [email protected] if you have any questions.', errors))
3368 return results
3369
3370
agrieve7b6479d82015-10-07 14:24:223371def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3372 """Checks if MDPI assets are placed in a correct directory."""
3373 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3374 ('/res/drawable/' in f.LocalPath() or
3375 '/res/drawable-ldrtl/' in f.LocalPath()))
3376 errors = []
3377 for f in input_api.AffectedFiles(include_deletes=False,
3378 file_filter=file_filter):
3379 errors.append(' %s' % f.LocalPath())
3380
3381 results = []
3382 if errors:
3383 results.append(output_api.PresubmitError(
3384 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3385 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3386 '/res/drawable-ldrtl/.\n'
3387 'Contact [email protected] if you have questions.', errors))
3388 return results
3389
3390
Nate Fischer535972b2017-09-16 01:06:183391def _CheckAndroidWebkitImports(input_api, output_api):
3392 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353393 android.webview.ValueCallback except in the WebView glue layer
3394 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183395 """
3396 valuecallback_import_pattern = input_api.re.compile(
3397 r'^import android\.webkit\.ValueCallback;$')
3398
3399 errors = []
3400
3401 sources = lambda affected_file: input_api.FilterSourceFile(
3402 affected_file,
James Cook24a504192020-07-23 00:08:443403 files_to_skip=(_EXCLUDED_PATHS +
3404 _TEST_CODE_EXCLUDED_PATHS +
3405 input_api.DEFAULT_FILES_TO_SKIP +
3406 (r'^android_webview[\\/]glue[\\/].*',
3407 r'^weblayer[\\/].*',)),
3408 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183409
3410 for f in input_api.AffectedSourceFiles(sources):
3411 for line_num, line in f.ChangedContents():
3412 if valuecallback_import_pattern.search(line):
3413 errors.append("%s:%d" % (f.LocalPath(), line_num))
3414
3415 results = []
3416
3417 if errors:
3418 results.append(output_api.PresubmitError(
3419 'android.webkit.ValueCallback usage is detected outside of the glue'
3420 ' layer. To stay compatible with the support library, android.webkit.*'
3421 ' classes should only be used inside the glue layer and'
3422 ' org.chromium.base.Callback should be used instead.',
3423 errors))
3424
3425 return results
3426
3427
Becky Zhou7c69b50992018-12-10 19:37:573428def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3429 """Checks Android XML styles """
3430 import sys
3431 original_sys_path = sys.path
3432 try:
3433 sys.path = sys.path + [input_api.os_path.join(
3434 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3435 import checkxmlstyle
3436 finally:
3437 # Restore sys.path to what it was before.
3438 sys.path = original_sys_path
3439
3440 if is_check_on_upload:
3441 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3442 else:
3443 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3444
3445
agrievef32bcc72016-04-04 14:57:403446class PydepsChecker(object):
3447 def __init__(self, input_api, pydeps_files):
3448 self._file_cache = {}
3449 self._input_api = input_api
3450 self._pydeps_files = pydeps_files
3451
3452 def _LoadFile(self, path):
3453 """Returns the list of paths within a .pydeps file relative to //."""
3454 if path not in self._file_cache:
3455 with open(path) as f:
3456 self._file_cache[path] = f.read()
3457 return self._file_cache[path]
3458
3459 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3460 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393461 pydeps_data = self._LoadFile(pydeps_path)
3462 uses_gn_paths = '--gn-paths' in pydeps_data
3463 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3464 if uses_gn_paths:
3465 # Paths look like: //foo/bar/baz
3466 return (e[2:] for e in entries)
3467 else:
3468 # Paths look like: path/relative/to/file.pydeps
3469 os_path = self._input_api.os_path
3470 pydeps_dir = os_path.dirname(pydeps_path)
3471 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403472
3473 def _CreateFilesToPydepsMap(self):
3474 """Returns a map of local_path -> list_of_pydeps."""
3475 ret = {}
3476 for pydep_local_path in self._pydeps_files:
3477 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3478 ret.setdefault(path, []).append(pydep_local_path)
3479 return ret
3480
3481 def ComputeAffectedPydeps(self):
3482 """Returns an iterable of .pydeps files that might need regenerating."""
3483 affected_pydeps = set()
3484 file_to_pydeps_map = None
3485 for f in self._input_api.AffectedFiles(include_deletes=True):
3486 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463487 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3488 # subrepositories. We can't figure out which files change, so re-check
3489 # all files.
3490 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383491 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3492 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403493 return self._pydeps_files
3494 elif local_path.endswith('.pydeps'):
3495 if local_path in self._pydeps_files:
3496 affected_pydeps.add(local_path)
3497 elif local_path.endswith('.py'):
3498 if file_to_pydeps_map is None:
3499 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3500 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3501 return affected_pydeps
3502
3503 def DetermineIfStale(self, pydeps_path):
3504 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413505 import difflib
John Budorick47ca3fe2018-02-10 00:53:103506 import os
3507
agrievef32bcc72016-04-04 14:57:403508 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033509 if old_pydeps_data:
3510 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393511 if '--output' not in cmd:
3512 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033513 old_contents = old_pydeps_data[2:]
3514 else:
3515 # A default cmd that should work in most cases (as long as pydeps filename
3516 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3517 # file is empty/new.
3518 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3519 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3520 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103521 env = dict(os.environ)
3522 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403523 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103524 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413525 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033526 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413527 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403528
3529
Tibor Goldschwendt360793f72019-06-25 18:23:493530def _ParseGclientArgs():
3531 args = {}
3532 with open('build/config/gclient_args.gni', 'r') as f:
3533 for line in f:
3534 line = line.strip()
3535 if not line or line.startswith('#'):
3536 continue
3537 attribute, value = line.split('=')
3538 args[attribute.strip()] = value.strip()
3539 return args
3540
3541
Saagar Sanghavifceeaae2020-08-12 16:40:363542def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403543 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403544 # This check is for Python dependency lists (.pydeps files), and involves
3545 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3546 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283547 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003548 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493549 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403550 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403551 results = []
3552 # First, check for new / deleted .pydeps.
3553 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033554 # Check whether we are running the presubmit check for a file in src.
3555 # f.LocalPath is relative to repo (src, or internal repo).
3556 # os_path.exists is relative to src repo.
3557 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3558 # to src and we can conclude that the pydeps is in src.
3559 if input_api.os_path.exists(f.LocalPath()):
3560 if f.LocalPath().endswith('.pydeps'):
3561 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3562 results.append(output_api.PresubmitError(
3563 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3564 'remove %s' % f.LocalPath()))
3565 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3566 results.append(output_api.PresubmitError(
3567 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3568 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403569
3570 if results:
3571 return results
3572
Mohamed Heikal7cd4d8312020-06-16 16:49:403573 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3574 affected_pydeps = set(checker.ComputeAffectedPydeps())
3575 affected_android_pydeps = affected_pydeps.intersection(
3576 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3577 if affected_android_pydeps and not is_android:
3578 results.append(output_api.PresubmitPromptOrNotify(
3579 'You have changed python files that may affect pydeps for android\n'
3580 'specific scripts. However, the relevant presumbit check cannot be\n'
3581 'run because you are not using an Android checkout. To validate that\n'
3582 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3583 'use the android-internal-presubmit optional trybot.\n'
3584 'Possibly stale pydeps files:\n{}'.format(
3585 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403586
Mohamed Heikal7cd4d8312020-06-16 16:49:403587 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3588 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403589 try:
phajdan.jr0d9878552016-11-04 10:49:413590 result = checker.DetermineIfStale(pydep_path)
3591 if result:
3592 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403593 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413594 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3595 'To regenerate, run:\n\n %s' %
3596 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403597 except input_api.subprocess.CalledProcessError as error:
3598 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3599 long_text=error.output)]
3600
3601 return results
3602
3603
Saagar Sanghavifceeaae2020-08-12 16:40:363604def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433605 """Checks to make sure no header files have |Singleton<|."""
3606 def FileFilter(affected_file):
3607 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443608 files_to_skip = (_EXCLUDED_PATHS +
3609 input_api.DEFAULT_FILES_TO_SKIP +
3610 (r"^base[\\/]memory[\\/]singleton\.h$",
3611 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3612 r"quic_singleton_impl\.h$"))
3613 return input_api.FilterSourceFile(affected_file,
3614 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433615
sergeyu34d21222015-09-16 00:11:443616 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433617 files = []
3618 for f in input_api.AffectedSourceFiles(FileFilter):
3619 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3620 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3621 contents = input_api.ReadFile(f)
3622 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243623 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433624 pattern.search(line)):
3625 files.append(f)
3626 break
3627
3628 if files:
yolandyandaabc6d2016-04-18 18:29:393629 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443630 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433631 'Please move them to an appropriate source file so that the ' +
3632 'template gets instantiated in a single compilation unit.',
3633 files) ]
3634 return []
3635
3636
[email protected]fd20b902014-05-09 02:14:533637_DEPRECATED_CSS = [
3638 # Values
3639 ( "-webkit-box", "flex" ),
3640 ( "-webkit-inline-box", "inline-flex" ),
3641 ( "-webkit-flex", "flex" ),
3642 ( "-webkit-inline-flex", "inline-flex" ),
3643 ( "-webkit-min-content", "min-content" ),
3644 ( "-webkit-max-content", "max-content" ),
3645
3646 # Properties
3647 ( "-webkit-background-clip", "background-clip" ),
3648 ( "-webkit-background-origin", "background-origin" ),
3649 ( "-webkit-background-size", "background-size" ),
3650 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443651 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533652
3653 # Functions
3654 ( "-webkit-gradient", "gradient" ),
3655 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3656 ( "-webkit-linear-gradient", "linear-gradient" ),
3657 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3658 ( "-webkit-radial-gradient", "radial-gradient" ),
3659 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3660]
3661
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203662
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493663# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363664def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533665 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253666 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343667 documentation and iOS CSS for dom distiller
3668 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253669 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533670 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493671 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443672 files_to_skip = (_EXCLUDED_PATHS +
3673 _TEST_CODE_EXCLUDED_PATHS +
3674 input_api.DEFAULT_FILES_TO_SKIP +
3675 (r"^chrome/common/extensions/docs",
3676 r"^chrome/docs",
3677 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3678 r"^components/neterror/resources/neterror.css",
3679 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253680 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443681 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533682 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3683 for line_num, line in fpath.ChangedContents():
3684 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023685 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533686 results.append(output_api.PresubmitError(
3687 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3688 (fpath.LocalPath(), line_num, deprecated_value, value)))
3689 return results
3690
mohan.reddyf21db962014-10-16 12:26:473691
Saagar Sanghavifceeaae2020-08-12 16:40:363692def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363693 bad_files = {}
3694 for f in input_api.AffectedFiles(include_deletes=False):
3695 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493696 not f.LocalPath().startswith('third_party/blink') and
3697 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363698 continue
3699
Daniel Bratell65b033262019-04-23 08:17:063700 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363701 continue
3702
Vaclav Brozekd5de76a2018-03-17 07:57:503703 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363704 if "#include" in line and "../" in line]
3705 if not relative_includes:
3706 continue
3707 bad_files[f.LocalPath()] = relative_includes
3708
3709 if not bad_files:
3710 return []
3711
3712 error_descriptions = []
Dirk Prankee3c9c62d2021-05-18 18:35:593713 for file_path, bad_lines in bad_files.items():
rlanday6802cf632017-05-30 17:48:363714 error_description = file_path
3715 for line in bad_lines:
3716 error_description += '\n ' + line
3717 error_descriptions.append(error_description)
3718
3719 results = []
3720 results.append(output_api.PresubmitError(
3721 'You added one or more relative #include paths (including "../").\n'
3722 'These shouldn\'t be used because they can be used to include headers\n'
3723 'from code that\'s not correctly specified as a dependency in the\n'
3724 'relevant BUILD.gn file(s).',
3725 error_descriptions))
3726
3727 return results
3728
Takeshi Yoshinoe387aa32017-08-02 13:16:133729
Saagar Sanghavifceeaae2020-08-12 16:40:363730def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063731 """Check that nobody tries to include a cc file. It's a relatively
3732 common error which results in duplicate symbols in object
3733 files. This may not always break the build until someone later gets
3734 very confusing linking errors."""
3735 results = []
3736 for f in input_api.AffectedFiles(include_deletes=False):
3737 # We let third_party code do whatever it wants
3738 if (f.LocalPath().startswith('third_party') and
3739 not f.LocalPath().startswith('third_party/blink') and
3740 not f.LocalPath().startswith('third_party\\blink')):
3741 continue
3742
3743 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3744 continue
3745
3746 for _, line in f.ChangedContents():
3747 if line.startswith('#include "'):
3748 included_file = line.split('"')[1]
3749 if _IsCPlusPlusFile(input_api, included_file):
3750 # The most common naming for external files with C++ code,
3751 # apart from standard headers, is to call them foo.inc, but
3752 # Chromium sometimes uses foo-inc.cc so allow that as well.
3753 if not included_file.endswith(('.h', '-inc.cc')):
3754 results.append(output_api.PresubmitError(
3755 'Only header files or .inc files should be included in other\n'
3756 'C++ files. Compiling the contents of a cc file more than once\n'
3757 'will cause duplicate information in the build which may later\n'
3758 'result in strange link_errors.\n' +
3759 f.LocalPath() + ':\n ' +
3760 line))
3761
3762 return results
3763
3764
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203765def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3766 if not isinstance(key, ast.Str):
3767 return 'Key at line %d must be a string literal' % key.lineno
3768 if not isinstance(value, ast.Dict):
3769 return 'Value at line %d must be a dict' % value.lineno
3770 if len(value.keys) != 1:
3771 return 'Dict at line %d must have single entry' % value.lineno
3772 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3773 return (
3774 'Entry at line %d must have a string literal \'filepath\' as key' %
3775 value.lineno)
3776 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133777
Takeshi Yoshinoe387aa32017-08-02 13:16:133778
Sergey Ulanov4af16052018-11-08 02:41:463779def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203780 if not isinstance(key, ast.Str):
3781 return 'Key at line %d must be a string literal' % key.lineno
3782 if not isinstance(value, ast.List):
3783 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463784 for element in value.elts:
3785 if not isinstance(element, ast.Str):
3786 return 'Watchlist elements on line %d is not a string' % key.lineno
3787 if not email_regex.match(element.s):
3788 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3789 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203790 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133791
Takeshi Yoshinoe387aa32017-08-02 13:16:133792
Sergey Ulanov4af16052018-11-08 02:41:463793def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203794 mismatch_template = (
3795 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3796 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133797
Sergey Ulanov4af16052018-11-08 02:41:463798 email_regex = input_api.re.compile(
3799 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3800
3801 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203802 i = 0
3803 last_key = ''
3804 while True:
3805 if i >= len(wd_dict.keys):
3806 if i >= len(w_dict.keys):
3807 return None
3808 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3809 elif i >= len(w_dict.keys):
3810 return (
3811 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133812
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203813 wd_key = wd_dict.keys[i]
3814 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133815
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203816 result = _CheckWatchlistDefinitionsEntrySyntax(
3817 wd_key, wd_dict.values[i], ast)
3818 if result is not None:
3819 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133820
Sergey Ulanov4af16052018-11-08 02:41:463821 result = _CheckWatchlistsEntrySyntax(
3822 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203823 if result is not None:
3824 return 'Bad entry in WATCHLISTS dict: %s' % result
3825
3826 if wd_key.s != w_key.s:
3827 return mismatch_template % (
3828 '%s at line %d' % (wd_key.s, wd_key.lineno),
3829 '%s at line %d' % (w_key.s, w_key.lineno))
3830
3831 if wd_key.s < last_key:
3832 return (
3833 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3834 (wd_key.lineno, w_key.lineno))
3835 last_key = wd_key.s
3836
3837 i = i + 1
3838
3839
Sergey Ulanov4af16052018-11-08 02:41:463840def _CheckWATCHLISTSSyntax(expression, input_api):
3841 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203842 if not isinstance(expression, ast.Expression):
3843 return 'WATCHLISTS file must contain a valid expression'
3844 dictionary = expression.body
3845 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3846 return 'WATCHLISTS file must have single dict with exactly two entries'
3847
3848 first_key = dictionary.keys[0]
3849 first_value = dictionary.values[0]
3850 second_key = dictionary.keys[1]
3851 second_value = dictionary.values[1]
3852
3853 if (not isinstance(first_key, ast.Str) or
3854 first_key.s != 'WATCHLIST_DEFINITIONS' or
3855 not isinstance(first_value, ast.Dict)):
3856 return (
3857 'The first entry of the dict in WATCHLISTS file must be '
3858 'WATCHLIST_DEFINITIONS dict')
3859
3860 if (not isinstance(second_key, ast.Str) or
3861 second_key.s != 'WATCHLISTS' or
3862 not isinstance(second_value, ast.Dict)):
3863 return (
3864 'The second entry of the dict in WATCHLISTS file must be '
3865 'WATCHLISTS dict')
3866
Sergey Ulanov4af16052018-11-08 02:41:463867 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133868
3869
Saagar Sanghavifceeaae2020-08-12 16:40:363870def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133871 for f in input_api.AffectedFiles(include_deletes=False):
3872 if f.LocalPath() == 'WATCHLISTS':
3873 contents = input_api.ReadFile(f, 'r')
3874
3875 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203876 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133877 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203878 # Get an AST tree for it and scan the tree for detailed style checking.
3879 expression = input_api.ast.parse(
3880 contents, filename='WATCHLISTS', mode='eval')
3881 except ValueError as e:
3882 return [output_api.PresubmitError(
3883 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3884 except SyntaxError as e:
3885 return [output_api.PresubmitError(
3886 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3887 except TypeError as e:
3888 return [output_api.PresubmitError(
3889 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133890
Sergey Ulanov4af16052018-11-08 02:41:463891 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203892 if result is not None:
3893 return [output_api.PresubmitError(result)]
3894 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133895
3896 return []
3897
3898
Andrew Grieve1b290e4a22020-11-24 20:07:013899def CheckGnGlobForward(input_api, output_api):
3900 """Checks that forward_variables_from(invoker, "*") follows best practices.
3901
3902 As documented at //build/docs/writing_gn_templates.md
3903 """
3904 def gn_files(f):
3905 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3906
3907 problems = []
3908 for f in input_api.AffectedSourceFiles(gn_files):
3909 for line_num, line in f.ChangedContents():
3910 if 'forward_variables_from(invoker, "*")' in line:
3911 problems.append(
3912 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3913 f.LocalPath(), line_num))
3914
3915 if problems:
3916 return [output_api.PresubmitPromptWarning(
3917 'forward_variables_from("*") without exclusions',
3918 items=sorted(problems),
3919 long_text=('The variables "visibilty" and "test_only" should be '
3920 'explicitly listed in forward_variables_from(). For more '
3921 'details, see:\n'
3922 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
3923 'build/docs/writing_gn_templates.md'
3924 '#Using-forward_variables_from'))]
3925 return []
3926
3927
Saagar Sanghavifceeaae2020-08-12 16:40:363928def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193929 """Checks that newly added header files have corresponding GN changes.
3930 Note that this is only a heuristic. To be precise, run script:
3931 build/check_gn_headers.py.
3932 """
3933
3934 def headers(f):
3935 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443936 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193937
3938 new_headers = []
3939 for f in input_api.AffectedSourceFiles(headers):
3940 if f.Action() != 'A':
3941 continue
3942 new_headers.append(f.LocalPath())
3943
3944 def gn_files(f):
James Cook24a504192020-07-23 00:08:443945 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193946
3947 all_gn_changed_contents = ''
3948 for f in input_api.AffectedSourceFiles(gn_files):
3949 for _, line in f.ChangedContents():
3950 all_gn_changed_contents += line
3951
3952 problems = []
3953 for header in new_headers:
3954 basename = input_api.os_path.basename(header)
3955 if basename not in all_gn_changed_contents:
3956 problems.append(header)
3957
3958 if problems:
3959 return [output_api.PresubmitPromptWarning(
3960 'Missing GN changes for new header files', items=sorted(problems),
3961 long_text='Please double check whether newly added header files need '
3962 'corresponding changes in gn or gni files.\nThis checking is only a '
3963 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3964 'Read https://crbug.com/661774 for more info.')]
3965 return []
3966
3967
Saagar Sanghavifceeaae2020-08-12 16:40:363968def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:023969 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3970
3971 This assumes we won't intentionally reference one product from the other
3972 product.
3973 """
3974 all_problems = []
3975 test_cases = [{
3976 "filename_postfix": "google_chrome_strings.grd",
3977 "correct_name": "Chrome",
3978 "incorrect_name": "Chromium",
3979 }, {
3980 "filename_postfix": "chromium_strings.grd",
3981 "correct_name": "Chromium",
3982 "incorrect_name": "Chrome",
3983 }]
3984
3985 for test_case in test_cases:
3986 problems = []
3987 filename_filter = lambda x: x.LocalPath().endswith(
3988 test_case["filename_postfix"])
3989
3990 # Check each new line. Can yield false positives in multiline comments, but
3991 # easier than trying to parse the XML because messages can have nested
3992 # children, and associating message elements with affected lines is hard.
3993 for f in input_api.AffectedSourceFiles(filename_filter):
3994 for line_num, line in f.ChangedContents():
3995 if "<message" in line or "<!--" in line or "-->" in line:
3996 continue
3997 if test_case["incorrect_name"] in line:
3998 problems.append(
3999 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4000
4001 if problems:
4002 message = (
4003 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4004 % (test_case["correct_name"], test_case["correct_name"],
4005 test_case["incorrect_name"]))
4006 all_problems.append(
4007 output_api.PresubmitPromptWarning(message, items=problems))
4008
4009 return all_problems
4010
4011
Saagar Sanghavifceeaae2020-08-12 16:40:364012def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364013 """Avoid large files, especially binary files, in the repository since
4014 git doesn't scale well for those. They will be in everyone's repo
4015 clones forever, forever making Chromium slower to clone and work
4016 with."""
4017
4018 # Uploading files to cloud storage is not trivial so we don't want
4019 # to set the limit too low, but the upper limit for "normal" large
4020 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4021 # anything over 20 MB is exceptional.
4022 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4023
4024 too_large_files = []
4025 for f in input_api.AffectedFiles():
4026 # Check both added and modified files (but not deleted files).
4027 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384028 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364029 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4030 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4031
4032 if too_large_files:
4033 message = (
4034 'Do not commit large files to git since git scales badly for those.\n' +
4035 'Instead put the large files in cloud storage and use DEPS to\n' +
4036 'fetch them.\n' + '\n'.join(too_large_files)
4037 )
4038 return [output_api.PresubmitError(
4039 'Too large files found in commit', long_text=message + '\n')]
4040 else:
4041 return []
4042
Max Morozb47503b2019-08-08 21:03:274043
Saagar Sanghavifceeaae2020-08-12 16:40:364044def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274045 """Checks specific for fuzz target sources."""
4046 EXPORTED_SYMBOLS = [
4047 'LLVMFuzzerInitialize',
4048 'LLVMFuzzerCustomMutator',
4049 'LLVMFuzzerCustomCrossOver',
4050 'LLVMFuzzerMutate',
4051 ]
4052
4053 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4054
4055 def FilterFile(affected_file):
4056 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444057 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4058 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274059
4060 return input_api.FilterSourceFile(
4061 affected_file,
James Cook24a504192020-07-23 00:08:444062 files_to_check=[files_to_check],
4063 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274064
4065 files_with_missing_header = []
4066 for f in input_api.AffectedSourceFiles(FilterFile):
4067 contents = input_api.ReadFile(f, 'r')
4068 if REQUIRED_HEADER in contents:
4069 continue
4070
4071 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4072 files_with_missing_header.append(f.LocalPath())
4073
4074 if not files_with_missing_header:
4075 return []
4076
4077 long_text = (
4078 'If you define any of the libFuzzer optional functions (%s), it is '
4079 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4080 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4081 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4082 'to access command line arguments passed to the fuzzer. Instead, prefer '
4083 'static initialization and shared resources as documented in '
John Palmer0e0f72bf2021-06-07 09:10:204084 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
Max Morozb47503b2019-08-08 21:03:274085 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4086 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4087 )
4088
4089 return [output_api.PresubmitPromptWarning(
4090 message="Missing '%s' in:" % REQUIRED_HEADER,
4091 items=files_with_missing_header,
4092 long_text=long_text)]
4093
4094
Mohamed Heikald048240a2019-11-12 16:57:374095def _CheckNewImagesWarning(input_api, output_api):
4096 """
4097 Warns authors who add images into the repo to make sure their images are
4098 optimized before committing.
4099 """
4100 images_added = False
4101 image_paths = []
4102 errors = []
4103 filter_lambda = lambda x: input_api.FilterSourceFile(
4104 x,
James Cook24a504192020-07-23 00:08:444105 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4106 + input_api.DEFAULT_FILES_TO_SKIP),
4107 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374108 )
4109 for f in input_api.AffectedFiles(
4110 include_deletes=False, file_filter=filter_lambda):
4111 local_path = f.LocalPath().lower()
4112 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4113 images_added = True
4114 image_paths.append(f)
4115 if images_added:
4116 errors.append(output_api.PresubmitPromptWarning(
4117 'It looks like you are trying to commit some images. If these are '
4118 'non-test-only images, please make sure to read and apply the tips in '
4119 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4120 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4121 'FYI only and will not block your CL on the CQ.', image_paths))
4122 return errors
4123
4124
Saagar Sanghavifceeaae2020-08-12 16:40:364125def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574126 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224127 results = []
dgnaa68d5e2015-06-10 10:08:224128 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174129 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224130 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294131 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064132 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4133 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424134 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184135 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574136 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374137 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154138 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574139 return results
4140
Saagar Sanghavifceeaae2020-08-12 16:40:364141def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574142 """Groups commit checks that target android code."""
4143 results = []
4144 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224145 return results
4146
Chris Hall59f8d0c72020-05-01 07:31:194147# TODO(chrishall): could we additionally match on any path owned by
4148# ui/accessibility/OWNERS ?
4149_ACCESSIBILITY_PATHS = (
4150 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4151 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4152 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4153 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4154 r"^content[\\/]browser[\\/]accessibility[\\/]",
4155 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4156 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4157 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4158 r"^ui[\\/]accessibility[\\/]",
4159 r"^ui[\\/]views[\\/]accessibility[\\/]",
4160)
4161
Saagar Sanghavifceeaae2020-08-12 16:40:364162def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194163 """Checks that commits to accessibility code contain an AX-Relnotes field in
4164 their commit message."""
4165 def FileFilter(affected_file):
4166 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444167 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194168
4169 # Only consider changes affecting accessibility paths.
4170 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4171 return []
4172
Akihiro Ota08108e542020-05-20 15:30:534173 # AX-Relnotes can appear in either the description or the footer.
4174 # When searching the description, require 'AX-Relnotes:' to appear at the
4175 # beginning of a line.
4176 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4177 description_has_relnotes = any(ax_regex.match(line)
4178 for line in input_api.change.DescriptionText().lower().splitlines())
4179
4180 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4181 'AX-Relnotes', [])
4182 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194183 return []
4184
4185 # TODO(chrishall): link to Relnotes documentation in message.
4186 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4187 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4188 "user-facing changes"
4189 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4190 "user-facing effects"
4191 "\n if this is confusing or annoying then please contact members "
4192 "of ui/accessibility/OWNERS.")
4193
4194 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224195
seanmccullough4a9356252021-04-08 19:54:094196# string pattern, sequence of strings to show when pattern matches,
4197# error flag. True if match is a presubmit error, otherwise it's a warning.
4198_NON_INCLUSIVE_TERMS = (
4199 (
4200 # Note that \b pattern in python re is pretty particular. In this
4201 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4202 # ...' will not. This may require some tweaking to catch these cases
4203 # without triggering a lot of false positives. Leaving it naive and
4204 # less matchy for now.
4205 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4206 (
4207 'Please don\'t use blacklist, whitelist, ' # nocheck
4208 'or slave in your', # nocheck
4209 'code and make every effort to use other terms. Using "// nocheck"',
4210 '"# nocheck" or "<!-- nocheck -->"',
4211 'at the end of the offending line will bypass this PRESUBMIT error',
4212 'but avoid using this whenever possible. Reach out to',
4213 '[email protected] if you have questions'),
4214 True),)
4215
Saagar Sanghavifceeaae2020-08-12 16:40:364216def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394217 """Checks common to both upload and commit."""
4218 results = []
4219 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384220 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544221 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084222
4223 author = input_api.change.author_email
4224 if author and author not in _KNOWN_ROBOTS:
4225 results.extend(
4226 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4227
[email protected]9f919cc2013-07-31 03:04:044228 results.extend(
4229 input_api.canned_checks.CheckChangeHasNoTabs(
4230 input_api,
4231 output_api,
4232 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434233 results.extend(input_api.RunTests(
4234 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244235
Edward Lesmesce51df52020-08-04 22:10:174236 dirmd_bin = input_api.os_path.join(
4237 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4238 results.extend(input_api.RunTests(
4239 input_api.canned_checks.CheckDirMetadataFormat(
4240 input_api, output_api, dirmd_bin)))
4241 results.extend(
4242 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4243 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554244 results.extend(
4245 input_api.canned_checks.CheckNoNewMetadataInOwners(
4246 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094247 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4248 input_api, output_api,
4249 excluded_directories_relative_path = [
4250 'infra',
4251 'inclusive_language_presubmit_exempt_dirs.txt'
4252 ],
4253 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174254
Vaclav Brozekcdc7defb2018-03-20 09:54:354255 for f in input_api.AffectedFiles():
4256 path, name = input_api.os_path.split(f.LocalPath())
4257 if name == 'PRESUBMIT.py':
4258 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004259 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4260 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074261 # The PRESUBMIT.py file (and the directory containing it) might
4262 # have been affected by being moved or removed, so only try to
4263 # run the tests if they still exist.
Dirk Prankee3c9c62d2021-05-18 18:35:594264 use_python3 = False
4265 with open(f.LocalPath()) as fp:
Daniel Chengab582892021-09-30 20:53:194266 use_python3 = any(line.startswith('USE_PYTHON3 = True')
4267 for line in fp.readlines())
Dirk Prankee3c9c62d2021-05-18 18:35:594268
Dirk Pranke38557312018-04-18 00:53:074269 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4270 input_api, output_api, full_path,
Dirk Prankee3c9c62d2021-05-18 18:35:594271 files_to_check=[r'^PRESUBMIT_test\.py$'],
4272 run_on_python2=not use_python3,
4273 run_on_python3=use_python3))
[email protected]22c9bd72011-03-27 16:47:394274 return results
[email protected]1f7b4172010-01-28 01:17:344275
[email protected]b337cb5b2011-01-23 21:24:054276
Saagar Sanghavifceeaae2020-08-12 16:40:364277def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494278 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4279 if f.LocalPath().endswith(('.orig', '.rej'))]
4280 if problems:
4281 return [output_api.PresubmitError(
4282 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034283 else:
4284 return []
[email protected]b8079ae4a2012-12-05 19:56:494285
4286
Saagar Sanghavifceeaae2020-08-12 16:40:364287def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214288 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4289 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4290 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074291 include_re = input_api.re.compile(
4292 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4293 extension_re = input_api.re.compile(r'\.[a-z]+$')
4294 errors = []
Bruce Dawsonaae5e652021-06-24 15:05:394295 for f in input_api.AffectedFiles(include_deletes=False):
Kent Tamura5a8755d2017-06-29 23:37:074296 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4297 continue
4298 found_line_number = None
4299 found_macro = None
Bruce Dawsonaae5e652021-06-24 15:05:394300 all_lines = input_api.ReadFile(f, 'r').splitlines()
4301 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074302 match = macro_re.search(line)
4303 if match:
4304 found_line_number = line_num
4305 found_macro = match.group(2)
4306 break
4307 if not found_line_number:
4308 continue
4309
Bruce Dawsonaae5e652021-06-24 15:05:394310 found_include_line = -1
4311 for line_num, line in enumerate(all_lines):
Kent Tamura5a8755d2017-06-29 23:37:074312 if include_re.search(line):
Bruce Dawsonaae5e652021-06-24 15:05:394313 found_include_line = line_num
Kent Tamura5a8755d2017-06-29 23:37:074314 break
Bruce Dawsonaae5e652021-06-24 15:05:394315 if found_include_line >= 0 and found_include_line < found_line_number:
Kent Tamura5a8755d2017-06-29 23:37:074316 continue
4317
4318 if not f.LocalPath().endswith('.h'):
4319 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4320 try:
4321 content = input_api.ReadFile(primary_header_path, 'r')
4322 if include_re.search(content):
4323 continue
4324 except IOError:
4325 pass
Bruce Dawsonaae5e652021-06-24 15:05:394326 errors.append('%s:%d %s macro is used without first including build/'
Kent Tamura5a8755d2017-06-29 23:37:074327 'build_config.h.'
4328 % (f.LocalPath(), found_line_number, found_macro))
4329 if errors:
4330 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4331 return []
4332
4333
Lei Zhang1c12a22f2021-05-12 11:28:454334def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
4335 stl_include_re = input_api.re.compile(
Lei Zhang0643e342021-05-12 18:02:124336 r'^#include\s+<('
Lei Zhang1c12a22f2021-05-12 11:28:454337 r'algorithm|'
4338 r'array|'
4339 r'limits|'
4340 r'list|'
4341 r'map|'
4342 r'memory|'
4343 r'queue|'
4344 r'set|'
4345 r'string|'
4346 r'unordered_map|'
4347 r'unordered_set|'
4348 r'utility|'
Lei Zhang0643e342021-05-12 18:02:124349 r'vector)>')
Lei Zhang1c12a22f2021-05-12 11:28:454350 std_namespace_re = input_api.re.compile(r'std::')
4351 errors = []
4352 for f in input_api.AffectedFiles():
4353 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4354 continue
4355
4356 uses_std_namespace = False
4357 has_stl_include = False
4358 for line in f.NewContents():
4359 if has_stl_include and uses_std_namespace:
4360 break
4361
4362 if not has_stl_include and stl_include_re.search(line):
4363 has_stl_include = True
4364 continue
4365
4366 if not uses_std_namespace and std_namespace_re.search(line):
4367 uses_std_namespace = True
4368 continue
4369
4370 if has_stl_include and not uses_std_namespace:
4371 errors.append('%s: Includes STL header(s) but does not reference std::'
4372 % f.LocalPath())
4373 if errors:
4374 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4375 return []
4376
4377
[email protected]b00342e7f2013-03-26 16:21:544378def _DidYouMeanOSMacro(bad_macro):
4379 try:
4380 return {'A': 'OS_ANDROID',
4381 'B': 'OS_BSD',
4382 'C': 'OS_CHROMEOS',
4383 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444384 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544385 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444386 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544387 'N': 'OS_NACL',
4388 'O': 'OS_OPENBSD',
4389 'P': 'OS_POSIX',
4390 'S': 'OS_SOLARIS',
4391 'W': 'OS_WIN'}[bad_macro[3].upper()]
4392 except KeyError:
4393 return ''
4394
4395
4396def _CheckForInvalidOSMacrosInFile(input_api, f):
4397 """Check for sensible looking, totally invalid OS macros."""
4398 preprocessor_statement = input_api.re.compile(r'^\s*#')
4399 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4400 results = []
4401 for lnum, line in f.ChangedContents():
4402 if preprocessor_statement.search(line):
4403 for match in os_macro.finditer(line):
4404 if not match.group(1) in _VALID_OS_MACROS:
4405 good = _DidYouMeanOSMacro(match.group(1))
4406 did_you_mean = ' (did you mean %s?)' % good if good else ''
4407 results.append(' %s:%d %s%s' % (f.LocalPath(),
4408 lnum,
4409 match.group(1),
4410 did_you_mean))
4411 return results
4412
4413
Saagar Sanghavifceeaae2020-08-12 16:40:364414def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544415 """Check all affected files for invalid OS macros."""
4416 bad_macros = []
tzik3f295992018-12-04 20:32:234417 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474418 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544419 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4420
4421 if not bad_macros:
4422 return []
4423
4424 return [output_api.PresubmitError(
4425 'Possibly invalid OS macro[s] found. Please fix your code\n'
4426 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4427
lliabraa35bab3932014-10-01 12:16:444428
4429def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4430 """Check all affected files for invalid "if defined" macros."""
4431 ALWAYS_DEFINED_MACROS = (
4432 "TARGET_CPU_PPC",
4433 "TARGET_CPU_PPC64",
4434 "TARGET_CPU_68K",
4435 "TARGET_CPU_X86",
4436 "TARGET_CPU_ARM",
4437 "TARGET_CPU_MIPS",
4438 "TARGET_CPU_SPARC",
4439 "TARGET_CPU_ALPHA",
4440 "TARGET_IPHONE_SIMULATOR",
4441 "TARGET_OS_EMBEDDED",
4442 "TARGET_OS_IPHONE",
4443 "TARGET_OS_MAC",
4444 "TARGET_OS_UNIX",
4445 "TARGET_OS_WIN32",
4446 )
4447 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4448 results = []
4449 for lnum, line in f.ChangedContents():
4450 for match in ifdef_macro.finditer(line):
4451 if match.group(1) in ALWAYS_DEFINED_MACROS:
4452 always_defined = ' %s is always defined. ' % match.group(1)
4453 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4454 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4455 lnum,
4456 always_defined,
4457 did_you_mean))
4458 return results
4459
4460
Saagar Sanghavifceeaae2020-08-12 16:40:364461def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444462 """Check all affected files for invalid "if defined" macros."""
4463 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054464 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444465 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054466 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214467 continue
lliabraa35bab3932014-10-01 12:16:444468 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4469 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4470
4471 if not bad_macros:
4472 return []
4473
4474 return [output_api.PresubmitError(
4475 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4476 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4477 bad_macros)]
4478
4479
Saagar Sanghavifceeaae2020-08-12 16:40:364480def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044481 """Check for same IPC rules described in
4482 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4483 """
4484 base_pattern = r'IPC_ENUM_TRAITS\('
4485 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4486 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4487
4488 problems = []
4489 for f in input_api.AffectedSourceFiles(None):
4490 local_path = f.LocalPath()
4491 if not local_path.endswith('.h'):
4492 continue
4493 for line_number, line in f.ChangedContents():
4494 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4495 problems.append(
4496 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4497
4498 if problems:
4499 return [output_api.PresubmitPromptWarning(
4500 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4501 else:
4502 return []
4503
[email protected]b00342e7f2013-03-26 16:21:544504
Saagar Sanghavifceeaae2020-08-12 16:40:364505def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054506 """Check to make sure no files being submitted have long paths.
4507 This causes issues on Windows.
4508 """
4509 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194510 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054511 local_path = f.LocalPath()
4512 # Windows has a path limit of 260 characters. Limit path length to 200 so
4513 # that we have some extra for the prefix on dev machines and the bots.
4514 if len(local_path) > 200:
4515 problems.append(local_path)
4516
4517 if problems:
4518 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4519 else:
4520 return []
4521
4522
Saagar Sanghavifceeaae2020-08-12 16:40:364523def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144524 """Check that header files have proper guards against multiple inclusion.
4525 If a file should not have such guards (and it probably should) then it
4526 should include the string "no-include-guard-because-multiply-included".
4527 """
Daniel Bratell6a75baef62018-06-04 10:04:454528 def is_chromium_header_file(f):
4529 # We only check header files under the control of the Chromium
4530 # project. That is, those outside third_party apart from
4531 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324532 # We also exclude *_message_generator.h headers as they use
4533 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454534 file_with_path = input_api.os_path.normpath(f.LocalPath())
4535 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324536 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454537 (not file_with_path.startswith('third_party') or
4538 file_with_path.startswith(
4539 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144540
4541 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344542 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144543
4544 errors = []
4545
Daniel Bratell6a75baef62018-06-04 10:04:454546 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144547 guard_name = None
4548 guard_line_number = None
4549 seen_guard_end = False
4550
4551 file_with_path = input_api.os_path.normpath(f.LocalPath())
4552 base_file_name = input_api.os_path.splitext(
4553 input_api.os_path.basename(file_with_path))[0]
4554 upper_base_file_name = base_file_name.upper()
4555
4556 expected_guard = replace_special_with_underscore(
4557 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144558
4559 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574560 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4561 # are too many (1000+) files with slight deviations from the
4562 # coding style. The most important part is that the include guard
4563 # is there, and that it's unique, not the name so this check is
4564 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144565 #
4566 # As code becomes more uniform, this could be made stricter.
4567
4568 guard_name_pattern_list = [
4569 # Anything with the right suffix (maybe with an extra _).
4570 r'\w+_H__?',
4571
Daniel Bratell39b5b062018-05-16 18:09:574572 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144573 r'\w+_h',
4574
4575 # Anything including the uppercase name of the file.
4576 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4577 upper_base_file_name)) + r'\w*',
4578 ]
4579 guard_name_pattern = '|'.join(guard_name_pattern_list)
4580 guard_pattern = input_api.re.compile(
4581 r'#ifndef\s+(' + guard_name_pattern + ')')
4582
4583 for line_number, line in enumerate(f.NewContents()):
4584 if 'no-include-guard-because-multiply-included' in line:
4585 guard_name = 'DUMMY' # To not trigger check outside the loop.
4586 break
4587
4588 if guard_name is None:
4589 match = guard_pattern.match(line)
4590 if match:
4591 guard_name = match.group(1)
4592 guard_line_number = line_number
4593
Daniel Bratell39b5b062018-05-16 18:09:574594 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454595 # don't match the chromium style guide, but new files should
4596 # get it right.
4597 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574598 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144599 errors.append(output_api.PresubmitPromptWarning(
4600 'Header using the wrong include guard name %s' % guard_name,
4601 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574602 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144603 else:
4604 # The line after #ifndef should have a #define of the same name.
4605 if line_number == guard_line_number + 1:
4606 expected_line = '#define %s' % guard_name
4607 if line != expected_line:
4608 errors.append(output_api.PresubmitPromptWarning(
4609 'Missing "%s" for include guard' % expected_line,
4610 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4611 'Expected: %r\nGot: %r' % (expected_line, line)))
4612
4613 if not seen_guard_end and line == '#endif // %s' % guard_name:
4614 seen_guard_end = True
4615 elif seen_guard_end:
4616 if line.strip() != '':
4617 errors.append(output_api.PresubmitPromptWarning(
4618 'Include guard %s not covering the whole file' % (
4619 guard_name), [f.LocalPath()]))
4620 break # Nothing else to check and enough to warn once.
4621
4622 if guard_name is None:
4623 errors.append(output_api.PresubmitPromptWarning(
4624 'Missing include guard %s' % expected_guard,
4625 [f.LocalPath()],
4626 'Missing include guard in %s\n'
4627 'Recommended name: %s\n'
4628 'This check can be disabled by having the string\n'
4629 'no-include-guard-because-multiply-included in the header.' %
4630 (f.LocalPath(), expected_guard)))
4631
4632 return errors
4633
4634
Saagar Sanghavifceeaae2020-08-12 16:40:364635def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234636 """Check source code and known ascii text files for Windows style line
4637 endings.
4638 """
Evan Stade6cfc964c12021-05-18 20:21:164639 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234640
4641 file_inclusion_pattern = (
4642 known_text_files,
Bruce Dawson6141d4a2021-06-08 15:56:114643 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4644 r'.+%s' % _HEADER_EXTENSIONS
mostynbb639aca52015-01-07 20:31:234645 )
4646
mostynbb639aca52015-01-07 20:31:234647 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534648 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444649 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534650 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504651 include_file = False
Bruce Dawsonb2cfdfe2021-06-10 19:01:204652 for line in input_api.ReadFile(f, 'r').splitlines(True):
mostynbb639aca52015-01-07 20:31:234653 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504654 include_file = True
4655 if include_file:
4656 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234657
4658 if problems:
4659 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4660 'these files to contain Windows style line endings?\n' +
4661 '\n'.join(problems))]
4662
4663 return []
4664
Evan Stade6cfc964c12021-05-18 20:21:164665def CheckIconFilesForLicenseHeaders(input_api, output_api):
4666 """Check that .icon files (which are fragments of C++) have license headers.
4667 """
4668
4669 icon_files = (r'.*\.icon$',)
4670
4671 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4672 return input_api.canned_checks.CheckLicense(
4673 input_api, output_api, source_file_filter=icons)
4674
Jose Magana2b456f22021-03-09 23:26:404675def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4676 """Check source code for use of Chrome App technologies being
4677 deprecated.
4678 """
4679
4680 def _CheckForDeprecatedTech(input_api, output_api,
4681 detection_list, files_to_check = None, files_to_skip = None):
4682
4683 if (files_to_check or files_to_skip):
4684 source_file_filter = lambda f: input_api.FilterSourceFile(
4685 f, files_to_check=files_to_check,
4686 files_to_skip=files_to_skip)
4687 else:
4688 source_file_filter = None
4689
4690 problems = []
4691
4692 for f in input_api.AffectedSourceFiles(source_file_filter):
4693 if f.Action() == 'D':
4694 continue
4695 for _, line in f.ChangedContents():
4696 if any( detect in line for detect in detection_list ):
4697 problems.append(f.LocalPath())
4698
4699 return problems
4700
4701 # to avoid this presubmit script triggering warnings
4702 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4703
4704 problems =[]
4705
4706 # NMF: any files with extensions .nmf or NMF
4707 _NMF_FILES = r'\.(nmf|NMF)$'
4708 problems += _CheckForDeprecatedTech(input_api, output_api,
4709 detection_list = [''], # any change to the file will trigger warning
4710 files_to_check = [ r'.+%s' % _NMF_FILES ])
4711
4712 # MANIFEST: any manifest.json that in its diff includes "app":
4713 _MANIFEST_FILES = r'(manifest\.json)$'
4714 problems += _CheckForDeprecatedTech(input_api, output_api,
4715 detection_list = ['"app":'],
4716 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4717
4718 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4719 problems += _CheckForDeprecatedTech(input_api, output_api,
4720 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4721 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4722
4723 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4724 problems += _CheckForDeprecatedTech(input_api, output_api,
4725 detection_list = ['#include "ppapi','#include <ppapi'],
4726 files_to_check = (
4727 r'.+%s' % _HEADER_EXTENSIONS,
4728 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4729 files_to_skip = [r"^ppapi[\\/]"] )
4730
Jose Magana2b456f22021-03-09 23:26:404731 if problems:
4732 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4733 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4734 ' PNaCl, PPAPI). See this blog post for more details:\n'
4735 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4736 'and this documentation for options to replace these technologies:\n'
4737 'https://developer.chrome.com/docs/apps/migration/\n'+
4738 '\n'.join(problems))]
4739
4740 return []
4741
mostynbb639aca52015-01-07 20:31:234742
Saagar Sanghavifceeaae2020-08-12 16:40:364743def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134744 """Checks that all source files use SYSLOG properly."""
4745 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364746 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564747 for line_number, line in f.ChangedContents():
4748 if 'SYSLOG' in line:
4749 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4750
pastarmovj89f7ee12016-09-20 14:58:134751 if syslog_files:
4752 return [output_api.PresubmitPromptWarning(
4753 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4754 ' calls.\nFiles to check:\n', items=syslog_files)]
4755 return []
4756
4757
[email protected]1f7b4172010-01-28 01:17:344758def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364759 if input_api.version < [2, 0, 0]:
4760 return [output_api.PresubmitError("Your depot_tools is out of date. "
4761 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4762 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344763 results = []
scottmg39b29952014-12-08 18:31:284764 results.extend(
jam93a6ee792017-02-08 23:59:224765 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544766 return results
[email protected]ca8d1982009-02-19 16:33:124767
4768
4769def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364770 if input_api.version < [2, 0, 0]:
4771 return [output_api.PresubmitError("Your depot_tools is out of date. "
4772 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4773 "but your version is %d.%d.%d" % tuple(input_api.version))]
4774
[email protected]fe5f57c52009-06-05 14:25:544775 results = []
[email protected]fe5f57c52009-06-05 14:25:544776 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274777 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344778 input_api,
4779 output_api,
[email protected]2fdd1f362013-01-16 03:56:034780 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274781
jam93a6ee792017-02-08 23:59:224782 results.extend(
4783 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544784 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4785 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384786 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4787 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414788 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4789 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544790 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144791
4792
Saagar Sanghavifceeaae2020-08-12 16:40:364793def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264794 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024795 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4796 # footer is set to true.
4797 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264798 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024799 footer.lower()
4800 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264801 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024802
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144803 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264804 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144805 import sys
4806 from io import StringIO
4807
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144808 new_or_added_paths = set(f.LocalPath()
4809 for f in input_api.AffectedFiles()
4810 if (f.Action() == 'A' or f.Action() == 'M'))
4811 removed_paths = set(f.LocalPath()
4812 for f in input_api.AffectedFiles(include_deletes=True)
4813 if f.Action() == 'D')
4814
Andrew Grieve0e8790c2020-09-03 17:27:324815 affected_grds = [
4816 f for f in input_api.AffectedFiles()
4817 if f.LocalPath().endswith(('.grd', '.grdp'))
4818 ]
4819 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164820 if not affected_grds:
4821 return []
4822
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144823 affected_png_paths = [f.AbsoluteLocalPath()
4824 for f in input_api.AffectedFiles()
4825 if (f.LocalPath().endswith('.png'))]
4826
4827 # Check for screenshots. Developers can upload screenshots using
4828 # tools/translation/upload_screenshots.py which finds and uploads
4829 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4830 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4831 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4832 #
4833 # The logic here is as follows:
4834 #
4835 # - If the CL has a .png file under the screenshots directory for a grd
4836 # file, warn the developer. Actual images should never be checked into the
4837 # Chrome repo.
4838 #
4839 # - If the CL contains modified or new messages in grd files and doesn't
4840 # contain the corresponding .sha1 files, warn the developer to add images
4841 # and upload them via tools/translation/upload_screenshots.py.
4842 #
4843 # - If the CL contains modified or new messages in grd files and the
4844 # corresponding .sha1 files, everything looks good.
4845 #
4846 # - If the CL contains removed messages in grd files but the corresponding
4847 # .sha1 files aren't removed, warn the developer to remove them.
4848 unnecessary_screenshots = []
4849 missing_sha1 = []
4850 unnecessary_sha1_files = []
4851
Rainhard Findlingfc31844c52020-05-15 09:58:264852 # This checks verifies that the ICU syntax of messages this CL touched is
4853 # valid, and reports any found syntax errors.
4854 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4855 # without developers being aware of them. Later on, such ICU syntax errors
4856 # break message extraction for translation, hence would block Chromium
4857 # translations until they are fixed.
4858 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144859
4860 def _CheckScreenshotAdded(screenshots_dir, message_id):
4861 sha1_path = input_api.os_path.join(
4862 screenshots_dir, message_id + '.png.sha1')
4863 if sha1_path not in new_or_added_paths:
4864 missing_sha1.append(sha1_path)
4865
4866
4867 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4868 sha1_path = input_api.os_path.join(
4869 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034870 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144871 unnecessary_sha1_files.append(sha1_path)
4872
Rainhard Findlingfc31844c52020-05-15 09:58:264873
4874 def _ValidateIcuSyntax(text, level, signatures):
Daniel Chengab582892021-09-30 20:53:194875 """Validates ICU syntax of a text string.
Rainhard Findlingfc31844c52020-05-15 09:58:264876
4877 Check if text looks similar to ICU and checks for ICU syntax correctness
4878 in this case. Reports various issues with ICU syntax and values of
4879 variants. Supports checking of nested messages. Accumulate information of
4880 each ICU messages found in the text for further checking.
4881
4882 Args:
4883 text: a string to check.
4884 level: a number of current nesting level.
4885 signatures: an accumulator, a list of tuple of (level, variable,
4886 kind, variants).
4887
4888 Returns:
4889 None if a string is not ICU or no issue detected.
4890 A tuple of (message, start index, end index) if an issue detected.
4891 """
Daniel Chengab582892021-09-30 20:53:194892 valid_types = {
4893 'plural': (frozenset(
4894 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4895 frozenset(['=1', 'other'])),
4896 'selectordinal': (frozenset(
4897 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4898 frozenset(['one', 'other'])),
4899 'select': (frozenset(), frozenset(['other'])),
4900 }
Rainhard Findlingfc31844c52020-05-15 09:58:264901
Daniel Chengab582892021-09-30 20:53:194902 # Check if the message looks like an attempt to use ICU
4903 # plural. If yes - check if its syntax strictly matches ICU format.
4904 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4905 if not like:
4906 signatures.append((level, None, None, None))
4907 return
Rainhard Findlingfc31844c52020-05-15 09:58:264908
Daniel Chengab582892021-09-30 20:53:194909 # Check for valid prefix and suffix
4910 m = re.match(
4911 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4912 r'(plural|selectordinal|select),\s*'
4913 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4914 if not m:
4915 return (('This message looks like an ICU plural, '
4916 'but does not follow ICU syntax.'), like.start(), like.end())
4917 starting, variable, kind, variant_pairs = m.groups()
4918 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4919 if depth:
4920 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4921 len(text))
4922 first = text[0]
4923 ending = text[last_pos:]
4924 if not starting:
4925 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4926 last_pos)
4927 if not ending or '}' not in ending:
4928 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4929 last_pos)
4930 elif first != '{':
4931 return (
4932 ('Invalid ICU format. Extra characters at the start of a complex '
4933 'message (go/icu-message-migration): "%s"') %
4934 starting, 0, len(starting))
4935 elif ending != '}':
4936 return (('Invalid ICU format. Extra characters at the end of a complex '
4937 'message (go/icu-message-migration): "%s"')
4938 % ending, last_pos - 1, len(text) - 1)
4939 if kind not in valid_types:
4940 return (('Unknown ICU message type %s. '
4941 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4942 known, required = valid_types[kind]
4943 defined_variants = set()
4944 for variant, variant_range, value, value_range in variants:
4945 start, end = variant_range
4946 if variant in defined_variants:
4947 return ('Variant "%s" is defined more than once' % variant,
4948 start, end)
4949 elif known and variant not in known:
4950 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4951 start, end)
4952 defined_variants.add(variant)
4953 # Check for nested structure
4954 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4955 if res:
4956 return (res[0], res[1] + value_range[0] + 1,
4957 res[2] + value_range[0] + 1)
4958 missing = required - defined_variants
4959 if missing:
4960 return ('Required variants missing: %s' % ', '.join(missing), 0,
4961 len(text))
4962 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:264963
4964
4965 def _ParseIcuVariants(text, offset=0):
4966 """Parse variants part of ICU complex message.
4967
4968 Builds a tuple of variant names and values, as well as
4969 their offsets in the input string.
4970
4971 Args:
4972 text: a string to parse
4973 offset: additional offset to add to positions in the text to get correct
4974 position in the complete ICU string.
4975
4976 Returns:
4977 List of tuples, each tuple consist of four fields: variant name,
4978 variant name span (tuple of two integers), variant value, value
4979 span (tuple of two integers).
4980 """
4981 depth, start, end = 0, -1, -1
4982 variants = []
4983 key = None
4984 for idx, char in enumerate(text):
4985 if char == '{':
4986 if not depth:
4987 start = idx
4988 chunk = text[end + 1:start]
4989 key = chunk.strip()
4990 pos = offset + end + 1 + chunk.find(key)
4991 span = (pos, pos + len(key))
4992 depth += 1
4993 elif char == '}':
4994 if not depth:
4995 return variants, depth, offset + idx
4996 depth -= 1
4997 if not depth:
4998 end = idx
4999 variants.append((key, span, text[start:end + 1], (offset + start,
5000 offset + end + 1)))
5001 return variants, depth, offset + end + 1
5002
meacer8c0d3832019-12-26 21:46:165003 try:
5004 old_sys_path = sys.path
5005 sys.path = sys.path + [input_api.os_path.join(
5006 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5007 from helper import grd_helper
5008 finally:
5009 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145010
5011 for f in affected_grds:
5012 file_path = f.LocalPath()
5013 old_id_to_msg_map = {}
5014 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385015 # Note that this code doesn't check if the file has been deleted. This is
5016 # OK because it only uses the old and new file contents and doesn't load
5017 # the file via its path.
5018 # It's also possible that a file's content refers to a renamed or deleted
5019 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5020 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5021 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145022 if file_path.endswith('.grdp'):
5023 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585024 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595025 '\n'.join(f.OldContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145026 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585027 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Dirk Prankee3c9c62d2021-05-18 18:35:595028 '\n'.join(f.NewContents()))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145029 else:
meacerff8a9b62019-12-10 19:43:585030 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145031 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585032 old_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595033 StringIO('\n'.join(f.OldContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145034 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585035 new_id_to_msg_map = grd_helper.GetGrdMessages(
Dirk Prankee3c9c62d2021-05-18 18:35:595036 StringIO('\n'.join(f.NewContents())), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145037
Rainhard Findlingd8d04372020-08-13 13:30:095038 grd_name, ext = input_api.os_path.splitext(
5039 input_api.os_path.basename(file_path))
5040 screenshots_dir = input_api.os_path.join(
5041 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5042
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145043 # Compute added, removed and modified message IDs.
5044 old_ids = set(old_id_to_msg_map)
5045 new_ids = set(new_id_to_msg_map)
5046 added_ids = new_ids - old_ids
5047 removed_ids = old_ids - new_ids
5048 modified_ids = set([])
5049 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355050 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095051 != new_id_to_msg_map[key].ContentsAsXml('', True)):
Daniel Chengab582892021-09-30 20:53:195052 # The message content itself changed. Require an updated screenshot.
5053 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355054 elif old_id_to_msg_map[key].attrs['meaning'] != \
5055 new_id_to_msg_map[key].attrs['meaning']:
5056 # The message meaning changed. Ensure there is a screenshot for it.
5057 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5058 if sha1_path not in new_or_added_paths and not \
5059 input_api.os_path.exists(sha1_path):
5060 # There is neither a previous screenshot nor is a new one added now.
5061 # Require a screenshot.
5062 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145063
Rainhard Findlingfc31844c52020-05-15 09:58:265064 if run_screenshot_check:
5065 # Check the screenshot directory for .png files. Warn if there is any.
5066 for png_path in affected_png_paths:
5067 if png_path.startswith(screenshots_dir):
5068 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145069
Rainhard Findlingfc31844c52020-05-15 09:58:265070 for added_id in added_ids:
5071 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145072
Rainhard Findlingfc31844c52020-05-15 09:58:265073 for modified_id in modified_ids:
5074 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145075
Rainhard Findlingfc31844c52020-05-15 09:58:265076 for removed_id in removed_ids:
5077 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5078
5079 # Check new and changed strings for ICU syntax errors.
5080 for key in added_ids.union(modified_ids):
5081 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5082 err = _ValidateIcuSyntax(msg, 0, [])
5083 if err is not None:
5084 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145085
5086 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265087 if run_screenshot_check:
5088 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005089 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265090 'Do not include actual screenshots in the changelist. Run '
5091 'tools/translate/upload_screenshots.py to upload them instead:',
5092 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145093
Rainhard Findlingfc31844c52020-05-15 09:58:265094 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005095 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265096 'You are adding or modifying UI strings.\n'
5097 'To ensure the best translations, take screenshots of the relevant UI '
5098 '(https://g.co/chrome/translation) and add these files to your '
5099 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145100
Rainhard Findlingfc31844c52020-05-15 09:58:265101 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005102 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265103 'You removed strings associated with these files. Remove:',
5104 sorted(unnecessary_sha1_files)))
5105 else:
5106 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5107 'screenshots check.'))
5108
5109 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075110 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265111 'ICU syntax errors were found in the following strings (problems or '
5112 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145113
5114 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125115
5116
Saagar Sanghavifceeaae2020-08-12 16:40:365117def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125118 repo_root=None,
5119 translation_expectations_path=None,
5120 grd_files=None):
5121 import sys
5122 affected_grds = [f for f in input_api.AffectedFiles()
5123 if (f.LocalPath().endswith('.grd') or
5124 f.LocalPath().endswith('.grdp'))]
5125 if not affected_grds:
5126 return []
5127
5128 try:
5129 old_sys_path = sys.path
5130 sys.path = sys.path + [
5131 input_api.os_path.join(
5132 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5133 from helper import git_helper
5134 from helper import translation_helper
5135 finally:
5136 sys.path = old_sys_path
5137
5138 # Check that translation expectations can be parsed and we can get a list of
5139 # translatable grd files. |repo_root| and |translation_expectations_path| are
5140 # only passed by tests.
5141 if not repo_root:
5142 repo_root = input_api.PresubmitLocalPath()
5143 if not translation_expectations_path:
5144 translation_expectations_path = input_api.os_path.join(
5145 repo_root, 'tools', 'gritsettings',
5146 'translation_expectations.pyl')
5147 if not grd_files:
5148 grd_files = git_helper.list_grds_in_repository(repo_root)
5149
dpapad8e21b472020-10-23 17:15:035150 # Ignore bogus grd files used only for testing
5151 # ui/webui/resoucres/tools/generate_grd.py.
5152 ignore_path = input_api.os_path.join(
5153 'ui', 'webui', 'resources', 'tools', 'tests')
Dirk Prankee3c9c62d2021-05-18 18:35:595154 grd_files = [p for p in grd_files if ignore_path not in p]
dpapad8e21b472020-10-23 17:15:035155
Mustafa Emre Acer51f2f742020-03-09 19:41:125156 try:
5157 translation_helper.get_translatable_grds(repo_root, grd_files,
5158 translation_expectations_path)
5159 except Exception as e:
5160 return [output_api.PresubmitNotifyResult(
5161 'Failed to get a list of translatable grd files. This happens when:\n'
5162 ' - One of the modified grd or grdp files cannot be parsed or\n'
5163 ' - %s is not updated.\n'
5164 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5165 return []
Ken Rockotc31f4832020-05-29 18:58:515166
5167
Saagar Sanghavifceeaae2020-08-12 16:40:365168def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515169 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095170 changed_mojoms = input_api.AffectedFiles(
5171 include_deletes=True,
5172 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515173 delta = []
5174 for mojom in changed_mojoms:
5175 old_contents = ''.join(mojom.OldContents()) or None
5176 new_contents = ''.join(mojom.NewContents()) or None
5177 delta.append({
5178 'filename': mojom.LocalPath(),
5179 'old': '\n'.join(mojom.OldContents()) or None,
5180 'new': '\n'.join(mojom.NewContents()) or None,
5181 })
5182
5183 process = input_api.subprocess.Popen(
5184 [input_api.python_executable,
5185 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5186 'public', 'tools', 'mojom',
5187 'check_stable_mojom_compatibility.py'),
5188 '--src-root', input_api.PresubmitLocalPath()],
5189 stdin=input_api.subprocess.PIPE,
5190 stdout=input_api.subprocess.PIPE,
5191 stderr=input_api.subprocess.PIPE,
5192 universal_newlines=True)
5193 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5194 if process.returncode:
5195 return [output_api.PresubmitError(
5196 'One or more [Stable] mojom definitions appears to have been changed '
5197 'in a way that is not backward-compatible.',
5198 long_text=error)]
5199 return []
Dominic Battre645d42342020-12-04 16:14:105200
5201def CheckDeprecationOfPreferences(input_api, output_api):
5202 """Removing a preference should come with a deprecation."""
5203
5204 def FilterFile(affected_file):
5205 """Accept only .cc files and the like."""
5206 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5207 files_to_skip = (_EXCLUDED_PATHS +
5208 _TEST_CODE_EXCLUDED_PATHS +
5209 input_api.DEFAULT_FILES_TO_SKIP)
5210 return input_api.FilterSourceFile(
5211 affected_file,
5212 files_to_check=file_inclusion_pattern,
5213 files_to_skip=files_to_skip)
5214
5215 def ModifiedLines(affected_file):
5216 """Returns a list of tuples (line number, line text) of added and removed
5217 lines.
5218
5219 Deleted lines share the same line number as the previous line.
5220
5221 This relies on the scm diff output describing each changed code section
5222 with a line of the form
5223
5224 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5225 """
5226 line_num = 0
5227 modified_lines = []
5228 for line in affected_file.GenerateScmDiff().splitlines():
5229 # Extract <new line num> of the patch fragment (see format above).
5230 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5231 if m:
5232 line_num = int(m.groups(1)[0])
5233 continue
5234 if ((line.startswith('+') and not line.startswith('++')) or
5235 (line.startswith('-') and not line.startswith('--'))):
5236 modified_lines.append((line_num, line))
5237
5238 if not line.startswith('-'):
5239 line_num += 1
5240 return modified_lines
5241
5242 def FindLineWith(lines, needle):
5243 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5244
5245 If 0 or >1 lines contain `needle`, -1 is returned.
5246 """
5247 matching_line_numbers = [
5248 # + 1 for 1-based counting of line numbers.
5249 i + 1 for i, line
5250 in enumerate(lines)
5251 if needle in line]
5252 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5253
5254 def ModifiedPrefMigration(affected_file):
5255 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5256 # Determine first and last lines of MigrateObsolete.*Pref functions.
5257 new_contents = affected_file.NewContents();
5258 range_1 = (
5259 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5260 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5261 range_2 = (
5262 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5263 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5264 if (-1 in range_1 + range_2):
5265 raise Exception(
5266 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5267
5268 # Check whether any of the modified lines are part of the
5269 # MigrateObsolete.*Pref functions.
5270 for line_nr, line in ModifiedLines(affected_file):
5271 if (range_1[0] <= line_nr <= range_1[1] or
5272 range_2[0] <= line_nr <= range_2[1]):
5273 return True
5274 return False
5275
5276 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5277 browser_prefs_file_pattern = input_api.re.compile(
5278 r'chrome/browser/prefs/browser_prefs.cc')
5279
5280 changes = input_api.AffectedFiles(include_deletes=True,
5281 file_filter=FilterFile)
5282 potential_problems = []
5283 for f in changes:
5284 for line in f.GenerateScmDiff().splitlines():
5285 # Check deleted lines for pref registrations.
5286 if (line.startswith('-') and not line.startswith('--') and
5287 register_pref_pattern.search(line)):
5288 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5289
5290 if browser_prefs_file_pattern.search(f.LocalPath()):
5291 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5292 # assume that they knew that they have to deprecate preferences and don't
5293 # warn.
5294 try:
5295 if ModifiedPrefMigration(f):
5296 return []
5297 except Exception as e:
5298 return [output_api.PresubmitError(str(e))]
5299
5300 if potential_problems:
5301 return [output_api.PresubmitPromptWarning(
5302 'Discovered possible removal of preference registrations.\n\n'
5303 'Please make sure to properly deprecate preferences by clearing their\n'
5304 'value for a couple of milestones before finally removing the code.\n'
5305 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195306 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5307 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105308 'This may be a false positive warning (e.g. if you move preference\n'
5309 'registrations to a different place).\n',
5310 potential_problems
5311 )]
5312 return []
Matt Stark6ef08872021-07-29 01:21:465313
5314def CheckConsistentGrdChanges(input_api, output_api):
5315 """Changes to GRD files must be consistent for tools to read them."""
5316 changed_grds = input_api.AffectedFiles(
5317 include_deletes=False,
5318 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5319 errors = []
Daniel Chengab582892021-09-30 20:53:195320 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5321 for matcher, msg in _INVALID_GRD_FILE_LINE]
Matt Stark6ef08872021-07-29 01:21:465322 for grd in changed_grds:
5323 for i, line in enumerate(grd.NewContents()):
5324 for matcher, msg in invalid_file_regexes:
5325 if matcher.search(line):
Daniel Chengab582892021-09-30 20:53:195326 errors.append(
5327 output_api.PresubmitError('Problem on {grd}:{i} - {msg}'.format(
5328 grd=grd.LocalPath(), i=i + 1, msg=msg)))
Matt Stark6ef08872021-07-29 01:21:465329 return errors