blob: a75d8f9596bd23c0dc1e6b2d150ce068f16bd87c [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
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Ilya Shermane8a7d2d2020-07-25 04:33:4713 # Generated file.
14 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2615 r"client_variations.js"),
Egor Paskoce145c42018-09-28 19:31:0416 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
17 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
18 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
19 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
20 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4921 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4623 # sqlite is an imported third party dependency.
24 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0425 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5426 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5327 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1228 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0429 r".+[\\/]pnacl_shim\.c$",
30 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0431 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1432 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0433 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5434 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0435 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4036)
[email protected]ca8d1982009-02-19 16:33:1237
John Abd-El-Malek759fea62021-03-13 03:41:1438_EXCLUDED_SET_NO_PARENT_PATHS = (
39 # It's for historical reasons that blink isn't a top level directory, where
40 # it would be allowed to have "set noparent" to avoid top level owners
41 # accidentally +1ing changes.
42 'third_party/blink/OWNERS',
43)
44
wnwenbdc444e2016-05-25 13:44:1545
[email protected]06e6d0ff2012-12-11 01:36:4446# Fragment of a regular expression that matches C++ and Objective-C++
47# implementation files.
48_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
49
wnwenbdc444e2016-05-25 13:44:1550
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1951# Fragment of a regular expression that matches C++ and Objective-C++
52# header files.
53_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
54
55
[email protected]06e6d0ff2012-12-11 01:36:4456# Regular expression that matches code only used for test binaries
57# (best effort).
58_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0459 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4460 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1361 # Test suite files, like:
62 # foo_browsertest.cc
63 # bar_unittest_mac.cc (suffix)
64 # baz_unittests.cc (plural)
65 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1266 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1867 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4468 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0469 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4370 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0471 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4372 # Web test harness.
73 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4774 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0475 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0876 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0477 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4178 # EarlGrey app side code for tests.
79 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1780 # Views Examples code
81 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4182 # Chromium Codelab
83 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4484)
[email protected]ca8d1982009-02-19 16:33:1285
Daniel Bratell609102be2019-03-27 20:53:2186_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1587
[email protected]eea609a2011-11-18 13:10:1288_TEST_ONLY_WARNING = (
89 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5590 'production code. If you are doing this from inside another method\n'
91 'named as *ForTesting(), then consider exposing things to have tests\n'
92 'make that same call directly.\n'
93 'If that is not possible, you may put a comment on the same line with\n'
94 ' // IN-TEST \n'
95 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
96 'method and can be ignored. Do not do this inside production code.\n'
97 'The android-binary-size trybot will block if the method exists in the\n'
98 'release apk.')
[email protected]eea609a2011-11-18 13:10:1299
100
[email protected]cf9b78f2012-11-14 11:40:28101_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:40102 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:21103 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
104 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:28105
Michael Thiessen44457642020-02-06 00:24:15106# Format: Sequence of tuples containing:
107# * Full import path.
108# * Sequence of strings to show when the pattern matches.
109# * Sequence of path or filename exceptions to this rule
110_BANNED_JAVA_IMPORTS = (
111 (
Colin Blundell170d78c82020-03-12 13:56:04112 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15113 (
114 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
115 ),
116 (
117 'net/android/javatests/src/org/chromium/net/'
118 'AndroidProxySelectorTest.java',
119 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04120 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15121 ),
122 ),
Michael Thiessened631912020-08-07 19:01:31123 (
124 'android.support.test.rule.UiThreadTestRule;',
125 (
126 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43127 '@org.chromium.base.test.UiThreadTest on test methods that should run '
128 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31129 ),
130 (),
131 ),
132 (
133 'android.support.test.annotation.UiThreadTest;',
134 (
135 'Do not use android.support.test.annotation.UiThreadTest, use '
136 'org.chromium.base.test.UiThreadTest instead. See '
137 'https://crbug.com/1111893.',
138 ),
139 ()
Michael Thiessenfd6919b2020-12-08 20:44:01140 ),
141 (
142 'android.support.test.rule.ActivityTestRule;',
143 (
144 'Do not use ActivityTestRule, use '
145 'org.chromium.base.test.BaseActivityTestRule instead.',
146 ),
147 (
148 'components/cronet/',
149 )
Michael Thiessened631912020-08-07 19:01:31150 )
Michael Thiessen44457642020-02-06 00:24:15151)
wnwenbdc444e2016-05-25 13:44:15152
Daniel Bratell609102be2019-03-27 20:53:21153# Format: Sequence of tuples containing:
154# * String pattern or, if starting with a slash, a regular expression.
155# * Sequence of strings to show when the pattern matches.
156# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41157_BANNED_JAVA_FUNCTIONS = (
158 (
159 'StrictMode.allowThreadDiskReads()',
160 (
161 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
162 'directly.',
163 ),
164 False,
165 ),
166 (
167 'StrictMode.allowThreadDiskWrites()',
168 (
169 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
170 'directly.',
171 ),
172 False,
173 ),
Michael Thiessen0f2547e2020-07-27 21:55:36174 (
175 '.waitForIdleSync()',
176 (
177 'Do not use waitForIdleSync as it masks underlying issues. There is '
178 'almost always something else you should wait on instead.',
179 ),
180 False,
181 ),
Eric Stevensona9a980972017-09-23 00:04:41182)
183
Daniel Bratell609102be2019-03-27 20:53:21184# Format: Sequence of tuples containing:
185# * String pattern or, if starting with a slash, a regular expression.
186# * Sequence of strings to show when the pattern matches.
187# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59188_BANNED_OBJC_FUNCTIONS = (
189 (
190 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20191 (
192 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59193 'prohibited. Please use CrTrackingArea instead.',
194 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
195 ),
196 False,
197 ),
198 (
[email protected]eaae1972014-04-16 04:17:26199 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20200 (
201 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59202 'instead.',
203 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
204 ),
205 False,
206 ),
207 (
208 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20209 (
210 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59211 'Please use |convertPoint:(point) fromView:nil| instead.',
212 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
213 ),
214 True,
215 ),
216 (
217 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20218 (
219 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59220 'Please use |convertPoint:(point) toView:nil| instead.',
221 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
222 ),
223 True,
224 ),
225 (
226 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20227 (
228 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59229 'Please use |convertRect:(point) fromView:nil| instead.',
230 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
231 ),
232 True,
233 ),
234 (
235 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20236 (
237 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59238 'Please use |convertRect:(point) toView:nil| instead.',
239 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
240 ),
241 True,
242 ),
243 (
244 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20245 (
246 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59247 'Please use |convertSize:(point) fromView:nil| instead.',
248 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
249 ),
250 True,
251 ),
252 (
253 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20254 (
255 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59256 'Please use |convertSize:(point) toView:nil| instead.',
257 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
258 ),
259 True,
260 ),
jif65398702016-10-27 10:19:48261 (
262 r"/\s+UTF8String\s*]",
263 (
264 'The use of -[NSString UTF8String] is dangerous as it can return null',
265 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
266 'Please use |SysNSStringToUTF8| instead.',
267 ),
268 True,
269 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34270 (
271 r'__unsafe_unretained',
272 (
273 'The use of __unsafe_unretained is almost certainly wrong, unless',
274 'when interacting with NSFastEnumeration or NSInvocation.',
275 'Please use __weak in files build with ARC, nothing otherwise.',
276 ),
277 False,
278 ),
Avi Drissman7382afa02019-04-29 23:27:13279 (
280 'freeWhenDone:NO',
281 (
282 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
283 'Foundation types is prohibited.',
284 ),
285 True,
286 ),
[email protected]127f18ec2012-06-16 05:05:59287)
288
Daniel Bratell609102be2019-03-27 20:53:21289# Format: Sequence of tuples containing:
290# * String pattern or, if starting with a slash, a regular expression.
291# * Sequence of strings to show when the pattern matches.
292# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54293_BANNED_IOS_OBJC_FUNCTIONS = (
294 (
295 r'/\bTEST[(]',
296 (
297 'TEST() macro should not be used in Objective-C++ code as it does not ',
298 'drain the autorelease pool at the end of the test. Use TEST_F() ',
299 'macro instead with a fixture inheriting from PlatformTest (or a ',
300 'typedef).'
301 ),
302 True,
303 ),
304 (
305 r'/\btesting::Test\b',
306 (
307 'testing::Test should not be used in Objective-C++ code as it does ',
308 'not drain the autorelease pool at the end of the test. Use ',
309 'PlatformTest instead.'
310 ),
311 True,
312 ),
313)
314
Peter K. Lee6c03ccff2019-07-15 14:40:05315# Format: Sequence of tuples containing:
316# * String pattern or, if starting with a slash, a regular expression.
317# * Sequence of strings to show when the pattern matches.
318# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
319_BANNED_IOS_EGTEST_FUNCTIONS = (
320 (
321 r'/\bEXPECT_OCMOCK_VERIFY\b',
322 (
323 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
324 'it is meant for GTests. Use [mock verify] instead.'
325 ),
326 True,
327 ),
328)
329
Daniel Bratell609102be2019-03-27 20:53:21330# Format: Sequence of tuples containing:
331# * String pattern or, if starting with a slash, a regular expression.
332# * Sequence of strings to show when the pattern matches.
333# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
334# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59335_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20336 (
Peter Kasting94a56c42019-10-25 21:54:04337 r'/\busing namespace ',
338 (
339 'Using directives ("using namespace x") are banned by the Google Style',
340 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
341 'Explicitly qualify symbols or use using declarations ("using x::foo").',
342 ),
343 True,
344 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
345 ),
Antonio Gomes07300d02019-03-13 20:59:57346 # Make sure that gtest's FRIEND_TEST() macro is not used; the
347 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
348 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53349 (
[email protected]23e6cbc2012-06-16 18:51:20350 'FRIEND_TEST(',
351 (
[email protected]e3c945502012-06-26 20:01:49352 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20353 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
354 ),
355 False,
[email protected]7345da02012-11-27 14:31:49356 (),
[email protected]23e6cbc2012-06-16 18:51:20357 ),
358 (
tomhudsone2c14d552016-05-26 17:07:46359 'setMatrixClip',
360 (
361 'Overriding setMatrixClip() is prohibited; ',
362 'the base function is deprecated. ',
363 ),
364 True,
365 (),
366 ),
367 (
[email protected]52657f62013-05-20 05:30:31368 'SkRefPtr',
369 (
370 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22371 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31372 ),
373 True,
374 (),
375 ),
376 (
377 'SkAutoRef',
378 (
379 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22380 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31381 ),
382 True,
383 (),
384 ),
385 (
386 'SkAutoTUnref',
387 (
388 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22389 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31390 ),
391 True,
392 (),
393 ),
394 (
395 'SkAutoUnref',
396 (
397 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
398 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22399 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31400 ),
401 True,
402 (),
403 ),
[email protected]d89eec82013-12-03 14:10:59404 (
405 r'/HANDLE_EINTR\(.*close',
406 (
407 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
408 'descriptor will be closed, and it is incorrect to retry the close.',
409 'Either call close directly and ignore its return value, or wrap close',
410 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
411 ),
412 True,
413 (),
414 ),
415 (
416 r'/IGNORE_EINTR\((?!.*close)',
417 (
418 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
419 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
420 ),
421 True,
422 (
423 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04424 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
425 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59426 ),
427 ),
[email protected]ec5b3f02014-04-04 18:43:43428 (
429 r'/v8::Extension\(',
430 (
431 'Do not introduce new v8::Extensions into the code base, use',
432 'gin::Wrappable instead. See http://crbug.com/334679',
433 ),
434 True,
[email protected]f55c90ee62014-04-12 00:50:03435 (
Egor Paskoce145c42018-09-28 19:31:04436 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03437 ),
[email protected]ec5b3f02014-04-04 18:43:43438 ),
skyostilf9469f72015-04-20 10:38:52439 (
jame2d1a952016-04-02 00:27:10440 '#pragma comment(lib,',
441 (
442 'Specify libraries to link with in build files and not in the source.',
443 ),
444 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41445 (
tzik3f295992018-12-04 20:32:23446 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04447 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41448 ),
jame2d1a952016-04-02 00:27:10449 ),
fdorayc4ac18d2017-05-01 21:39:59450 (
Gabriel Charette7cc6c432018-04-25 20:52:02451 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59452 (
453 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
454 ),
455 False,
456 (),
457 ),
458 (
Gabriel Charette7cc6c432018-04-25 20:52:02459 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59460 (
461 'Consider using THREAD_CHECKER macros instead of the class directly.',
462 ),
463 False,
464 (),
465 ),
dbeamb6f4fde2017-06-15 04:03:06466 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06467 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
468 (
469 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
470 'deprecated (http://crbug.com/634507). Please avoid converting away',
471 'from the Time types in Chromium code, especially if any math is',
472 'being done on time values. For interfacing with platform/library',
473 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
474 'type converter methods instead. For faking TimeXXX values (for unit',
475 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
476 'other use cases, please contact base/time/OWNERS.',
477 ),
478 False,
479 (),
480 ),
481 (
dbeamb6f4fde2017-06-15 04:03:06482 'CallJavascriptFunctionUnsafe',
483 (
484 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
485 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
486 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
487 ),
488 False,
489 (
Egor Paskoce145c42018-09-28 19:31:04490 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
491 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
492 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06493 ),
494 ),
dskiba1474c2bfd62017-07-20 02:19:24495 (
496 'leveldb::DB::Open',
497 (
498 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
499 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
500 "Chrome's tracing, making their memory usage visible.",
501 ),
502 True,
503 (
504 r'^third_party/leveldatabase/.*\.(cc|h)$',
505 ),
Gabriel Charette0592c3a2017-07-26 12:02:04506 ),
507 (
Chris Mumfordc38afb62017-10-09 17:55:08508 'leveldb::NewMemEnv',
509 (
510 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58511 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
512 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08513 ),
514 True,
515 (
516 r'^third_party/leveldatabase/.*\.(cc|h)$',
517 ),
518 ),
519 (
Gabriel Charetted9839bc2017-07-29 14:17:47520 'RunLoop::QuitCurrent',
521 (
Robert Liao64b7ab22017-08-04 23:03:43522 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
523 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47524 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41525 False,
Gabriel Charetted9839bc2017-07-29 14:17:47526 (),
Gabriel Charettea44975052017-08-21 23:14:04527 ),
528 (
529 'base::ScopedMockTimeMessageLoopTaskRunner',
530 (
Gabriel Charette87cc1af2018-04-25 20:52:51531 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11532 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51533 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
534 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
535 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04536 ),
Gabriel Charette87cc1af2018-04-25 20:52:51537 False,
Gabriel Charettea44975052017-08-21 23:14:04538 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57539 ),
540 (
Dave Tapuska98199b612019-07-10 13:30:44541 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57542 (
543 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02544 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57545 ),
546 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16547 # Abseil's benchmarks never linked into chrome.
548 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38549 ),
550 (
Peter Kasting991618a62019-06-17 22:00:09551 r'/\bstd::stoi\b',
552 (
553 'std::stoi uses exceptions to communicate results. ',
554 'Use base::StringToInt() instead.',
555 ),
556 True,
557 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
558 ),
559 (
560 r'/\bstd::stol\b',
561 (
562 'std::stol uses exceptions to communicate results. ',
563 'Use base::StringToInt() instead.',
564 ),
565 True,
566 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
567 ),
568 (
569 r'/\bstd::stoul\b',
570 (
571 'std::stoul uses exceptions to communicate results. ',
572 'Use base::StringToUint() instead.',
573 ),
574 True,
575 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
576 ),
577 (
578 r'/\bstd::stoll\b',
579 (
580 'std::stoll uses exceptions to communicate results. ',
581 'Use base::StringToInt64() instead.',
582 ),
583 True,
584 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
585 ),
586 (
587 r'/\bstd::stoull\b',
588 (
589 'std::stoull uses exceptions to communicate results. ',
590 'Use base::StringToUint64() instead.',
591 ),
592 True,
593 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
594 ),
595 (
596 r'/\bstd::stof\b',
597 (
598 'std::stof uses exceptions to communicate results. ',
599 'For locale-independent values, e.g. reading numbers from disk',
600 'profiles, use base::StringToDouble().',
601 'For user-visible values, parse using ICU.',
602 ),
603 True,
604 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
605 ),
606 (
607 r'/\bstd::stod\b',
608 (
609 'std::stod uses exceptions to communicate results. ',
610 'For locale-independent values, e.g. reading numbers from disk',
611 'profiles, use base::StringToDouble().',
612 'For user-visible values, parse using ICU.',
613 ),
614 True,
615 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
616 ),
617 (
618 r'/\bstd::stold\b',
619 (
620 'std::stold uses exceptions to communicate results. ',
621 'For locale-independent values, e.g. reading numbers from disk',
622 'profiles, use base::StringToDouble().',
623 'For user-visible values, parse using ICU.',
624 ),
625 True,
626 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
627 ),
628 (
Daniel Bratell69334cc2019-03-26 11:07:45629 r'/\bstd::to_string\b',
630 (
631 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09632 'For locale-independent strings, e.g. writing numbers to disk',
633 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45634 'For user-visible strings, use base::FormatNumber() and',
635 'the related functions in base/i18n/number_formatting.h.',
636 ),
Peter Kasting991618a62019-06-17 22:00:09637 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21638 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45639 ),
640 (
641 r'/\bstd::shared_ptr\b',
642 (
643 'std::shared_ptr should not be used. Use scoped_refptr instead.',
644 ),
645 True,
Ulan Degenbaev947043882021-02-10 14:02:31646 [
647 # Needed for interop with third-party library.
648 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57649 'array_buffer_contents\.(cc|h)',
Wez5f56be52021-05-04 09:30:58650 '^gin/array_buffer\.(cc|h)',
651 '^chrome/services/sharing/nearby/',
Meilin Wang00efc7c2021-05-13 01:12:42652 # gRPC provides some C++ libraries that use std::shared_ptr<>.
653 '^chromeos/services/libassistant/grpc/',
Wez5f56be52021-05-04 09:30:58654 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
655 '.*fuchsia.*test\.(cc|h)',
Alex Chau9eb03cdd52020-07-13 21:04:57656 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21657 ),
658 (
Peter Kasting991618a62019-06-17 22:00:09659 r'/\bstd::weak_ptr\b',
660 (
661 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
662 ),
663 True,
664 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
665 ),
666 (
Daniel Bratell609102be2019-03-27 20:53:21667 r'/\blong long\b',
668 (
669 'long long is banned. Use stdint.h if you need a 64 bit number.',
670 ),
671 False, # Only a warning since it is already used.
672 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
673 ),
674 (
675 r'/\bstd::bind\b',
676 (
677 'std::bind is banned because of lifetime risks.',
678 'Use base::BindOnce or base::BindRepeating instead.',
679 ),
680 True,
681 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
682 ),
683 (
684 r'/\b#include <chrono>\b',
685 (
686 '<chrono> overlaps with Time APIs in base. Keep using',
687 'base classes.',
688 ),
689 True,
690 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
691 ),
692 (
693 r'/\b#include <exception>\b',
694 (
695 'Exceptions are banned and disabled in Chromium.',
696 ),
697 True,
698 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
699 ),
700 (
701 r'/\bstd::function\b',
702 (
Colin Blundellea615d422021-05-12 09:35:41703 'std::function is banned. Instead use base::OnceCallback or ',
704 'base::RepeatingCallback, which directly support Chromium\'s weak ',
705 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21706 ),
Peter Kasting991618a62019-06-17 22:00:09707 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21708 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
709 ),
710 (
711 r'/\b#include <random>\b',
712 (
713 'Do not use any random number engines from <random>. Instead',
714 'use base::RandomBitGenerator.',
715 ),
716 True,
717 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
718 ),
719 (
Tom Andersona95e12042020-09-09 23:08:00720 r'/\b#include <X11/',
721 (
722 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
723 ),
724 True,
725 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
726 ),
727 (
Daniel Bratell609102be2019-03-27 20:53:21728 r'/\bstd::ratio\b',
729 (
730 'std::ratio is banned by the Google Style Guide.',
731 ),
732 True,
733 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45734 ),
735 (
Francois Doray43670e32017-09-27 12:40:38736 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
737 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
738 (
739 'Use the new API in base/threading/thread_restrictions.h.',
740 ),
Gabriel Charette04b138f2018-08-06 00:03:22741 False,
Francois Doray43670e32017-09-27 12:40:38742 (),
743 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38744 (
Michael Giuffrida7f93d6922019-04-19 14:39:58745 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19746 (
747 'RunMessageLoop is deprecated, use RunLoop instead.',
748 ),
749 False,
750 (),
751 ),
752 (
Dave Tapuska98199b612019-07-10 13:30:44753 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19754 (
755 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
756 ),
757 False,
758 (),
759 ),
760 (
Dave Tapuska98199b612019-07-10 13:30:44761 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19762 (
763 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
764 "if you're convinced you need this.",
765 ),
766 False,
767 (),
768 ),
769 (
Dave Tapuska98199b612019-07-10 13:30:44770 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19771 (
772 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04773 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19774 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
775 'async events instead of flushing threads.',
776 ),
777 False,
778 (),
779 ),
780 (
781 r'MessageLoopRunner',
782 (
783 'MessageLoopRunner is deprecated, use RunLoop instead.',
784 ),
785 False,
786 (),
787 ),
788 (
Dave Tapuska98199b612019-07-10 13:30:44789 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19790 (
791 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
792 "gab@ if you found a use case where this is the only solution.",
793 ),
794 False,
795 (),
796 ),
797 (
Victor Costane48a2e82019-03-15 22:02:34798 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16799 (
Victor Costane48a2e82019-03-15 22:02:34800 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16801 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
802 ),
803 True,
804 (
805 r'^sql/initialization\.(cc|h)$',
806 r'^third_party/sqlite/.*\.(c|cc|h)$',
807 ),
808 ),
Matt Menke7f520a82018-03-28 21:38:37809 (
Dave Tapuska98199b612019-07-10 13:30:44810 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47811 (
812 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
813 'base::RandomShuffle instead.'
814 ),
815 True,
816 (),
817 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24818 (
819 'ios/web/public/test/http_server',
820 (
821 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
822 ),
823 False,
824 (),
825 ),
Robert Liao764c9492019-01-24 18:46:28826 (
827 'GetAddressOf',
828 (
829 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53830 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11831 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53832 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28833 ),
834 True,
835 (),
836 ),
Antonio Gomes07300d02019-03-13 20:59:57837 (
Ben Lewisa9514602019-04-29 17:53:05838 'SHFileOperation',
839 (
840 'SHFileOperation was deprecated in Windows Vista, and there are less ',
841 'complex functions to achieve the same goals. Use IFileOperation for ',
842 'any esoteric actions instead.'
843 ),
844 True,
845 (),
846 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18847 (
Cliff Smolinsky81951642019-04-30 21:39:51848 'StringFromGUID2',
849 (
850 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24851 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51852 ),
853 True,
854 (
855 r'/base/win/win_util_unittest.cc'
856 ),
857 ),
858 (
859 'StringFromCLSID',
860 (
861 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24862 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51863 ),
864 True,
865 (
866 r'/base/win/win_util_unittest.cc'
867 ),
868 ),
869 (
Avi Drissman7382afa02019-04-29 23:27:13870 'kCFAllocatorNull',
871 (
872 'The use of kCFAllocatorNull with the NoCopy creation of ',
873 'CoreFoundation types is prohibited.',
874 ),
875 True,
876 (),
877 ),
Oksana Zhuravlovafd247772019-05-16 16:57:29878 (
879 'mojo::ConvertTo',
880 (
881 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
882 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
883 'StringTraits if you would like to convert between custom types and',
884 'the wire format of mojom types.'
885 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22886 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29887 (
Wezf89dec092019-09-11 19:38:33888 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
889 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29890 r'^third_party/blink/.*\.(cc|h)$',
891 r'^content/renderer/.*\.(cc|h)$',
892 ),
893 ),
Robert Liao1d78df52019-11-11 20:02:01894 (
Oksana Zhuravlovac8222d22019-12-19 19:21:16895 'GetInterfaceProvider',
896 (
897 'InterfaceProvider is deprecated.',
898 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
899 'or Platform::GetBrowserInterfaceBroker.'
900 ),
901 False,
902 (),
903 ),
904 (
Robert Liao1d78df52019-11-11 20:02:01905 'CComPtr',
906 (
907 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
908 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
909 'details.'
910 ),
911 False,
912 (),
913 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:20914 (
915 r'/\b(IFACE|STD)METHOD_?\(',
916 (
917 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
918 'Instead, always use IFACEMETHODIMP in the declaration.'
919 ),
920 False,
921 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
922 ),
Allen Bauer53b43fb12020-03-12 17:21:47923 (
924 'set_owned_by_client',
925 (
926 'set_owned_by_client is deprecated.',
927 'views::View already owns the child views by default. This introduces ',
928 'a competing ownership model which makes the code difficult to reason ',
929 'about. See http://crbug.com/1044687 for more details.'
930 ),
931 False,
932 (),
933 ),
Eric Secklerbe6f48d2020-05-06 18:09:12934 (
935 r'/\bTRACE_EVENT_ASYNC_',
936 (
937 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
938 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
939 ),
940 False,
941 (
942 r'^base/trace_event/.*',
943 r'^base/tracing/.*',
944 ),
945 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:26946 (
947 r'/\bScopedObserver',
948 (
949 'ScopedObserver is deprecated.',
950 'Please use base::ScopedObservation for observing a single source,',
951 'or base::ScopedMultiSourceObservation for observing multple sources',
952 ),
953 False,
954 (),
955 ),
Jan Wilken Dörrie60df2362021-04-08 19:44:21956 (
Robert Liao22f66a52021-04-10 00:57:52957 'RoInitialize',
958 (
Robert Liao48018922021-04-16 23:03:02959 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:52960 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
961 'instead. See http://crbug.com/1197722 for more information.'
962 ),
963 True,
Robert Liao48018922021-04-16 23:03:02964 (
965 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$'
966 ),
Robert Liao22f66a52021-04-10 00:57:52967 ),
[email protected]127f18ec2012-06-16 05:05:59968)
969
Mario Sanchez Prada2472cab2019-09-18 10:58:31970# Format: Sequence of tuples containing:
971# * String pattern or, if starting with a slash, a regular expression.
972# * Sequence of strings to show when the pattern matches.
973_DEPRECATED_MOJO_TYPES = (
974 (
975 r'/\bmojo::AssociatedBinding\b',
976 (
977 'mojo::AssociatedBinding<Interface> is deprecated.',
978 'Use mojo::AssociatedReceiver<Interface> instead.',
979 ),
980 ),
981 (
982 r'/\bmojo::AssociatedBindingSet\b',
983 (
984 'mojo::AssociatedBindingSet<Interface> is deprecated.',
985 'Use mojo::AssociatedReceiverSet<Interface> instead.',
986 ),
987 ),
988 (
989 r'/\bmojo::AssociatedInterfacePtr\b',
990 (
991 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
992 'Use mojo::AssociatedRemote<Interface> instead.',
993 ),
994 ),
995 (
996 r'/\bmojo::AssociatedInterfacePtrInfo\b',
997 (
998 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
999 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1000 ),
1001 ),
1002 (
1003 r'/\bmojo::AssociatedInterfaceRequest\b',
1004 (
1005 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1006 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1007 ),
1008 ),
1009 (
1010 r'/\bmojo::Binding\b',
1011 (
1012 'mojo::Binding<Interface> is deprecated.',
1013 'Use mojo::Receiver<Interface> instead.',
1014 ),
1015 ),
1016 (
1017 r'/\bmojo::BindingSet\b',
1018 (
1019 'mojo::BindingSet<Interface> is deprecated.',
1020 'Use mojo::ReceiverSet<Interface> instead.',
1021 ),
1022 ),
1023 (
1024 r'/\bmojo::InterfacePtr\b',
1025 (
1026 'mojo::InterfacePtr<Interface> is deprecated.',
1027 'Use mojo::Remote<Interface> instead.',
1028 ),
1029 ),
1030 (
1031 r'/\bmojo::InterfacePtrInfo\b',
1032 (
1033 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1034 'Use mojo::PendingRemote<Interface> instead.',
1035 ),
1036 ),
1037 (
1038 r'/\bmojo::InterfaceRequest\b',
1039 (
1040 'mojo::InterfaceRequest<Interface> is deprecated.',
1041 'Use mojo::PendingReceiver<Interface> instead.',
1042 ),
1043 ),
1044 (
1045 r'/\bmojo::MakeRequest\b',
1046 (
1047 'mojo::MakeRequest is deprecated.',
1048 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1049 ),
1050 ),
1051 (
1052 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1053 (
1054 'mojo::MakeRequest is deprecated.',
1055 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181056 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311057 ),
1058 ),
1059 (
1060 r'/\bmojo::MakeStrongBinding\b',
1061 (
1062 'mojo::MakeStrongBinding is deprecated.',
1063 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1064 'mojo::MakeSelfOwnedReceiver() instead.',
1065 ),
1066 ),
1067 (
1068 r'/\bmojo::MakeStrongAssociatedBinding\b',
1069 (
1070 'mojo::MakeStrongAssociatedBinding is deprecated.',
1071 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1072 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1073 ),
1074 ),
1075 (
Gyuyoung Kim4952ba62020-07-07 07:33:441076 r'/\bmojo::StrongAssociatedBinding\b',
1077 (
1078 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1079 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1080 ),
1081 ),
1082 (
1083 r'/\bmojo::StrongBinding\b',
1084 (
1085 'mojo::StrongBinding<Interface> is deprecated.',
1086 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1087 ),
1088 ),
1089 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311090 r'/\bmojo::StrongAssociatedBindingSet\b',
1091 (
1092 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1093 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1094 ),
1095 ),
1096 (
1097 r'/\bmojo::StrongBindingSet\b',
1098 (
1099 'mojo::StrongBindingSet<Interface> is deprecated.',
1100 'Use mojo::UniqueReceiverSet<Interface> instead.',
1101 ),
1102 ),
1103)
wnwenbdc444e2016-05-25 13:44:151104
mlamouria82272622014-09-16 18:45:041105_IPC_ENUM_TRAITS_DEPRECATED = (
1106 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501107 'See http://www.chromium.org/Home/chromium-security/education/'
1108 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041109
Stephen Martinis97a394142018-06-07 23:06:051110_LONG_PATH_ERROR = (
1111 'Some files included in this CL have file names that are too long (> 200'
1112 ' characters). If committed, these files will cause issues on Windows. See'
1113 ' https://crbug.com/612667 for more details.'
1114)
1115
Shenghua Zhangbfaa38b82017-11-16 21:58:021116_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041117 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041118 r".*[\\/]BuildHooksAndroidImpl\.java",
1119 r".*[\\/]LicenseContentProvider\.java",
1120 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281121 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021122]
[email protected]127f18ec2012-06-16 05:05:591123
Mohamed Heikald048240a2019-11-12 16:57:371124# List of image extensions that are used as resources in chromium.
1125_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1126
Sean Kau46e29bc2017-08-28 16:31:161127# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401128_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041129 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401130 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041131 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1132 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041133 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431134 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161135]
1136
1137
[email protected]b00342e7f2013-03-26 16:21:541138_VALID_OS_MACROS = (
1139 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081140 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541141 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441142 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121143 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541144 'OS_BSD',
1145 'OS_CAT', # For testing.
1146 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041147 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541148 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371149 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541150 'OS_IOS',
1151 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441152 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541153 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211154 'OS_NACL_NONSFI',
1155 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121156 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541157 'OS_OPENBSD',
1158 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371159 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541160 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541161 'OS_WIN',
1162)
1163
1164
Andrew Grieveb773bad2020-06-05 18:00:381165# These are not checked on the public chromium-presubmit trybot.
1166# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041167# checkouts.
agrievef32bcc72016-04-04 14:57:401168_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381169 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381170]
1171
1172
1173_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041174 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361175 'base/android/jni_generator/jni_generator.pydeps',
1176 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361177 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041178 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361179 'build/android/gyp/aar.pydeps',
1180 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271181 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361182 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381183 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361184 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021185 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221186 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111187 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361188 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361189 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361190 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111191 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041192 'build/android/gyp/create_app_bundle_apks.pydeps',
1193 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361194 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121195 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091196 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221197 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001198 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361199 'build/android/gyp/desugar.pydeps',
1200 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421201 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041202 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361203 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361204 'build/android/gyp/filter_zip.pydeps',
1205 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361206 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361207 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581208 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361209 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141210 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261211 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471212 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011213 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041214 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361215 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361216 'build/android/gyp/merge_manifest.pydeps',
1217 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221218 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361219 'build/android/gyp/proguard.pydeps',
Mohamed Heikala9dd71a2021-04-15 15:39:271220 'build/android/gyp/resources_shrinker/shrinker.pydeps',
Peter Wen578730b2020-03-19 19:55:461221 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241222 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361223 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461224 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561225 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361226 'build/android/incremental_install/generate_android_manifest.pydeps',
1227 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041228 'build/android/resource_sizes.pydeps',
1229 'build/android/test_runner.pydeps',
1230 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361231 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361232 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321233 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271234 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1235 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041236 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001237 'components/cronet/tools/generate_javadoc.pydeps',
1238 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381239 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001240 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381241 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041242 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181243 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041244 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421245 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1246 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131247 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501248 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061249 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221250 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401251]
1252
wnwenbdc444e2016-05-25 13:44:151253
agrievef32bcc72016-04-04 14:57:401254_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1255
1256
Eric Boren6fd2b932018-01-25 15:05:081257# Bypass the AUTHORS check for these accounts.
1258_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591259 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451260 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591261 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521262 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071263 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041264 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271265 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041266 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161267 for s in ('chromium-internal-autoroll',)
1268 ) | set('%[email protected]' % s
1269 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081270
1271
Daniel Bratell65b033262019-04-23 08:17:061272def _IsCPlusPlusFile(input_api, file_path):
1273 """Returns True if this file contains C++-like code (and not Python,
1274 Go, Java, MarkDown, ...)"""
1275
1276 ext = input_api.os_path.splitext(file_path)[1]
1277 # This list is compatible with CppChecker.IsCppFile but we should
1278 # consider adding ".c" to it. If we do that we can use this function
1279 # at more places in the code.
1280 return ext in (
1281 '.h',
1282 '.cc',
1283 '.cpp',
1284 '.m',
1285 '.mm',
1286 )
1287
1288def _IsCPlusPlusHeaderFile(input_api, file_path):
1289 return input_api.os_path.splitext(file_path)[1] == ".h"
1290
1291
1292def _IsJavaFile(input_api, file_path):
1293 return input_api.os_path.splitext(file_path)[1] == ".java"
1294
1295
1296def _IsProtoFile(input_api, file_path):
1297 return input_api.os_path.splitext(file_path)[1] == ".proto"
1298
Mohamed Heikal5e5b7922020-10-29 18:57:591299
1300def CheckNoUpstreamDepsOnClank(input_api, output_api):
1301 """Prevent additions of dependencies from the upstream repo on //clank."""
1302 # clank can depend on clank
1303 if input_api.change.RepositoryRoot().endswith('clank'):
1304 return []
1305 build_file_patterns = [
1306 r'(.+/)?BUILD\.gn',
1307 r'.+\.gni',
1308 ]
1309 excluded_files = [
1310 r'build[/\\]config[/\\]android[/\\]config\.gni'
1311 ]
1312 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1313
1314 error_message = 'Disallowed import on //clank in an upstream build file:'
1315
1316 def FilterFile(affected_file):
1317 return input_api.FilterSourceFile(
1318 affected_file,
1319 files_to_check=build_file_patterns,
1320 files_to_skip=excluded_files)
1321
1322 problems = []
1323 for f in input_api.AffectedSourceFiles(FilterFile):
1324 local_path = f.LocalPath()
1325 for line_number, line in f.ChangedContents():
1326 if (bad_pattern.search(line)):
1327 problems.append(
1328 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1329 if problems:
1330 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1331 else:
1332 return []
1333
1334
Saagar Sanghavifceeaae2020-08-12 16:40:361335def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191336 """Attempts to prevent use of functions intended only for testing in
1337 non-testing code. For now this is just a best-effort implementation
1338 that ignores header files and may have some false positives. A
1339 better implementation would probably need a proper C++ parser.
1340 """
1341 # We only scan .cc files and the like, as the declaration of
1342 # for-testing functions in header files are hard to distinguish from
1343 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491344 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191345
jochenc0d4808c2015-07-27 09:25:421346 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191347 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091348 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131349 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191350 exclusion_pattern = input_api.re.compile(
1351 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1352 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131353 # Avoid a false positive in this case, where the method name, the ::, and
1354 # the closing { are all on different lines due to line wrapping.
1355 # HelperClassForTesting::
1356 # HelperClassForTesting(
1357 # args)
1358 # : member(0) {}
1359 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191360
1361 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441362 files_to_skip = (_EXCLUDED_PATHS +
1363 _TEST_CODE_EXCLUDED_PATHS +
1364 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191365 return input_api.FilterSourceFile(
1366 affected_file,
James Cook24a504192020-07-23 00:08:441367 files_to_check=file_inclusion_pattern,
1368 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191369
1370 problems = []
1371 for f in input_api.AffectedSourceFiles(FilterFile):
1372 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131373 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241374 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031375 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461376 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131377 not exclusion_pattern.search(line) and
1378 not allowlist_pattern.search(line) and
1379 not in_method_defn):
[email protected]55459852011-08-10 15:17:191380 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031381 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131382 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191383
1384 if problems:
[email protected]f7051d52013-04-02 18:31:421385 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031386 else:
1387 return []
[email protected]55459852011-08-10 15:17:191388
1389
Saagar Sanghavifceeaae2020-08-12 16:40:361390def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231391 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591392 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231393 """
1394 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1395 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1396 name_pattern = r'ForTest(s|ing)?'
1397 # Describes an occurrence of "ForTest*" inside a // comment.
1398 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501399 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551400 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231401 # Catch calls.
1402 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1403 # Ignore definitions. (Comments are ignored separately.)
1404 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1405
1406 problems = []
1407 sources = lambda x: input_api.FilterSourceFile(
1408 x,
James Cook24a504192020-07-23 00:08:441409 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1410 + input_api.DEFAULT_FILES_TO_SKIP),
1411 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231412 )
1413 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1414 local_path = f.LocalPath()
1415 is_inside_javadoc = False
1416 for line_number, line in f.ChangedContents():
1417 if is_inside_javadoc and javadoc_end_re.search(line):
1418 is_inside_javadoc = False
1419 if not is_inside_javadoc and javadoc_start_re.search(line):
1420 is_inside_javadoc = True
1421 if is_inside_javadoc:
1422 continue
1423 if (inclusion_re.search(line) and
1424 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501425 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231426 not exclusion_re.search(line)):
1427 problems.append(
1428 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1429
1430 if problems:
1431 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1432 else:
1433 return []
1434
1435
Saagar Sanghavifceeaae2020-08-12 16:40:361436def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541437 """Checks to make sure no .h files include <iostream>."""
1438 files = []
1439 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1440 input_api.re.MULTILINE)
1441 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1442 if not f.LocalPath().endswith('.h'):
1443 continue
1444 contents = input_api.ReadFile(f)
1445 if pattern.search(contents):
1446 files.append(f)
1447
1448 if len(files):
yolandyandaabc6d2016-04-18 18:29:391449 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061450 'Do not #include <iostream> in header files, since it inserts static '
1451 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541452 '#include <ostream>. See http://crbug.com/94794',
1453 files) ]
1454 return []
1455
Danil Chapovalov3518f362018-08-11 16:13:431456def _CheckNoStrCatRedefines(input_api, output_api):
1457 """Checks no windows headers with StrCat redefined are included directly."""
1458 files = []
1459 pattern_deny = input_api.re.compile(
1460 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1461 input_api.re.MULTILINE)
1462 pattern_allow = input_api.re.compile(
1463 r'^#include\s"base/win/windows_defines.inc"',
1464 input_api.re.MULTILINE)
1465 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1466 contents = input_api.ReadFile(f)
1467 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1468 files.append(f.LocalPath())
1469
1470 if len(files):
1471 return [output_api.PresubmitError(
1472 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1473 'directly since they pollute code with StrCat macro. Instead, '
1474 'include matching header from base/win. See http://crbug.com/856536',
1475 files) ]
1476 return []
1477
[email protected]10689ca2011-09-02 02:31:541478
Saagar Sanghavifceeaae2020-08-12 16:40:361479def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521480 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181481 problems = []
1482 for f in input_api.AffectedFiles():
1483 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1484 continue
1485
1486 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041487 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181488 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1489
1490 if not problems:
1491 return []
1492 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1493 '\n'.join(problems))]
1494
Saagar Sanghavifceeaae2020-08-12 16:40:361495def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341496 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1497
1498 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1499 instead of DISABLED_. To filter false positives, reports are only generated
1500 if a corresponding MAYBE_ line exists.
1501 """
1502 problems = []
1503
1504 # The following two patterns are looked for in tandem - is a test labeled
1505 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1506 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1507 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1508
1509 # This is for the case that a test is disabled on all platforms.
1510 full_disable_pattern = input_api.re.compile(
1511 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1512 input_api.re.MULTILINE)
1513
Katie Df13948e2018-09-25 07:33:441514 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341515 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1516 continue
1517
1518 # Search for MABYE_, DISABLE_ pairs.
1519 disable_lines = {} # Maps of test name to line number.
1520 maybe_lines = {}
1521 for line_num, line in f.ChangedContents():
1522 disable_match = disable_pattern.search(line)
1523 if disable_match:
1524 disable_lines[disable_match.group(1)] = line_num
1525 maybe_match = maybe_pattern.search(line)
1526 if maybe_match:
1527 maybe_lines[maybe_match.group(1)] = line_num
1528
1529 # Search for DISABLE_ occurrences within a TEST() macro.
1530 disable_tests = set(disable_lines.keys())
1531 maybe_tests = set(maybe_lines.keys())
1532 for test in disable_tests.intersection(maybe_tests):
1533 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1534
1535 contents = input_api.ReadFile(f)
1536 full_disable_match = full_disable_pattern.search(contents)
1537 if full_disable_match:
1538 problems.append(' %s' % f.LocalPath())
1539
1540 if not problems:
1541 return []
1542 return [
1543 output_api.PresubmitPromptWarning(
1544 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1545 '\n'.join(problems))
1546 ]
1547
[email protected]72df4e782012-06-21 16:28:181548
Saagar Sanghavifceeaae2020-08-12 16:40:361549def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571550 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521551 errors = []
Hans Wennborg944479f2020-06-25 21:39:251552 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521553 input_api.re.MULTILINE)
1554 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1555 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1556 continue
1557 for lnum, line in f.ChangedContents():
1558 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171559 errors.append(output_api.PresubmitError(
1560 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571561 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171562 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521563 return errors
1564
1565
Weilun Shia487fad2020-10-28 00:10:341566# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1567# more reliable way. See
1568# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191569
wnwenbdc444e2016-05-25 13:44:151570
Saagar Sanghavifceeaae2020-08-12 16:40:361571def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391572 """Check that FlakyTest annotation is our own instead of the android one"""
1573 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1574 files = []
1575 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1576 if f.LocalPath().endswith('Test.java'):
1577 if pattern.search(input_api.ReadFile(f)):
1578 files.append(f)
1579 if len(files):
1580 return [output_api.PresubmitError(
1581 'Use org.chromium.base.test.util.FlakyTest instead of '
1582 'android.test.FlakyTest',
1583 files)]
1584 return []
mcasasb7440c282015-02-04 14:52:191585
wnwenbdc444e2016-05-25 13:44:151586
Saagar Sanghavifceeaae2020-08-12 16:40:361587def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441588 """Make sure .DEPS.git is never modified manually."""
1589 if any(f.LocalPath().endswith('.DEPS.git') for f in
1590 input_api.AffectedFiles()):
1591 return [output_api.PresubmitError(
1592 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1593 'automated system based on what\'s in DEPS and your changes will be\n'
1594 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501595 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1596 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441597 'for more information')]
1598 return []
1599
1600
Saagar Sanghavifceeaae2020-08-12 16:40:361601def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471602 """Checks that DEPS file deps are from allowed_hosts."""
1603 # Run only if DEPS file has been modified to annoy fewer bystanders.
1604 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1605 return []
1606 # Outsource work to gclient verify
1607 try:
John Budorickf20c0042019-04-25 23:23:401608 gclient_path = input_api.os_path.join(
1609 input_api.PresubmitLocalPath(),
1610 'third_party', 'depot_tools', 'gclient.py')
1611 input_api.subprocess.check_output(
1612 [input_api.python_executable, gclient_path, 'verify'],
1613 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471614 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201615 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471616 return [output_api.PresubmitError(
1617 'DEPS file must have only git dependencies.',
1618 long_text=error.output)]
1619
1620
Mario Sanchez Prada2472cab2019-09-18 10:58:311621def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1622 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591623 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311624
1625 Returns an string composed of the name of the file, the line number where the
1626 match has been found and the additional text passed as |message| in case the
1627 target type name matches the text inside the line passed as parameter.
1628 """
Peng Huang9c5949a02020-06-11 19:20:541629 result = []
1630
danakjd18e8892020-12-17 17:42:011631 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1632 return result
1633 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541634 return result
1635
Mario Sanchez Prada2472cab2019-09-18 10:58:311636 matched = False
1637 if type_name[0:1] == '/':
1638 regex = type_name[1:]
1639 if input_api.re.search(regex, line):
1640 matched = True
1641 elif type_name in line:
1642 matched = True
1643
Mario Sanchez Prada2472cab2019-09-18 10:58:311644 if matched:
1645 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1646 for message_line in message:
1647 result.append(' %s' % message_line)
1648
1649 return result
1650
1651
Saagar Sanghavifceeaae2020-08-12 16:40:361652def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591653 """Make sure that banned functions are not used."""
1654 warnings = []
1655 errors = []
1656
James Cook24a504192020-07-23 00:08:441657 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151658 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441659 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151660 if input_api.re.match(item, local_path):
1661 return True
1662 return False
1663
Peter K. Lee6c03ccff2019-07-15 14:40:051664 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541665 local_path = affected_file.LocalPath()
1666 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1667 return False
1668 basename = input_api.os_path.basename(local_path)
1669 if 'ios' in basename.split('_'):
1670 return True
1671 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1672 if sep and 'ios' in local_path.split(sep):
1673 return True
1674 return False
1675
wnwenbdc444e2016-05-25 13:44:151676 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311677 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1678 func_name, message)
1679 if problems:
wnwenbdc444e2016-05-25 13:44:151680 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311681 errors.extend(problems)
1682 else:
1683 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151684
Eric Stevensona9a980972017-09-23 00:04:411685 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1686 for f in input_api.AffectedFiles(file_filter=file_filter):
1687 for line_num, line in f.ChangedContents():
1688 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1689 CheckForMatch(f, line_num, line, func_name, message, error)
1690
[email protected]127f18ec2012-06-16 05:05:591691 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1692 for f in input_api.AffectedFiles(file_filter=file_filter):
1693 for line_num, line in f.ChangedContents():
1694 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151695 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591696
Peter K. Lee6c03ccff2019-07-15 14:40:051697 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541698 for line_num, line in f.ChangedContents():
1699 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1700 CheckForMatch(f, line_num, line, func_name, message, error)
1701
Peter K. Lee6c03ccff2019-07-15 14:40:051702 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1703 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1704 for line_num, line in f.ChangedContents():
1705 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1706 CheckForMatch(f, line_num, line, func_name, message, error)
1707
[email protected]127f18ec2012-06-16 05:05:591708 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1709 for f in input_api.AffectedFiles(file_filter=file_filter):
1710 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491711 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441712 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491713 continue
wnwenbdc444e2016-05-25 13:44:151714 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591715
1716 result = []
1717 if (warnings):
1718 result.append(output_api.PresubmitPromptWarning(
1719 'Banned functions were used.\n' + '\n'.join(warnings)))
1720 if (errors):
1721 result.append(output_api.PresubmitError(
1722 'Banned functions were used.\n' + '\n'.join(errors)))
1723 return result
1724
1725
Michael Thiessen44457642020-02-06 00:24:151726def _CheckAndroidNoBannedImports(input_api, output_api):
1727 """Make sure that banned java imports are not used."""
1728 errors = []
1729
1730 def IsException(path, exceptions):
1731 for exception in exceptions:
1732 if (path.startswith(exception)):
1733 return True
1734 return False
1735
1736 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1737 for f in input_api.AffectedFiles(file_filter=file_filter):
1738 for line_num, line in f.ChangedContents():
1739 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1740 if IsException(f.LocalPath(), exceptions):
1741 continue;
1742 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1743 'import ' + import_name, message)
1744 if problems:
1745 errors.extend(problems)
1746 result = []
1747 if (errors):
1748 result.append(output_api.PresubmitError(
1749 'Banned imports were used.\n' + '\n'.join(errors)))
1750 return result
1751
1752
Saagar Sanghavifceeaae2020-08-12 16:40:361753def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311754 """Make sure that old Mojo types are not used."""
1755 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571756 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311757
Mario Sanchez Pradaaab91382019-12-19 08:57:091758 # For any path that is not an "ok" or an "error" path, a warning will be
1759 # raised if deprecated mojo types are found.
1760 ok_paths = ['components/arc']
1761 error_paths = ['third_party/blink', 'content']
1762
Mario Sanchez Prada2472cab2019-09-18 10:58:311763 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1764 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571765 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091766 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311767 continue
1768
1769 for line_num, line in f.ChangedContents():
1770 for func_name, message in _DEPRECATED_MOJO_TYPES:
1771 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1772 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571773
Mario Sanchez Prada2472cab2019-09-18 10:58:311774 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091775 # Raise errors inside |error_paths| and warnings everywhere else.
1776 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571777 errors.extend(problems)
1778 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311779 warnings.extend(problems)
1780
1781 result = []
1782 if (warnings):
1783 result.append(output_api.PresubmitPromptWarning(
1784 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571785 if (errors):
1786 result.append(output_api.PresubmitError(
1787 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311788 return result
1789
1790
Saagar Sanghavifceeaae2020-08-12 16:40:361791def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061792 """Make sure that banned functions are not used."""
1793 files = []
1794 pattern = input_api.re.compile(r'^#pragma\s+once',
1795 input_api.re.MULTILINE)
1796 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1797 if not f.LocalPath().endswith('.h'):
1798 continue
1799 contents = input_api.ReadFile(f)
1800 if pattern.search(contents):
1801 files.append(f)
1802
1803 if files:
1804 return [output_api.PresubmitError(
1805 'Do not use #pragma once in header files.\n'
1806 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1807 files)]
1808 return []
1809
[email protected]127f18ec2012-06-16 05:05:591810
Saagar Sanghavifceeaae2020-08-12 16:40:361811def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121812 """Checks to make sure we don't introduce use of foo ? true : false."""
1813 problems = []
1814 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1815 for f in input_api.AffectedFiles():
1816 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1817 continue
1818
1819 for line_num, line in f.ChangedContents():
1820 if pattern.match(line):
1821 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1822
1823 if not problems:
1824 return []
1825 return [output_api.PresubmitPromptWarning(
1826 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1827 '\n'.join(problems))]
1828
1829
Saagar Sanghavifceeaae2020-08-12 16:40:361830def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281831 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181832 change. Breaking - rules is an error, breaking ! rules is a
1833 warning.
1834 """
mohan.reddyf21db962014-10-16 12:26:471835 import sys
[email protected]55f9f382012-07-31 11:02:181836 # We need to wait until we have an input_api object and use this
1837 # roundabout construct to import checkdeps because this file is
1838 # eval-ed and thus doesn't have __file__.
1839 original_sys_path = sys.path
1840 try:
1841 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471842 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181843 import checkdeps
[email protected]55f9f382012-07-31 11:02:181844 from rules import Rule
1845 finally:
1846 # Restore sys.path to what it was before.
1847 sys.path = original_sys_path
1848
1849 added_includes = []
rhalavati08acd232017-04-03 07:23:281850 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241851 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181852 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061853 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501854 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081855 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061856 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501857 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081858 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061859 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501860 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081861 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181862
[email protected]26385172013-05-09 23:11:351863 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181864
1865 error_descriptions = []
1866 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281867 error_subjects = set()
1868 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361869
[email protected]55f9f382012-07-31 11:02:181870 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1871 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081872 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181873 description_with_path = '%s\n %s' % (path, rule_description)
1874 if rule_type == Rule.DISALLOW:
1875 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281876 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181877 else:
1878 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281879 warning_subjects.add("#includes")
1880
1881 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1882 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081883 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281884 description_with_path = '%s\n %s' % (path, rule_description)
1885 if rule_type == Rule.DISALLOW:
1886 error_descriptions.append(description_with_path)
1887 error_subjects.add("imports")
1888 else:
1889 warning_descriptions.append(description_with_path)
1890 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181891
Jinsuk Kim5a092672017-10-24 22:42:241892 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021893 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081894 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241895 description_with_path = '%s\n %s' % (path, rule_description)
1896 if rule_type == Rule.DISALLOW:
1897 error_descriptions.append(description_with_path)
1898 error_subjects.add("imports")
1899 else:
1900 warning_descriptions.append(description_with_path)
1901 warning_subjects.add("imports")
1902
[email protected]55f9f382012-07-31 11:02:181903 results = []
1904 if error_descriptions:
1905 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281906 'You added one or more %s that violate checkdeps rules.'
1907 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181908 error_descriptions))
1909 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421910 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281911 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181912 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281913 '%s? See relevant DEPS file(s) for details and contacts.' %
1914 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181915 warning_descriptions))
1916 return results
1917
1918
Saagar Sanghavifceeaae2020-08-12 16:40:361919def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:221920 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151921 if input_api.platform == 'win32':
1922 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291923 checkperms_tool = input_api.os_path.join(
1924 input_api.PresubmitLocalPath(),
1925 'tools', 'checkperms', 'checkperms.py')
1926 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471927 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391928 with input_api.CreateTemporaryFile() as file_list:
1929 for f in input_api.AffectedFiles():
1930 # checkperms.py file/directory arguments must be relative to the
1931 # repository.
1932 file_list.write(f.LocalPath() + '\n')
1933 file_list.close()
1934 args += ['--file-list', file_list.name]
1935 try:
1936 input_api.subprocess.check_output(args)
1937 return []
1938 except input_api.subprocess.CalledProcessError as error:
1939 return [output_api.PresubmitError(
1940 'checkperms.py failed:',
1941 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221942
1943
Saagar Sanghavifceeaae2020-08-12 16:40:361944def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:491945 """Makes sure we don't include ui/aura/window_property.h
1946 in header files.
1947 """
1948 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1949 errors = []
1950 for f in input_api.AffectedFiles():
1951 if not f.LocalPath().endswith('.h'):
1952 continue
1953 for line_num, line in f.ChangedContents():
1954 if pattern.match(line):
1955 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1956
1957 results = []
1958 if errors:
1959 results.append(output_api.PresubmitError(
1960 'Header files should not include ui/aura/window_property.h', errors))
1961 return results
1962
1963
Omer Katzcc77ea92021-04-26 10:23:281964def CheckNoInternalHeapIncludes(input_api, output_api):
1965 """Makes sure we don't include any headers from
1966 third_party/blink/renderer/platform/heap/impl or
1967 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1968 third_party/blink/renderer/platform/heap
1969 """
1970 impl_pattern = input_api.re.compile(
1971 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1972 v8_wrapper_pattern = input_api.re.compile(
1973 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"')
1974 file_filter = lambda f: not input_api.re.match(
1975 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1976 f.LocalPath())
1977 errors = []
1978
1979 for f in input_api.AffectedFiles(file_filter=file_filter):
1980 for line_num, line in f.ChangedContents():
1981 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1982 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1983
1984 results = []
1985 if errors:
1986 results.append(output_api.PresubmitError(
1987 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1988 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1989 'relevant counterparts from third_party/blink/renderer/platform/heap',
1990 errors))
1991 return results
1992
1993
[email protected]70ca77752012-11-20 03:45:031994def _CheckForVersionControlConflictsInFile(input_api, f):
1995 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1996 errors = []
1997 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161998 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231999 # First-level headers in markdown look a lot like version control
2000 # conflict markers. http://daringfireball.net/projects/markdown/basics
2001 continue
[email protected]70ca77752012-11-20 03:45:032002 if pattern.match(line):
2003 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2004 return errors
2005
2006
Saagar Sanghavifceeaae2020-08-12 16:40:362007def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032008 """Usually this is not intentional and will cause a compile failure."""
2009 errors = []
2010 for f in input_api.AffectedFiles():
2011 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2012
2013 results = []
2014 if errors:
2015 results.append(output_api.PresubmitError(
2016 'Version control conflict markers found, please resolve.', errors))
2017 return results
2018
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202019
Saagar Sanghavifceeaae2020-08-12 16:40:362020def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162021 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2022 errors = []
2023 for f in input_api.AffectedFiles():
2024 for line_num, line in f.ChangedContents():
2025 if pattern.search(line):
2026 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2027
2028 results = []
2029 if errors:
2030 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502031 'Found Google support URL addressed by answer number. Please replace '
2032 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162033 return results
2034
[email protected]70ca77752012-11-20 03:45:032035
Saagar Sanghavifceeaae2020-08-12 16:40:362036def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442037 def FilterFile(affected_file):
2038 """Filter function for use with input_api.AffectedSourceFiles,
2039 below. This filters out everything except non-test files from
2040 top-level directories that generally speaking should not hard-code
2041 service URLs (e.g. src/android_webview/, src/content/ and others).
2042 """
2043 return input_api.FilterSourceFile(
2044 affected_file,
James Cook24a504192020-07-23 00:08:442045 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2046 files_to_skip=(_EXCLUDED_PATHS +
2047 _TEST_CODE_EXCLUDED_PATHS +
2048 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442049
reillyi38965732015-11-16 18:27:332050 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2051 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462052 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2053 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442054 problems = [] # items are (filename, line_number, line)
2055 for f in input_api.AffectedSourceFiles(FilterFile):
2056 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462057 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442058 problems.append((f.LocalPath(), line_num, line))
2059
2060 if problems:
[email protected]f7051d52013-04-02 18:31:422061 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442062 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582063 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442064 [' %s:%d: %s' % (
2065 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032066 else:
2067 return []
[email protected]06e6d0ff2012-12-11 01:36:442068
2069
Saagar Sanghavifceeaae2020-08-12 16:40:362070def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292071 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2072 def FileFilter(affected_file):
2073 """Includes directories known to be Chrome OS only."""
2074 return input_api.FilterSourceFile(
2075 affected_file,
James Cook24a504192020-07-23 00:08:442076 files_to_check=('^ash/',
2077 '^chromeos/', # Top-level src/chromeos.
2078 '/chromeos/', # Any path component.
2079 '^components/arc',
2080 '^components/exo'),
2081 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292082
2083 prefs = []
2084 priority_prefs = []
2085 for f in input_api.AffectedFiles(file_filter=FileFilter):
2086 for line_num, line in f.ChangedContents():
2087 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2088 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2089 prefs.append(' %s' % line)
2090 if input_api.re.search(
2091 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2092 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2093 priority_prefs.append(' %s' % line)
2094
2095 results = []
2096 if (prefs):
2097 results.append(output_api.PresubmitPromptWarning(
2098 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2099 'by browser sync settings. If these prefs should be controlled by OS '
2100 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2101 if (priority_prefs):
2102 results.append(output_api.PresubmitPromptWarning(
2103 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2104 'controlled by browser sync settings. If these prefs should be '
2105 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2106 'instead.\n' + '\n'.join(prefs)))
2107 return results
2108
2109
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492110# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362111def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272112 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312113 The native_client_sdk directory is excluded because it has auto-generated PNG
2114 files for documentation.
[email protected]d2530012013-01-25 16:39:272115 """
[email protected]d2530012013-01-25 16:39:272116 errors = []
James Cook24a504192020-07-23 00:08:442117 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2118 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312119 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442120 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312121 for f in input_api.AffectedFiles(include_deletes=False,
2122 file_filter=file_filter):
2123 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272124
2125 results = []
2126 if errors:
2127 results.append(output_api.PresubmitError(
2128 'The name of PNG files should not have abbreviations. \n'
2129 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2130 'Contact [email protected] if you have questions.', errors))
2131 return results
2132
2133
Daniel Cheng4dcdb6b2017-04-13 08:30:172134def _ExtractAddRulesFromParsedDeps(parsed_deps):
2135 """Extract the rules that add dependencies from a parsed DEPS file.
2136
2137 Args:
2138 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2139 add_rules = set()
2140 add_rules.update([
2141 rule[1:] for rule in parsed_deps.get('include_rules', [])
2142 if rule.startswith('+') or rule.startswith('!')
2143 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502144 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172145 {}).iteritems():
2146 add_rules.update([
2147 rule[1:] for rule in rules
2148 if rule.startswith('+') or rule.startswith('!')
2149 ])
2150 return add_rules
2151
2152
2153def _ParseDeps(contents):
2154 """Simple helper for parsing DEPS files."""
2155 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172156 class _VarImpl:
2157
2158 def __init__(self, local_scope):
2159 self._local_scope = local_scope
2160
2161 def Lookup(self, var_name):
2162 """Implements the Var syntax."""
2163 try:
2164 return self._local_scope['vars'][var_name]
2165 except KeyError:
2166 raise Exception('Var is not defined: %s' % var_name)
2167
2168 local_scope = {}
2169 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172170 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592171 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172172 }
Dirk Pranke1b9e06382021-05-14 01:16:222173
2174 # TODO(crbug.com/1207012): We need to strip the BOM because it isn't
2175 # legal in Python source files. We can remove this check once the CL
2176 # that actually removes the BOM from //third_party/crashpad/DEPS lands.
2177 if contents.startswith(u'\ufeff'):
2178 contents = contents[1:]
Daniel Cheng4dcdb6b2017-04-13 08:30:172179 exec contents in global_scope, local_scope
2180 return local_scope
2181
2182
2183def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592184 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412185 a set of DEPS entries that we should look up.
2186
2187 For a directory (rather than a specific filename) we fake a path to
2188 a specific filename by adding /DEPS. This is chosen as a file that
2189 will seldom or never be subject to per-file include_rules.
2190 """
[email protected]2b438d62013-11-14 17:54:142191 # We ignore deps entries on auto-generated directories.
2192 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082193
Daniel Cheng4dcdb6b2017-04-13 08:30:172194 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2195 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2196
2197 added_deps = new_deps.difference(old_deps)
2198
[email protected]2b438d62013-11-14 17:54:142199 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172200 for added_dep in added_deps:
2201 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2202 continue
2203 # Assume that a rule that ends in .h is a rule for a specific file.
2204 if added_dep.endswith('.h'):
2205 results.add(added_dep)
2206 else:
2207 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082208 return results
2209
2210
Saagar Sanghavifceeaae2020-08-12 16:40:362211def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552212 """When a dependency prefixed with + is added to a DEPS file, we
2213 want to make sure that the change is reviewed by an OWNER of the
2214 target file or directory, to avoid layering violations from being
2215 introduced. This check verifies that this happens.
2216 """
Joey Mou57048132021-02-26 22:17:552217 # We rely on Gerrit's code-owners to check approvals.
2218 # input_api.gerrit is always set for Chromium, but other projects
2219 # might not use Gerrit.
2220 if not input_api.gerrit:
2221 return []
Edward Lesmes44feb2332021-03-19 01:27:522222 if (input_api.change.issue and
2223 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232224 # Skip OWNERS check when Owners-Override label is approved. This is intended
2225 # for global owners, trusted bots, and on-call sheriffs. Review is still
2226 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522227 return []
Edward Lesmes6fba51082021-01-20 04:20:232228
Daniel Cheng4dcdb6b2017-04-13 08:30:172229 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242230
2231 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492232 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242233 for f in input_api.AffectedFiles(include_deletes=False,
2234 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552235 filename = input_api.os_path.basename(f.LocalPath())
2236 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172237 virtual_depended_on_files.update(_CalculateAddedDeps(
2238 input_api.os_path,
2239 '\n'.join(f.OldContents()),
2240 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552241
[email protected]e871964c2013-05-13 14:14:552242 if not virtual_depended_on_files:
2243 return []
2244
2245 if input_api.is_committing:
2246 if input_api.tbr:
2247 return [output_api.PresubmitNotifyResult(
2248 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272249 if input_api.dry_run:
2250 return [output_api.PresubmitNotifyResult(
2251 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552252 if not input_api.change.issue:
2253 return [output_api.PresubmitError(
2254 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402255 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552256 output = output_api.PresubmitError
2257 else:
2258 output = output_api.PresubmitNotifyResult
2259
tandriied3b7e12016-05-12 14:38:502260 owner_email, reviewers = (
2261 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2262 input_api,
Edward Lesmesa3846442021-02-08 20:20:032263 None,
tandriied3b7e12016-05-12 14:38:502264 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552265
2266 owner_email = owner_email or input_api.change.author_email
2267
Edward Lesmesa3846442021-02-08 20:20:032268 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2269 virtual_depended_on_files, reviewers.union([owner_email]), [])
2270 missing_files = [
2271 f for f in virtual_depended_on_files
2272 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412273
2274 # We strip the /DEPS part that was added by
2275 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2276 # directory.
2277 def StripDeps(path):
2278 start_deps = path.rfind('/DEPS')
2279 if start_deps != -1:
2280 return path[:start_deps]
2281 else:
2282 return path
2283 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552284 for path in missing_files]
2285
2286 if unapproved_dependencies:
2287 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152288 output('You need LGTM from owners of depends-on paths in DEPS that were '
2289 'modified in this CL:\n %s' %
2290 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032291 suggested_owners = input_api.owners_client.SuggestOwners(
2292 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152293 output_list.append(output(
2294 'Suggested missing target path OWNERS:\n %s' %
2295 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552296 return output_list
2297
2298 return []
2299
2300
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492301# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362302def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492303 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442304 files_to_skip = (_EXCLUDED_PATHS +
2305 _TEST_CODE_EXCLUDED_PATHS +
2306 input_api.DEFAULT_FILES_TO_SKIP +
2307 (r"^base[\\/]logging\.h$",
2308 r"^base[\\/]logging\.cc$",
2309 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2310 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2311 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2312 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2313 r"startup_browser_creator\.cc$",
2314 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2315 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2316 r"diagnostics_writer\.cc$",
2317 r"^chrome[\\/]chrome_cleaner[\\/].*",
2318 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2319 r"dll_hash_main\.cc$",
2320 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2321 r"^chromecast[\\/]",
2322 r"^cloud_print[\\/]",
2323 r"^components[\\/]browser_watcher[\\/]"
2324 r"dump_stability_report_main_win.cc$",
2325 r"^components[\\/]media_control[\\/]renderer[\\/]"
2326 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352327 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2328 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442329 r"^components[\\/]zucchini[\\/].*",
2330 # TODO(peter): Remove exception. https://crbug.com/534537
2331 r"^content[\\/]browser[\\/]notifications[\\/]"
2332 r"notification_event_dispatcher_impl\.cc$",
2333 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2334 r"gl_helper_benchmark\.cc$",
2335 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2336 r"^courgette[\\/]courgette_tool\.cc$",
2337 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2338 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2339 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Sergey Ulanov6db14b4d62021-05-10 07:59:482340 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
James Cook24a504192020-07-23 00:08:442341 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2342 r"^ipc[\\/]ipc_logging\.cc$",
2343 r"^native_client_sdk[\\/]",
2344 r"^remoting[\\/]base[\\/]logging\.h$",
2345 r"^remoting[\\/]host[\\/].*",
2346 r"^sandbox[\\/]linux[\\/].*",
2347 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2348 r"dump_file_system.cc$",
2349 r"^tools[\\/]",
2350 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2351 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2352 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2353 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2354 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402355 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442356 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402357
thomasanderson625d3932017-03-29 07:16:582358 log_info = set([])
2359 printf = set([])
[email protected]85218562013-11-22 07:41:402360
2361 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582362 for _, line in f.ChangedContents():
2363 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2364 log_info.add(f.LocalPath())
2365 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2366 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372367
thomasanderson625d3932017-03-29 07:16:582368 if input_api.re.search(r"\bprintf\(", line):
2369 printf.add(f.LocalPath())
2370 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2371 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402372
2373 if log_info:
2374 return [output_api.PresubmitError(
2375 'These files spam the console log with LOG(INFO):',
2376 items=log_info)]
2377 if printf:
2378 return [output_api.PresubmitError(
2379 'These files spam the console log with printf/fprintf:',
2380 items=printf)]
2381 return []
2382
2383
Saagar Sanghavifceeaae2020-08-12 16:40:362384def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162385 """These types are all expected to hold locks while in scope and
2386 so should never be anonymous (which causes them to be immediately
2387 destroyed)."""
2388 they_who_must_be_named = [
2389 'base::AutoLock',
2390 'base::AutoReset',
2391 'base::AutoUnlock',
2392 'SkAutoAlphaRestore',
2393 'SkAutoBitmapShaderInstall',
2394 'SkAutoBlitterChoose',
2395 'SkAutoBounderCommit',
2396 'SkAutoCallProc',
2397 'SkAutoCanvasRestore',
2398 'SkAutoCommentBlock',
2399 'SkAutoDescriptor',
2400 'SkAutoDisableDirectionCheck',
2401 'SkAutoDisableOvalCheck',
2402 'SkAutoFree',
2403 'SkAutoGlyphCache',
2404 'SkAutoHDC',
2405 'SkAutoLockColors',
2406 'SkAutoLockPixels',
2407 'SkAutoMalloc',
2408 'SkAutoMaskFreeImage',
2409 'SkAutoMutexAcquire',
2410 'SkAutoPathBoundsUpdate',
2411 'SkAutoPDFRelease',
2412 'SkAutoRasterClipValidate',
2413 'SkAutoRef',
2414 'SkAutoTime',
2415 'SkAutoTrace',
2416 'SkAutoUnref',
2417 ]
2418 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2419 # bad: base::AutoLock(lock.get());
2420 # not bad: base::AutoLock lock(lock.get());
2421 bad_pattern = input_api.re.compile(anonymous)
2422 # good: new base::AutoLock(lock.get())
2423 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2424 errors = []
2425
2426 for f in input_api.AffectedFiles():
2427 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2428 continue
2429 for linenum, line in f.ChangedContents():
2430 if bad_pattern.search(line) and not good_pattern.search(line):
2431 errors.append('%s:%d' % (f.LocalPath(), linenum))
2432
2433 if errors:
2434 return [output_api.PresubmitError(
2435 'These lines create anonymous variables that need to be named:',
2436 items=errors)]
2437 return []
2438
2439
Saagar Sanghavifceeaae2020-08-12 16:40:362440def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532441 # Returns whether |template_str| is of the form <T, U...> for some types T
2442 # and U. Assumes that |template_str| is already in the form <...>.
2443 def HasMoreThanOneArg(template_str):
2444 # Level of <...> nesting.
2445 nesting = 0
2446 for c in template_str:
2447 if c == '<':
2448 nesting += 1
2449 elif c == '>':
2450 nesting -= 1
2451 elif c == ',' and nesting == 1:
2452 return True
2453 return False
2454
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492455 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102456 sources = lambda affected_file: input_api.FilterSourceFile(
2457 affected_file,
James Cook24a504192020-07-23 00:08:442458 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2459 input_api.DEFAULT_FILES_TO_SKIP),
2460 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552461
2462 # Pattern to capture a single "<...>" block of template arguments. It can
2463 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2464 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2465 # latter would likely require counting that < and > match, which is not
2466 # expressible in regular languages. Should the need arise, one can introduce
2467 # limited counting (matching up to a total number of nesting depth), which
2468 # should cover all practical cases for already a low nesting limit.
2469 template_arg_pattern = (
2470 r'<[^>]*' # Opening block of <.
2471 r'>([^<]*>)?') # Closing block of >.
2472 # Prefix expressing that whatever follows is not already inside a <...>
2473 # block.
2474 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102475 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552476 not_inside_template_arg_pattern
2477 + r'\bstd::unique_ptr'
2478 + template_arg_pattern
2479 + r'\(\)')
2480
2481 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2482 template_arg_no_array_pattern = (
2483 r'<[^>]*[^]]' # Opening block of <.
2484 r'>([^(<]*[^]]>)?') # Closing block of >.
2485 # Prefix saying that what follows is the start of an expression.
2486 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2487 # Suffix saying that what follows are call parentheses with a non-empty list
2488 # of arguments.
2489 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532490 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552491 return_construct_pattern = input_api.re.compile(
2492 start_of_expr_pattern
2493 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532494 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552495 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532496 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552497 + nonempty_arg_list_pattern)
2498
Vaclav Brozek851d9602018-04-04 16:13:052499 problems_constructor = []
2500 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102501 for f in input_api.AffectedSourceFiles(sources):
2502 for line_number, line in f.ChangedContents():
2503 # Disallow:
2504 # return std::unique_ptr<T>(foo);
2505 # bar = std::unique_ptr<T>(foo);
2506 # But allow:
2507 # return std::unique_ptr<T[]>(foo);
2508 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532509 # And also allow cases when the second template argument is present. Those
2510 # cases cannot be handled by std::make_unique:
2511 # return std::unique_ptr<T, U>(foo);
2512 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052513 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532514 return_construct_result = return_construct_pattern.search(line)
2515 if return_construct_result and not HasMoreThanOneArg(
2516 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052517 problems_constructor.append(
2518 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102519 # Disallow:
2520 # std::unique_ptr<T>()
2521 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052522 problems_nullptr.append(
2523 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2524
2525 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162526 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052527 errors.append(output_api.PresubmitError(
2528 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162529 problems_nullptr))
2530 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052531 errors.append(output_api.PresubmitError(
2532 'The following files use explicit std::unique_ptr constructor.'
2533 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162534 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102535 return errors
2536
2537
Saagar Sanghavifceeaae2020-08-12 16:40:362538def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082539 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522540 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082541 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522542 # If actions.xml is already included in the changelist, the PRESUBMIT
2543 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082544 return []
2545
Alexei Svitkine64505a92021-03-11 22:00:542546 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2547 files_to_skip = (_EXCLUDED_PATHS +
2548 _TEST_CODE_EXCLUDED_PATHS +
2549 input_api.DEFAULT_FILES_TO_SKIP )
2550 file_filter = lambda f: input_api.FilterSourceFile(
2551 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2552
[email protected]999261d2014-03-03 20:08:082553 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522554 current_actions = None
[email protected]999261d2014-03-03 20:08:082555 for f in input_api.AffectedFiles(file_filter=file_filter):
2556 for line_num, line in f.ChangedContents():
2557 match = input_api.re.search(action_re, line)
2558 if match:
[email protected]2f92dec2014-03-07 19:21:522559 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2560 # loaded only once.
2561 if not current_actions:
2562 with open('tools/metrics/actions/actions.xml') as actions_f:
2563 current_actions = actions_f.read()
2564 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082565 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522566 action = 'name="{0}"'.format(action_name)
2567 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082568 return [output_api.PresubmitPromptWarning(
2569 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522570 'tools/metrics/actions/actions.xml. Please run '
2571 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082572 % (f.LocalPath(), line_num, action_name))]
2573 return []
2574
2575
Daniel Cheng13ca61a882017-08-25 15:11:252576def _ImportJSONCommentEater(input_api):
2577 import sys
2578 sys.path = sys.path + [input_api.os_path.join(
2579 input_api.PresubmitLocalPath(),
2580 'tools', 'json_comment_eater')]
2581 import json_comment_eater
2582 return json_comment_eater
2583
2584
[email protected]99171a92014-06-03 08:44:472585def _GetJSONParseError(input_api, filename, eat_comments=True):
2586 try:
2587 contents = input_api.ReadFile(filename)
2588 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252589 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132590 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472591
2592 input_api.json.loads(contents)
2593 except ValueError as e:
2594 return e
2595 return None
2596
2597
2598def _GetIDLParseError(input_api, filename):
2599 try:
2600 contents = input_api.ReadFile(filename)
2601 idl_schema = input_api.os_path.join(
2602 input_api.PresubmitLocalPath(),
2603 'tools', 'json_schema_compiler', 'idl_schema.py')
2604 process = input_api.subprocess.Popen(
2605 [input_api.python_executable, idl_schema],
2606 stdin=input_api.subprocess.PIPE,
2607 stdout=input_api.subprocess.PIPE,
2608 stderr=input_api.subprocess.PIPE,
2609 universal_newlines=True)
2610 (_, error) = process.communicate(input=contents)
2611 return error or None
2612 except ValueError as e:
2613 return e
2614
2615
Saagar Sanghavifceeaae2020-08-12 16:40:362616def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472617 """Check that IDL and JSON files do not contain syntax errors."""
2618 actions = {
2619 '.idl': _GetIDLParseError,
2620 '.json': _GetJSONParseError,
2621 }
[email protected]99171a92014-06-03 08:44:472622 # Most JSON files are preprocessed and support comments, but these do not.
2623 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042624 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472625 ]
2626 # Only run IDL checker on files in these directories.
2627 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042628 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2629 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472630 ]
2631
2632 def get_action(affected_file):
2633 filename = affected_file.LocalPath()
2634 return actions.get(input_api.os_path.splitext(filename)[1])
2635
[email protected]99171a92014-06-03 08:44:472636 def FilterFile(affected_file):
2637 action = get_action(affected_file)
2638 if not action:
2639 return False
2640 path = affected_file.LocalPath()
2641
Erik Staab2dd72b12020-04-16 15:03:402642 if _MatchesFile(input_api,
2643 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2644 path):
[email protected]99171a92014-06-03 08:44:472645 return False
2646
2647 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162648 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472649 return False
2650 return True
2651
2652 results = []
2653 for affected_file in input_api.AffectedFiles(
2654 file_filter=FilterFile, include_deletes=False):
2655 action = get_action(affected_file)
2656 kwargs = {}
2657 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162658 _MatchesFile(input_api, json_no_comments_patterns,
2659 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472660 kwargs['eat_comments'] = False
2661 parse_error = action(input_api,
2662 affected_file.AbsoluteLocalPath(),
2663 **kwargs)
2664 if parse_error:
2665 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2666 (affected_file.LocalPath(), parse_error)))
2667 return results
2668
2669
Saagar Sanghavifceeaae2020-08-12 16:40:362670def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492671 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472672 import sys
[email protected]760deea2013-12-10 19:33:492673 original_sys_path = sys.path
2674 try:
2675 sys.path = sys.path + [input_api.os_path.join(
2676 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2677 import checkstyle
2678 finally:
2679 # Restore sys.path to what it was before.
2680 sys.path = original_sys_path
2681
2682 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092683 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442684 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492685
2686
Saagar Sanghavifceeaae2020-08-12 16:40:362687def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002688 """Checks to make sure devil is initialized correctly in python scripts."""
2689 script_common_initialize_pattern = input_api.re.compile(
2690 r'script_common\.InitializeEnvironment\(')
2691 devil_env_config_initialize = input_api.re.compile(
2692 r'devil_env\.config\.Initialize\(')
2693
2694 errors = []
2695
2696 sources = lambda affected_file: input_api.FilterSourceFile(
2697 affected_file,
James Cook24a504192020-07-23 00:08:442698 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2699 (r'^build[\\/]android[\\/]devil_chromium\.py',
2700 r'^third_party[\\/].*',)),
2701 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002702
2703 for f in input_api.AffectedSourceFiles(sources):
2704 for line_num, line in f.ChangedContents():
2705 if (script_common_initialize_pattern.search(line) or
2706 devil_env_config_initialize.search(line)):
2707 errors.append("%s:%d" % (f.LocalPath(), line_num))
2708
2709 results = []
2710
2711 if errors:
2712 results.append(output_api.PresubmitError(
2713 'Devil initialization should always be done using '
2714 'devil_chromium.Initialize() in the chromium project, to use better '
2715 'defaults for dependencies (ex. up-to-date version of adb).',
2716 errors))
2717
2718 return results
2719
2720
Sean Kau46e29bc2017-08-28 16:31:162721def _MatchesFile(input_api, patterns, path):
2722 for pattern in patterns:
2723 if input_api.re.search(pattern, path):
2724 return True
2725 return False
2726
2727
Daniel Cheng7052cdf2017-11-21 19:23:292728def _GetOwnersFilesToCheckForIpcOwners(input_api):
2729 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172730
Daniel Cheng7052cdf2017-11-21 19:23:292731 Returns:
2732 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2733 contain to cover IPC-related files with noparent reviewer rules.
2734 """
2735 # Whether or not a file affects IPC is (mostly) determined by a simple list
2736 # of filename patterns.
dchenge07de812016-06-20 19:27:172737 file_patterns = [
palmerb19a0932017-01-24 04:00:312738 # Legacy IPC:
dchenge07de812016-06-20 19:27:172739 '*_messages.cc',
2740 '*_messages*.h',
2741 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312742 # Mojo IPC:
dchenge07de812016-06-20 19:27:172743 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472744 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172745 '*_struct_traits*.*',
2746 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312747 '*.typemap',
2748 # Android native IPC:
2749 '*.aidl',
2750 # Blink uses a different file naming convention:
2751 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472752 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172753 '*StructTraits*.*',
2754 '*TypeConverter*.*',
2755 ]
2756
scottmg7a6ed5ba2016-11-04 18:22:042757 # These third_party directories do not contain IPCs, but contain files
2758 # matching the above patterns, which trigger false positives.
2759 exclude_paths = [
2760 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162761 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232762 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292763 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542764 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162765 # These files are just used to communicate between class loaders running
2766 # in the same process.
2767 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572768 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2769
scottmg7a6ed5ba2016-11-04 18:22:042770 ]
2771
dchenge07de812016-06-20 19:27:172772 # Dictionary mapping an OWNERS file path to Patterns.
2773 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2774 # rules ) to a PatternEntry.
2775 # PatternEntry is a dictionary with two keys:
2776 # - 'files': the files that are matched by this pattern
2777 # - 'rules': the per-file rules needed for this pattern
2778 # For example, if we expect OWNERS file to contain rules for *.mojom and
2779 # *_struct_traits*.*, Patterns might look like this:
2780 # {
2781 # '*.mojom': {
2782 # 'files': ...,
2783 # 'rules': [
2784 # 'per-file *.mojom=set noparent',
2785 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2786 # ],
2787 # },
2788 # '*_struct_traits*.*': {
2789 # 'files': ...,
2790 # 'rules': [
2791 # 'per-file *_struct_traits*.*=set noparent',
2792 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2793 # ],
2794 # },
2795 # }
2796 to_check = {}
2797
Daniel Cheng13ca61a882017-08-25 15:11:252798 def AddPatternToCheck(input_file, pattern):
2799 owners_file = input_api.os_path.join(
2800 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2801 if owners_file not in to_check:
2802 to_check[owners_file] = {}
2803 if pattern not in to_check[owners_file]:
2804 to_check[owners_file][pattern] = {
2805 'files': [],
2806 'rules': [
2807 'per-file %s=set noparent' % pattern,
2808 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2809 ]
2810 }
Vaclav Brozekd5de76a2018-03-17 07:57:502811 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252812
dchenge07de812016-06-20 19:27:172813 # Iterate through the affected files to see what we actually need to check
2814 # for. We should only nag patch authors about per-file rules if a file in that
2815 # directory would match that pattern. If a directory only contains *.mojom
2816 # files and no *_messages*.h files, we should only nag about rules for
2817 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252818 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262819 # Manifest files don't have a strong naming convention. Instead, try to find
2820 # affected .cc and .h files which look like they contain a manifest
2821 # definition.
2822 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2823 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2824 if (manifest_pattern.search(f.LocalPath()) and not
2825 test_manifest_pattern.search(f.LocalPath())):
2826 # We expect all actual service manifest files to contain at least one
2827 # qualified reference to service_manager::Manifest.
2828 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252829 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172830 for pattern in file_patterns:
2831 if input_api.fnmatch.fnmatch(
2832 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042833 skip = False
2834 for exclude in exclude_paths:
2835 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2836 skip = True
2837 break
2838 if skip:
2839 continue
Daniel Cheng13ca61a882017-08-25 15:11:252840 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172841 break
2842
Daniel Cheng7052cdf2017-11-21 19:23:292843 return to_check
2844
2845
Wez17c66962020-04-29 15:26:032846def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2847 """Adds OWNERS files to check for correct Fuchsia security owners."""
2848
2849 file_patterns = [
2850 # Component specifications.
2851 '*.cml', # Component Framework v2.
2852 '*.cmx', # Component Framework v1.
2853
2854 # Fuchsia IDL protocol specifications.
2855 '*.fidl',
2856 ]
2857
Joshua Peraza1ca6d392020-12-08 00:14:092858 # Don't check for owners files for changes in these directories.
2859 exclude_paths = [
2860 'third_party/crashpad/*',
2861 ]
2862
Wez17c66962020-04-29 15:26:032863 def AddPatternToCheck(input_file, pattern):
2864 owners_file = input_api.os_path.join(
2865 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2866 if owners_file not in to_check:
2867 to_check[owners_file] = {}
2868 if pattern not in to_check[owners_file]:
2869 to_check[owners_file][pattern] = {
2870 'files': [],
2871 'rules': [
2872 'per-file %s=set noparent' % pattern,
2873 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2874 ]
2875 }
2876 to_check[owners_file][pattern]['files'].append(input_file)
2877
2878 # Iterate through the affected files to see what we actually need to check
2879 # for. We should only nag patch authors about per-file rules if a file in that
2880 # directory would match that pattern.
2881 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092882 skip = False
2883 for exclude in exclude_paths:
2884 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2885 skip = True
2886 if skip:
2887 continue
2888
Wez17c66962020-04-29 15:26:032889 for pattern in file_patterns:
2890 if input_api.fnmatch.fnmatch(
2891 input_api.os_path.basename(f.LocalPath()), pattern):
2892 AddPatternToCheck(f, pattern)
2893 break
2894
2895 return to_check
2896
2897
Saagar Sanghavifceeaae2020-08-12 16:40:362898def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292899 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2900 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032901 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292902
2903 if to_check:
2904 # If there are any OWNERS files to check, there are IPC-related changes in
2905 # this CL. Auto-CC the review list.
2906 output_api.AppendCC('[email protected]')
2907
2908 # Go through the OWNERS files to check, filtering out rules that are already
2909 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172910 for owners_file, patterns in to_check.iteritems():
2911 try:
2912 with file(owners_file) as f:
2913 lines = set(f.read().splitlines())
2914 for entry in patterns.itervalues():
2915 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2916 ]
2917 except IOError:
2918 # No OWNERS file, so all the rules are definitely missing.
2919 continue
2920
2921 # All the remaining lines weren't found in OWNERS files, so emit an error.
2922 errors = []
2923 for owners_file, patterns in to_check.iteritems():
2924 missing_lines = []
2925 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502926 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172927 missing_lines.extend(entry['rules'])
2928 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2929 if missing_lines:
2930 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052931 'Because of the presence of files:\n%s\n\n'
2932 '%s needs the following %d lines added:\n\n%s' %
2933 ('\n'.join(files), owners_file, len(missing_lines),
2934 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172935
2936 results = []
2937 if errors:
vabrf5ce3bf92016-07-11 14:52:412938 if input_api.is_committing:
2939 output = output_api.PresubmitError
2940 else:
2941 output = output_api.PresubmitPromptWarning
2942 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592943 'Found OWNERS files that need to be updated for IPC security ' +
2944 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172945 long_text='\n\n'.join(errors)))
2946
2947 return results
2948
2949
Robert Sesek2c905332020-05-06 23:17:132950def _GetFilesUsingSecurityCriticalFunctions(input_api):
2951 """Checks affected files for changes to security-critical calls. This
2952 function checks the full change diff, to catch both additions/changes
2953 and removals.
2954
2955 Returns a dict keyed by file name, and the value is a set of detected
2956 functions.
2957 """
2958 # Map of function pretty name (displayed in an error) to the pattern to
2959 # match it with.
2960 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:372961 'content::GetServiceSandboxType<>()':
2962 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:132963 }
2964 _PATTERNS_TO_CHECK = {
2965 k: input_api.re.compile(v)
2966 for k, v in _PATTERNS_TO_CHECK.items()
2967 }
2968
2969 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2970 files_to_functions = {}
2971 for f in input_api.AffectedFiles():
2972 diff = f.GenerateScmDiff()
2973 for line in diff.split('\n'):
2974 # Not using just RightHandSideLines() because removing a
2975 # call to a security-critical function can be just as important
2976 # as adding or changing the arguments.
2977 if line.startswith('-') or (line.startswith('+') and
2978 not line.startswith('++')):
2979 for name, pattern in _PATTERNS_TO_CHECK.items():
2980 if pattern.search(line):
2981 path = f.LocalPath()
2982 if not path in files_to_functions:
2983 files_to_functions[path] = set()
2984 files_to_functions[path].add(name)
2985 return files_to_functions
2986
2987
Saagar Sanghavifceeaae2020-08-12 16:40:362988def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:132989 """Checks that changes involving security-critical functions are reviewed
2990 by the security team.
2991 """
2992 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:122993 if not len(files_to_functions):
2994 return []
Robert Sesek2c905332020-05-06 23:17:132995
Edward Lesmes1e9fade2021-02-08 20:31:122996 owner_email, reviewers = (
2997 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2998 input_api,
2999 None,
3000 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:133001
Edward Lesmes1e9fade2021-02-08 20:31:123002 # Load the OWNERS file for security changes.
3003 owners_file = 'ipc/SECURITY_OWNERS'
3004 security_owners = input_api.owners_client.ListOwners(owners_file)
3005 has_security_owner = any([owner in reviewers for owner in security_owners])
3006 if has_security_owner:
3007 return []
Robert Sesek2c905332020-05-06 23:17:133008
Edward Lesmes1e9fade2021-02-08 20:31:123009 msg = 'The following files change calls to security-sensive functions\n' \
3010 'that need to be reviewed by {}.\n'.format(owners_file)
3011 for path, names in files_to_functions.items():
3012 msg += ' {}\n'.format(path)
3013 for name in names:
3014 msg += ' {}\n'.format(name)
3015 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133016
Edward Lesmes1e9fade2021-02-08 20:31:123017 if input_api.is_committing:
3018 output = output_api.PresubmitError
3019 else:
3020 output = output_api.PresubmitNotifyResult
3021 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133022
3023
Saagar Sanghavifceeaae2020-08-12 16:40:363024def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263025 """Checks that set noparent is only used together with an OWNERS file in
3026 //build/OWNERS.setnoparent (see also
3027 //docs/code_reviews.md#owners-files-details)
3028 """
3029 errors = []
3030
3031 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3032 allowed_owners_files = set()
3033 with open(allowed_owners_files_file, 'r') as f:
3034 for line in f:
3035 line = line.strip()
3036 if not line or line.startswith('#'):
3037 continue
3038 allowed_owners_files.add(line)
3039
3040 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3041
3042 for f in input_api.AffectedFiles(include_deletes=False):
3043 if not f.LocalPath().endswith('OWNERS'):
3044 continue
3045
3046 found_owners_files = set()
3047 found_set_noparent_lines = dict()
3048
3049 # Parse the OWNERS file.
3050 for lineno, line in enumerate(f.NewContents(), 1):
3051 line = line.strip()
3052 if line.startswith('set noparent'):
3053 found_set_noparent_lines[''] = lineno
3054 if line.startswith('file://'):
3055 if line in allowed_owners_files:
3056 found_owners_files.add('')
3057 if line.startswith('per-file'):
3058 match = per_file_pattern.match(line)
3059 if match:
3060 glob = match.group(1).strip()
3061 directive = match.group(2).strip()
3062 if directive == 'set noparent':
3063 found_set_noparent_lines[glob] = lineno
3064 if directive.startswith('file://'):
3065 if directive in allowed_owners_files:
3066 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153067
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263068 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403069 # listed in build/OWNERS.setnoparent. An exception is made for top level
3070 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143071 if (f.LocalPath().count('/') != 1 and
3072 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403073 for set_noparent_line in found_set_noparent_lines:
3074 if set_noparent_line in found_owners_files:
3075 continue
3076 errors.append(' %s:%d' % (f.LocalPath(),
3077 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263078
3079 results = []
3080 if errors:
3081 if input_api.is_committing:
3082 output = output_api.PresubmitError
3083 else:
3084 output = output_api.PresubmitPromptWarning
3085 results.append(output(
3086 'Found the following "set noparent" restrictions in OWNERS files that '
3087 'do not include owners from build/OWNERS.setnoparent:',
3088 long_text='\n\n'.join(errors)))
3089 return results
3090
3091
Saagar Sanghavifceeaae2020-08-12 16:40:363092def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313093 """Checks that added or removed lines in non third party affected
3094 header files do not lead to new useless class or struct forward
3095 declaration.
jbriance9e12f162016-11-25 07:57:503096 """
3097 results = []
3098 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3099 input_api.re.MULTILINE)
3100 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3101 input_api.re.MULTILINE)
3102 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313103 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193104 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493105 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313106 continue
3107
jbriance9e12f162016-11-25 07:57:503108 if not f.LocalPath().endswith('.h'):
3109 continue
3110
3111 contents = input_api.ReadFile(f)
3112 fwd_decls = input_api.re.findall(class_pattern, contents)
3113 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3114
3115 useless_fwd_decls = []
3116 for decl in fwd_decls:
3117 count = sum(1 for _ in input_api.re.finditer(
3118 r'\b%s\b' % input_api.re.escape(decl), contents))
3119 if count == 1:
3120 useless_fwd_decls.append(decl)
3121
3122 if not useless_fwd_decls:
3123 continue
3124
3125 for line in f.GenerateScmDiff().splitlines():
3126 if (line.startswith('-') and not line.startswith('--') or
3127 line.startswith('+') and not line.startswith('++')):
3128 for decl in useless_fwd_decls:
3129 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3130 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243131 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503132 (f.LocalPath(), decl)))
3133 useless_fwd_decls.remove(decl)
3134
3135 return results
3136
Jinsong Fan91ebbbd2019-04-16 14:57:173137def _CheckAndroidDebuggableBuild(input_api, output_api):
3138 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3139 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3140 this is a debuggable build of Android.
3141 """
3142 build_type_check_pattern = input_api.re.compile(
3143 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3144
3145 errors = []
3146
3147 sources = lambda affected_file: input_api.FilterSourceFile(
3148 affected_file,
James Cook24a504192020-07-23 00:08:443149 files_to_skip=(_EXCLUDED_PATHS +
3150 _TEST_CODE_EXCLUDED_PATHS +
3151 input_api.DEFAULT_FILES_TO_SKIP +
3152 (r"^android_webview[\\/]support_library[\\/]"
3153 "boundary_interfaces[\\/]",
3154 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3155 r'^third_party[\\/].*',
3156 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3157 r"webview[\\/]chromium[\\/]License.*",)),
3158 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173159
3160 for f in input_api.AffectedSourceFiles(sources):
3161 for line_num, line in f.ChangedContents():
3162 if build_type_check_pattern.search(line):
3163 errors.append("%s:%d" % (f.LocalPath(), line_num))
3164
3165 results = []
3166
3167 if errors:
3168 results.append(output_api.PresubmitPromptWarning(
3169 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3170 ' Please use BuildInfo.isDebugAndroid() instead.',
3171 errors))
3172
3173 return results
jbriance9e12f162016-11-25 07:57:503174
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493175# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293176def _CheckAndroidToastUsage(input_api, output_api):
3177 """Checks that code uses org.chromium.ui.widget.Toast instead of
3178 android.widget.Toast (Chromium Toast doesn't force hardware
3179 acceleration on low-end devices, saving memory).
3180 """
3181 toast_import_pattern = input_api.re.compile(
3182 r'^import android\.widget\.Toast;$')
3183
3184 errors = []
3185
3186 sources = lambda affected_file: input_api.FilterSourceFile(
3187 affected_file,
James Cook24a504192020-07-23 00:08:443188 files_to_skip=(_EXCLUDED_PATHS +
3189 _TEST_CODE_EXCLUDED_PATHS +
3190 input_api.DEFAULT_FILES_TO_SKIP +
3191 (r'^chromecast[\\/].*',
3192 r'^remoting[\\/].*')),
3193 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293194
3195 for f in input_api.AffectedSourceFiles(sources):
3196 for line_num, line in f.ChangedContents():
3197 if toast_import_pattern.search(line):
3198 errors.append("%s:%d" % (f.LocalPath(), line_num))
3199
3200 results = []
3201
3202 if errors:
3203 results.append(output_api.PresubmitError(
3204 'android.widget.Toast usage is detected. Android toasts use hardware'
3205 ' acceleration, and can be\ncostly on low-end devices. Please use'
3206 ' org.chromium.ui.widget.Toast instead.\n'
3207 'Contact [email protected] if you have any questions.',
3208 errors))
3209
3210 return results
3211
3212
dgnaa68d5e2015-06-10 10:08:223213def _CheckAndroidCrLogUsage(input_api, output_api):
3214 """Checks that new logs using org.chromium.base.Log:
3215 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513216 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223217 """
pkotwicza1dd0b002016-05-16 14:41:043218
torne89540622017-03-24 19:41:303219 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043220 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303221 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043222 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303223 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043224 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3225 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093226 # The customtabs_benchmark is a small app that does not depend on Chromium
3227 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043228 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043229 ]
3230
dgnaa68d5e2015-06-10 10:08:223231 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123232 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3233 class_in_base_pattern = input_api.re.compile(
3234 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3235 has_some_log_import_pattern = input_api.re.compile(
3236 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223237 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553238 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223239 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463240 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553241 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223242
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463243 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443244 sources = lambda x: input_api.FilterSourceFile(x,
3245 files_to_check=[r'.*\.java$'],
3246 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123247
dgnaa68d5e2015-06-10 10:08:223248 tag_decl_errors = []
3249 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123250 tag_errors = []
dgn38736db2015-09-18 19:20:513251 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123252 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223253
3254 for f in input_api.AffectedSourceFiles(sources):
3255 file_content = input_api.ReadFile(f)
3256 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223257 # Per line checks
dgn87d9fb62015-06-12 09:15:123258 if (cr_log_import_pattern.search(file_content) or
3259 (class_in_base_pattern.search(file_content) and
3260 not has_some_log_import_pattern.search(file_content))):
3261 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223262 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553263 if rough_log_decl_pattern.search(line):
3264 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223265
3266 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123267 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223268 if match:
3269 has_modified_logs = True
3270
3271 # Make sure it uses "TAG"
3272 if not match.group('tag') == 'TAG':
3273 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123274 else:
3275 # Report non cr Log function calls in changed lines
3276 for line_num, line in f.ChangedContents():
3277 if log_call_pattern.search(line):
3278 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223279
3280 # Per file checks
3281 if has_modified_logs:
3282 # Make sure the tag is using the "cr" prefix and is not too long
3283 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513284 tag_name = match.group('name') if match else None
3285 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223286 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513287 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223288 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513289 elif '.' in tag_name:
3290 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223291
3292 results = []
3293 if tag_decl_errors:
3294 results.append(output_api.PresubmitPromptWarning(
3295 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513296 '"private static final String TAG = "<package tag>".\n'
3297 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223298 tag_decl_errors))
3299
3300 if tag_length_errors:
3301 results.append(output_api.PresubmitError(
3302 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513303 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223304 tag_length_errors))
3305
3306 if tag_errors:
3307 results.append(output_api.PresubmitPromptWarning(
3308 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3309 tag_errors))
3310
dgn87d9fb62015-06-12 09:15:123311 if util_log_errors:
dgn4401aa52015-04-29 16:26:173312 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123313 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3314 util_log_errors))
3315
dgn38736db2015-09-18 19:20:513316 if tag_with_dot_errors:
3317 results.append(output_api.PresubmitPromptWarning(
3318 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3319 tag_with_dot_errors))
3320
dgn4401aa52015-04-29 16:26:173321 return results
3322
3323
Yoland Yanb92fa522017-08-28 17:37:063324def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3325 """Checks that junit.framework.* is no longer used."""
3326 deprecated_junit_framework_pattern = input_api.re.compile(
3327 r'^import junit\.framework\..*;',
3328 input_api.re.MULTILINE)
3329 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443330 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063331 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133332 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063333 for line_num, line in f.ChangedContents():
3334 if deprecated_junit_framework_pattern.search(line):
3335 errors.append("%s:%d" % (f.LocalPath(), line_num))
3336
3337 results = []
3338 if errors:
3339 results.append(output_api.PresubmitError(
3340 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3341 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3342 ' if you have any question.', errors))
3343 return results
3344
3345
3346def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3347 """Checks that if new Java test classes have inheritance.
3348 Either the new test class is JUnit3 test or it is a JUnit4 test class
3349 with a base class, either case is undesirable.
3350 """
3351 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3352
3353 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443354 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063355 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133356 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063357 if not f.OldContents():
3358 class_declaration_start_flag = False
3359 for line_num, line in f.ChangedContents():
3360 if class_declaration_pattern.search(line):
3361 class_declaration_start_flag = True
3362 if class_declaration_start_flag and ' extends ' in line:
3363 errors.append('%s:%d' % (f.LocalPath(), line_num))
3364 if '{' in line:
3365 class_declaration_start_flag = False
3366
3367 results = []
3368 if errors:
3369 results.append(output_api.PresubmitPromptWarning(
3370 'The newly created files include Test classes that inherits from base'
3371 ' class. Please do not use inheritance in JUnit4 tests or add new'
3372 ' JUnit3 tests. Contact [email protected] if you have any'
3373 ' questions.', errors))
3374 return results
3375
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203376
yolandyan45001472016-12-21 21:12:423377def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3378 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3379 deprecated_annotation_import_pattern = input_api.re.compile(
3380 r'^import android\.test\.suitebuilder\.annotation\..*;',
3381 input_api.re.MULTILINE)
3382 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443383 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423384 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133385 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423386 for line_num, line in f.ChangedContents():
3387 if deprecated_annotation_import_pattern.search(line):
3388 errors.append("%s:%d" % (f.LocalPath(), line_num))
3389
3390 results = []
3391 if errors:
3392 results.append(output_api.PresubmitError(
3393 'Annotations in android.test.suitebuilder.annotation have been'
3394 ' deprecated since API level 24. Please use android.support.test.filters'
3395 ' from //third_party/android_support_test_runner:runner_java instead.'
3396 ' Contact [email protected] if you have any questions.', errors))
3397 return results
3398
3399
agrieve7b6479d82015-10-07 14:24:223400def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3401 """Checks if MDPI assets are placed in a correct directory."""
3402 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3403 ('/res/drawable/' in f.LocalPath() or
3404 '/res/drawable-ldrtl/' in f.LocalPath()))
3405 errors = []
3406 for f in input_api.AffectedFiles(include_deletes=False,
3407 file_filter=file_filter):
3408 errors.append(' %s' % f.LocalPath())
3409
3410 results = []
3411 if errors:
3412 results.append(output_api.PresubmitError(
3413 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3414 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3415 '/res/drawable-ldrtl/.\n'
3416 'Contact [email protected] if you have questions.', errors))
3417 return results
3418
3419
Nate Fischer535972b2017-09-16 01:06:183420def _CheckAndroidWebkitImports(input_api, output_api):
3421 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353422 android.webview.ValueCallback except in the WebView glue layer
3423 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183424 """
3425 valuecallback_import_pattern = input_api.re.compile(
3426 r'^import android\.webkit\.ValueCallback;$')
3427
3428 errors = []
3429
3430 sources = lambda affected_file: input_api.FilterSourceFile(
3431 affected_file,
James Cook24a504192020-07-23 00:08:443432 files_to_skip=(_EXCLUDED_PATHS +
3433 _TEST_CODE_EXCLUDED_PATHS +
3434 input_api.DEFAULT_FILES_TO_SKIP +
3435 (r'^android_webview[\\/]glue[\\/].*',
3436 r'^weblayer[\\/].*',)),
3437 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183438
3439 for f in input_api.AffectedSourceFiles(sources):
3440 for line_num, line in f.ChangedContents():
3441 if valuecallback_import_pattern.search(line):
3442 errors.append("%s:%d" % (f.LocalPath(), line_num))
3443
3444 results = []
3445
3446 if errors:
3447 results.append(output_api.PresubmitError(
3448 'android.webkit.ValueCallback usage is detected outside of the glue'
3449 ' layer. To stay compatible with the support library, android.webkit.*'
3450 ' classes should only be used inside the glue layer and'
3451 ' org.chromium.base.Callback should be used instead.',
3452 errors))
3453
3454 return results
3455
3456
Becky Zhou7c69b50992018-12-10 19:37:573457def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3458 """Checks Android XML styles """
3459 import sys
3460 original_sys_path = sys.path
3461 try:
3462 sys.path = sys.path + [input_api.os_path.join(
3463 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3464 import checkxmlstyle
3465 finally:
3466 # Restore sys.path to what it was before.
3467 sys.path = original_sys_path
3468
3469 if is_check_on_upload:
3470 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3471 else:
3472 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3473
3474
agrievef32bcc72016-04-04 14:57:403475class PydepsChecker(object):
3476 def __init__(self, input_api, pydeps_files):
3477 self._file_cache = {}
3478 self._input_api = input_api
3479 self._pydeps_files = pydeps_files
3480
3481 def _LoadFile(self, path):
3482 """Returns the list of paths within a .pydeps file relative to //."""
3483 if path not in self._file_cache:
3484 with open(path) as f:
3485 self._file_cache[path] = f.read()
3486 return self._file_cache[path]
3487
3488 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3489 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393490 pydeps_data = self._LoadFile(pydeps_path)
3491 uses_gn_paths = '--gn-paths' in pydeps_data
3492 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3493 if uses_gn_paths:
3494 # Paths look like: //foo/bar/baz
3495 return (e[2:] for e in entries)
3496 else:
3497 # Paths look like: path/relative/to/file.pydeps
3498 os_path = self._input_api.os_path
3499 pydeps_dir = os_path.dirname(pydeps_path)
3500 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403501
3502 def _CreateFilesToPydepsMap(self):
3503 """Returns a map of local_path -> list_of_pydeps."""
3504 ret = {}
3505 for pydep_local_path in self._pydeps_files:
3506 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3507 ret.setdefault(path, []).append(pydep_local_path)
3508 return ret
3509
3510 def ComputeAffectedPydeps(self):
3511 """Returns an iterable of .pydeps files that might need regenerating."""
3512 affected_pydeps = set()
3513 file_to_pydeps_map = None
3514 for f in self._input_api.AffectedFiles(include_deletes=True):
3515 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463516 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3517 # subrepositories. We can't figure out which files change, so re-check
3518 # all files.
3519 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383520 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3521 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403522 return self._pydeps_files
3523 elif local_path.endswith('.pydeps'):
3524 if local_path in self._pydeps_files:
3525 affected_pydeps.add(local_path)
3526 elif local_path.endswith('.py'):
3527 if file_to_pydeps_map is None:
3528 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3529 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3530 return affected_pydeps
3531
3532 def DetermineIfStale(self, pydeps_path):
3533 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413534 import difflib
John Budorick47ca3fe2018-02-10 00:53:103535 import os
3536
agrievef32bcc72016-04-04 14:57:403537 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033538 if old_pydeps_data:
3539 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393540 if '--output' not in cmd:
3541 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033542 old_contents = old_pydeps_data[2:]
3543 else:
3544 # A default cmd that should work in most cases (as long as pydeps filename
3545 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3546 # file is empty/new.
3547 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3548 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3549 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103550 env = dict(os.environ)
3551 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403552 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103553 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413554 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033555 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413556 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403557
3558
Tibor Goldschwendt360793f72019-06-25 18:23:493559def _ParseGclientArgs():
3560 args = {}
3561 with open('build/config/gclient_args.gni', 'r') as f:
3562 for line in f:
3563 line = line.strip()
3564 if not line or line.startswith('#'):
3565 continue
3566 attribute, value = line.split('=')
3567 args[attribute.strip()] = value.strip()
3568 return args
3569
3570
Saagar Sanghavifceeaae2020-08-12 16:40:363571def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403572 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403573 # This check is for Python dependency lists (.pydeps files), and involves
3574 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3575 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283576 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003577 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493578 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403579 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403580 results = []
3581 # First, check for new / deleted .pydeps.
3582 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033583 # Check whether we are running the presubmit check for a file in src.
3584 # f.LocalPath is relative to repo (src, or internal repo).
3585 # os_path.exists is relative to src repo.
3586 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3587 # to src and we can conclude that the pydeps is in src.
3588 if input_api.os_path.exists(f.LocalPath()):
3589 if f.LocalPath().endswith('.pydeps'):
3590 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3591 results.append(output_api.PresubmitError(
3592 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3593 'remove %s' % f.LocalPath()))
3594 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3595 results.append(output_api.PresubmitError(
3596 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3597 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403598
3599 if results:
3600 return results
3601
Mohamed Heikal7cd4d8312020-06-16 16:49:403602 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3603 affected_pydeps = set(checker.ComputeAffectedPydeps())
3604 affected_android_pydeps = affected_pydeps.intersection(
3605 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3606 if affected_android_pydeps and not is_android:
3607 results.append(output_api.PresubmitPromptOrNotify(
3608 'You have changed python files that may affect pydeps for android\n'
3609 'specific scripts. However, the relevant presumbit check cannot be\n'
3610 'run because you are not using an Android checkout. To validate that\n'
3611 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3612 'use the android-internal-presubmit optional trybot.\n'
3613 'Possibly stale pydeps files:\n{}'.format(
3614 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403615
Mohamed Heikal7cd4d8312020-06-16 16:49:403616 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3617 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403618 try:
phajdan.jr0d9878552016-11-04 10:49:413619 result = checker.DetermineIfStale(pydep_path)
3620 if result:
3621 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403622 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413623 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3624 'To regenerate, run:\n\n %s' %
3625 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403626 except input_api.subprocess.CalledProcessError as error:
3627 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3628 long_text=error.output)]
3629
3630 return results
3631
3632
Saagar Sanghavifceeaae2020-08-12 16:40:363633def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433634 """Checks to make sure no header files have |Singleton<|."""
3635 def FileFilter(affected_file):
3636 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443637 files_to_skip = (_EXCLUDED_PATHS +
3638 input_api.DEFAULT_FILES_TO_SKIP +
3639 (r"^base[\\/]memory[\\/]singleton\.h$",
3640 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3641 r"quic_singleton_impl\.h$"))
3642 return input_api.FilterSourceFile(affected_file,
3643 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433644
sergeyu34d21222015-09-16 00:11:443645 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433646 files = []
3647 for f in input_api.AffectedSourceFiles(FileFilter):
3648 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3649 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3650 contents = input_api.ReadFile(f)
3651 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243652 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433653 pattern.search(line)):
3654 files.append(f)
3655 break
3656
3657 if files:
yolandyandaabc6d2016-04-18 18:29:393658 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443659 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433660 'Please move them to an appropriate source file so that the ' +
3661 'template gets instantiated in a single compilation unit.',
3662 files) ]
3663 return []
3664
3665
[email protected]fd20b902014-05-09 02:14:533666_DEPRECATED_CSS = [
3667 # Values
3668 ( "-webkit-box", "flex" ),
3669 ( "-webkit-inline-box", "inline-flex" ),
3670 ( "-webkit-flex", "flex" ),
3671 ( "-webkit-inline-flex", "inline-flex" ),
3672 ( "-webkit-min-content", "min-content" ),
3673 ( "-webkit-max-content", "max-content" ),
3674
3675 # Properties
3676 ( "-webkit-background-clip", "background-clip" ),
3677 ( "-webkit-background-origin", "background-origin" ),
3678 ( "-webkit-background-size", "background-size" ),
3679 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443680 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533681
3682 # Functions
3683 ( "-webkit-gradient", "gradient" ),
3684 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3685 ( "-webkit-linear-gradient", "linear-gradient" ),
3686 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3687 ( "-webkit-radial-gradient", "radial-gradient" ),
3688 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3689]
3690
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203691
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493692# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363693def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533694 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253695 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343696 documentation and iOS CSS for dom distiller
3697 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253698 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533699 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493700 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443701 files_to_skip = (_EXCLUDED_PATHS +
3702 _TEST_CODE_EXCLUDED_PATHS +
3703 input_api.DEFAULT_FILES_TO_SKIP +
3704 (r"^chrome/common/extensions/docs",
3705 r"^chrome/docs",
3706 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3707 r"^components/neterror/resources/neterror.css",
3708 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253709 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443710 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533711 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3712 for line_num, line in fpath.ChangedContents():
3713 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023714 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533715 results.append(output_api.PresubmitError(
3716 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3717 (fpath.LocalPath(), line_num, deprecated_value, value)))
3718 return results
3719
mohan.reddyf21db962014-10-16 12:26:473720
Saagar Sanghavifceeaae2020-08-12 16:40:363721def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363722 bad_files = {}
3723 for f in input_api.AffectedFiles(include_deletes=False):
3724 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493725 not f.LocalPath().startswith('third_party/blink') and
3726 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363727 continue
3728
Daniel Bratell65b033262019-04-23 08:17:063729 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363730 continue
3731
Vaclav Brozekd5de76a2018-03-17 07:57:503732 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363733 if "#include" in line and "../" in line]
3734 if not relative_includes:
3735 continue
3736 bad_files[f.LocalPath()] = relative_includes
3737
3738 if not bad_files:
3739 return []
3740
3741 error_descriptions = []
3742 for file_path, bad_lines in bad_files.iteritems():
3743 error_description = file_path
3744 for line in bad_lines:
3745 error_description += '\n ' + line
3746 error_descriptions.append(error_description)
3747
3748 results = []
3749 results.append(output_api.PresubmitError(
3750 'You added one or more relative #include paths (including "../").\n'
3751 'These shouldn\'t be used because they can be used to include headers\n'
3752 'from code that\'s not correctly specified as a dependency in the\n'
3753 'relevant BUILD.gn file(s).',
3754 error_descriptions))
3755
3756 return results
3757
Takeshi Yoshinoe387aa32017-08-02 13:16:133758
Saagar Sanghavifceeaae2020-08-12 16:40:363759def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063760 """Check that nobody tries to include a cc file. It's a relatively
3761 common error which results in duplicate symbols in object
3762 files. This may not always break the build until someone later gets
3763 very confusing linking errors."""
3764 results = []
3765 for f in input_api.AffectedFiles(include_deletes=False):
3766 # We let third_party code do whatever it wants
3767 if (f.LocalPath().startswith('third_party') and
3768 not f.LocalPath().startswith('third_party/blink') and
3769 not f.LocalPath().startswith('third_party\\blink')):
3770 continue
3771
3772 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3773 continue
3774
3775 for _, line in f.ChangedContents():
3776 if line.startswith('#include "'):
3777 included_file = line.split('"')[1]
3778 if _IsCPlusPlusFile(input_api, included_file):
3779 # The most common naming for external files with C++ code,
3780 # apart from standard headers, is to call them foo.inc, but
3781 # Chromium sometimes uses foo-inc.cc so allow that as well.
3782 if not included_file.endswith(('.h', '-inc.cc')):
3783 results.append(output_api.PresubmitError(
3784 'Only header files or .inc files should be included in other\n'
3785 'C++ files. Compiling the contents of a cc file more than once\n'
3786 'will cause duplicate information in the build which may later\n'
3787 'result in strange link_errors.\n' +
3788 f.LocalPath() + ':\n ' +
3789 line))
3790
3791 return results
3792
3793
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203794def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3795 if not isinstance(key, ast.Str):
3796 return 'Key at line %d must be a string literal' % key.lineno
3797 if not isinstance(value, ast.Dict):
3798 return 'Value at line %d must be a dict' % value.lineno
3799 if len(value.keys) != 1:
3800 return 'Dict at line %d must have single entry' % value.lineno
3801 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3802 return (
3803 'Entry at line %d must have a string literal \'filepath\' as key' %
3804 value.lineno)
3805 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133806
Takeshi Yoshinoe387aa32017-08-02 13:16:133807
Sergey Ulanov4af16052018-11-08 02:41:463808def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203809 if not isinstance(key, ast.Str):
3810 return 'Key at line %d must be a string literal' % key.lineno
3811 if not isinstance(value, ast.List):
3812 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463813 for element in value.elts:
3814 if not isinstance(element, ast.Str):
3815 return 'Watchlist elements on line %d is not a string' % key.lineno
3816 if not email_regex.match(element.s):
3817 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3818 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203819 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133820
Takeshi Yoshinoe387aa32017-08-02 13:16:133821
Sergey Ulanov4af16052018-11-08 02:41:463822def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203823 mismatch_template = (
3824 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3825 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133826
Sergey Ulanov4af16052018-11-08 02:41:463827 email_regex = input_api.re.compile(
3828 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3829
3830 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203831 i = 0
3832 last_key = ''
3833 while True:
3834 if i >= len(wd_dict.keys):
3835 if i >= len(w_dict.keys):
3836 return None
3837 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3838 elif i >= len(w_dict.keys):
3839 return (
3840 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133841
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203842 wd_key = wd_dict.keys[i]
3843 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133844
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203845 result = _CheckWatchlistDefinitionsEntrySyntax(
3846 wd_key, wd_dict.values[i], ast)
3847 if result is not None:
3848 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133849
Sergey Ulanov4af16052018-11-08 02:41:463850 result = _CheckWatchlistsEntrySyntax(
3851 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203852 if result is not None:
3853 return 'Bad entry in WATCHLISTS dict: %s' % result
3854
3855 if wd_key.s != w_key.s:
3856 return mismatch_template % (
3857 '%s at line %d' % (wd_key.s, wd_key.lineno),
3858 '%s at line %d' % (w_key.s, w_key.lineno))
3859
3860 if wd_key.s < last_key:
3861 return (
3862 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3863 (wd_key.lineno, w_key.lineno))
3864 last_key = wd_key.s
3865
3866 i = i + 1
3867
3868
Sergey Ulanov4af16052018-11-08 02:41:463869def _CheckWATCHLISTSSyntax(expression, input_api):
3870 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203871 if not isinstance(expression, ast.Expression):
3872 return 'WATCHLISTS file must contain a valid expression'
3873 dictionary = expression.body
3874 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3875 return 'WATCHLISTS file must have single dict with exactly two entries'
3876
3877 first_key = dictionary.keys[0]
3878 first_value = dictionary.values[0]
3879 second_key = dictionary.keys[1]
3880 second_value = dictionary.values[1]
3881
3882 if (not isinstance(first_key, ast.Str) or
3883 first_key.s != 'WATCHLIST_DEFINITIONS' or
3884 not isinstance(first_value, ast.Dict)):
3885 return (
3886 'The first entry of the dict in WATCHLISTS file must be '
3887 'WATCHLIST_DEFINITIONS dict')
3888
3889 if (not isinstance(second_key, ast.Str) or
3890 second_key.s != 'WATCHLISTS' or
3891 not isinstance(second_value, ast.Dict)):
3892 return (
3893 'The second entry of the dict in WATCHLISTS file must be '
3894 'WATCHLISTS dict')
3895
Sergey Ulanov4af16052018-11-08 02:41:463896 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133897
3898
Saagar Sanghavifceeaae2020-08-12 16:40:363899def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133900 for f in input_api.AffectedFiles(include_deletes=False):
3901 if f.LocalPath() == 'WATCHLISTS':
3902 contents = input_api.ReadFile(f, 'r')
3903
3904 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203905 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133906 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203907 # Get an AST tree for it and scan the tree for detailed style checking.
3908 expression = input_api.ast.parse(
3909 contents, filename='WATCHLISTS', mode='eval')
3910 except ValueError as e:
3911 return [output_api.PresubmitError(
3912 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3913 except SyntaxError as e:
3914 return [output_api.PresubmitError(
3915 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3916 except TypeError as e:
3917 return [output_api.PresubmitError(
3918 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133919
Sergey Ulanov4af16052018-11-08 02:41:463920 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203921 if result is not None:
3922 return [output_api.PresubmitError(result)]
3923 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133924
3925 return []
3926
3927
Andrew Grieve1b290e4a22020-11-24 20:07:013928def CheckGnGlobForward(input_api, output_api):
3929 """Checks that forward_variables_from(invoker, "*") follows best practices.
3930
3931 As documented at //build/docs/writing_gn_templates.md
3932 """
3933 def gn_files(f):
3934 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3935
3936 problems = []
3937 for f in input_api.AffectedSourceFiles(gn_files):
3938 for line_num, line in f.ChangedContents():
3939 if 'forward_variables_from(invoker, "*")' in line:
3940 problems.append(
3941 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3942 f.LocalPath(), line_num))
3943
3944 if problems:
3945 return [output_api.PresubmitPromptWarning(
3946 'forward_variables_from("*") without exclusions',
3947 items=sorted(problems),
3948 long_text=('The variables "visibilty" and "test_only" should be '
3949 'explicitly listed in forward_variables_from(). For more '
3950 'details, see:\n'
3951 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
3952 'build/docs/writing_gn_templates.md'
3953 '#Using-forward_variables_from'))]
3954 return []
3955
3956
Saagar Sanghavifceeaae2020-08-12 16:40:363957def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193958 """Checks that newly added header files have corresponding GN changes.
3959 Note that this is only a heuristic. To be precise, run script:
3960 build/check_gn_headers.py.
3961 """
3962
3963 def headers(f):
3964 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443965 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193966
3967 new_headers = []
3968 for f in input_api.AffectedSourceFiles(headers):
3969 if f.Action() != 'A':
3970 continue
3971 new_headers.append(f.LocalPath())
3972
3973 def gn_files(f):
James Cook24a504192020-07-23 00:08:443974 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193975
3976 all_gn_changed_contents = ''
3977 for f in input_api.AffectedSourceFiles(gn_files):
3978 for _, line in f.ChangedContents():
3979 all_gn_changed_contents += line
3980
3981 problems = []
3982 for header in new_headers:
3983 basename = input_api.os_path.basename(header)
3984 if basename not in all_gn_changed_contents:
3985 problems.append(header)
3986
3987 if problems:
3988 return [output_api.PresubmitPromptWarning(
3989 'Missing GN changes for new header files', items=sorted(problems),
3990 long_text='Please double check whether newly added header files need '
3991 'corresponding changes in gn or gni files.\nThis checking is only a '
3992 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3993 'Read https://crbug.com/661774 for more info.')]
3994 return []
3995
3996
Saagar Sanghavifceeaae2020-08-12 16:40:363997def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:023998 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3999
4000 This assumes we won't intentionally reference one product from the other
4001 product.
4002 """
4003 all_problems = []
4004 test_cases = [{
4005 "filename_postfix": "google_chrome_strings.grd",
4006 "correct_name": "Chrome",
4007 "incorrect_name": "Chromium",
4008 }, {
4009 "filename_postfix": "chromium_strings.grd",
4010 "correct_name": "Chromium",
4011 "incorrect_name": "Chrome",
4012 }]
4013
4014 for test_case in test_cases:
4015 problems = []
4016 filename_filter = lambda x: x.LocalPath().endswith(
4017 test_case["filename_postfix"])
4018
4019 # Check each new line. Can yield false positives in multiline comments, but
4020 # easier than trying to parse the XML because messages can have nested
4021 # children, and associating message elements with affected lines is hard.
4022 for f in input_api.AffectedSourceFiles(filename_filter):
4023 for line_num, line in f.ChangedContents():
4024 if "<message" in line or "<!--" in line or "-->" in line:
4025 continue
4026 if test_case["incorrect_name"] in line:
4027 problems.append(
4028 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4029
4030 if problems:
4031 message = (
4032 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4033 % (test_case["correct_name"], test_case["correct_name"],
4034 test_case["incorrect_name"]))
4035 all_problems.append(
4036 output_api.PresubmitPromptWarning(message, items=problems))
4037
4038 return all_problems
4039
4040
Saagar Sanghavifceeaae2020-08-12 16:40:364041def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364042 """Avoid large files, especially binary files, in the repository since
4043 git doesn't scale well for those. They will be in everyone's repo
4044 clones forever, forever making Chromium slower to clone and work
4045 with."""
4046
4047 # Uploading files to cloud storage is not trivial so we don't want
4048 # to set the limit too low, but the upper limit for "normal" large
4049 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4050 # anything over 20 MB is exceptional.
4051 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4052
4053 too_large_files = []
4054 for f in input_api.AffectedFiles():
4055 # Check both added and modified files (but not deleted files).
4056 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384057 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364058 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4059 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4060
4061 if too_large_files:
4062 message = (
4063 'Do not commit large files to git since git scales badly for those.\n' +
4064 'Instead put the large files in cloud storage and use DEPS to\n' +
4065 'fetch them.\n' + '\n'.join(too_large_files)
4066 )
4067 return [output_api.PresubmitError(
4068 'Too large files found in commit', long_text=message + '\n')]
4069 else:
4070 return []
4071
Max Morozb47503b2019-08-08 21:03:274072
Saagar Sanghavifceeaae2020-08-12 16:40:364073def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274074 """Checks specific for fuzz target sources."""
4075 EXPORTED_SYMBOLS = [
4076 'LLVMFuzzerInitialize',
4077 'LLVMFuzzerCustomMutator',
4078 'LLVMFuzzerCustomCrossOver',
4079 'LLVMFuzzerMutate',
4080 ]
4081
4082 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4083
4084 def FilterFile(affected_file):
4085 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444086 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4087 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274088
4089 return input_api.FilterSourceFile(
4090 affected_file,
James Cook24a504192020-07-23 00:08:444091 files_to_check=[files_to_check],
4092 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274093
4094 files_with_missing_header = []
4095 for f in input_api.AffectedSourceFiles(FilterFile):
4096 contents = input_api.ReadFile(f, 'r')
4097 if REQUIRED_HEADER in contents:
4098 continue
4099
4100 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4101 files_with_missing_header.append(f.LocalPath())
4102
4103 if not files_with_missing_header:
4104 return []
4105
4106 long_text = (
4107 'If you define any of the libFuzzer optional functions (%s), it is '
4108 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4109 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4110 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4111 'to access command line arguments passed to the fuzzer. Instead, prefer '
4112 'static initialization and shared resources as documented in '
4113 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4114 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4115 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4116 )
4117
4118 return [output_api.PresubmitPromptWarning(
4119 message="Missing '%s' in:" % REQUIRED_HEADER,
4120 items=files_with_missing_header,
4121 long_text=long_text)]
4122
4123
Mohamed Heikald048240a2019-11-12 16:57:374124def _CheckNewImagesWarning(input_api, output_api):
4125 """
4126 Warns authors who add images into the repo to make sure their images are
4127 optimized before committing.
4128 """
4129 images_added = False
4130 image_paths = []
4131 errors = []
4132 filter_lambda = lambda x: input_api.FilterSourceFile(
4133 x,
James Cook24a504192020-07-23 00:08:444134 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4135 + input_api.DEFAULT_FILES_TO_SKIP),
4136 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374137 )
4138 for f in input_api.AffectedFiles(
4139 include_deletes=False, file_filter=filter_lambda):
4140 local_path = f.LocalPath().lower()
4141 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4142 images_added = True
4143 image_paths.append(f)
4144 if images_added:
4145 errors.append(output_api.PresubmitPromptWarning(
4146 'It looks like you are trying to commit some images. If these are '
4147 'non-test-only images, please make sure to read and apply the tips in '
4148 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4149 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4150 'FYI only and will not block your CL on the CQ.', image_paths))
4151 return errors
4152
4153
Saagar Sanghavifceeaae2020-08-12 16:40:364154def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574155 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224156 results = []
dgnaa68d5e2015-06-10 10:08:224157 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174158 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224159 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294160 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064161 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4162 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424163 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184164 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574165 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374166 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154167 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574168 return results
4169
Saagar Sanghavifceeaae2020-08-12 16:40:364170def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574171 """Groups commit checks that target android code."""
4172 results = []
4173 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224174 return results
4175
Chris Hall59f8d0c72020-05-01 07:31:194176# TODO(chrishall): could we additionally match on any path owned by
4177# ui/accessibility/OWNERS ?
4178_ACCESSIBILITY_PATHS = (
4179 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4180 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4181 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4182 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4183 r"^content[\\/]browser[\\/]accessibility[\\/]",
4184 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4185 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4186 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4187 r"^ui[\\/]accessibility[\\/]",
4188 r"^ui[\\/]views[\\/]accessibility[\\/]",
4189)
4190
Saagar Sanghavifceeaae2020-08-12 16:40:364191def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194192 """Checks that commits to accessibility code contain an AX-Relnotes field in
4193 their commit message."""
4194 def FileFilter(affected_file):
4195 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444196 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194197
4198 # Only consider changes affecting accessibility paths.
4199 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4200 return []
4201
Akihiro Ota08108e542020-05-20 15:30:534202 # AX-Relnotes can appear in either the description or the footer.
4203 # When searching the description, require 'AX-Relnotes:' to appear at the
4204 # beginning of a line.
4205 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4206 description_has_relnotes = any(ax_regex.match(line)
4207 for line in input_api.change.DescriptionText().lower().splitlines())
4208
4209 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4210 'AX-Relnotes', [])
4211 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194212 return []
4213
4214 # TODO(chrishall): link to Relnotes documentation in message.
4215 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4216 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4217 "user-facing changes"
4218 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4219 "user-facing effects"
4220 "\n if this is confusing or annoying then please contact members "
4221 "of ui/accessibility/OWNERS.")
4222
4223 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224224
seanmccullough4a9356252021-04-08 19:54:094225# string pattern, sequence of strings to show when pattern matches,
4226# error flag. True if match is a presubmit error, otherwise it's a warning.
4227_NON_INCLUSIVE_TERMS = (
4228 (
4229 # Note that \b pattern in python re is pretty particular. In this
4230 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4231 # ...' will not. This may require some tweaking to catch these cases
4232 # without triggering a lot of false positives. Leaving it naive and
4233 # less matchy for now.
4234 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4235 (
4236 'Please don\'t use blacklist, whitelist, ' # nocheck
4237 'or slave in your', # nocheck
4238 'code and make every effort to use other terms. Using "// nocheck"',
4239 '"# nocheck" or "<!-- nocheck -->"',
4240 'at the end of the offending line will bypass this PRESUBMIT error',
4241 'but avoid using this whenever possible. Reach out to',
4242 '[email protected] if you have questions'),
4243 True),)
4244
Saagar Sanghavifceeaae2020-08-12 16:40:364245def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394246 """Checks common to both upload and commit."""
4247 results = []
4248 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384249 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544250 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084251
4252 author = input_api.change.author_email
4253 if author and author not in _KNOWN_ROBOTS:
4254 results.extend(
4255 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4256
[email protected]9f919cc2013-07-31 03:04:044257 results.extend(
4258 input_api.canned_checks.CheckChangeHasNoTabs(
4259 input_api,
4260 output_api,
4261 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434262 results.extend(input_api.RunTests(
4263 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244264
Edward Lesmesce51df52020-08-04 22:10:174265 dirmd_bin = input_api.os_path.join(
4266 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4267 results.extend(input_api.RunTests(
4268 input_api.canned_checks.CheckDirMetadataFormat(
4269 input_api, output_api, dirmd_bin)))
4270 results.extend(
4271 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4272 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554273 results.extend(
4274 input_api.canned_checks.CheckNoNewMetadataInOwners(
4275 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094276 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4277 input_api, output_api,
4278 excluded_directories_relative_path = [
4279 'infra',
4280 'inclusive_language_presubmit_exempt_dirs.txt'
4281 ],
4282 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174283
Vaclav Brozekcdc7defb2018-03-20 09:54:354284 for f in input_api.AffectedFiles():
4285 path, name = input_api.os_path.split(f.LocalPath())
4286 if name == 'PRESUBMIT.py':
4287 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004288 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4289 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074290 # The PRESUBMIT.py file (and the directory containing it) might
4291 # have been affected by being moved or removed, so only try to
4292 # run the tests if they still exist.
4293 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4294 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444295 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394296 return results
[email protected]1f7b4172010-01-28 01:17:344297
[email protected]b337cb5b2011-01-23 21:24:054298
Saagar Sanghavifceeaae2020-08-12 16:40:364299def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494300 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4301 if f.LocalPath().endswith(('.orig', '.rej'))]
4302 if problems:
4303 return [output_api.PresubmitError(
4304 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034305 else:
4306 return []
[email protected]b8079ae4a2012-12-05 19:56:494307
4308
Saagar Sanghavifceeaae2020-08-12 16:40:364309def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214310 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4311 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4312 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074313 include_re = input_api.re.compile(
4314 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4315 extension_re = input_api.re.compile(r'\.[a-z]+$')
4316 errors = []
4317 for f in input_api.AffectedFiles():
4318 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4319 continue
4320 found_line_number = None
4321 found_macro = None
4322 for line_num, line in f.ChangedContents():
4323 match = macro_re.search(line)
4324 if match:
4325 found_line_number = line_num
4326 found_macro = match.group(2)
4327 break
4328 if not found_line_number:
4329 continue
4330
4331 found_include = False
4332 for line in f.NewContents():
4333 if include_re.search(line):
4334 found_include = True
4335 break
4336 if found_include:
4337 continue
4338
4339 if not f.LocalPath().endswith('.h'):
4340 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4341 try:
4342 content = input_api.ReadFile(primary_header_path, 'r')
4343 if include_re.search(content):
4344 continue
4345 except IOError:
4346 pass
4347 errors.append('%s:%d %s macro is used without including build/'
4348 'build_config.h.'
4349 % (f.LocalPath(), found_line_number, found_macro))
4350 if errors:
4351 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4352 return []
4353
4354
Lei Zhang1c12a22f2021-05-12 11:28:454355def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
4356 stl_include_re = input_api.re.compile(
Lei Zhang0643e342021-05-12 18:02:124357 r'^#include\s+<('
Lei Zhang1c12a22f2021-05-12 11:28:454358 r'algorithm|'
4359 r'array|'
4360 r'limits|'
4361 r'list|'
4362 r'map|'
4363 r'memory|'
4364 r'queue|'
4365 r'set|'
4366 r'string|'
4367 r'unordered_map|'
4368 r'unordered_set|'
4369 r'utility|'
Lei Zhang0643e342021-05-12 18:02:124370 r'vector)>')
Lei Zhang1c12a22f2021-05-12 11:28:454371 std_namespace_re = input_api.re.compile(r'std::')
4372 errors = []
4373 for f in input_api.AffectedFiles():
4374 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4375 continue
4376
4377 uses_std_namespace = False
4378 has_stl_include = False
4379 for line in f.NewContents():
4380 if has_stl_include and uses_std_namespace:
4381 break
4382
4383 if not has_stl_include and stl_include_re.search(line):
4384 has_stl_include = True
4385 continue
4386
4387 if not uses_std_namespace and std_namespace_re.search(line):
4388 uses_std_namespace = True
4389 continue
4390
4391 if has_stl_include and not uses_std_namespace:
4392 errors.append('%s: Includes STL header(s) but does not reference std::'
4393 % f.LocalPath())
4394 if errors:
4395 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4396 return []
4397
4398
[email protected]b00342e7f2013-03-26 16:21:544399def _DidYouMeanOSMacro(bad_macro):
4400 try:
4401 return {'A': 'OS_ANDROID',
4402 'B': 'OS_BSD',
4403 'C': 'OS_CHROMEOS',
4404 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444405 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544406 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444407 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544408 'N': 'OS_NACL',
4409 'O': 'OS_OPENBSD',
4410 'P': 'OS_POSIX',
4411 'S': 'OS_SOLARIS',
4412 'W': 'OS_WIN'}[bad_macro[3].upper()]
4413 except KeyError:
4414 return ''
4415
4416
4417def _CheckForInvalidOSMacrosInFile(input_api, f):
4418 """Check for sensible looking, totally invalid OS macros."""
4419 preprocessor_statement = input_api.re.compile(r'^\s*#')
4420 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4421 results = []
4422 for lnum, line in f.ChangedContents():
4423 if preprocessor_statement.search(line):
4424 for match in os_macro.finditer(line):
4425 if not match.group(1) in _VALID_OS_MACROS:
4426 good = _DidYouMeanOSMacro(match.group(1))
4427 did_you_mean = ' (did you mean %s?)' % good if good else ''
4428 results.append(' %s:%d %s%s' % (f.LocalPath(),
4429 lnum,
4430 match.group(1),
4431 did_you_mean))
4432 return results
4433
4434
Saagar Sanghavifceeaae2020-08-12 16:40:364435def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544436 """Check all affected files for invalid OS macros."""
4437 bad_macros = []
tzik3f295992018-12-04 20:32:234438 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474439 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544440 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4441
4442 if not bad_macros:
4443 return []
4444
4445 return [output_api.PresubmitError(
4446 'Possibly invalid OS macro[s] found. Please fix your code\n'
4447 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4448
lliabraa35bab3932014-10-01 12:16:444449
4450def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4451 """Check all affected files for invalid "if defined" macros."""
4452 ALWAYS_DEFINED_MACROS = (
4453 "TARGET_CPU_PPC",
4454 "TARGET_CPU_PPC64",
4455 "TARGET_CPU_68K",
4456 "TARGET_CPU_X86",
4457 "TARGET_CPU_ARM",
4458 "TARGET_CPU_MIPS",
4459 "TARGET_CPU_SPARC",
4460 "TARGET_CPU_ALPHA",
4461 "TARGET_IPHONE_SIMULATOR",
4462 "TARGET_OS_EMBEDDED",
4463 "TARGET_OS_IPHONE",
4464 "TARGET_OS_MAC",
4465 "TARGET_OS_UNIX",
4466 "TARGET_OS_WIN32",
4467 )
4468 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4469 results = []
4470 for lnum, line in f.ChangedContents():
4471 for match in ifdef_macro.finditer(line):
4472 if match.group(1) in ALWAYS_DEFINED_MACROS:
4473 always_defined = ' %s is always defined. ' % match.group(1)
4474 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4475 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4476 lnum,
4477 always_defined,
4478 did_you_mean))
4479 return results
4480
4481
Saagar Sanghavifceeaae2020-08-12 16:40:364482def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444483 """Check all affected files for invalid "if defined" macros."""
4484 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054485 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444486 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054487 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214488 continue
lliabraa35bab3932014-10-01 12:16:444489 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4490 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4491
4492 if not bad_macros:
4493 return []
4494
4495 return [output_api.PresubmitError(
4496 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4497 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4498 bad_macros)]
4499
4500
Saagar Sanghavifceeaae2020-08-12 16:40:364501def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044502 """Check for same IPC rules described in
4503 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4504 """
4505 base_pattern = r'IPC_ENUM_TRAITS\('
4506 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4507 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4508
4509 problems = []
4510 for f in input_api.AffectedSourceFiles(None):
4511 local_path = f.LocalPath()
4512 if not local_path.endswith('.h'):
4513 continue
4514 for line_number, line in f.ChangedContents():
4515 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4516 problems.append(
4517 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4518
4519 if problems:
4520 return [output_api.PresubmitPromptWarning(
4521 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4522 else:
4523 return []
4524
[email protected]b00342e7f2013-03-26 16:21:544525
Saagar Sanghavifceeaae2020-08-12 16:40:364526def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054527 """Check to make sure no files being submitted have long paths.
4528 This causes issues on Windows.
4529 """
4530 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194531 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054532 local_path = f.LocalPath()
4533 # Windows has a path limit of 260 characters. Limit path length to 200 so
4534 # that we have some extra for the prefix on dev machines and the bots.
4535 if len(local_path) > 200:
4536 problems.append(local_path)
4537
4538 if problems:
4539 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4540 else:
4541 return []
4542
4543
Saagar Sanghavifceeaae2020-08-12 16:40:364544def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144545 """Check that header files have proper guards against multiple inclusion.
4546 If a file should not have such guards (and it probably should) then it
4547 should include the string "no-include-guard-because-multiply-included".
4548 """
Daniel Bratell6a75baef62018-06-04 10:04:454549 def is_chromium_header_file(f):
4550 # We only check header files under the control of the Chromium
4551 # project. That is, those outside third_party apart from
4552 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324553 # We also exclude *_message_generator.h headers as they use
4554 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454555 file_with_path = input_api.os_path.normpath(f.LocalPath())
4556 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324557 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454558 (not file_with_path.startswith('third_party') or
4559 file_with_path.startswith(
4560 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144561
4562 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344563 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144564
4565 errors = []
4566
Daniel Bratell6a75baef62018-06-04 10:04:454567 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144568 guard_name = None
4569 guard_line_number = None
4570 seen_guard_end = False
4571
4572 file_with_path = input_api.os_path.normpath(f.LocalPath())
4573 base_file_name = input_api.os_path.splitext(
4574 input_api.os_path.basename(file_with_path))[0]
4575 upper_base_file_name = base_file_name.upper()
4576
4577 expected_guard = replace_special_with_underscore(
4578 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144579
4580 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574581 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4582 # are too many (1000+) files with slight deviations from the
4583 # coding style. The most important part is that the include guard
4584 # is there, and that it's unique, not the name so this check is
4585 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144586 #
4587 # As code becomes more uniform, this could be made stricter.
4588
4589 guard_name_pattern_list = [
4590 # Anything with the right suffix (maybe with an extra _).
4591 r'\w+_H__?',
4592
Daniel Bratell39b5b062018-05-16 18:09:574593 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144594 r'\w+_h',
4595
4596 # Anything including the uppercase name of the file.
4597 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4598 upper_base_file_name)) + r'\w*',
4599 ]
4600 guard_name_pattern = '|'.join(guard_name_pattern_list)
4601 guard_pattern = input_api.re.compile(
4602 r'#ifndef\s+(' + guard_name_pattern + ')')
4603
4604 for line_number, line in enumerate(f.NewContents()):
4605 if 'no-include-guard-because-multiply-included' in line:
4606 guard_name = 'DUMMY' # To not trigger check outside the loop.
4607 break
4608
4609 if guard_name is None:
4610 match = guard_pattern.match(line)
4611 if match:
4612 guard_name = match.group(1)
4613 guard_line_number = line_number
4614
Daniel Bratell39b5b062018-05-16 18:09:574615 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454616 # don't match the chromium style guide, but new files should
4617 # get it right.
4618 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574619 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144620 errors.append(output_api.PresubmitPromptWarning(
4621 'Header using the wrong include guard name %s' % guard_name,
4622 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574623 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144624 else:
4625 # The line after #ifndef should have a #define of the same name.
4626 if line_number == guard_line_number + 1:
4627 expected_line = '#define %s' % guard_name
4628 if line != expected_line:
4629 errors.append(output_api.PresubmitPromptWarning(
4630 'Missing "%s" for include guard' % expected_line,
4631 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4632 'Expected: %r\nGot: %r' % (expected_line, line)))
4633
4634 if not seen_guard_end and line == '#endif // %s' % guard_name:
4635 seen_guard_end = True
4636 elif seen_guard_end:
4637 if line.strip() != '':
4638 errors.append(output_api.PresubmitPromptWarning(
4639 'Include guard %s not covering the whole file' % (
4640 guard_name), [f.LocalPath()]))
4641 break # Nothing else to check and enough to warn once.
4642
4643 if guard_name is None:
4644 errors.append(output_api.PresubmitPromptWarning(
4645 'Missing include guard %s' % expected_guard,
4646 [f.LocalPath()],
4647 'Missing include guard in %s\n'
4648 'Recommended name: %s\n'
4649 'This check can be disabled by having the string\n'
4650 'no-include-guard-because-multiply-included in the header.' %
4651 (f.LocalPath(), expected_guard)))
4652
4653 return errors
4654
4655
Saagar Sanghavifceeaae2020-08-12 16:40:364656def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234657 """Check source code and known ascii text files for Windows style line
4658 endings.
4659 """
earthdok1b5e0ee2015-03-10 15:19:104660 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234661
4662 file_inclusion_pattern = (
4663 known_text_files,
4664 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4665 )
4666
mostynbb639aca52015-01-07 20:31:234667 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534668 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444669 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534670 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504671 include_file = False
4672 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234673 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504674 include_file = True
4675 if include_file:
4676 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234677
4678 if problems:
4679 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4680 'these files to contain Windows style line endings?\n' +
4681 '\n'.join(problems))]
4682
4683 return []
4684
Jose Magana2b456f22021-03-09 23:26:404685def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4686 """Check source code for use of Chrome App technologies being
4687 deprecated.
4688 """
4689
4690 def _CheckForDeprecatedTech(input_api, output_api,
4691 detection_list, files_to_check = None, files_to_skip = None):
4692
4693 if (files_to_check or files_to_skip):
4694 source_file_filter = lambda f: input_api.FilterSourceFile(
4695 f, files_to_check=files_to_check,
4696 files_to_skip=files_to_skip)
4697 else:
4698 source_file_filter = None
4699
4700 problems = []
4701
4702 for f in input_api.AffectedSourceFiles(source_file_filter):
4703 if f.Action() == 'D':
4704 continue
4705 for _, line in f.ChangedContents():
4706 if any( detect in line for detect in detection_list ):
4707 problems.append(f.LocalPath())
4708
4709 return problems
4710
4711 # to avoid this presubmit script triggering warnings
4712 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4713
4714 problems =[]
4715
4716 # NMF: any files with extensions .nmf or NMF
4717 _NMF_FILES = r'\.(nmf|NMF)$'
4718 problems += _CheckForDeprecatedTech(input_api, output_api,
4719 detection_list = [''], # any change to the file will trigger warning
4720 files_to_check = [ r'.+%s' % _NMF_FILES ])
4721
4722 # MANIFEST: any manifest.json that in its diff includes "app":
4723 _MANIFEST_FILES = r'(manifest\.json)$'
4724 problems += _CheckForDeprecatedTech(input_api, output_api,
4725 detection_list = ['"app":'],
4726 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4727
4728 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4729 problems += _CheckForDeprecatedTech(input_api, output_api,
4730 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4731 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4732
4733 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4734 problems += _CheckForDeprecatedTech(input_api, output_api,
4735 detection_list = ['#include "ppapi','#include <ppapi'],
4736 files_to_check = (
4737 r'.+%s' % _HEADER_EXTENSIONS,
4738 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4739 files_to_skip = [r"^ppapi[\\/]"] )
4740
Jose Magana2b456f22021-03-09 23:26:404741 if problems:
4742 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4743 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4744 ' PNaCl, PPAPI). See this blog post for more details:\n'
4745 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4746 'and this documentation for options to replace these technologies:\n'
4747 'https://developer.chrome.com/docs/apps/migration/\n'+
4748 '\n'.join(problems))]
4749
4750 return []
4751
mostynbb639aca52015-01-07 20:31:234752
Saagar Sanghavifceeaae2020-08-12 16:40:364753def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134754 """Checks that all source files use SYSLOG properly."""
4755 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364756 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564757 for line_number, line in f.ChangedContents():
4758 if 'SYSLOG' in line:
4759 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4760
pastarmovj89f7ee12016-09-20 14:58:134761 if syslog_files:
4762 return [output_api.PresubmitPromptWarning(
4763 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4764 ' calls.\nFiles to check:\n', items=syslog_files)]
4765 return []
4766
4767
[email protected]1f7b4172010-01-28 01:17:344768def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364769 if input_api.version < [2, 0, 0]:
4770 return [output_api.PresubmitError("Your depot_tools is out of date. "
4771 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4772 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344773 results = []
scottmg39b29952014-12-08 18:31:284774 results.extend(
jam93a6ee792017-02-08 23:59:224775 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544776 return results
[email protected]ca8d1982009-02-19 16:33:124777
4778
4779def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364780 if input_api.version < [2, 0, 0]:
4781 return [output_api.PresubmitError("Your depot_tools is out of date. "
4782 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4783 "but your version is %d.%d.%d" % tuple(input_api.version))]
4784
[email protected]fe5f57c52009-06-05 14:25:544785 results = []
[email protected]fe5f57c52009-06-05 14:25:544786 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274787 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344788 input_api,
4789 output_api,
[email protected]2fdd1f362013-01-16 03:56:034790 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274791
jam93a6ee792017-02-08 23:59:224792 results.extend(
4793 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544794 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4795 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384796 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4797 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414798 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4799 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544800 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144801
4802
Saagar Sanghavifceeaae2020-08-12 16:40:364803def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264804 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024805 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4806 # footer is set to true.
4807 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264808 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024809 footer.lower()
4810 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264811 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024812
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144813 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264814 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144815 import sys
4816 from io import StringIO
4817
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144818 new_or_added_paths = set(f.LocalPath()
4819 for f in input_api.AffectedFiles()
4820 if (f.Action() == 'A' or f.Action() == 'M'))
4821 removed_paths = set(f.LocalPath()
4822 for f in input_api.AffectedFiles(include_deletes=True)
4823 if f.Action() == 'D')
4824
Andrew Grieve0e8790c2020-09-03 17:27:324825 affected_grds = [
4826 f for f in input_api.AffectedFiles()
4827 if f.LocalPath().endswith(('.grd', '.grdp'))
4828 ]
4829 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164830 if not affected_grds:
4831 return []
4832
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144833 affected_png_paths = [f.AbsoluteLocalPath()
4834 for f in input_api.AffectedFiles()
4835 if (f.LocalPath().endswith('.png'))]
4836
4837 # Check for screenshots. Developers can upload screenshots using
4838 # tools/translation/upload_screenshots.py which finds and uploads
4839 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4840 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4841 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4842 #
4843 # The logic here is as follows:
4844 #
4845 # - If the CL has a .png file under the screenshots directory for a grd
4846 # file, warn the developer. Actual images should never be checked into the
4847 # Chrome repo.
4848 #
4849 # - If the CL contains modified or new messages in grd files and doesn't
4850 # contain the corresponding .sha1 files, warn the developer to add images
4851 # and upload them via tools/translation/upload_screenshots.py.
4852 #
4853 # - If the CL contains modified or new messages in grd files and the
4854 # corresponding .sha1 files, everything looks good.
4855 #
4856 # - If the CL contains removed messages in grd files but the corresponding
4857 # .sha1 files aren't removed, warn the developer to remove them.
4858 unnecessary_screenshots = []
4859 missing_sha1 = []
4860 unnecessary_sha1_files = []
4861
Rainhard Findlingfc31844c52020-05-15 09:58:264862 # This checks verifies that the ICU syntax of messages this CL touched is
4863 # valid, and reports any found syntax errors.
4864 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4865 # without developers being aware of them. Later on, such ICU syntax errors
4866 # break message extraction for translation, hence would block Chromium
4867 # translations until they are fixed.
4868 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144869
4870 def _CheckScreenshotAdded(screenshots_dir, message_id):
4871 sha1_path = input_api.os_path.join(
4872 screenshots_dir, message_id + '.png.sha1')
4873 if sha1_path not in new_or_added_paths:
4874 missing_sha1.append(sha1_path)
4875
4876
4877 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4878 sha1_path = input_api.os_path.join(
4879 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034880 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144881 unnecessary_sha1_files.append(sha1_path)
4882
Rainhard Findlingfc31844c52020-05-15 09:58:264883
4884 def _ValidateIcuSyntax(text, level, signatures):
4885 """Validates ICU syntax of a text string.
4886
4887 Check if text looks similar to ICU and checks for ICU syntax correctness
4888 in this case. Reports various issues with ICU syntax and values of
4889 variants. Supports checking of nested messages. Accumulate information of
4890 each ICU messages found in the text for further checking.
4891
4892 Args:
4893 text: a string to check.
4894 level: a number of current nesting level.
4895 signatures: an accumulator, a list of tuple of (level, variable,
4896 kind, variants).
4897
4898 Returns:
4899 None if a string is not ICU or no issue detected.
4900 A tuple of (message, start index, end index) if an issue detected.
4901 """
4902 valid_types = {
4903 'plural': (frozenset(
4904 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4905 frozenset(['=1', 'other'])),
4906 'selectordinal': (frozenset(
4907 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4908 frozenset(['one', 'other'])),
4909 'select': (frozenset(), frozenset(['other'])),
4910 }
4911
4912 # Check if the message looks like an attempt to use ICU
4913 # plural. If yes - check if its syntax strictly matches ICU format.
4914 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4915 if not like:
4916 signatures.append((level, None, None, None))
4917 return
4918
4919 # Check for valid prefix and suffix
4920 m = re.match(
4921 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4922 r'(plural|selectordinal|select),\s*'
4923 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4924 if not m:
4925 return (('This message looks like an ICU plural, '
4926 'but does not follow ICU syntax.'), like.start(), like.end())
4927 starting, variable, kind, variant_pairs = m.groups()
4928 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4929 if depth:
4930 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4931 len(text))
4932 first = text[0]
4933 ending = text[last_pos:]
4934 if not starting:
4935 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4936 last_pos)
4937 if not ending or '}' not in ending:
4938 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4939 last_pos)
4940 elif first != '{':
4941 return (
4942 ('Invalid ICU format. Extra characters at the start of a complex '
4943 'message (go/icu-message-migration): "%s"') %
4944 starting, 0, len(starting))
4945 elif ending != '}':
4946 return (('Invalid ICU format. Extra characters at the end of a complex '
4947 'message (go/icu-message-migration): "%s"')
4948 % ending, last_pos - 1, len(text) - 1)
4949 if kind not in valid_types:
4950 return (('Unknown ICU message type %s. '
4951 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4952 known, required = valid_types[kind]
4953 defined_variants = set()
4954 for variant, variant_range, value, value_range in variants:
4955 start, end = variant_range
4956 if variant in defined_variants:
4957 return ('Variant "%s" is defined more than once' % variant,
4958 start, end)
4959 elif known and variant not in known:
4960 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4961 start, end)
4962 defined_variants.add(variant)
4963 # Check for nested structure
4964 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4965 if res:
4966 return (res[0], res[1] + value_range[0] + 1,
4967 res[2] + value_range[0] + 1)
4968 missing = required - defined_variants
4969 if missing:
4970 return ('Required variants missing: %s' % ', '.join(missing), 0,
4971 len(text))
4972 signatures.append((level, variable, kind, defined_variants))
4973
4974
4975 def _ParseIcuVariants(text, offset=0):
4976 """Parse variants part of ICU complex message.
4977
4978 Builds a tuple of variant names and values, as well as
4979 their offsets in the input string.
4980
4981 Args:
4982 text: a string to parse
4983 offset: additional offset to add to positions in the text to get correct
4984 position in the complete ICU string.
4985
4986 Returns:
4987 List of tuples, each tuple consist of four fields: variant name,
4988 variant name span (tuple of two integers), variant value, value
4989 span (tuple of two integers).
4990 """
4991 depth, start, end = 0, -1, -1
4992 variants = []
4993 key = None
4994 for idx, char in enumerate(text):
4995 if char == '{':
4996 if not depth:
4997 start = idx
4998 chunk = text[end + 1:start]
4999 key = chunk.strip()
5000 pos = offset + end + 1 + chunk.find(key)
5001 span = (pos, pos + len(key))
5002 depth += 1
5003 elif char == '}':
5004 if not depth:
5005 return variants, depth, offset + idx
5006 depth -= 1
5007 if not depth:
5008 end = idx
5009 variants.append((key, span, text[start:end + 1], (offset + start,
5010 offset + end + 1)))
5011 return variants, depth, offset + end + 1
5012
meacer8c0d3832019-12-26 21:46:165013 try:
5014 old_sys_path = sys.path
5015 sys.path = sys.path + [input_api.os_path.join(
5016 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5017 from helper import grd_helper
5018 finally:
5019 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145020
5021 for f in affected_grds:
5022 file_path = f.LocalPath()
5023 old_id_to_msg_map = {}
5024 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385025 # Note that this code doesn't check if the file has been deleted. This is
5026 # OK because it only uses the old and new file contents and doesn't load
5027 # the file via its path.
5028 # It's also possible that a file's content refers to a renamed or deleted
5029 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5030 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5031 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145032 if file_path.endswith('.grdp'):
5033 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585034 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395035 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145036 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585037 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395038 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145039 else:
meacerff8a9b62019-12-10 19:43:585040 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145041 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585042 old_id_to_msg_map = grd_helper.GetGrdMessages(
5043 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145044 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585045 new_id_to_msg_map = grd_helper.GetGrdMessages(
5046 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145047
Rainhard Findlingd8d04372020-08-13 13:30:095048 grd_name, ext = input_api.os_path.splitext(
5049 input_api.os_path.basename(file_path))
5050 screenshots_dir = input_api.os_path.join(
5051 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5052
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145053 # Compute added, removed and modified message IDs.
5054 old_ids = set(old_id_to_msg_map)
5055 new_ids = set(new_id_to_msg_map)
5056 added_ids = new_ids - old_ids
5057 removed_ids = old_ids - new_ids
5058 modified_ids = set([])
5059 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355060 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095061 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5062 # The message content itself changed. Require an updated screenshot.
5063 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355064 elif old_id_to_msg_map[key].attrs['meaning'] != \
5065 new_id_to_msg_map[key].attrs['meaning']:
5066 # The message meaning changed. Ensure there is a screenshot for it.
5067 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5068 if sha1_path not in new_or_added_paths and not \
5069 input_api.os_path.exists(sha1_path):
5070 # There is neither a previous screenshot nor is a new one added now.
5071 # Require a screenshot.
5072 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145073
Rainhard Findlingfc31844c52020-05-15 09:58:265074 if run_screenshot_check:
5075 # Check the screenshot directory for .png files. Warn if there is any.
5076 for png_path in affected_png_paths:
5077 if png_path.startswith(screenshots_dir):
5078 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145079
Rainhard Findlingfc31844c52020-05-15 09:58:265080 for added_id in added_ids:
5081 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145082
Rainhard Findlingfc31844c52020-05-15 09:58:265083 for modified_id in modified_ids:
5084 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145085
Rainhard Findlingfc31844c52020-05-15 09:58:265086 for removed_id in removed_ids:
5087 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5088
5089 # Check new and changed strings for ICU syntax errors.
5090 for key in added_ids.union(modified_ids):
5091 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5092 err = _ValidateIcuSyntax(msg, 0, [])
5093 if err is not None:
5094 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145095
5096 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265097 if run_screenshot_check:
5098 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005099 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265100 'Do not include actual screenshots in the changelist. Run '
5101 'tools/translate/upload_screenshots.py to upload them instead:',
5102 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145103
Rainhard Findlingfc31844c52020-05-15 09:58:265104 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005105 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265106 'You are adding or modifying UI strings.\n'
5107 'To ensure the best translations, take screenshots of the relevant UI '
5108 '(https://g.co/chrome/translation) and add these files to your '
5109 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145110
Rainhard Findlingfc31844c52020-05-15 09:58:265111 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005112 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265113 'You removed strings associated with these files. Remove:',
5114 sorted(unnecessary_sha1_files)))
5115 else:
5116 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5117 'screenshots check.'))
5118
5119 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075120 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265121 'ICU syntax errors were found in the following strings (problems or '
5122 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145123
5124 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125125
5126
Saagar Sanghavifceeaae2020-08-12 16:40:365127def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125128 repo_root=None,
5129 translation_expectations_path=None,
5130 grd_files=None):
5131 import sys
5132 affected_grds = [f for f in input_api.AffectedFiles()
5133 if (f.LocalPath().endswith('.grd') or
5134 f.LocalPath().endswith('.grdp'))]
5135 if not affected_grds:
5136 return []
5137
5138 try:
5139 old_sys_path = sys.path
5140 sys.path = sys.path + [
5141 input_api.os_path.join(
5142 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5143 from helper import git_helper
5144 from helper import translation_helper
5145 finally:
5146 sys.path = old_sys_path
5147
5148 # Check that translation expectations can be parsed and we can get a list of
5149 # translatable grd files. |repo_root| and |translation_expectations_path| are
5150 # only passed by tests.
5151 if not repo_root:
5152 repo_root = input_api.PresubmitLocalPath()
5153 if not translation_expectations_path:
5154 translation_expectations_path = input_api.os_path.join(
5155 repo_root, 'tools', 'gritsettings',
5156 'translation_expectations.pyl')
5157 if not grd_files:
5158 grd_files = git_helper.list_grds_in_repository(repo_root)
5159
dpapad8e21b472020-10-23 17:15:035160 # Ignore bogus grd files used only for testing
5161 # ui/webui/resoucres/tools/generate_grd.py.
5162 ignore_path = input_api.os_path.join(
5163 'ui', 'webui', 'resources', 'tools', 'tests')
5164 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5165
Mustafa Emre Acer51f2f742020-03-09 19:41:125166 try:
5167 translation_helper.get_translatable_grds(repo_root, grd_files,
5168 translation_expectations_path)
5169 except Exception as e:
5170 return [output_api.PresubmitNotifyResult(
5171 'Failed to get a list of translatable grd files. This happens when:\n'
5172 ' - One of the modified grd or grdp files cannot be parsed or\n'
5173 ' - %s is not updated.\n'
5174 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5175 return []
Ken Rockotc31f4832020-05-29 18:58:515176
5177
Saagar Sanghavifceeaae2020-08-12 16:40:365178def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515179 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095180 changed_mojoms = input_api.AffectedFiles(
5181 include_deletes=True,
5182 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515183 delta = []
5184 for mojom in changed_mojoms:
5185 old_contents = ''.join(mojom.OldContents()) or None
5186 new_contents = ''.join(mojom.NewContents()) or None
5187 delta.append({
5188 'filename': mojom.LocalPath(),
5189 'old': '\n'.join(mojom.OldContents()) or None,
5190 'new': '\n'.join(mojom.NewContents()) or None,
5191 })
5192
5193 process = input_api.subprocess.Popen(
5194 [input_api.python_executable,
5195 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5196 'public', 'tools', 'mojom',
5197 'check_stable_mojom_compatibility.py'),
5198 '--src-root', input_api.PresubmitLocalPath()],
5199 stdin=input_api.subprocess.PIPE,
5200 stdout=input_api.subprocess.PIPE,
5201 stderr=input_api.subprocess.PIPE,
5202 universal_newlines=True)
5203 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5204 if process.returncode:
5205 return [output_api.PresubmitError(
5206 'One or more [Stable] mojom definitions appears to have been changed '
5207 'in a way that is not backward-compatible.',
5208 long_text=error)]
5209 return []
Dominic Battre645d42342020-12-04 16:14:105210
5211def CheckDeprecationOfPreferences(input_api, output_api):
5212 """Removing a preference should come with a deprecation."""
5213
5214 def FilterFile(affected_file):
5215 """Accept only .cc files and the like."""
5216 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5217 files_to_skip = (_EXCLUDED_PATHS +
5218 _TEST_CODE_EXCLUDED_PATHS +
5219 input_api.DEFAULT_FILES_TO_SKIP)
5220 return input_api.FilterSourceFile(
5221 affected_file,
5222 files_to_check=file_inclusion_pattern,
5223 files_to_skip=files_to_skip)
5224
5225 def ModifiedLines(affected_file):
5226 """Returns a list of tuples (line number, line text) of added and removed
5227 lines.
5228
5229 Deleted lines share the same line number as the previous line.
5230
5231 This relies on the scm diff output describing each changed code section
5232 with a line of the form
5233
5234 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5235 """
5236 line_num = 0
5237 modified_lines = []
5238 for line in affected_file.GenerateScmDiff().splitlines():
5239 # Extract <new line num> of the patch fragment (see format above).
5240 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5241 if m:
5242 line_num = int(m.groups(1)[0])
5243 continue
5244 if ((line.startswith('+') and not line.startswith('++')) or
5245 (line.startswith('-') and not line.startswith('--'))):
5246 modified_lines.append((line_num, line))
5247
5248 if not line.startswith('-'):
5249 line_num += 1
5250 return modified_lines
5251
5252 def FindLineWith(lines, needle):
5253 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5254
5255 If 0 or >1 lines contain `needle`, -1 is returned.
5256 """
5257 matching_line_numbers = [
5258 # + 1 for 1-based counting of line numbers.
5259 i + 1 for i, line
5260 in enumerate(lines)
5261 if needle in line]
5262 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5263
5264 def ModifiedPrefMigration(affected_file):
5265 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5266 # Determine first and last lines of MigrateObsolete.*Pref functions.
5267 new_contents = affected_file.NewContents();
5268 range_1 = (
5269 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5270 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5271 range_2 = (
5272 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5273 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5274 if (-1 in range_1 + range_2):
5275 raise Exception(
5276 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5277
5278 # Check whether any of the modified lines are part of the
5279 # MigrateObsolete.*Pref functions.
5280 for line_nr, line in ModifiedLines(affected_file):
5281 if (range_1[0] <= line_nr <= range_1[1] or
5282 range_2[0] <= line_nr <= range_2[1]):
5283 return True
5284 return False
5285
5286 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5287 browser_prefs_file_pattern = input_api.re.compile(
5288 r'chrome/browser/prefs/browser_prefs.cc')
5289
5290 changes = input_api.AffectedFiles(include_deletes=True,
5291 file_filter=FilterFile)
5292 potential_problems = []
5293 for f in changes:
5294 for line in f.GenerateScmDiff().splitlines():
5295 # Check deleted lines for pref registrations.
5296 if (line.startswith('-') and not line.startswith('--') and
5297 register_pref_pattern.search(line)):
5298 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5299
5300 if browser_prefs_file_pattern.search(f.LocalPath()):
5301 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5302 # assume that they knew that they have to deprecate preferences and don't
5303 # warn.
5304 try:
5305 if ModifiedPrefMigration(f):
5306 return []
5307 except Exception as e:
5308 return [output_api.PresubmitError(str(e))]
5309
5310 if potential_problems:
5311 return [output_api.PresubmitPromptWarning(
5312 'Discovered possible removal of preference registrations.\n\n'
5313 'Please make sure to properly deprecate preferences by clearing their\n'
5314 'value for a couple of milestones before finally removing the code.\n'
5315 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195316 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5317 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105318 'This may be a false positive warning (e.g. if you move preference\n'
5319 'registrations to a different place).\n',
5320 potential_problems
5321 )]
5322 return []