blob: 135c91f01e499d4a524cfc4e4680f6e6c460512f [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/',
652 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
653 '.*fuchsia.*test\.(cc|h)',
Alex Chau9eb03cdd52020-07-13 21:04:57654 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21655 ),
656 (
Peter Kasting991618a62019-06-17 22:00:09657 r'/\bstd::weak_ptr\b',
658 (
659 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
660 ),
661 True,
662 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
663 ),
664 (
Daniel Bratell609102be2019-03-27 20:53:21665 r'/\blong long\b',
666 (
667 'long long is banned. Use stdint.h if you need a 64 bit number.',
668 ),
669 False, # Only a warning since it is already used.
670 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
671 ),
672 (
673 r'/\bstd::bind\b',
674 (
675 'std::bind is banned because of lifetime risks.',
676 'Use base::BindOnce or base::BindRepeating instead.',
677 ),
678 True,
679 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
680 ),
681 (
682 r'/\b#include <chrono>\b',
683 (
684 '<chrono> overlaps with Time APIs in base. Keep using',
685 'base classes.',
686 ),
687 True,
688 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
689 ),
690 (
691 r'/\b#include <exception>\b',
692 (
693 'Exceptions are banned and disabled in Chromium.',
694 ),
695 True,
696 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
697 ),
698 (
699 r'/\bstd::function\b',
700 (
Colin Blundellea615d422021-05-12 09:35:41701 'std::function is banned. Instead use base::OnceCallback or ',
702 'base::RepeatingCallback, which directly support Chromium\'s weak ',
703 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21704 ),
Peter Kasting991618a62019-06-17 22:00:09705 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21706 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
707 ),
708 (
709 r'/\b#include <random>\b',
710 (
711 'Do not use any random number engines from <random>. Instead',
712 'use base::RandomBitGenerator.',
713 ),
714 True,
715 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
716 ),
717 (
Tom Andersona95e12042020-09-09 23:08:00718 r'/\b#include <X11/',
719 (
720 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
721 ),
722 True,
723 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
724 ),
725 (
Daniel Bratell609102be2019-03-27 20:53:21726 r'/\bstd::ratio\b',
727 (
728 'std::ratio is banned by the Google Style Guide.',
729 ),
730 True,
731 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45732 ),
733 (
Francois Doray43670e32017-09-27 12:40:38734 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
735 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
736 (
737 'Use the new API in base/threading/thread_restrictions.h.',
738 ),
Gabriel Charette04b138f2018-08-06 00:03:22739 False,
Francois Doray43670e32017-09-27 12:40:38740 (),
741 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38742 (
Michael Giuffrida7f93d6922019-04-19 14:39:58743 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19744 (
745 'RunMessageLoop is deprecated, use RunLoop instead.',
746 ),
747 False,
748 (),
749 ),
750 (
Dave Tapuska98199b612019-07-10 13:30:44751 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19752 (
753 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
754 ),
755 False,
756 (),
757 ),
758 (
Dave Tapuska98199b612019-07-10 13:30:44759 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19760 (
761 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
762 "if you're convinced you need this.",
763 ),
764 False,
765 (),
766 ),
767 (
Dave Tapuska98199b612019-07-10 13:30:44768 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19769 (
770 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04771 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19772 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
773 'async events instead of flushing threads.',
774 ),
775 False,
776 (),
777 ),
778 (
779 r'MessageLoopRunner',
780 (
781 'MessageLoopRunner is deprecated, use RunLoop instead.',
782 ),
783 False,
784 (),
785 ),
786 (
Dave Tapuska98199b612019-07-10 13:30:44787 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19788 (
789 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
790 "gab@ if you found a use case where this is the only solution.",
791 ),
792 False,
793 (),
794 ),
795 (
Victor Costane48a2e82019-03-15 22:02:34796 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16797 (
Victor Costane48a2e82019-03-15 22:02:34798 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16799 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
800 ),
801 True,
802 (
803 r'^sql/initialization\.(cc|h)$',
804 r'^third_party/sqlite/.*\.(c|cc|h)$',
805 ),
806 ),
Matt Menke7f520a82018-03-28 21:38:37807 (
Dave Tapuska98199b612019-07-10 13:30:44808 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47809 (
810 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
811 'base::RandomShuffle instead.'
812 ),
813 True,
814 (),
815 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24816 (
817 'ios/web/public/test/http_server',
818 (
819 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
820 ),
821 False,
822 (),
823 ),
Robert Liao764c9492019-01-24 18:46:28824 (
825 'GetAddressOf',
826 (
827 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53828 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11829 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53830 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28831 ),
832 True,
833 (),
834 ),
Antonio Gomes07300d02019-03-13 20:59:57835 (
Ben Lewisa9514602019-04-29 17:53:05836 'SHFileOperation',
837 (
838 'SHFileOperation was deprecated in Windows Vista, and there are less ',
839 'complex functions to achieve the same goals. Use IFileOperation for ',
840 'any esoteric actions instead.'
841 ),
842 True,
843 (),
844 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18845 (
Cliff Smolinsky81951642019-04-30 21:39:51846 'StringFromGUID2',
847 (
848 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24849 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51850 ),
851 True,
852 (
853 r'/base/win/win_util_unittest.cc'
854 ),
855 ),
856 (
857 'StringFromCLSID',
858 (
859 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24860 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51861 ),
862 True,
863 (
864 r'/base/win/win_util_unittest.cc'
865 ),
866 ),
867 (
Avi Drissman7382afa02019-04-29 23:27:13868 'kCFAllocatorNull',
869 (
870 'The use of kCFAllocatorNull with the NoCopy creation of ',
871 'CoreFoundation types is prohibited.',
872 ),
873 True,
874 (),
875 ),
Oksana Zhuravlovafd247772019-05-16 16:57:29876 (
877 'mojo::ConvertTo',
878 (
879 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
880 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
881 'StringTraits if you would like to convert between custom types and',
882 'the wire format of mojom types.'
883 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22884 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29885 (
Wezf89dec092019-09-11 19:38:33886 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
887 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29888 r'^third_party/blink/.*\.(cc|h)$',
889 r'^content/renderer/.*\.(cc|h)$',
890 ),
891 ),
Robert Liao1d78df52019-11-11 20:02:01892 (
Oksana Zhuravlovac8222d22019-12-19 19:21:16893 'GetInterfaceProvider',
894 (
895 'InterfaceProvider is deprecated.',
896 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
897 'or Platform::GetBrowserInterfaceBroker.'
898 ),
899 False,
900 (),
901 ),
902 (
Robert Liao1d78df52019-11-11 20:02:01903 'CComPtr',
904 (
905 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
906 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
907 'details.'
908 ),
909 False,
910 (),
911 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:20912 (
913 r'/\b(IFACE|STD)METHOD_?\(',
914 (
915 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
916 'Instead, always use IFACEMETHODIMP in the declaration.'
917 ),
918 False,
919 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
920 ),
Allen Bauer53b43fb12020-03-12 17:21:47921 (
922 'set_owned_by_client',
923 (
924 'set_owned_by_client is deprecated.',
925 'views::View already owns the child views by default. This introduces ',
926 'a competing ownership model which makes the code difficult to reason ',
927 'about. See http://crbug.com/1044687 for more details.'
928 ),
929 False,
930 (),
931 ),
Eric Secklerbe6f48d2020-05-06 18:09:12932 (
933 r'/\bTRACE_EVENT_ASYNC_',
934 (
935 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
936 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
937 ),
938 False,
939 (
940 r'^base/trace_event/.*',
941 r'^base/tracing/.*',
942 ),
943 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:26944 (
945 r'/\bScopedObserver',
946 (
947 'ScopedObserver is deprecated.',
948 'Please use base::ScopedObservation for observing a single source,',
949 'or base::ScopedMultiSourceObservation for observing multple sources',
950 ),
951 False,
952 (),
953 ),
Jan Wilken Dörrie60df2362021-04-08 19:44:21954 (
Robert Liao22f66a52021-04-10 00:57:52955 'RoInitialize',
956 (
Robert Liao48018922021-04-16 23:03:02957 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:52958 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
959 'instead. See http://crbug.com/1197722 for more information.'
960 ),
961 True,
Robert Liao48018922021-04-16 23:03:02962 (
963 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$'
964 ),
Robert Liao22f66a52021-04-10 00:57:52965 ),
[email protected]127f18ec2012-06-16 05:05:59966)
967
Mario Sanchez Prada2472cab2019-09-18 10:58:31968# Format: Sequence of tuples containing:
969# * String pattern or, if starting with a slash, a regular expression.
970# * Sequence of strings to show when the pattern matches.
971_DEPRECATED_MOJO_TYPES = (
972 (
973 r'/\bmojo::AssociatedBinding\b',
974 (
975 'mojo::AssociatedBinding<Interface> is deprecated.',
976 'Use mojo::AssociatedReceiver<Interface> instead.',
977 ),
978 ),
979 (
980 r'/\bmojo::AssociatedBindingSet\b',
981 (
982 'mojo::AssociatedBindingSet<Interface> is deprecated.',
983 'Use mojo::AssociatedReceiverSet<Interface> instead.',
984 ),
985 ),
986 (
987 r'/\bmojo::AssociatedInterfacePtr\b',
988 (
989 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
990 'Use mojo::AssociatedRemote<Interface> instead.',
991 ),
992 ),
993 (
994 r'/\bmojo::AssociatedInterfacePtrInfo\b',
995 (
996 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
997 'Use mojo::PendingAssociatedRemote<Interface> instead.',
998 ),
999 ),
1000 (
1001 r'/\bmojo::AssociatedInterfaceRequest\b',
1002 (
1003 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1004 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1005 ),
1006 ),
1007 (
1008 r'/\bmojo::Binding\b',
1009 (
1010 'mojo::Binding<Interface> is deprecated.',
1011 'Use mojo::Receiver<Interface> instead.',
1012 ),
1013 ),
1014 (
1015 r'/\bmojo::BindingSet\b',
1016 (
1017 'mojo::BindingSet<Interface> is deprecated.',
1018 'Use mojo::ReceiverSet<Interface> instead.',
1019 ),
1020 ),
1021 (
1022 r'/\bmojo::InterfacePtr\b',
1023 (
1024 'mojo::InterfacePtr<Interface> is deprecated.',
1025 'Use mojo::Remote<Interface> instead.',
1026 ),
1027 ),
1028 (
1029 r'/\bmojo::InterfacePtrInfo\b',
1030 (
1031 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1032 'Use mojo::PendingRemote<Interface> instead.',
1033 ),
1034 ),
1035 (
1036 r'/\bmojo::InterfaceRequest\b',
1037 (
1038 'mojo::InterfaceRequest<Interface> is deprecated.',
1039 'Use mojo::PendingReceiver<Interface> instead.',
1040 ),
1041 ),
1042 (
1043 r'/\bmojo::MakeRequest\b',
1044 (
1045 'mojo::MakeRequest is deprecated.',
1046 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1047 ),
1048 ),
1049 (
1050 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1051 (
1052 'mojo::MakeRequest is deprecated.',
1053 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181054 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311055 ),
1056 ),
1057 (
1058 r'/\bmojo::MakeStrongBinding\b',
1059 (
1060 'mojo::MakeStrongBinding is deprecated.',
1061 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1062 'mojo::MakeSelfOwnedReceiver() instead.',
1063 ),
1064 ),
1065 (
1066 r'/\bmojo::MakeStrongAssociatedBinding\b',
1067 (
1068 'mojo::MakeStrongAssociatedBinding is deprecated.',
1069 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1070 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1071 ),
1072 ),
1073 (
Gyuyoung Kim4952ba62020-07-07 07:33:441074 r'/\bmojo::StrongAssociatedBinding\b',
1075 (
1076 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1077 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1078 ),
1079 ),
1080 (
1081 r'/\bmojo::StrongBinding\b',
1082 (
1083 'mojo::StrongBinding<Interface> is deprecated.',
1084 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1085 ),
1086 ),
1087 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311088 r'/\bmojo::StrongAssociatedBindingSet\b',
1089 (
1090 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1091 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1092 ),
1093 ),
1094 (
1095 r'/\bmojo::StrongBindingSet\b',
1096 (
1097 'mojo::StrongBindingSet<Interface> is deprecated.',
1098 'Use mojo::UniqueReceiverSet<Interface> instead.',
1099 ),
1100 ),
1101)
wnwenbdc444e2016-05-25 13:44:151102
mlamouria82272622014-09-16 18:45:041103_IPC_ENUM_TRAITS_DEPRECATED = (
1104 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501105 'See http://www.chromium.org/Home/chromium-security/education/'
1106 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041107
Stephen Martinis97a394142018-06-07 23:06:051108_LONG_PATH_ERROR = (
1109 'Some files included in this CL have file names that are too long (> 200'
1110 ' characters). If committed, these files will cause issues on Windows. See'
1111 ' https://crbug.com/612667 for more details.'
1112)
1113
Shenghua Zhangbfaa38b82017-11-16 21:58:021114_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041115 r".*[\\/]BuildHooksAndroidImpl\.java",
1116 r".*[\\/]LicenseContentProvider\.java",
1117 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281118 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021119]
[email protected]127f18ec2012-06-16 05:05:591120
Mohamed Heikald048240a2019-11-12 16:57:371121# List of image extensions that are used as resources in chromium.
1122_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1123
Sean Kau46e29bc2017-08-28 16:31:161124# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401125_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041126 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401127 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041128 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1129 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041130 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431131 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161132]
1133
1134
[email protected]b00342e7f2013-03-26 16:21:541135_VALID_OS_MACROS = (
1136 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081137 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541138 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441139 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121140 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541141 'OS_BSD',
1142 'OS_CAT', # For testing.
1143 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041144 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541145 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371146 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541147 'OS_IOS',
1148 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441149 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541150 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211151 'OS_NACL_NONSFI',
1152 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121153 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541154 'OS_OPENBSD',
1155 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371156 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541157 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541158 'OS_WIN',
1159)
1160
1161
Andrew Grieveb773bad2020-06-05 18:00:381162# These are not checked on the public chromium-presubmit trybot.
1163# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041164# checkouts.
agrievef32bcc72016-04-04 14:57:401165_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381166 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381167]
1168
1169
1170_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041171 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361172 'base/android/jni_generator/jni_generator.pydeps',
1173 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361174 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041175 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361176 'build/android/gyp/aar.pydeps',
1177 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271178 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361179 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381180 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361181 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021182 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221183 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111184 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361185 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361186 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361187 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111188 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041189 'build/android/gyp/create_app_bundle_apks.pydeps',
1190 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361191 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121192 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091193 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221194 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001195 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361196 'build/android/gyp/desugar.pydeps',
1197 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421198 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041199 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361200 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361201 'build/android/gyp/filter_zip.pydeps',
1202 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361203 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361204 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581205 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361206 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141207 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261208 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471209 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011210 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041211 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361212 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361213 'build/android/gyp/merge_manifest.pydeps',
1214 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221215 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361216 'build/android/gyp/proguard.pydeps',
Mohamed Heikala9dd71a2021-04-15 15:39:271217 'build/android/gyp/resources_shrinker/shrinker.pydeps',
Peter Wen578730b2020-03-19 19:55:461218 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241219 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361220 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461221 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561222 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361223 'build/android/incremental_install/generate_android_manifest.pydeps',
1224 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041225 'build/android/resource_sizes.pydeps',
1226 'build/android/test_runner.pydeps',
1227 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361228 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361229 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321230 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271231 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1232 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041233 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001234 'components/cronet/tools/generate_javadoc.pydeps',
1235 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381236 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001237 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381238 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041239 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181240 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041241 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421242 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1243 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131244 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501245 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061246 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221247 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401248]
1249
wnwenbdc444e2016-05-25 13:44:151250
agrievef32bcc72016-04-04 14:57:401251_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1252
1253
Eric Boren6fd2b932018-01-25 15:05:081254# Bypass the AUTHORS check for these accounts.
1255_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591256 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451257 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591258 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521259 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071260 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041261 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271262 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041263 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161264 for s in ('chromium-internal-autoroll',)
1265 ) | set('%[email protected]' % s
1266 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081267
1268
Daniel Bratell65b033262019-04-23 08:17:061269def _IsCPlusPlusFile(input_api, file_path):
1270 """Returns True if this file contains C++-like code (and not Python,
1271 Go, Java, MarkDown, ...)"""
1272
1273 ext = input_api.os_path.splitext(file_path)[1]
1274 # This list is compatible with CppChecker.IsCppFile but we should
1275 # consider adding ".c" to it. If we do that we can use this function
1276 # at more places in the code.
1277 return ext in (
1278 '.h',
1279 '.cc',
1280 '.cpp',
1281 '.m',
1282 '.mm',
1283 )
1284
1285def _IsCPlusPlusHeaderFile(input_api, file_path):
1286 return input_api.os_path.splitext(file_path)[1] == ".h"
1287
1288
1289def _IsJavaFile(input_api, file_path):
1290 return input_api.os_path.splitext(file_path)[1] == ".java"
1291
1292
1293def _IsProtoFile(input_api, file_path):
1294 return input_api.os_path.splitext(file_path)[1] == ".proto"
1295
Mohamed Heikal5e5b7922020-10-29 18:57:591296
1297def CheckNoUpstreamDepsOnClank(input_api, output_api):
1298 """Prevent additions of dependencies from the upstream repo on //clank."""
1299 # clank can depend on clank
1300 if input_api.change.RepositoryRoot().endswith('clank'):
1301 return []
1302 build_file_patterns = [
1303 r'(.+/)?BUILD\.gn',
1304 r'.+\.gni',
1305 ]
1306 excluded_files = [
1307 r'build[/\\]config[/\\]android[/\\]config\.gni'
1308 ]
1309 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1310
1311 error_message = 'Disallowed import on //clank in an upstream build file:'
1312
1313 def FilterFile(affected_file):
1314 return input_api.FilterSourceFile(
1315 affected_file,
1316 files_to_check=build_file_patterns,
1317 files_to_skip=excluded_files)
1318
1319 problems = []
1320 for f in input_api.AffectedSourceFiles(FilterFile):
1321 local_path = f.LocalPath()
1322 for line_number, line in f.ChangedContents():
1323 if (bad_pattern.search(line)):
1324 problems.append(
1325 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1326 if problems:
1327 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1328 else:
1329 return []
1330
1331
Saagar Sanghavifceeaae2020-08-12 16:40:361332def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191333 """Attempts to prevent use of functions intended only for testing in
1334 non-testing code. For now this is just a best-effort implementation
1335 that ignores header files and may have some false positives. A
1336 better implementation would probably need a proper C++ parser.
1337 """
1338 # We only scan .cc files and the like, as the declaration of
1339 # for-testing functions in header files are hard to distinguish from
1340 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491341 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191342
jochenc0d4808c2015-07-27 09:25:421343 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191344 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091345 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131346 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191347 exclusion_pattern = input_api.re.compile(
1348 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1349 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131350 # Avoid a false positive in this case, where the method name, the ::, and
1351 # the closing { are all on different lines due to line wrapping.
1352 # HelperClassForTesting::
1353 # HelperClassForTesting(
1354 # args)
1355 # : member(0) {}
1356 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191357
1358 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441359 files_to_skip = (_EXCLUDED_PATHS +
1360 _TEST_CODE_EXCLUDED_PATHS +
1361 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191362 return input_api.FilterSourceFile(
1363 affected_file,
James Cook24a504192020-07-23 00:08:441364 files_to_check=file_inclusion_pattern,
1365 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191366
1367 problems = []
1368 for f in input_api.AffectedSourceFiles(FilterFile):
1369 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131370 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241371 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031372 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461373 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131374 not exclusion_pattern.search(line) and
1375 not allowlist_pattern.search(line) and
1376 not in_method_defn):
[email protected]55459852011-08-10 15:17:191377 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031378 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131379 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191380
1381 if problems:
[email protected]f7051d52013-04-02 18:31:421382 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031383 else:
1384 return []
[email protected]55459852011-08-10 15:17:191385
1386
Saagar Sanghavifceeaae2020-08-12 16:40:361387def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231388 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591389 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231390 """
1391 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1392 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1393 name_pattern = r'ForTest(s|ing)?'
1394 # Describes an occurrence of "ForTest*" inside a // comment.
1395 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501396 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551397 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231398 # Catch calls.
1399 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1400 # Ignore definitions. (Comments are ignored separately.)
1401 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1402
1403 problems = []
1404 sources = lambda x: input_api.FilterSourceFile(
1405 x,
James Cook24a504192020-07-23 00:08:441406 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1407 + input_api.DEFAULT_FILES_TO_SKIP),
1408 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231409 )
1410 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1411 local_path = f.LocalPath()
1412 is_inside_javadoc = False
1413 for line_number, line in f.ChangedContents():
1414 if is_inside_javadoc and javadoc_end_re.search(line):
1415 is_inside_javadoc = False
1416 if not is_inside_javadoc and javadoc_start_re.search(line):
1417 is_inside_javadoc = True
1418 if is_inside_javadoc:
1419 continue
1420 if (inclusion_re.search(line) and
1421 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501422 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231423 not exclusion_re.search(line)):
1424 problems.append(
1425 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1426
1427 if problems:
1428 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1429 else:
1430 return []
1431
1432
Saagar Sanghavifceeaae2020-08-12 16:40:361433def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541434 """Checks to make sure no .h files include <iostream>."""
1435 files = []
1436 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1437 input_api.re.MULTILINE)
1438 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1439 if not f.LocalPath().endswith('.h'):
1440 continue
1441 contents = input_api.ReadFile(f)
1442 if pattern.search(contents):
1443 files.append(f)
1444
1445 if len(files):
yolandyandaabc6d2016-04-18 18:29:391446 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061447 'Do not #include <iostream> in header files, since it inserts static '
1448 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541449 '#include <ostream>. See http://crbug.com/94794',
1450 files) ]
1451 return []
1452
Danil Chapovalov3518f362018-08-11 16:13:431453def _CheckNoStrCatRedefines(input_api, output_api):
1454 """Checks no windows headers with StrCat redefined are included directly."""
1455 files = []
1456 pattern_deny = input_api.re.compile(
1457 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1458 input_api.re.MULTILINE)
1459 pattern_allow = input_api.re.compile(
1460 r'^#include\s"base/win/windows_defines.inc"',
1461 input_api.re.MULTILINE)
1462 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1463 contents = input_api.ReadFile(f)
1464 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1465 files.append(f.LocalPath())
1466
1467 if len(files):
1468 return [output_api.PresubmitError(
1469 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1470 'directly since they pollute code with StrCat macro. Instead, '
1471 'include matching header from base/win. See http://crbug.com/856536',
1472 files) ]
1473 return []
1474
[email protected]10689ca2011-09-02 02:31:541475
Saagar Sanghavifceeaae2020-08-12 16:40:361476def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521477 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181478 problems = []
1479 for f in input_api.AffectedFiles():
1480 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1481 continue
1482
1483 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041484 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181485 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1486
1487 if not problems:
1488 return []
1489 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1490 '\n'.join(problems))]
1491
Saagar Sanghavifceeaae2020-08-12 16:40:361492def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341493 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1494
1495 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1496 instead of DISABLED_. To filter false positives, reports are only generated
1497 if a corresponding MAYBE_ line exists.
1498 """
1499 problems = []
1500
1501 # The following two patterns are looked for in tandem - is a test labeled
1502 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1503 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1504 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1505
1506 # This is for the case that a test is disabled on all platforms.
1507 full_disable_pattern = input_api.re.compile(
1508 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1509 input_api.re.MULTILINE)
1510
Katie Df13948e2018-09-25 07:33:441511 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341512 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1513 continue
1514
1515 # Search for MABYE_, DISABLE_ pairs.
1516 disable_lines = {} # Maps of test name to line number.
1517 maybe_lines = {}
1518 for line_num, line in f.ChangedContents():
1519 disable_match = disable_pattern.search(line)
1520 if disable_match:
1521 disable_lines[disable_match.group(1)] = line_num
1522 maybe_match = maybe_pattern.search(line)
1523 if maybe_match:
1524 maybe_lines[maybe_match.group(1)] = line_num
1525
1526 # Search for DISABLE_ occurrences within a TEST() macro.
1527 disable_tests = set(disable_lines.keys())
1528 maybe_tests = set(maybe_lines.keys())
1529 for test in disable_tests.intersection(maybe_tests):
1530 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1531
1532 contents = input_api.ReadFile(f)
1533 full_disable_match = full_disable_pattern.search(contents)
1534 if full_disable_match:
1535 problems.append(' %s' % f.LocalPath())
1536
1537 if not problems:
1538 return []
1539 return [
1540 output_api.PresubmitPromptWarning(
1541 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1542 '\n'.join(problems))
1543 ]
1544
[email protected]72df4e782012-06-21 16:28:181545
Saagar Sanghavifceeaae2020-08-12 16:40:361546def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571547 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521548 errors = []
Hans Wennborg944479f2020-06-25 21:39:251549 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521550 input_api.re.MULTILINE)
1551 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1552 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1553 continue
1554 for lnum, line in f.ChangedContents():
1555 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171556 errors.append(output_api.PresubmitError(
1557 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571558 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171559 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521560 return errors
1561
1562
Weilun Shia487fad2020-10-28 00:10:341563# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1564# more reliable way. See
1565# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191566
wnwenbdc444e2016-05-25 13:44:151567
Saagar Sanghavifceeaae2020-08-12 16:40:361568def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391569 """Check that FlakyTest annotation is our own instead of the android one"""
1570 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1571 files = []
1572 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1573 if f.LocalPath().endswith('Test.java'):
1574 if pattern.search(input_api.ReadFile(f)):
1575 files.append(f)
1576 if len(files):
1577 return [output_api.PresubmitError(
1578 'Use org.chromium.base.test.util.FlakyTest instead of '
1579 'android.test.FlakyTest',
1580 files)]
1581 return []
mcasasb7440c282015-02-04 14:52:191582
wnwenbdc444e2016-05-25 13:44:151583
Saagar Sanghavifceeaae2020-08-12 16:40:361584def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441585 """Make sure .DEPS.git is never modified manually."""
1586 if any(f.LocalPath().endswith('.DEPS.git') for f in
1587 input_api.AffectedFiles()):
1588 return [output_api.PresubmitError(
1589 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1590 'automated system based on what\'s in DEPS and your changes will be\n'
1591 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501592 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1593 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441594 'for more information')]
1595 return []
1596
1597
Saagar Sanghavifceeaae2020-08-12 16:40:361598def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471599 """Checks that DEPS file deps are from allowed_hosts."""
1600 # Run only if DEPS file has been modified to annoy fewer bystanders.
1601 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1602 return []
1603 # Outsource work to gclient verify
1604 try:
John Budorickf20c0042019-04-25 23:23:401605 gclient_path = input_api.os_path.join(
1606 input_api.PresubmitLocalPath(),
1607 'third_party', 'depot_tools', 'gclient.py')
1608 input_api.subprocess.check_output(
1609 [input_api.python_executable, gclient_path, 'verify'],
1610 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471611 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201612 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471613 return [output_api.PresubmitError(
1614 'DEPS file must have only git dependencies.',
1615 long_text=error.output)]
1616
1617
Mario Sanchez Prada2472cab2019-09-18 10:58:311618def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1619 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591620 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311621
1622 Returns an string composed of the name of the file, the line number where the
1623 match has been found and the additional text passed as |message| in case the
1624 target type name matches the text inside the line passed as parameter.
1625 """
Peng Huang9c5949a02020-06-11 19:20:541626 result = []
1627
danakjd18e8892020-12-17 17:42:011628 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1629 return result
1630 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541631 return result
1632
Mario Sanchez Prada2472cab2019-09-18 10:58:311633 matched = False
1634 if type_name[0:1] == '/':
1635 regex = type_name[1:]
1636 if input_api.re.search(regex, line):
1637 matched = True
1638 elif type_name in line:
1639 matched = True
1640
Mario Sanchez Prada2472cab2019-09-18 10:58:311641 if matched:
1642 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1643 for message_line in message:
1644 result.append(' %s' % message_line)
1645
1646 return result
1647
1648
Saagar Sanghavifceeaae2020-08-12 16:40:361649def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591650 """Make sure that banned functions are not used."""
1651 warnings = []
1652 errors = []
1653
James Cook24a504192020-07-23 00:08:441654 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151655 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441656 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151657 if input_api.re.match(item, local_path):
1658 return True
1659 return False
1660
Peter K. Lee6c03ccff2019-07-15 14:40:051661 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541662 local_path = affected_file.LocalPath()
1663 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1664 return False
1665 basename = input_api.os_path.basename(local_path)
1666 if 'ios' in basename.split('_'):
1667 return True
1668 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1669 if sep and 'ios' in local_path.split(sep):
1670 return True
1671 return False
1672
wnwenbdc444e2016-05-25 13:44:151673 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311674 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1675 func_name, message)
1676 if problems:
wnwenbdc444e2016-05-25 13:44:151677 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311678 errors.extend(problems)
1679 else:
1680 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151681
Eric Stevensona9a980972017-09-23 00:04:411682 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1683 for f in input_api.AffectedFiles(file_filter=file_filter):
1684 for line_num, line in f.ChangedContents():
1685 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1686 CheckForMatch(f, line_num, line, func_name, message, error)
1687
[email protected]127f18ec2012-06-16 05:05:591688 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1689 for f in input_api.AffectedFiles(file_filter=file_filter):
1690 for line_num, line in f.ChangedContents():
1691 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151692 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591693
Peter K. Lee6c03ccff2019-07-15 14:40:051694 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541695 for line_num, line in f.ChangedContents():
1696 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1697 CheckForMatch(f, line_num, line, func_name, message, error)
1698
Peter K. Lee6c03ccff2019-07-15 14:40:051699 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1700 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1701 for line_num, line in f.ChangedContents():
1702 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1703 CheckForMatch(f, line_num, line, func_name, message, error)
1704
[email protected]127f18ec2012-06-16 05:05:591705 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1706 for f in input_api.AffectedFiles(file_filter=file_filter):
1707 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491708 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441709 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491710 continue
wnwenbdc444e2016-05-25 13:44:151711 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591712
1713 result = []
1714 if (warnings):
1715 result.append(output_api.PresubmitPromptWarning(
1716 'Banned functions were used.\n' + '\n'.join(warnings)))
1717 if (errors):
1718 result.append(output_api.PresubmitError(
1719 'Banned functions were used.\n' + '\n'.join(errors)))
1720 return result
1721
1722
Michael Thiessen44457642020-02-06 00:24:151723def _CheckAndroidNoBannedImports(input_api, output_api):
1724 """Make sure that banned java imports are not used."""
1725 errors = []
1726
1727 def IsException(path, exceptions):
1728 for exception in exceptions:
1729 if (path.startswith(exception)):
1730 return True
1731 return False
1732
1733 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1734 for f in input_api.AffectedFiles(file_filter=file_filter):
1735 for line_num, line in f.ChangedContents():
1736 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1737 if IsException(f.LocalPath(), exceptions):
1738 continue;
1739 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1740 'import ' + import_name, message)
1741 if problems:
1742 errors.extend(problems)
1743 result = []
1744 if (errors):
1745 result.append(output_api.PresubmitError(
1746 'Banned imports were used.\n' + '\n'.join(errors)))
1747 return result
1748
1749
Saagar Sanghavifceeaae2020-08-12 16:40:361750def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311751 """Make sure that old Mojo types are not used."""
1752 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571753 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311754
Mario Sanchez Pradaaab91382019-12-19 08:57:091755 # For any path that is not an "ok" or an "error" path, a warning will be
1756 # raised if deprecated mojo types are found.
1757 ok_paths = ['components/arc']
1758 error_paths = ['third_party/blink', 'content']
1759
Mario Sanchez Prada2472cab2019-09-18 10:58:311760 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1761 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571762 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091763 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311764 continue
1765
1766 for line_num, line in f.ChangedContents():
1767 for func_name, message in _DEPRECATED_MOJO_TYPES:
1768 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1769 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571770
Mario Sanchez Prada2472cab2019-09-18 10:58:311771 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091772 # Raise errors inside |error_paths| and warnings everywhere else.
1773 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571774 errors.extend(problems)
1775 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311776 warnings.extend(problems)
1777
1778 result = []
1779 if (warnings):
1780 result.append(output_api.PresubmitPromptWarning(
1781 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571782 if (errors):
1783 result.append(output_api.PresubmitError(
1784 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311785 return result
1786
1787
Saagar Sanghavifceeaae2020-08-12 16:40:361788def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061789 """Make sure that banned functions are not used."""
1790 files = []
1791 pattern = input_api.re.compile(r'^#pragma\s+once',
1792 input_api.re.MULTILINE)
1793 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1794 if not f.LocalPath().endswith('.h'):
1795 continue
1796 contents = input_api.ReadFile(f)
1797 if pattern.search(contents):
1798 files.append(f)
1799
1800 if files:
1801 return [output_api.PresubmitError(
1802 'Do not use #pragma once in header files.\n'
1803 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1804 files)]
1805 return []
1806
[email protected]127f18ec2012-06-16 05:05:591807
Saagar Sanghavifceeaae2020-08-12 16:40:361808def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121809 """Checks to make sure we don't introduce use of foo ? true : false."""
1810 problems = []
1811 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1812 for f in input_api.AffectedFiles():
1813 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1814 continue
1815
1816 for line_num, line in f.ChangedContents():
1817 if pattern.match(line):
1818 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1819
1820 if not problems:
1821 return []
1822 return [output_api.PresubmitPromptWarning(
1823 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1824 '\n'.join(problems))]
1825
1826
Saagar Sanghavifceeaae2020-08-12 16:40:361827def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281828 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181829 change. Breaking - rules is an error, breaking ! rules is a
1830 warning.
1831 """
mohan.reddyf21db962014-10-16 12:26:471832 import sys
[email protected]55f9f382012-07-31 11:02:181833 # We need to wait until we have an input_api object and use this
1834 # roundabout construct to import checkdeps because this file is
1835 # eval-ed and thus doesn't have __file__.
1836 original_sys_path = sys.path
1837 try:
1838 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471839 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181840 import checkdeps
[email protected]55f9f382012-07-31 11:02:181841 from rules import Rule
1842 finally:
1843 # Restore sys.path to what it was before.
1844 sys.path = original_sys_path
1845
1846 added_includes = []
rhalavati08acd232017-04-03 07:23:281847 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241848 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181849 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061850 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501851 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081852 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061853 elif _IsProtoFile(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_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061856 elif _IsJavaFile(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_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181859
[email protected]26385172013-05-09 23:11:351860 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181861
1862 error_descriptions = []
1863 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281864 error_subjects = set()
1865 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361866
[email protected]55f9f382012-07-31 11:02:181867 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1868 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081869 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181870 description_with_path = '%s\n %s' % (path, rule_description)
1871 if rule_type == Rule.DISALLOW:
1872 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281873 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181874 else:
1875 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281876 warning_subjects.add("#includes")
1877
1878 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1879 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081880 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281881 description_with_path = '%s\n %s' % (path, rule_description)
1882 if rule_type == Rule.DISALLOW:
1883 error_descriptions.append(description_with_path)
1884 error_subjects.add("imports")
1885 else:
1886 warning_descriptions.append(description_with_path)
1887 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181888
Jinsuk Kim5a092672017-10-24 22:42:241889 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021890 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081891 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241892 description_with_path = '%s\n %s' % (path, rule_description)
1893 if rule_type == Rule.DISALLOW:
1894 error_descriptions.append(description_with_path)
1895 error_subjects.add("imports")
1896 else:
1897 warning_descriptions.append(description_with_path)
1898 warning_subjects.add("imports")
1899
[email protected]55f9f382012-07-31 11:02:181900 results = []
1901 if error_descriptions:
1902 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281903 'You added one or more %s that violate checkdeps rules.'
1904 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181905 error_descriptions))
1906 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421907 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281908 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181909 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281910 '%s? See relevant DEPS file(s) for details and contacts.' %
1911 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181912 warning_descriptions))
1913 return results
1914
1915
Saagar Sanghavifceeaae2020-08-12 16:40:361916def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:221917 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151918 if input_api.platform == 'win32':
1919 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291920 checkperms_tool = input_api.os_path.join(
1921 input_api.PresubmitLocalPath(),
1922 'tools', 'checkperms', 'checkperms.py')
1923 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471924 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391925 with input_api.CreateTemporaryFile() as file_list:
1926 for f in input_api.AffectedFiles():
1927 # checkperms.py file/directory arguments must be relative to the
1928 # repository.
1929 file_list.write(f.LocalPath() + '\n')
1930 file_list.close()
1931 args += ['--file-list', file_list.name]
1932 try:
1933 input_api.subprocess.check_output(args)
1934 return []
1935 except input_api.subprocess.CalledProcessError as error:
1936 return [output_api.PresubmitError(
1937 'checkperms.py failed:',
1938 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221939
1940
Saagar Sanghavifceeaae2020-08-12 16:40:361941def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:491942 """Makes sure we don't include ui/aura/window_property.h
1943 in header files.
1944 """
1945 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1946 errors = []
1947 for f in input_api.AffectedFiles():
1948 if not f.LocalPath().endswith('.h'):
1949 continue
1950 for line_num, line in f.ChangedContents():
1951 if pattern.match(line):
1952 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1953
1954 results = []
1955 if errors:
1956 results.append(output_api.PresubmitError(
1957 'Header files should not include ui/aura/window_property.h', errors))
1958 return results
1959
1960
Omer Katzcc77ea92021-04-26 10:23:281961def CheckNoInternalHeapIncludes(input_api, output_api):
1962 """Makes sure we don't include any headers from
1963 third_party/blink/renderer/platform/heap/impl or
1964 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1965 third_party/blink/renderer/platform/heap
1966 """
1967 impl_pattern = input_api.re.compile(
1968 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1969 v8_wrapper_pattern = input_api.re.compile(
1970 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"')
1971 file_filter = lambda f: not input_api.re.match(
1972 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1973 f.LocalPath())
1974 errors = []
1975
1976 for f in input_api.AffectedFiles(file_filter=file_filter):
1977 for line_num, line in f.ChangedContents():
1978 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1979 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1980
1981 results = []
1982 if errors:
1983 results.append(output_api.PresubmitError(
1984 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1985 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1986 'relevant counterparts from third_party/blink/renderer/platform/heap',
1987 errors))
1988 return results
1989
1990
[email protected]70ca77752012-11-20 03:45:031991def _CheckForVersionControlConflictsInFile(input_api, f):
1992 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1993 errors = []
1994 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161995 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231996 # First-level headers in markdown look a lot like version control
1997 # conflict markers. http://daringfireball.net/projects/markdown/basics
1998 continue
[email protected]70ca77752012-11-20 03:45:031999 if pattern.match(line):
2000 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2001 return errors
2002
2003
Saagar Sanghavifceeaae2020-08-12 16:40:362004def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032005 """Usually this is not intentional and will cause a compile failure."""
2006 errors = []
2007 for f in input_api.AffectedFiles():
2008 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2009
2010 results = []
2011 if errors:
2012 results.append(output_api.PresubmitError(
2013 'Version control conflict markers found, please resolve.', errors))
2014 return results
2015
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202016
Saagar Sanghavifceeaae2020-08-12 16:40:362017def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162018 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2019 errors = []
2020 for f in input_api.AffectedFiles():
2021 for line_num, line in f.ChangedContents():
2022 if pattern.search(line):
2023 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2024
2025 results = []
2026 if errors:
2027 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502028 'Found Google support URL addressed by answer number. Please replace '
2029 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162030 return results
2031
[email protected]70ca77752012-11-20 03:45:032032
Saagar Sanghavifceeaae2020-08-12 16:40:362033def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442034 def FilterFile(affected_file):
2035 """Filter function for use with input_api.AffectedSourceFiles,
2036 below. This filters out everything except non-test files from
2037 top-level directories that generally speaking should not hard-code
2038 service URLs (e.g. src/android_webview/, src/content/ and others).
2039 """
2040 return input_api.FilterSourceFile(
2041 affected_file,
James Cook24a504192020-07-23 00:08:442042 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2043 files_to_skip=(_EXCLUDED_PATHS +
2044 _TEST_CODE_EXCLUDED_PATHS +
2045 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442046
reillyi38965732015-11-16 18:27:332047 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2048 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462049 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2050 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442051 problems = [] # items are (filename, line_number, line)
2052 for f in input_api.AffectedSourceFiles(FilterFile):
2053 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462054 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442055 problems.append((f.LocalPath(), line_num, line))
2056
2057 if problems:
[email protected]f7051d52013-04-02 18:31:422058 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442059 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582060 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442061 [' %s:%d: %s' % (
2062 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032063 else:
2064 return []
[email protected]06e6d0ff2012-12-11 01:36:442065
2066
Saagar Sanghavifceeaae2020-08-12 16:40:362067def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292068 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2069 def FileFilter(affected_file):
2070 """Includes directories known to be Chrome OS only."""
2071 return input_api.FilterSourceFile(
2072 affected_file,
James Cook24a504192020-07-23 00:08:442073 files_to_check=('^ash/',
2074 '^chromeos/', # Top-level src/chromeos.
2075 '/chromeos/', # Any path component.
2076 '^components/arc',
2077 '^components/exo'),
2078 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292079
2080 prefs = []
2081 priority_prefs = []
2082 for f in input_api.AffectedFiles(file_filter=FileFilter):
2083 for line_num, line in f.ChangedContents():
2084 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2085 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2086 prefs.append(' %s' % line)
2087 if input_api.re.search(
2088 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2089 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2090 priority_prefs.append(' %s' % line)
2091
2092 results = []
2093 if (prefs):
2094 results.append(output_api.PresubmitPromptWarning(
2095 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2096 'by browser sync settings. If these prefs should be controlled by OS '
2097 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2098 if (priority_prefs):
2099 results.append(output_api.PresubmitPromptWarning(
2100 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2101 'controlled by browser sync settings. If these prefs should be '
2102 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2103 'instead.\n' + '\n'.join(prefs)))
2104 return results
2105
2106
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492107# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362108def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272109 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312110 The native_client_sdk directory is excluded because it has auto-generated PNG
2111 files for documentation.
[email protected]d2530012013-01-25 16:39:272112 """
[email protected]d2530012013-01-25 16:39:272113 errors = []
James Cook24a504192020-07-23 00:08:442114 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2115 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312116 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442117 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312118 for f in input_api.AffectedFiles(include_deletes=False,
2119 file_filter=file_filter):
2120 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272121
2122 results = []
2123 if errors:
2124 results.append(output_api.PresubmitError(
2125 'The name of PNG files should not have abbreviations. \n'
2126 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2127 'Contact [email protected] if you have questions.', errors))
2128 return results
2129
2130
Daniel Cheng4dcdb6b2017-04-13 08:30:172131def _ExtractAddRulesFromParsedDeps(parsed_deps):
2132 """Extract the rules that add dependencies from a parsed DEPS file.
2133
2134 Args:
2135 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2136 add_rules = set()
2137 add_rules.update([
2138 rule[1:] for rule in parsed_deps.get('include_rules', [])
2139 if rule.startswith('+') or rule.startswith('!')
2140 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502141 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172142 {}).iteritems():
2143 add_rules.update([
2144 rule[1:] for rule in rules
2145 if rule.startswith('+') or rule.startswith('!')
2146 ])
2147 return add_rules
2148
2149
2150def _ParseDeps(contents):
2151 """Simple helper for parsing DEPS files."""
2152 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172153 class _VarImpl:
2154
2155 def __init__(self, local_scope):
2156 self._local_scope = local_scope
2157
2158 def Lookup(self, var_name):
2159 """Implements the Var syntax."""
2160 try:
2161 return self._local_scope['vars'][var_name]
2162 except KeyError:
2163 raise Exception('Var is not defined: %s' % var_name)
2164
2165 local_scope = {}
2166 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172167 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592168 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172169 }
2170 exec contents in global_scope, local_scope
2171 return local_scope
2172
2173
2174def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592175 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412176 a set of DEPS entries that we should look up.
2177
2178 For a directory (rather than a specific filename) we fake a path to
2179 a specific filename by adding /DEPS. This is chosen as a file that
2180 will seldom or never be subject to per-file include_rules.
2181 """
[email protected]2b438d62013-11-14 17:54:142182 # We ignore deps entries on auto-generated directories.
2183 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082184
Daniel Cheng4dcdb6b2017-04-13 08:30:172185 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2186 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2187
2188 added_deps = new_deps.difference(old_deps)
2189
[email protected]2b438d62013-11-14 17:54:142190 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172191 for added_dep in added_deps:
2192 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2193 continue
2194 # Assume that a rule that ends in .h is a rule for a specific file.
2195 if added_dep.endswith('.h'):
2196 results.add(added_dep)
2197 else:
2198 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082199 return results
2200
2201
Saagar Sanghavifceeaae2020-08-12 16:40:362202def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552203 """When a dependency prefixed with + is added to a DEPS file, we
2204 want to make sure that the change is reviewed by an OWNER of the
2205 target file or directory, to avoid layering violations from being
2206 introduced. This check verifies that this happens.
2207 """
Joey Mou57048132021-02-26 22:17:552208 # We rely on Gerrit's code-owners to check approvals.
2209 # input_api.gerrit is always set for Chromium, but other projects
2210 # might not use Gerrit.
2211 if not input_api.gerrit:
2212 return []
Edward Lesmes44feb2332021-03-19 01:27:522213 if (input_api.change.issue and
2214 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232215 # Skip OWNERS check when Owners-Override label is approved. This is intended
2216 # for global owners, trusted bots, and on-call sheriffs. Review is still
2217 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522218 return []
Edward Lesmes6fba51082021-01-20 04:20:232219
Daniel Cheng4dcdb6b2017-04-13 08:30:172220 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242221
2222 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492223 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242224 for f in input_api.AffectedFiles(include_deletes=False,
2225 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552226 filename = input_api.os_path.basename(f.LocalPath())
2227 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172228 virtual_depended_on_files.update(_CalculateAddedDeps(
2229 input_api.os_path,
2230 '\n'.join(f.OldContents()),
2231 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552232
[email protected]e871964c2013-05-13 14:14:552233 if not virtual_depended_on_files:
2234 return []
2235
2236 if input_api.is_committing:
2237 if input_api.tbr:
2238 return [output_api.PresubmitNotifyResult(
2239 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272240 if input_api.dry_run:
2241 return [output_api.PresubmitNotifyResult(
2242 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552243 if not input_api.change.issue:
2244 return [output_api.PresubmitError(
2245 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402246 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552247 output = output_api.PresubmitError
2248 else:
2249 output = output_api.PresubmitNotifyResult
2250
tandriied3b7e12016-05-12 14:38:502251 owner_email, reviewers = (
2252 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2253 input_api,
Edward Lesmesa3846442021-02-08 20:20:032254 None,
tandriied3b7e12016-05-12 14:38:502255 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552256
2257 owner_email = owner_email or input_api.change.author_email
2258
Edward Lesmesa3846442021-02-08 20:20:032259 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2260 virtual_depended_on_files, reviewers.union([owner_email]), [])
2261 missing_files = [
2262 f for f in virtual_depended_on_files
2263 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412264
2265 # We strip the /DEPS part that was added by
2266 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2267 # directory.
2268 def StripDeps(path):
2269 start_deps = path.rfind('/DEPS')
2270 if start_deps != -1:
2271 return path[:start_deps]
2272 else:
2273 return path
2274 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552275 for path in missing_files]
2276
2277 if unapproved_dependencies:
2278 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152279 output('You need LGTM from owners of depends-on paths in DEPS that were '
2280 'modified in this CL:\n %s' %
2281 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032282 suggested_owners = input_api.owners_client.SuggestOwners(
2283 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152284 output_list.append(output(
2285 'Suggested missing target path OWNERS:\n %s' %
2286 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552287 return output_list
2288
2289 return []
2290
2291
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492292# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362293def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492294 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442295 files_to_skip = (_EXCLUDED_PATHS +
2296 _TEST_CODE_EXCLUDED_PATHS +
2297 input_api.DEFAULT_FILES_TO_SKIP +
2298 (r"^base[\\/]logging\.h$",
2299 r"^base[\\/]logging\.cc$",
2300 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2301 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2302 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2303 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2304 r"startup_browser_creator\.cc$",
2305 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2306 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2307 r"diagnostics_writer\.cc$",
2308 r"^chrome[\\/]chrome_cleaner[\\/].*",
2309 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2310 r"dll_hash_main\.cc$",
2311 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2312 r"^chromecast[\\/]",
2313 r"^cloud_print[\\/]",
2314 r"^components[\\/]browser_watcher[\\/]"
2315 r"dump_stability_report_main_win.cc$",
2316 r"^components[\\/]media_control[\\/]renderer[\\/]"
2317 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352318 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2319 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442320 r"^components[\\/]zucchini[\\/].*",
2321 # TODO(peter): Remove exception. https://crbug.com/534537
2322 r"^content[\\/]browser[\\/]notifications[\\/]"
2323 r"notification_event_dispatcher_impl\.cc$",
2324 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2325 r"gl_helper_benchmark\.cc$",
2326 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2327 r"^courgette[\\/]courgette_tool\.cc$",
2328 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2329 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2330 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Sergey Ulanov6db14b4d62021-05-10 07:59:482331 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
James Cook24a504192020-07-23 00:08:442332 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2333 r"^ipc[\\/]ipc_logging\.cc$",
2334 r"^native_client_sdk[\\/]",
2335 r"^remoting[\\/]base[\\/]logging\.h$",
2336 r"^remoting[\\/]host[\\/].*",
2337 r"^sandbox[\\/]linux[\\/].*",
2338 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2339 r"dump_file_system.cc$",
2340 r"^tools[\\/]",
2341 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2342 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2343 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2344 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2345 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402346 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442347 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402348
thomasanderson625d3932017-03-29 07:16:582349 log_info = set([])
2350 printf = set([])
[email protected]85218562013-11-22 07:41:402351
2352 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582353 for _, line in f.ChangedContents():
2354 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2355 log_info.add(f.LocalPath())
2356 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2357 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372358
thomasanderson625d3932017-03-29 07:16:582359 if input_api.re.search(r"\bprintf\(", line):
2360 printf.add(f.LocalPath())
2361 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2362 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402363
2364 if log_info:
2365 return [output_api.PresubmitError(
2366 'These files spam the console log with LOG(INFO):',
2367 items=log_info)]
2368 if printf:
2369 return [output_api.PresubmitError(
2370 'These files spam the console log with printf/fprintf:',
2371 items=printf)]
2372 return []
2373
2374
Saagar Sanghavifceeaae2020-08-12 16:40:362375def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162376 """These types are all expected to hold locks while in scope and
2377 so should never be anonymous (which causes them to be immediately
2378 destroyed)."""
2379 they_who_must_be_named = [
2380 'base::AutoLock',
2381 'base::AutoReset',
2382 'base::AutoUnlock',
2383 'SkAutoAlphaRestore',
2384 'SkAutoBitmapShaderInstall',
2385 'SkAutoBlitterChoose',
2386 'SkAutoBounderCommit',
2387 'SkAutoCallProc',
2388 'SkAutoCanvasRestore',
2389 'SkAutoCommentBlock',
2390 'SkAutoDescriptor',
2391 'SkAutoDisableDirectionCheck',
2392 'SkAutoDisableOvalCheck',
2393 'SkAutoFree',
2394 'SkAutoGlyphCache',
2395 'SkAutoHDC',
2396 'SkAutoLockColors',
2397 'SkAutoLockPixels',
2398 'SkAutoMalloc',
2399 'SkAutoMaskFreeImage',
2400 'SkAutoMutexAcquire',
2401 'SkAutoPathBoundsUpdate',
2402 'SkAutoPDFRelease',
2403 'SkAutoRasterClipValidate',
2404 'SkAutoRef',
2405 'SkAutoTime',
2406 'SkAutoTrace',
2407 'SkAutoUnref',
2408 ]
2409 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2410 # bad: base::AutoLock(lock.get());
2411 # not bad: base::AutoLock lock(lock.get());
2412 bad_pattern = input_api.re.compile(anonymous)
2413 # good: new base::AutoLock(lock.get())
2414 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2415 errors = []
2416
2417 for f in input_api.AffectedFiles():
2418 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2419 continue
2420 for linenum, line in f.ChangedContents():
2421 if bad_pattern.search(line) and not good_pattern.search(line):
2422 errors.append('%s:%d' % (f.LocalPath(), linenum))
2423
2424 if errors:
2425 return [output_api.PresubmitError(
2426 'These lines create anonymous variables that need to be named:',
2427 items=errors)]
2428 return []
2429
2430
Saagar Sanghavifceeaae2020-08-12 16:40:362431def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532432 # Returns whether |template_str| is of the form <T, U...> for some types T
2433 # and U. Assumes that |template_str| is already in the form <...>.
2434 def HasMoreThanOneArg(template_str):
2435 # Level of <...> nesting.
2436 nesting = 0
2437 for c in template_str:
2438 if c == '<':
2439 nesting += 1
2440 elif c == '>':
2441 nesting -= 1
2442 elif c == ',' and nesting == 1:
2443 return True
2444 return False
2445
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492446 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102447 sources = lambda affected_file: input_api.FilterSourceFile(
2448 affected_file,
James Cook24a504192020-07-23 00:08:442449 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2450 input_api.DEFAULT_FILES_TO_SKIP),
2451 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552452
2453 # Pattern to capture a single "<...>" block of template arguments. It can
2454 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2455 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2456 # latter would likely require counting that < and > match, which is not
2457 # expressible in regular languages. Should the need arise, one can introduce
2458 # limited counting (matching up to a total number of nesting depth), which
2459 # should cover all practical cases for already a low nesting limit.
2460 template_arg_pattern = (
2461 r'<[^>]*' # Opening block of <.
2462 r'>([^<]*>)?') # Closing block of >.
2463 # Prefix expressing that whatever follows is not already inside a <...>
2464 # block.
2465 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102466 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552467 not_inside_template_arg_pattern
2468 + r'\bstd::unique_ptr'
2469 + template_arg_pattern
2470 + r'\(\)')
2471
2472 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2473 template_arg_no_array_pattern = (
2474 r'<[^>]*[^]]' # Opening block of <.
2475 r'>([^(<]*[^]]>)?') # Closing block of >.
2476 # Prefix saying that what follows is the start of an expression.
2477 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2478 # Suffix saying that what follows are call parentheses with a non-empty list
2479 # of arguments.
2480 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532481 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552482 return_construct_pattern = input_api.re.compile(
2483 start_of_expr_pattern
2484 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532485 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552486 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532487 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552488 + nonempty_arg_list_pattern)
2489
Vaclav Brozek851d9602018-04-04 16:13:052490 problems_constructor = []
2491 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102492 for f in input_api.AffectedSourceFiles(sources):
2493 for line_number, line in f.ChangedContents():
2494 # Disallow:
2495 # return std::unique_ptr<T>(foo);
2496 # bar = std::unique_ptr<T>(foo);
2497 # But allow:
2498 # return std::unique_ptr<T[]>(foo);
2499 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532500 # And also allow cases when the second template argument is present. Those
2501 # cases cannot be handled by std::make_unique:
2502 # return std::unique_ptr<T, U>(foo);
2503 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052504 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532505 return_construct_result = return_construct_pattern.search(line)
2506 if return_construct_result and not HasMoreThanOneArg(
2507 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052508 problems_constructor.append(
2509 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102510 # Disallow:
2511 # std::unique_ptr<T>()
2512 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052513 problems_nullptr.append(
2514 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2515
2516 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162517 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052518 errors.append(output_api.PresubmitError(
2519 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162520 problems_nullptr))
2521 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052522 errors.append(output_api.PresubmitError(
2523 'The following files use explicit std::unique_ptr constructor.'
2524 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162525 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102526 return errors
2527
2528
Saagar Sanghavifceeaae2020-08-12 16:40:362529def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082530 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522531 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082532 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522533 # If actions.xml is already included in the changelist, the PRESUBMIT
2534 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082535 return []
2536
Alexei Svitkine64505a92021-03-11 22:00:542537 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2538 files_to_skip = (_EXCLUDED_PATHS +
2539 _TEST_CODE_EXCLUDED_PATHS +
2540 input_api.DEFAULT_FILES_TO_SKIP )
2541 file_filter = lambda f: input_api.FilterSourceFile(
2542 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2543
[email protected]999261d2014-03-03 20:08:082544 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522545 current_actions = None
[email protected]999261d2014-03-03 20:08:082546 for f in input_api.AffectedFiles(file_filter=file_filter):
2547 for line_num, line in f.ChangedContents():
2548 match = input_api.re.search(action_re, line)
2549 if match:
[email protected]2f92dec2014-03-07 19:21:522550 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2551 # loaded only once.
2552 if not current_actions:
2553 with open('tools/metrics/actions/actions.xml') as actions_f:
2554 current_actions = actions_f.read()
2555 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082556 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522557 action = 'name="{0}"'.format(action_name)
2558 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082559 return [output_api.PresubmitPromptWarning(
2560 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522561 'tools/metrics/actions/actions.xml. Please run '
2562 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082563 % (f.LocalPath(), line_num, action_name))]
2564 return []
2565
2566
Daniel Cheng13ca61a882017-08-25 15:11:252567def _ImportJSONCommentEater(input_api):
2568 import sys
2569 sys.path = sys.path + [input_api.os_path.join(
2570 input_api.PresubmitLocalPath(),
2571 'tools', 'json_comment_eater')]
2572 import json_comment_eater
2573 return json_comment_eater
2574
2575
[email protected]99171a92014-06-03 08:44:472576def _GetJSONParseError(input_api, filename, eat_comments=True):
2577 try:
2578 contents = input_api.ReadFile(filename)
2579 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252580 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132581 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472582
2583 input_api.json.loads(contents)
2584 except ValueError as e:
2585 return e
2586 return None
2587
2588
2589def _GetIDLParseError(input_api, filename):
2590 try:
2591 contents = input_api.ReadFile(filename)
2592 idl_schema = input_api.os_path.join(
2593 input_api.PresubmitLocalPath(),
2594 'tools', 'json_schema_compiler', 'idl_schema.py')
2595 process = input_api.subprocess.Popen(
2596 [input_api.python_executable, idl_schema],
2597 stdin=input_api.subprocess.PIPE,
2598 stdout=input_api.subprocess.PIPE,
2599 stderr=input_api.subprocess.PIPE,
2600 universal_newlines=True)
2601 (_, error) = process.communicate(input=contents)
2602 return error or None
2603 except ValueError as e:
2604 return e
2605
2606
Saagar Sanghavifceeaae2020-08-12 16:40:362607def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472608 """Check that IDL and JSON files do not contain syntax errors."""
2609 actions = {
2610 '.idl': _GetIDLParseError,
2611 '.json': _GetJSONParseError,
2612 }
[email protected]99171a92014-06-03 08:44:472613 # Most JSON files are preprocessed and support comments, but these do not.
2614 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042615 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472616 ]
2617 # Only run IDL checker on files in these directories.
2618 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042619 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2620 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472621 ]
2622
2623 def get_action(affected_file):
2624 filename = affected_file.LocalPath()
2625 return actions.get(input_api.os_path.splitext(filename)[1])
2626
[email protected]99171a92014-06-03 08:44:472627 def FilterFile(affected_file):
2628 action = get_action(affected_file)
2629 if not action:
2630 return False
2631 path = affected_file.LocalPath()
2632
Erik Staab2dd72b12020-04-16 15:03:402633 if _MatchesFile(input_api,
2634 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2635 path):
[email protected]99171a92014-06-03 08:44:472636 return False
2637
2638 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162639 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472640 return False
2641 return True
2642
2643 results = []
2644 for affected_file in input_api.AffectedFiles(
2645 file_filter=FilterFile, include_deletes=False):
2646 action = get_action(affected_file)
2647 kwargs = {}
2648 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162649 _MatchesFile(input_api, json_no_comments_patterns,
2650 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472651 kwargs['eat_comments'] = False
2652 parse_error = action(input_api,
2653 affected_file.AbsoluteLocalPath(),
2654 **kwargs)
2655 if parse_error:
2656 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2657 (affected_file.LocalPath(), parse_error)))
2658 return results
2659
2660
Saagar Sanghavifceeaae2020-08-12 16:40:362661def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492662 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472663 import sys
[email protected]760deea2013-12-10 19:33:492664 original_sys_path = sys.path
2665 try:
2666 sys.path = sys.path + [input_api.os_path.join(
2667 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2668 import checkstyle
2669 finally:
2670 # Restore sys.path to what it was before.
2671 sys.path = original_sys_path
2672
2673 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092674 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442675 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492676
2677
Saagar Sanghavifceeaae2020-08-12 16:40:362678def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002679 """Checks to make sure devil is initialized correctly in python scripts."""
2680 script_common_initialize_pattern = input_api.re.compile(
2681 r'script_common\.InitializeEnvironment\(')
2682 devil_env_config_initialize = input_api.re.compile(
2683 r'devil_env\.config\.Initialize\(')
2684
2685 errors = []
2686
2687 sources = lambda affected_file: input_api.FilterSourceFile(
2688 affected_file,
James Cook24a504192020-07-23 00:08:442689 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2690 (r'^build[\\/]android[\\/]devil_chromium\.py',
2691 r'^third_party[\\/].*',)),
2692 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002693
2694 for f in input_api.AffectedSourceFiles(sources):
2695 for line_num, line in f.ChangedContents():
2696 if (script_common_initialize_pattern.search(line) or
2697 devil_env_config_initialize.search(line)):
2698 errors.append("%s:%d" % (f.LocalPath(), line_num))
2699
2700 results = []
2701
2702 if errors:
2703 results.append(output_api.PresubmitError(
2704 'Devil initialization should always be done using '
2705 'devil_chromium.Initialize() in the chromium project, to use better '
2706 'defaults for dependencies (ex. up-to-date version of adb).',
2707 errors))
2708
2709 return results
2710
2711
Sean Kau46e29bc2017-08-28 16:31:162712def _MatchesFile(input_api, patterns, path):
2713 for pattern in patterns:
2714 if input_api.re.search(pattern, path):
2715 return True
2716 return False
2717
2718
Daniel Cheng7052cdf2017-11-21 19:23:292719def _GetOwnersFilesToCheckForIpcOwners(input_api):
2720 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172721
Daniel Cheng7052cdf2017-11-21 19:23:292722 Returns:
2723 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2724 contain to cover IPC-related files with noparent reviewer rules.
2725 """
2726 # Whether or not a file affects IPC is (mostly) determined by a simple list
2727 # of filename patterns.
dchenge07de812016-06-20 19:27:172728 file_patterns = [
palmerb19a0932017-01-24 04:00:312729 # Legacy IPC:
dchenge07de812016-06-20 19:27:172730 '*_messages.cc',
2731 '*_messages*.h',
2732 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312733 # Mojo IPC:
dchenge07de812016-06-20 19:27:172734 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472735 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172736 '*_struct_traits*.*',
2737 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312738 '*.typemap',
2739 # Android native IPC:
2740 '*.aidl',
2741 # Blink uses a different file naming convention:
2742 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472743 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172744 '*StructTraits*.*',
2745 '*TypeConverter*.*',
2746 ]
2747
scottmg7a6ed5ba2016-11-04 18:22:042748 # These third_party directories do not contain IPCs, but contain files
2749 # matching the above patterns, which trigger false positives.
2750 exclude_paths = [
2751 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162752 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232753 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292754 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542755 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162756 # These files are just used to communicate between class loaders running
2757 # in the same process.
2758 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572759 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2760
scottmg7a6ed5ba2016-11-04 18:22:042761 ]
2762
dchenge07de812016-06-20 19:27:172763 # Dictionary mapping an OWNERS file path to Patterns.
2764 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2765 # rules ) to a PatternEntry.
2766 # PatternEntry is a dictionary with two keys:
2767 # - 'files': the files that are matched by this pattern
2768 # - 'rules': the per-file rules needed for this pattern
2769 # For example, if we expect OWNERS file to contain rules for *.mojom and
2770 # *_struct_traits*.*, Patterns might look like this:
2771 # {
2772 # '*.mojom': {
2773 # 'files': ...,
2774 # 'rules': [
2775 # 'per-file *.mojom=set noparent',
2776 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2777 # ],
2778 # },
2779 # '*_struct_traits*.*': {
2780 # 'files': ...,
2781 # 'rules': [
2782 # 'per-file *_struct_traits*.*=set noparent',
2783 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2784 # ],
2785 # },
2786 # }
2787 to_check = {}
2788
Daniel Cheng13ca61a882017-08-25 15:11:252789 def AddPatternToCheck(input_file, pattern):
2790 owners_file = input_api.os_path.join(
2791 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2792 if owners_file not in to_check:
2793 to_check[owners_file] = {}
2794 if pattern not in to_check[owners_file]:
2795 to_check[owners_file][pattern] = {
2796 'files': [],
2797 'rules': [
2798 'per-file %s=set noparent' % pattern,
2799 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2800 ]
2801 }
Vaclav Brozekd5de76a2018-03-17 07:57:502802 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252803
dchenge07de812016-06-20 19:27:172804 # Iterate through the affected files to see what we actually need to check
2805 # for. We should only nag patch authors about per-file rules if a file in that
2806 # directory would match that pattern. If a directory only contains *.mojom
2807 # files and no *_messages*.h files, we should only nag about rules for
2808 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252809 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262810 # Manifest files don't have a strong naming convention. Instead, try to find
2811 # affected .cc and .h files which look like they contain a manifest
2812 # definition.
2813 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2814 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2815 if (manifest_pattern.search(f.LocalPath()) and not
2816 test_manifest_pattern.search(f.LocalPath())):
2817 # We expect all actual service manifest files to contain at least one
2818 # qualified reference to service_manager::Manifest.
2819 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252820 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172821 for pattern in file_patterns:
2822 if input_api.fnmatch.fnmatch(
2823 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042824 skip = False
2825 for exclude in exclude_paths:
2826 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2827 skip = True
2828 break
2829 if skip:
2830 continue
Daniel Cheng13ca61a882017-08-25 15:11:252831 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172832 break
2833
Daniel Cheng7052cdf2017-11-21 19:23:292834 return to_check
2835
2836
Wez17c66962020-04-29 15:26:032837def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2838 """Adds OWNERS files to check for correct Fuchsia security owners."""
2839
2840 file_patterns = [
2841 # Component specifications.
2842 '*.cml', # Component Framework v2.
2843 '*.cmx', # Component Framework v1.
2844
2845 # Fuchsia IDL protocol specifications.
2846 '*.fidl',
2847 ]
2848
Joshua Peraza1ca6d392020-12-08 00:14:092849 # Don't check for owners files for changes in these directories.
2850 exclude_paths = [
2851 'third_party/crashpad/*',
2852 ]
2853
Wez17c66962020-04-29 15:26:032854 def AddPatternToCheck(input_file, pattern):
2855 owners_file = input_api.os_path.join(
2856 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2857 if owners_file not in to_check:
2858 to_check[owners_file] = {}
2859 if pattern not in to_check[owners_file]:
2860 to_check[owners_file][pattern] = {
2861 'files': [],
2862 'rules': [
2863 'per-file %s=set noparent' % pattern,
2864 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2865 ]
2866 }
2867 to_check[owners_file][pattern]['files'].append(input_file)
2868
2869 # Iterate through the affected files to see what we actually need to check
2870 # for. We should only nag patch authors about per-file rules if a file in that
2871 # directory would match that pattern.
2872 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092873 skip = False
2874 for exclude in exclude_paths:
2875 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2876 skip = True
2877 if skip:
2878 continue
2879
Wez17c66962020-04-29 15:26:032880 for pattern in file_patterns:
2881 if input_api.fnmatch.fnmatch(
2882 input_api.os_path.basename(f.LocalPath()), pattern):
2883 AddPatternToCheck(f, pattern)
2884 break
2885
2886 return to_check
2887
2888
Saagar Sanghavifceeaae2020-08-12 16:40:362889def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292890 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2891 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032892 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292893
2894 if to_check:
2895 # If there are any OWNERS files to check, there are IPC-related changes in
2896 # this CL. Auto-CC the review list.
2897 output_api.AppendCC('[email protected]')
2898
2899 # Go through the OWNERS files to check, filtering out rules that are already
2900 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172901 for owners_file, patterns in to_check.iteritems():
2902 try:
2903 with file(owners_file) as f:
2904 lines = set(f.read().splitlines())
2905 for entry in patterns.itervalues():
2906 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2907 ]
2908 except IOError:
2909 # No OWNERS file, so all the rules are definitely missing.
2910 continue
2911
2912 # All the remaining lines weren't found in OWNERS files, so emit an error.
2913 errors = []
2914 for owners_file, patterns in to_check.iteritems():
2915 missing_lines = []
2916 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502917 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172918 missing_lines.extend(entry['rules'])
2919 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2920 if missing_lines:
2921 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052922 'Because of the presence of files:\n%s\n\n'
2923 '%s needs the following %d lines added:\n\n%s' %
2924 ('\n'.join(files), owners_file, len(missing_lines),
2925 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172926
2927 results = []
2928 if errors:
vabrf5ce3bf92016-07-11 14:52:412929 if input_api.is_committing:
2930 output = output_api.PresubmitError
2931 else:
2932 output = output_api.PresubmitPromptWarning
2933 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592934 'Found OWNERS files that need to be updated for IPC security ' +
2935 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172936 long_text='\n\n'.join(errors)))
2937
2938 return results
2939
2940
Robert Sesek2c905332020-05-06 23:17:132941def _GetFilesUsingSecurityCriticalFunctions(input_api):
2942 """Checks affected files for changes to security-critical calls. This
2943 function checks the full change diff, to catch both additions/changes
2944 and removals.
2945
2946 Returns a dict keyed by file name, and the value is a set of detected
2947 functions.
2948 """
2949 # Map of function pretty name (displayed in an error) to the pattern to
2950 # match it with.
2951 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:372952 'content::GetServiceSandboxType<>()':
2953 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:132954 }
2955 _PATTERNS_TO_CHECK = {
2956 k: input_api.re.compile(v)
2957 for k, v in _PATTERNS_TO_CHECK.items()
2958 }
2959
2960 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2961 files_to_functions = {}
2962 for f in input_api.AffectedFiles():
2963 diff = f.GenerateScmDiff()
2964 for line in diff.split('\n'):
2965 # Not using just RightHandSideLines() because removing a
2966 # call to a security-critical function can be just as important
2967 # as adding or changing the arguments.
2968 if line.startswith('-') or (line.startswith('+') and
2969 not line.startswith('++')):
2970 for name, pattern in _PATTERNS_TO_CHECK.items():
2971 if pattern.search(line):
2972 path = f.LocalPath()
2973 if not path in files_to_functions:
2974 files_to_functions[path] = set()
2975 files_to_functions[path].add(name)
2976 return files_to_functions
2977
2978
Saagar Sanghavifceeaae2020-08-12 16:40:362979def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:132980 """Checks that changes involving security-critical functions are reviewed
2981 by the security team.
2982 """
2983 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:122984 if not len(files_to_functions):
2985 return []
Robert Sesek2c905332020-05-06 23:17:132986
Edward Lesmes1e9fade2021-02-08 20:31:122987 owner_email, reviewers = (
2988 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2989 input_api,
2990 None,
2991 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:132992
Edward Lesmes1e9fade2021-02-08 20:31:122993 # Load the OWNERS file for security changes.
2994 owners_file = 'ipc/SECURITY_OWNERS'
2995 security_owners = input_api.owners_client.ListOwners(owners_file)
2996 has_security_owner = any([owner in reviewers for owner in security_owners])
2997 if has_security_owner:
2998 return []
Robert Sesek2c905332020-05-06 23:17:132999
Edward Lesmes1e9fade2021-02-08 20:31:123000 msg = 'The following files change calls to security-sensive functions\n' \
3001 'that need to be reviewed by {}.\n'.format(owners_file)
3002 for path, names in files_to_functions.items():
3003 msg += ' {}\n'.format(path)
3004 for name in names:
3005 msg += ' {}\n'.format(name)
3006 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133007
Edward Lesmes1e9fade2021-02-08 20:31:123008 if input_api.is_committing:
3009 output = output_api.PresubmitError
3010 else:
3011 output = output_api.PresubmitNotifyResult
3012 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133013
3014
Saagar Sanghavifceeaae2020-08-12 16:40:363015def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263016 """Checks that set noparent is only used together with an OWNERS file in
3017 //build/OWNERS.setnoparent (see also
3018 //docs/code_reviews.md#owners-files-details)
3019 """
3020 errors = []
3021
3022 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3023 allowed_owners_files = set()
3024 with open(allowed_owners_files_file, 'r') as f:
3025 for line in f:
3026 line = line.strip()
3027 if not line or line.startswith('#'):
3028 continue
3029 allowed_owners_files.add(line)
3030
3031 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3032
3033 for f in input_api.AffectedFiles(include_deletes=False):
3034 if not f.LocalPath().endswith('OWNERS'):
3035 continue
3036
3037 found_owners_files = set()
3038 found_set_noparent_lines = dict()
3039
3040 # Parse the OWNERS file.
3041 for lineno, line in enumerate(f.NewContents(), 1):
3042 line = line.strip()
3043 if line.startswith('set noparent'):
3044 found_set_noparent_lines[''] = lineno
3045 if line.startswith('file://'):
3046 if line in allowed_owners_files:
3047 found_owners_files.add('')
3048 if line.startswith('per-file'):
3049 match = per_file_pattern.match(line)
3050 if match:
3051 glob = match.group(1).strip()
3052 directive = match.group(2).strip()
3053 if directive == 'set noparent':
3054 found_set_noparent_lines[glob] = lineno
3055 if directive.startswith('file://'):
3056 if directive in allowed_owners_files:
3057 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153058
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263059 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403060 # listed in build/OWNERS.setnoparent. An exception is made for top level
3061 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143062 if (f.LocalPath().count('/') != 1 and
3063 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403064 for set_noparent_line in found_set_noparent_lines:
3065 if set_noparent_line in found_owners_files:
3066 continue
3067 errors.append(' %s:%d' % (f.LocalPath(),
3068 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263069
3070 results = []
3071 if errors:
3072 if input_api.is_committing:
3073 output = output_api.PresubmitError
3074 else:
3075 output = output_api.PresubmitPromptWarning
3076 results.append(output(
3077 'Found the following "set noparent" restrictions in OWNERS files that '
3078 'do not include owners from build/OWNERS.setnoparent:',
3079 long_text='\n\n'.join(errors)))
3080 return results
3081
3082
Saagar Sanghavifceeaae2020-08-12 16:40:363083def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313084 """Checks that added or removed lines in non third party affected
3085 header files do not lead to new useless class or struct forward
3086 declaration.
jbriance9e12f162016-11-25 07:57:503087 """
3088 results = []
3089 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3090 input_api.re.MULTILINE)
3091 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3092 input_api.re.MULTILINE)
3093 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313094 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193095 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493096 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313097 continue
3098
jbriance9e12f162016-11-25 07:57:503099 if not f.LocalPath().endswith('.h'):
3100 continue
3101
3102 contents = input_api.ReadFile(f)
3103 fwd_decls = input_api.re.findall(class_pattern, contents)
3104 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3105
3106 useless_fwd_decls = []
3107 for decl in fwd_decls:
3108 count = sum(1 for _ in input_api.re.finditer(
3109 r'\b%s\b' % input_api.re.escape(decl), contents))
3110 if count == 1:
3111 useless_fwd_decls.append(decl)
3112
3113 if not useless_fwd_decls:
3114 continue
3115
3116 for line in f.GenerateScmDiff().splitlines():
3117 if (line.startswith('-') and not line.startswith('--') or
3118 line.startswith('+') and not line.startswith('++')):
3119 for decl in useless_fwd_decls:
3120 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3121 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243122 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503123 (f.LocalPath(), decl)))
3124 useless_fwd_decls.remove(decl)
3125
3126 return results
3127
Jinsong Fan91ebbbd2019-04-16 14:57:173128def _CheckAndroidDebuggableBuild(input_api, output_api):
3129 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3130 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3131 this is a debuggable build of Android.
3132 """
3133 build_type_check_pattern = input_api.re.compile(
3134 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3135
3136 errors = []
3137
3138 sources = lambda affected_file: input_api.FilterSourceFile(
3139 affected_file,
James Cook24a504192020-07-23 00:08:443140 files_to_skip=(_EXCLUDED_PATHS +
3141 _TEST_CODE_EXCLUDED_PATHS +
3142 input_api.DEFAULT_FILES_TO_SKIP +
3143 (r"^android_webview[\\/]support_library[\\/]"
3144 "boundary_interfaces[\\/]",
3145 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3146 r'^third_party[\\/].*',
3147 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3148 r"webview[\\/]chromium[\\/]License.*",)),
3149 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173150
3151 for f in input_api.AffectedSourceFiles(sources):
3152 for line_num, line in f.ChangedContents():
3153 if build_type_check_pattern.search(line):
3154 errors.append("%s:%d" % (f.LocalPath(), line_num))
3155
3156 results = []
3157
3158 if errors:
3159 results.append(output_api.PresubmitPromptWarning(
3160 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3161 ' Please use BuildInfo.isDebugAndroid() instead.',
3162 errors))
3163
3164 return results
jbriance9e12f162016-11-25 07:57:503165
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493166# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293167def _CheckAndroidToastUsage(input_api, output_api):
3168 """Checks that code uses org.chromium.ui.widget.Toast instead of
3169 android.widget.Toast (Chromium Toast doesn't force hardware
3170 acceleration on low-end devices, saving memory).
3171 """
3172 toast_import_pattern = input_api.re.compile(
3173 r'^import android\.widget\.Toast;$')
3174
3175 errors = []
3176
3177 sources = lambda affected_file: input_api.FilterSourceFile(
3178 affected_file,
James Cook24a504192020-07-23 00:08:443179 files_to_skip=(_EXCLUDED_PATHS +
3180 _TEST_CODE_EXCLUDED_PATHS +
3181 input_api.DEFAULT_FILES_TO_SKIP +
3182 (r'^chromecast[\\/].*',
3183 r'^remoting[\\/].*')),
3184 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293185
3186 for f in input_api.AffectedSourceFiles(sources):
3187 for line_num, line in f.ChangedContents():
3188 if toast_import_pattern.search(line):
3189 errors.append("%s:%d" % (f.LocalPath(), line_num))
3190
3191 results = []
3192
3193 if errors:
3194 results.append(output_api.PresubmitError(
3195 'android.widget.Toast usage is detected. Android toasts use hardware'
3196 ' acceleration, and can be\ncostly on low-end devices. Please use'
3197 ' org.chromium.ui.widget.Toast instead.\n'
3198 'Contact [email protected] if you have any questions.',
3199 errors))
3200
3201 return results
3202
3203
dgnaa68d5e2015-06-10 10:08:223204def _CheckAndroidCrLogUsage(input_api, output_api):
3205 """Checks that new logs using org.chromium.base.Log:
3206 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513207 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223208 """
pkotwicza1dd0b002016-05-16 14:41:043209
torne89540622017-03-24 19:41:303210 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043211 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303212 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043213 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303214 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043215 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3216 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093217 # The customtabs_benchmark is a small app that does not depend on Chromium
3218 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043219 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043220 ]
3221
dgnaa68d5e2015-06-10 10:08:223222 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123223 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3224 class_in_base_pattern = input_api.re.compile(
3225 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3226 has_some_log_import_pattern = input_api.re.compile(
3227 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223228 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553229 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223230 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463231 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553232 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223233
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463234 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443235 sources = lambda x: input_api.FilterSourceFile(x,
3236 files_to_check=[r'.*\.java$'],
3237 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123238
dgnaa68d5e2015-06-10 10:08:223239 tag_decl_errors = []
3240 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123241 tag_errors = []
dgn38736db2015-09-18 19:20:513242 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123243 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223244
3245 for f in input_api.AffectedSourceFiles(sources):
3246 file_content = input_api.ReadFile(f)
3247 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223248 # Per line checks
dgn87d9fb62015-06-12 09:15:123249 if (cr_log_import_pattern.search(file_content) or
3250 (class_in_base_pattern.search(file_content) and
3251 not has_some_log_import_pattern.search(file_content))):
3252 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223253 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553254 if rough_log_decl_pattern.search(line):
3255 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223256
3257 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123258 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223259 if match:
3260 has_modified_logs = True
3261
3262 # Make sure it uses "TAG"
3263 if not match.group('tag') == 'TAG':
3264 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123265 else:
3266 # Report non cr Log function calls in changed lines
3267 for line_num, line in f.ChangedContents():
3268 if log_call_pattern.search(line):
3269 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223270
3271 # Per file checks
3272 if has_modified_logs:
3273 # Make sure the tag is using the "cr" prefix and is not too long
3274 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513275 tag_name = match.group('name') if match else None
3276 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223277 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513278 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223279 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513280 elif '.' in tag_name:
3281 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223282
3283 results = []
3284 if tag_decl_errors:
3285 results.append(output_api.PresubmitPromptWarning(
3286 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513287 '"private static final String TAG = "<package tag>".\n'
3288 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223289 tag_decl_errors))
3290
3291 if tag_length_errors:
3292 results.append(output_api.PresubmitError(
3293 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513294 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223295 tag_length_errors))
3296
3297 if tag_errors:
3298 results.append(output_api.PresubmitPromptWarning(
3299 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3300 tag_errors))
3301
dgn87d9fb62015-06-12 09:15:123302 if util_log_errors:
dgn4401aa52015-04-29 16:26:173303 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123304 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3305 util_log_errors))
3306
dgn38736db2015-09-18 19:20:513307 if tag_with_dot_errors:
3308 results.append(output_api.PresubmitPromptWarning(
3309 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3310 tag_with_dot_errors))
3311
dgn4401aa52015-04-29 16:26:173312 return results
3313
3314
Yoland Yanb92fa522017-08-28 17:37:063315def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3316 """Checks that junit.framework.* is no longer used."""
3317 deprecated_junit_framework_pattern = input_api.re.compile(
3318 r'^import junit\.framework\..*;',
3319 input_api.re.MULTILINE)
3320 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443321 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063322 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133323 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063324 for line_num, line in f.ChangedContents():
3325 if deprecated_junit_framework_pattern.search(line):
3326 errors.append("%s:%d" % (f.LocalPath(), line_num))
3327
3328 results = []
3329 if errors:
3330 results.append(output_api.PresubmitError(
3331 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3332 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3333 ' if you have any question.', errors))
3334 return results
3335
3336
3337def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3338 """Checks that if new Java test classes have inheritance.
3339 Either the new test class is JUnit3 test or it is a JUnit4 test class
3340 with a base class, either case is undesirable.
3341 """
3342 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3343
3344 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443345 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063346 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133347 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063348 if not f.OldContents():
3349 class_declaration_start_flag = False
3350 for line_num, line in f.ChangedContents():
3351 if class_declaration_pattern.search(line):
3352 class_declaration_start_flag = True
3353 if class_declaration_start_flag and ' extends ' in line:
3354 errors.append('%s:%d' % (f.LocalPath(), line_num))
3355 if '{' in line:
3356 class_declaration_start_flag = False
3357
3358 results = []
3359 if errors:
3360 results.append(output_api.PresubmitPromptWarning(
3361 'The newly created files include Test classes that inherits from base'
3362 ' class. Please do not use inheritance in JUnit4 tests or add new'
3363 ' JUnit3 tests. Contact [email protected] if you have any'
3364 ' questions.', errors))
3365 return results
3366
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203367
yolandyan45001472016-12-21 21:12:423368def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3369 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3370 deprecated_annotation_import_pattern = input_api.re.compile(
3371 r'^import android\.test\.suitebuilder\.annotation\..*;',
3372 input_api.re.MULTILINE)
3373 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443374 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423375 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133376 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423377 for line_num, line in f.ChangedContents():
3378 if deprecated_annotation_import_pattern.search(line):
3379 errors.append("%s:%d" % (f.LocalPath(), line_num))
3380
3381 results = []
3382 if errors:
3383 results.append(output_api.PresubmitError(
3384 'Annotations in android.test.suitebuilder.annotation have been'
3385 ' deprecated since API level 24. Please use android.support.test.filters'
3386 ' from //third_party/android_support_test_runner:runner_java instead.'
3387 ' Contact [email protected] if you have any questions.', errors))
3388 return results
3389
3390
agrieve7b6479d82015-10-07 14:24:223391def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3392 """Checks if MDPI assets are placed in a correct directory."""
3393 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3394 ('/res/drawable/' in f.LocalPath() or
3395 '/res/drawable-ldrtl/' in f.LocalPath()))
3396 errors = []
3397 for f in input_api.AffectedFiles(include_deletes=False,
3398 file_filter=file_filter):
3399 errors.append(' %s' % f.LocalPath())
3400
3401 results = []
3402 if errors:
3403 results.append(output_api.PresubmitError(
3404 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3405 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3406 '/res/drawable-ldrtl/.\n'
3407 'Contact [email protected] if you have questions.', errors))
3408 return results
3409
3410
Nate Fischer535972b2017-09-16 01:06:183411def _CheckAndroidWebkitImports(input_api, output_api):
3412 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353413 android.webview.ValueCallback except in the WebView glue layer
3414 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183415 """
3416 valuecallback_import_pattern = input_api.re.compile(
3417 r'^import android\.webkit\.ValueCallback;$')
3418
3419 errors = []
3420
3421 sources = lambda affected_file: input_api.FilterSourceFile(
3422 affected_file,
James Cook24a504192020-07-23 00:08:443423 files_to_skip=(_EXCLUDED_PATHS +
3424 _TEST_CODE_EXCLUDED_PATHS +
3425 input_api.DEFAULT_FILES_TO_SKIP +
3426 (r'^android_webview[\\/]glue[\\/].*',
3427 r'^weblayer[\\/].*',)),
3428 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183429
3430 for f in input_api.AffectedSourceFiles(sources):
3431 for line_num, line in f.ChangedContents():
3432 if valuecallback_import_pattern.search(line):
3433 errors.append("%s:%d" % (f.LocalPath(), line_num))
3434
3435 results = []
3436
3437 if errors:
3438 results.append(output_api.PresubmitError(
3439 'android.webkit.ValueCallback usage is detected outside of the glue'
3440 ' layer. To stay compatible with the support library, android.webkit.*'
3441 ' classes should only be used inside the glue layer and'
3442 ' org.chromium.base.Callback should be used instead.',
3443 errors))
3444
3445 return results
3446
3447
Becky Zhou7c69b50992018-12-10 19:37:573448def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3449 """Checks Android XML styles """
3450 import sys
3451 original_sys_path = sys.path
3452 try:
3453 sys.path = sys.path + [input_api.os_path.join(
3454 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3455 import checkxmlstyle
3456 finally:
3457 # Restore sys.path to what it was before.
3458 sys.path = original_sys_path
3459
3460 if is_check_on_upload:
3461 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3462 else:
3463 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3464
3465
agrievef32bcc72016-04-04 14:57:403466class PydepsChecker(object):
3467 def __init__(self, input_api, pydeps_files):
3468 self._file_cache = {}
3469 self._input_api = input_api
3470 self._pydeps_files = pydeps_files
3471
3472 def _LoadFile(self, path):
3473 """Returns the list of paths within a .pydeps file relative to //."""
3474 if path not in self._file_cache:
3475 with open(path) as f:
3476 self._file_cache[path] = f.read()
3477 return self._file_cache[path]
3478
3479 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3480 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393481 pydeps_data = self._LoadFile(pydeps_path)
3482 uses_gn_paths = '--gn-paths' in pydeps_data
3483 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3484 if uses_gn_paths:
3485 # Paths look like: //foo/bar/baz
3486 return (e[2:] for e in entries)
3487 else:
3488 # Paths look like: path/relative/to/file.pydeps
3489 os_path = self._input_api.os_path
3490 pydeps_dir = os_path.dirname(pydeps_path)
3491 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403492
3493 def _CreateFilesToPydepsMap(self):
3494 """Returns a map of local_path -> list_of_pydeps."""
3495 ret = {}
3496 for pydep_local_path in self._pydeps_files:
3497 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3498 ret.setdefault(path, []).append(pydep_local_path)
3499 return ret
3500
3501 def ComputeAffectedPydeps(self):
3502 """Returns an iterable of .pydeps files that might need regenerating."""
3503 affected_pydeps = set()
3504 file_to_pydeps_map = None
3505 for f in self._input_api.AffectedFiles(include_deletes=True):
3506 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463507 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3508 # subrepositories. We can't figure out which files change, so re-check
3509 # all files.
3510 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383511 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3512 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403513 return self._pydeps_files
3514 elif local_path.endswith('.pydeps'):
3515 if local_path in self._pydeps_files:
3516 affected_pydeps.add(local_path)
3517 elif local_path.endswith('.py'):
3518 if file_to_pydeps_map is None:
3519 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3520 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3521 return affected_pydeps
3522
3523 def DetermineIfStale(self, pydeps_path):
3524 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413525 import difflib
John Budorick47ca3fe2018-02-10 00:53:103526 import os
3527
agrievef32bcc72016-04-04 14:57:403528 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033529 if old_pydeps_data:
3530 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393531 if '--output' not in cmd:
3532 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033533 old_contents = old_pydeps_data[2:]
3534 else:
3535 # A default cmd that should work in most cases (as long as pydeps filename
3536 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3537 # file is empty/new.
3538 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3539 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3540 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103541 env = dict(os.environ)
3542 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403543 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103544 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413545 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033546 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413547 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403548
3549
Tibor Goldschwendt360793f72019-06-25 18:23:493550def _ParseGclientArgs():
3551 args = {}
3552 with open('build/config/gclient_args.gni', 'r') as f:
3553 for line in f:
3554 line = line.strip()
3555 if not line or line.startswith('#'):
3556 continue
3557 attribute, value = line.split('=')
3558 args[attribute.strip()] = value.strip()
3559 return args
3560
3561
Saagar Sanghavifceeaae2020-08-12 16:40:363562def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403563 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403564 # This check is for Python dependency lists (.pydeps files), and involves
3565 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3566 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283567 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003568 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493569 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403570 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403571 results = []
3572 # First, check for new / deleted .pydeps.
3573 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033574 # Check whether we are running the presubmit check for a file in src.
3575 # f.LocalPath is relative to repo (src, or internal repo).
3576 # os_path.exists is relative to src repo.
3577 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3578 # to src and we can conclude that the pydeps is in src.
3579 if input_api.os_path.exists(f.LocalPath()):
3580 if f.LocalPath().endswith('.pydeps'):
3581 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3582 results.append(output_api.PresubmitError(
3583 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3584 'remove %s' % f.LocalPath()))
3585 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3586 results.append(output_api.PresubmitError(
3587 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3588 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403589
3590 if results:
3591 return results
3592
Mohamed Heikal7cd4d8312020-06-16 16:49:403593 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3594 affected_pydeps = set(checker.ComputeAffectedPydeps())
3595 affected_android_pydeps = affected_pydeps.intersection(
3596 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3597 if affected_android_pydeps and not is_android:
3598 results.append(output_api.PresubmitPromptOrNotify(
3599 'You have changed python files that may affect pydeps for android\n'
3600 'specific scripts. However, the relevant presumbit check cannot be\n'
3601 'run because you are not using an Android checkout. To validate that\n'
3602 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3603 'use the android-internal-presubmit optional trybot.\n'
3604 'Possibly stale pydeps files:\n{}'.format(
3605 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403606
Mohamed Heikal7cd4d8312020-06-16 16:49:403607 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3608 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403609 try:
phajdan.jr0d9878552016-11-04 10:49:413610 result = checker.DetermineIfStale(pydep_path)
3611 if result:
3612 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403613 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413614 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3615 'To regenerate, run:\n\n %s' %
3616 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403617 except input_api.subprocess.CalledProcessError as error:
3618 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3619 long_text=error.output)]
3620
3621 return results
3622
3623
Saagar Sanghavifceeaae2020-08-12 16:40:363624def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433625 """Checks to make sure no header files have |Singleton<|."""
3626 def FileFilter(affected_file):
3627 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443628 files_to_skip = (_EXCLUDED_PATHS +
3629 input_api.DEFAULT_FILES_TO_SKIP +
3630 (r"^base[\\/]memory[\\/]singleton\.h$",
3631 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3632 r"quic_singleton_impl\.h$"))
3633 return input_api.FilterSourceFile(affected_file,
3634 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433635
sergeyu34d21222015-09-16 00:11:443636 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433637 files = []
3638 for f in input_api.AffectedSourceFiles(FileFilter):
3639 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3640 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3641 contents = input_api.ReadFile(f)
3642 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243643 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433644 pattern.search(line)):
3645 files.append(f)
3646 break
3647
3648 if files:
yolandyandaabc6d2016-04-18 18:29:393649 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443650 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433651 'Please move them to an appropriate source file so that the ' +
3652 'template gets instantiated in a single compilation unit.',
3653 files) ]
3654 return []
3655
3656
[email protected]fd20b902014-05-09 02:14:533657_DEPRECATED_CSS = [
3658 # Values
3659 ( "-webkit-box", "flex" ),
3660 ( "-webkit-inline-box", "inline-flex" ),
3661 ( "-webkit-flex", "flex" ),
3662 ( "-webkit-inline-flex", "inline-flex" ),
3663 ( "-webkit-min-content", "min-content" ),
3664 ( "-webkit-max-content", "max-content" ),
3665
3666 # Properties
3667 ( "-webkit-background-clip", "background-clip" ),
3668 ( "-webkit-background-origin", "background-origin" ),
3669 ( "-webkit-background-size", "background-size" ),
3670 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443671 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533672
3673 # Functions
3674 ( "-webkit-gradient", "gradient" ),
3675 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3676 ( "-webkit-linear-gradient", "linear-gradient" ),
3677 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3678 ( "-webkit-radial-gradient", "radial-gradient" ),
3679 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3680]
3681
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203682
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493683# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363684def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533685 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253686 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343687 documentation and iOS CSS for dom distiller
3688 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253689 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533690 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493691 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443692 files_to_skip = (_EXCLUDED_PATHS +
3693 _TEST_CODE_EXCLUDED_PATHS +
3694 input_api.DEFAULT_FILES_TO_SKIP +
3695 (r"^chrome/common/extensions/docs",
3696 r"^chrome/docs",
3697 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3698 r"^components/neterror/resources/neterror.css",
3699 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253700 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443701 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533702 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3703 for line_num, line in fpath.ChangedContents():
3704 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023705 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533706 results.append(output_api.PresubmitError(
3707 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3708 (fpath.LocalPath(), line_num, deprecated_value, value)))
3709 return results
3710
mohan.reddyf21db962014-10-16 12:26:473711
Saagar Sanghavifceeaae2020-08-12 16:40:363712def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363713 bad_files = {}
3714 for f in input_api.AffectedFiles(include_deletes=False):
3715 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493716 not f.LocalPath().startswith('third_party/blink') and
3717 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363718 continue
3719
Daniel Bratell65b033262019-04-23 08:17:063720 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363721 continue
3722
Vaclav Brozekd5de76a2018-03-17 07:57:503723 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363724 if "#include" in line and "../" in line]
3725 if not relative_includes:
3726 continue
3727 bad_files[f.LocalPath()] = relative_includes
3728
3729 if not bad_files:
3730 return []
3731
3732 error_descriptions = []
3733 for file_path, bad_lines in bad_files.iteritems():
3734 error_description = file_path
3735 for line in bad_lines:
3736 error_description += '\n ' + line
3737 error_descriptions.append(error_description)
3738
3739 results = []
3740 results.append(output_api.PresubmitError(
3741 'You added one or more relative #include paths (including "../").\n'
3742 'These shouldn\'t be used because they can be used to include headers\n'
3743 'from code that\'s not correctly specified as a dependency in the\n'
3744 'relevant BUILD.gn file(s).',
3745 error_descriptions))
3746
3747 return results
3748
Takeshi Yoshinoe387aa32017-08-02 13:16:133749
Saagar Sanghavifceeaae2020-08-12 16:40:363750def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063751 """Check that nobody tries to include a cc file. It's a relatively
3752 common error which results in duplicate symbols in object
3753 files. This may not always break the build until someone later gets
3754 very confusing linking errors."""
3755 results = []
3756 for f in input_api.AffectedFiles(include_deletes=False):
3757 # We let third_party code do whatever it wants
3758 if (f.LocalPath().startswith('third_party') and
3759 not f.LocalPath().startswith('third_party/blink') and
3760 not f.LocalPath().startswith('third_party\\blink')):
3761 continue
3762
3763 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3764 continue
3765
3766 for _, line in f.ChangedContents():
3767 if line.startswith('#include "'):
3768 included_file = line.split('"')[1]
3769 if _IsCPlusPlusFile(input_api, included_file):
3770 # The most common naming for external files with C++ code,
3771 # apart from standard headers, is to call them foo.inc, but
3772 # Chromium sometimes uses foo-inc.cc so allow that as well.
3773 if not included_file.endswith(('.h', '-inc.cc')):
3774 results.append(output_api.PresubmitError(
3775 'Only header files or .inc files should be included in other\n'
3776 'C++ files. Compiling the contents of a cc file more than once\n'
3777 'will cause duplicate information in the build which may later\n'
3778 'result in strange link_errors.\n' +
3779 f.LocalPath() + ':\n ' +
3780 line))
3781
3782 return results
3783
3784
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203785def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3786 if not isinstance(key, ast.Str):
3787 return 'Key at line %d must be a string literal' % key.lineno
3788 if not isinstance(value, ast.Dict):
3789 return 'Value at line %d must be a dict' % value.lineno
3790 if len(value.keys) != 1:
3791 return 'Dict at line %d must have single entry' % value.lineno
3792 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3793 return (
3794 'Entry at line %d must have a string literal \'filepath\' as key' %
3795 value.lineno)
3796 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133797
Takeshi Yoshinoe387aa32017-08-02 13:16:133798
Sergey Ulanov4af16052018-11-08 02:41:463799def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203800 if not isinstance(key, ast.Str):
3801 return 'Key at line %d must be a string literal' % key.lineno
3802 if not isinstance(value, ast.List):
3803 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463804 for element in value.elts:
3805 if not isinstance(element, ast.Str):
3806 return 'Watchlist elements on line %d is not a string' % key.lineno
3807 if not email_regex.match(element.s):
3808 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3809 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203810 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133811
Takeshi Yoshinoe387aa32017-08-02 13:16:133812
Sergey Ulanov4af16052018-11-08 02:41:463813def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203814 mismatch_template = (
3815 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3816 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133817
Sergey Ulanov4af16052018-11-08 02:41:463818 email_regex = input_api.re.compile(
3819 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3820
3821 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203822 i = 0
3823 last_key = ''
3824 while True:
3825 if i >= len(wd_dict.keys):
3826 if i >= len(w_dict.keys):
3827 return None
3828 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3829 elif i >= len(w_dict.keys):
3830 return (
3831 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133832
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203833 wd_key = wd_dict.keys[i]
3834 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133835
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203836 result = _CheckWatchlistDefinitionsEntrySyntax(
3837 wd_key, wd_dict.values[i], ast)
3838 if result is not None:
3839 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133840
Sergey Ulanov4af16052018-11-08 02:41:463841 result = _CheckWatchlistsEntrySyntax(
3842 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203843 if result is not None:
3844 return 'Bad entry in WATCHLISTS dict: %s' % result
3845
3846 if wd_key.s != w_key.s:
3847 return mismatch_template % (
3848 '%s at line %d' % (wd_key.s, wd_key.lineno),
3849 '%s at line %d' % (w_key.s, w_key.lineno))
3850
3851 if wd_key.s < last_key:
3852 return (
3853 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3854 (wd_key.lineno, w_key.lineno))
3855 last_key = wd_key.s
3856
3857 i = i + 1
3858
3859
Sergey Ulanov4af16052018-11-08 02:41:463860def _CheckWATCHLISTSSyntax(expression, input_api):
3861 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203862 if not isinstance(expression, ast.Expression):
3863 return 'WATCHLISTS file must contain a valid expression'
3864 dictionary = expression.body
3865 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3866 return 'WATCHLISTS file must have single dict with exactly two entries'
3867
3868 first_key = dictionary.keys[0]
3869 first_value = dictionary.values[0]
3870 second_key = dictionary.keys[1]
3871 second_value = dictionary.values[1]
3872
3873 if (not isinstance(first_key, ast.Str) or
3874 first_key.s != 'WATCHLIST_DEFINITIONS' or
3875 not isinstance(first_value, ast.Dict)):
3876 return (
3877 'The first entry of the dict in WATCHLISTS file must be '
3878 'WATCHLIST_DEFINITIONS dict')
3879
3880 if (not isinstance(second_key, ast.Str) or
3881 second_key.s != 'WATCHLISTS' or
3882 not isinstance(second_value, ast.Dict)):
3883 return (
3884 'The second entry of the dict in WATCHLISTS file must be '
3885 'WATCHLISTS dict')
3886
Sergey Ulanov4af16052018-11-08 02:41:463887 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133888
3889
Saagar Sanghavifceeaae2020-08-12 16:40:363890def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133891 for f in input_api.AffectedFiles(include_deletes=False):
3892 if f.LocalPath() == 'WATCHLISTS':
3893 contents = input_api.ReadFile(f, 'r')
3894
3895 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203896 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133897 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203898 # Get an AST tree for it and scan the tree for detailed style checking.
3899 expression = input_api.ast.parse(
3900 contents, filename='WATCHLISTS', mode='eval')
3901 except ValueError as e:
3902 return [output_api.PresubmitError(
3903 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3904 except SyntaxError as e:
3905 return [output_api.PresubmitError(
3906 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3907 except TypeError as e:
3908 return [output_api.PresubmitError(
3909 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133910
Sergey Ulanov4af16052018-11-08 02:41:463911 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203912 if result is not None:
3913 return [output_api.PresubmitError(result)]
3914 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133915
3916 return []
3917
3918
Andrew Grieve1b290e4a22020-11-24 20:07:013919def CheckGnGlobForward(input_api, output_api):
3920 """Checks that forward_variables_from(invoker, "*") follows best practices.
3921
3922 As documented at //build/docs/writing_gn_templates.md
3923 """
3924 def gn_files(f):
3925 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3926
3927 problems = []
3928 for f in input_api.AffectedSourceFiles(gn_files):
3929 for line_num, line in f.ChangedContents():
3930 if 'forward_variables_from(invoker, "*")' in line:
3931 problems.append(
3932 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3933 f.LocalPath(), line_num))
3934
3935 if problems:
3936 return [output_api.PresubmitPromptWarning(
3937 'forward_variables_from("*") without exclusions',
3938 items=sorted(problems),
3939 long_text=('The variables "visibilty" and "test_only" should be '
3940 'explicitly listed in forward_variables_from(). For more '
3941 'details, see:\n'
3942 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
3943 'build/docs/writing_gn_templates.md'
3944 '#Using-forward_variables_from'))]
3945 return []
3946
3947
Saagar Sanghavifceeaae2020-08-12 16:40:363948def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193949 """Checks that newly added header files have corresponding GN changes.
3950 Note that this is only a heuristic. To be precise, run script:
3951 build/check_gn_headers.py.
3952 """
3953
3954 def headers(f):
3955 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443956 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193957
3958 new_headers = []
3959 for f in input_api.AffectedSourceFiles(headers):
3960 if f.Action() != 'A':
3961 continue
3962 new_headers.append(f.LocalPath())
3963
3964 def gn_files(f):
James Cook24a504192020-07-23 00:08:443965 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193966
3967 all_gn_changed_contents = ''
3968 for f in input_api.AffectedSourceFiles(gn_files):
3969 for _, line in f.ChangedContents():
3970 all_gn_changed_contents += line
3971
3972 problems = []
3973 for header in new_headers:
3974 basename = input_api.os_path.basename(header)
3975 if basename not in all_gn_changed_contents:
3976 problems.append(header)
3977
3978 if problems:
3979 return [output_api.PresubmitPromptWarning(
3980 'Missing GN changes for new header files', items=sorted(problems),
3981 long_text='Please double check whether newly added header files need '
3982 'corresponding changes in gn or gni files.\nThis checking is only a '
3983 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3984 'Read https://crbug.com/661774 for more info.')]
3985 return []
3986
3987
Saagar Sanghavifceeaae2020-08-12 16:40:363988def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:023989 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3990
3991 This assumes we won't intentionally reference one product from the other
3992 product.
3993 """
3994 all_problems = []
3995 test_cases = [{
3996 "filename_postfix": "google_chrome_strings.grd",
3997 "correct_name": "Chrome",
3998 "incorrect_name": "Chromium",
3999 }, {
4000 "filename_postfix": "chromium_strings.grd",
4001 "correct_name": "Chromium",
4002 "incorrect_name": "Chrome",
4003 }]
4004
4005 for test_case in test_cases:
4006 problems = []
4007 filename_filter = lambda x: x.LocalPath().endswith(
4008 test_case["filename_postfix"])
4009
4010 # Check each new line. Can yield false positives in multiline comments, but
4011 # easier than trying to parse the XML because messages can have nested
4012 # children, and associating message elements with affected lines is hard.
4013 for f in input_api.AffectedSourceFiles(filename_filter):
4014 for line_num, line in f.ChangedContents():
4015 if "<message" in line or "<!--" in line or "-->" in line:
4016 continue
4017 if test_case["incorrect_name"] in line:
4018 problems.append(
4019 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4020
4021 if problems:
4022 message = (
4023 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4024 % (test_case["correct_name"], test_case["correct_name"],
4025 test_case["incorrect_name"]))
4026 all_problems.append(
4027 output_api.PresubmitPromptWarning(message, items=problems))
4028
4029 return all_problems
4030
4031
Saagar Sanghavifceeaae2020-08-12 16:40:364032def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364033 """Avoid large files, especially binary files, in the repository since
4034 git doesn't scale well for those. They will be in everyone's repo
4035 clones forever, forever making Chromium slower to clone and work
4036 with."""
4037
4038 # Uploading files to cloud storage is not trivial so we don't want
4039 # to set the limit too low, but the upper limit for "normal" large
4040 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4041 # anything over 20 MB is exceptional.
4042 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4043
4044 too_large_files = []
4045 for f in input_api.AffectedFiles():
4046 # Check both added and modified files (but not deleted files).
4047 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384048 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364049 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4050 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4051
4052 if too_large_files:
4053 message = (
4054 'Do not commit large files to git since git scales badly for those.\n' +
4055 'Instead put the large files in cloud storage and use DEPS to\n' +
4056 'fetch them.\n' + '\n'.join(too_large_files)
4057 )
4058 return [output_api.PresubmitError(
4059 'Too large files found in commit', long_text=message + '\n')]
4060 else:
4061 return []
4062
Max Morozb47503b2019-08-08 21:03:274063
Saagar Sanghavifceeaae2020-08-12 16:40:364064def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274065 """Checks specific for fuzz target sources."""
4066 EXPORTED_SYMBOLS = [
4067 'LLVMFuzzerInitialize',
4068 'LLVMFuzzerCustomMutator',
4069 'LLVMFuzzerCustomCrossOver',
4070 'LLVMFuzzerMutate',
4071 ]
4072
4073 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4074
4075 def FilterFile(affected_file):
4076 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444077 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4078 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274079
4080 return input_api.FilterSourceFile(
4081 affected_file,
James Cook24a504192020-07-23 00:08:444082 files_to_check=[files_to_check],
4083 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274084
4085 files_with_missing_header = []
4086 for f in input_api.AffectedSourceFiles(FilterFile):
4087 contents = input_api.ReadFile(f, 'r')
4088 if REQUIRED_HEADER in contents:
4089 continue
4090
4091 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4092 files_with_missing_header.append(f.LocalPath())
4093
4094 if not files_with_missing_header:
4095 return []
4096
4097 long_text = (
4098 'If you define any of the libFuzzer optional functions (%s), it is '
4099 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4100 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4101 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4102 'to access command line arguments passed to the fuzzer. Instead, prefer '
4103 'static initialization and shared resources as documented in '
4104 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4105 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4106 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4107 )
4108
4109 return [output_api.PresubmitPromptWarning(
4110 message="Missing '%s' in:" % REQUIRED_HEADER,
4111 items=files_with_missing_header,
4112 long_text=long_text)]
4113
4114
Mohamed Heikald048240a2019-11-12 16:57:374115def _CheckNewImagesWarning(input_api, output_api):
4116 """
4117 Warns authors who add images into the repo to make sure their images are
4118 optimized before committing.
4119 """
4120 images_added = False
4121 image_paths = []
4122 errors = []
4123 filter_lambda = lambda x: input_api.FilterSourceFile(
4124 x,
James Cook24a504192020-07-23 00:08:444125 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4126 + input_api.DEFAULT_FILES_TO_SKIP),
4127 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374128 )
4129 for f in input_api.AffectedFiles(
4130 include_deletes=False, file_filter=filter_lambda):
4131 local_path = f.LocalPath().lower()
4132 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4133 images_added = True
4134 image_paths.append(f)
4135 if images_added:
4136 errors.append(output_api.PresubmitPromptWarning(
4137 'It looks like you are trying to commit some images. If these are '
4138 'non-test-only images, please make sure to read and apply the tips in '
4139 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4140 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4141 'FYI only and will not block your CL on the CQ.', image_paths))
4142 return errors
4143
4144
Saagar Sanghavifceeaae2020-08-12 16:40:364145def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574146 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224147 results = []
dgnaa68d5e2015-06-10 10:08:224148 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174149 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224150 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294151 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064152 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4153 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424154 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184155 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574156 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374157 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154158 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574159 return results
4160
Saagar Sanghavifceeaae2020-08-12 16:40:364161def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574162 """Groups commit checks that target android code."""
4163 results = []
4164 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224165 return results
4166
Chris Hall59f8d0c72020-05-01 07:31:194167# TODO(chrishall): could we additionally match on any path owned by
4168# ui/accessibility/OWNERS ?
4169_ACCESSIBILITY_PATHS = (
4170 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4171 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4172 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4173 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4174 r"^content[\\/]browser[\\/]accessibility[\\/]",
4175 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4176 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4177 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4178 r"^ui[\\/]accessibility[\\/]",
4179 r"^ui[\\/]views[\\/]accessibility[\\/]",
4180)
4181
Saagar Sanghavifceeaae2020-08-12 16:40:364182def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194183 """Checks that commits to accessibility code contain an AX-Relnotes field in
4184 their commit message."""
4185 def FileFilter(affected_file):
4186 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444187 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194188
4189 # Only consider changes affecting accessibility paths.
4190 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4191 return []
4192
Akihiro Ota08108e542020-05-20 15:30:534193 # AX-Relnotes can appear in either the description or the footer.
4194 # When searching the description, require 'AX-Relnotes:' to appear at the
4195 # beginning of a line.
4196 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4197 description_has_relnotes = any(ax_regex.match(line)
4198 for line in input_api.change.DescriptionText().lower().splitlines())
4199
4200 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4201 'AX-Relnotes', [])
4202 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194203 return []
4204
4205 # TODO(chrishall): link to Relnotes documentation in message.
4206 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4207 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4208 "user-facing changes"
4209 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4210 "user-facing effects"
4211 "\n if this is confusing or annoying then please contact members "
4212 "of ui/accessibility/OWNERS.")
4213
4214 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224215
seanmccullough4a9356252021-04-08 19:54:094216# string pattern, sequence of strings to show when pattern matches,
4217# error flag. True if match is a presubmit error, otherwise it's a warning.
4218_NON_INCLUSIVE_TERMS = (
4219 (
4220 # Note that \b pattern in python re is pretty particular. In this
4221 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4222 # ...' will not. This may require some tweaking to catch these cases
4223 # without triggering a lot of false positives. Leaving it naive and
4224 # less matchy for now.
4225 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4226 (
4227 'Please don\'t use blacklist, whitelist, ' # nocheck
4228 'or slave in your', # nocheck
4229 'code and make every effort to use other terms. Using "// nocheck"',
4230 '"# nocheck" or "<!-- nocheck -->"',
4231 'at the end of the offending line will bypass this PRESUBMIT error',
4232 'but avoid using this whenever possible. Reach out to',
4233 '[email protected] if you have questions'),
4234 True),)
4235
Saagar Sanghavifceeaae2020-08-12 16:40:364236def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394237 """Checks common to both upload and commit."""
4238 results = []
4239 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384240 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544241 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084242
4243 author = input_api.change.author_email
4244 if author and author not in _KNOWN_ROBOTS:
4245 results.extend(
4246 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4247
[email protected]9f919cc2013-07-31 03:04:044248 results.extend(
4249 input_api.canned_checks.CheckChangeHasNoTabs(
4250 input_api,
4251 output_api,
4252 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434253 results.extend(input_api.RunTests(
4254 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244255
Edward Lesmesce51df52020-08-04 22:10:174256 dirmd_bin = input_api.os_path.join(
4257 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4258 results.extend(input_api.RunTests(
4259 input_api.canned_checks.CheckDirMetadataFormat(
4260 input_api, output_api, dirmd_bin)))
4261 results.extend(
4262 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4263 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554264 results.extend(
4265 input_api.canned_checks.CheckNoNewMetadataInOwners(
4266 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094267 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4268 input_api, output_api,
4269 excluded_directories_relative_path = [
4270 'infra',
4271 'inclusive_language_presubmit_exempt_dirs.txt'
4272 ],
4273 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174274
Vaclav Brozekcdc7defb2018-03-20 09:54:354275 for f in input_api.AffectedFiles():
4276 path, name = input_api.os_path.split(f.LocalPath())
4277 if name == 'PRESUBMIT.py':
4278 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004279 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4280 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074281 # The PRESUBMIT.py file (and the directory containing it) might
4282 # have been affected by being moved or removed, so only try to
4283 # run the tests if they still exist.
4284 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4285 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444286 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394287 return results
[email protected]1f7b4172010-01-28 01:17:344288
[email protected]b337cb5b2011-01-23 21:24:054289
Saagar Sanghavifceeaae2020-08-12 16:40:364290def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494291 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4292 if f.LocalPath().endswith(('.orig', '.rej'))]
4293 if problems:
4294 return [output_api.PresubmitError(
4295 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034296 else:
4297 return []
[email protected]b8079ae4a2012-12-05 19:56:494298
4299
Saagar Sanghavifceeaae2020-08-12 16:40:364300def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214301 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4302 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4303 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074304 include_re = input_api.re.compile(
4305 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4306 extension_re = input_api.re.compile(r'\.[a-z]+$')
4307 errors = []
4308 for f in input_api.AffectedFiles():
4309 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4310 continue
4311 found_line_number = None
4312 found_macro = None
4313 for line_num, line in f.ChangedContents():
4314 match = macro_re.search(line)
4315 if match:
4316 found_line_number = line_num
4317 found_macro = match.group(2)
4318 break
4319 if not found_line_number:
4320 continue
4321
4322 found_include = False
4323 for line in f.NewContents():
4324 if include_re.search(line):
4325 found_include = True
4326 break
4327 if found_include:
4328 continue
4329
4330 if not f.LocalPath().endswith('.h'):
4331 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4332 try:
4333 content = input_api.ReadFile(primary_header_path, 'r')
4334 if include_re.search(content):
4335 continue
4336 except IOError:
4337 pass
4338 errors.append('%s:%d %s macro is used without including build/'
4339 'build_config.h.'
4340 % (f.LocalPath(), found_line_number, found_macro))
4341 if errors:
4342 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4343 return []
4344
4345
[email protected]b00342e7f2013-03-26 16:21:544346def _DidYouMeanOSMacro(bad_macro):
4347 try:
4348 return {'A': 'OS_ANDROID',
4349 'B': 'OS_BSD',
4350 'C': 'OS_CHROMEOS',
4351 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444352 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544353 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444354 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544355 'N': 'OS_NACL',
4356 'O': 'OS_OPENBSD',
4357 'P': 'OS_POSIX',
4358 'S': 'OS_SOLARIS',
4359 'W': 'OS_WIN'}[bad_macro[3].upper()]
4360 except KeyError:
4361 return ''
4362
4363
4364def _CheckForInvalidOSMacrosInFile(input_api, f):
4365 """Check for sensible looking, totally invalid OS macros."""
4366 preprocessor_statement = input_api.re.compile(r'^\s*#')
4367 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4368 results = []
4369 for lnum, line in f.ChangedContents():
4370 if preprocessor_statement.search(line):
4371 for match in os_macro.finditer(line):
4372 if not match.group(1) in _VALID_OS_MACROS:
4373 good = _DidYouMeanOSMacro(match.group(1))
4374 did_you_mean = ' (did you mean %s?)' % good if good else ''
4375 results.append(' %s:%d %s%s' % (f.LocalPath(),
4376 lnum,
4377 match.group(1),
4378 did_you_mean))
4379 return results
4380
4381
Saagar Sanghavifceeaae2020-08-12 16:40:364382def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544383 """Check all affected files for invalid OS macros."""
4384 bad_macros = []
tzik3f295992018-12-04 20:32:234385 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474386 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544387 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4388
4389 if not bad_macros:
4390 return []
4391
4392 return [output_api.PresubmitError(
4393 'Possibly invalid OS macro[s] found. Please fix your code\n'
4394 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4395
lliabraa35bab3932014-10-01 12:16:444396
4397def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4398 """Check all affected files for invalid "if defined" macros."""
4399 ALWAYS_DEFINED_MACROS = (
4400 "TARGET_CPU_PPC",
4401 "TARGET_CPU_PPC64",
4402 "TARGET_CPU_68K",
4403 "TARGET_CPU_X86",
4404 "TARGET_CPU_ARM",
4405 "TARGET_CPU_MIPS",
4406 "TARGET_CPU_SPARC",
4407 "TARGET_CPU_ALPHA",
4408 "TARGET_IPHONE_SIMULATOR",
4409 "TARGET_OS_EMBEDDED",
4410 "TARGET_OS_IPHONE",
4411 "TARGET_OS_MAC",
4412 "TARGET_OS_UNIX",
4413 "TARGET_OS_WIN32",
4414 )
4415 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4416 results = []
4417 for lnum, line in f.ChangedContents():
4418 for match in ifdef_macro.finditer(line):
4419 if match.group(1) in ALWAYS_DEFINED_MACROS:
4420 always_defined = ' %s is always defined. ' % match.group(1)
4421 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4422 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4423 lnum,
4424 always_defined,
4425 did_you_mean))
4426 return results
4427
4428
Saagar Sanghavifceeaae2020-08-12 16:40:364429def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444430 """Check all affected files for invalid "if defined" macros."""
4431 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054432 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444433 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054434 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214435 continue
lliabraa35bab3932014-10-01 12:16:444436 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4437 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4438
4439 if not bad_macros:
4440 return []
4441
4442 return [output_api.PresubmitError(
4443 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4444 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4445 bad_macros)]
4446
4447
Saagar Sanghavifceeaae2020-08-12 16:40:364448def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044449 """Check for same IPC rules described in
4450 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4451 """
4452 base_pattern = r'IPC_ENUM_TRAITS\('
4453 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4454 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4455
4456 problems = []
4457 for f in input_api.AffectedSourceFiles(None):
4458 local_path = f.LocalPath()
4459 if not local_path.endswith('.h'):
4460 continue
4461 for line_number, line in f.ChangedContents():
4462 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4463 problems.append(
4464 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4465
4466 if problems:
4467 return [output_api.PresubmitPromptWarning(
4468 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4469 else:
4470 return []
4471
[email protected]b00342e7f2013-03-26 16:21:544472
Saagar Sanghavifceeaae2020-08-12 16:40:364473def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054474 """Check to make sure no files being submitted have long paths.
4475 This causes issues on Windows.
4476 """
4477 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194478 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054479 local_path = f.LocalPath()
4480 # Windows has a path limit of 260 characters. Limit path length to 200 so
4481 # that we have some extra for the prefix on dev machines and the bots.
4482 if len(local_path) > 200:
4483 problems.append(local_path)
4484
4485 if problems:
4486 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4487 else:
4488 return []
4489
4490
Saagar Sanghavifceeaae2020-08-12 16:40:364491def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144492 """Check that header files have proper guards against multiple inclusion.
4493 If a file should not have such guards (and it probably should) then it
4494 should include the string "no-include-guard-because-multiply-included".
4495 """
Daniel Bratell6a75baef62018-06-04 10:04:454496 def is_chromium_header_file(f):
4497 # We only check header files under the control of the Chromium
4498 # project. That is, those outside third_party apart from
4499 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324500 # We also exclude *_message_generator.h headers as they use
4501 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454502 file_with_path = input_api.os_path.normpath(f.LocalPath())
4503 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324504 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454505 (not file_with_path.startswith('third_party') or
4506 file_with_path.startswith(
4507 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144508
4509 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344510 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144511
4512 errors = []
4513
Daniel Bratell6a75baef62018-06-04 10:04:454514 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144515 guard_name = None
4516 guard_line_number = None
4517 seen_guard_end = False
4518
4519 file_with_path = input_api.os_path.normpath(f.LocalPath())
4520 base_file_name = input_api.os_path.splitext(
4521 input_api.os_path.basename(file_with_path))[0]
4522 upper_base_file_name = base_file_name.upper()
4523
4524 expected_guard = replace_special_with_underscore(
4525 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144526
4527 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574528 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4529 # are too many (1000+) files with slight deviations from the
4530 # coding style. The most important part is that the include guard
4531 # is there, and that it's unique, not the name so this check is
4532 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144533 #
4534 # As code becomes more uniform, this could be made stricter.
4535
4536 guard_name_pattern_list = [
4537 # Anything with the right suffix (maybe with an extra _).
4538 r'\w+_H__?',
4539
Daniel Bratell39b5b062018-05-16 18:09:574540 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144541 r'\w+_h',
4542
4543 # Anything including the uppercase name of the file.
4544 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4545 upper_base_file_name)) + r'\w*',
4546 ]
4547 guard_name_pattern = '|'.join(guard_name_pattern_list)
4548 guard_pattern = input_api.re.compile(
4549 r'#ifndef\s+(' + guard_name_pattern + ')')
4550
4551 for line_number, line in enumerate(f.NewContents()):
4552 if 'no-include-guard-because-multiply-included' in line:
4553 guard_name = 'DUMMY' # To not trigger check outside the loop.
4554 break
4555
4556 if guard_name is None:
4557 match = guard_pattern.match(line)
4558 if match:
4559 guard_name = match.group(1)
4560 guard_line_number = line_number
4561
Daniel Bratell39b5b062018-05-16 18:09:574562 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454563 # don't match the chromium style guide, but new files should
4564 # get it right.
4565 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574566 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144567 errors.append(output_api.PresubmitPromptWarning(
4568 'Header using the wrong include guard name %s' % guard_name,
4569 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574570 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144571 else:
4572 # The line after #ifndef should have a #define of the same name.
4573 if line_number == guard_line_number + 1:
4574 expected_line = '#define %s' % guard_name
4575 if line != expected_line:
4576 errors.append(output_api.PresubmitPromptWarning(
4577 'Missing "%s" for include guard' % expected_line,
4578 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4579 'Expected: %r\nGot: %r' % (expected_line, line)))
4580
4581 if not seen_guard_end and line == '#endif // %s' % guard_name:
4582 seen_guard_end = True
4583 elif seen_guard_end:
4584 if line.strip() != '':
4585 errors.append(output_api.PresubmitPromptWarning(
4586 'Include guard %s not covering the whole file' % (
4587 guard_name), [f.LocalPath()]))
4588 break # Nothing else to check and enough to warn once.
4589
4590 if guard_name is None:
4591 errors.append(output_api.PresubmitPromptWarning(
4592 'Missing include guard %s' % expected_guard,
4593 [f.LocalPath()],
4594 'Missing include guard in %s\n'
4595 'Recommended name: %s\n'
4596 'This check can be disabled by having the string\n'
4597 'no-include-guard-because-multiply-included in the header.' %
4598 (f.LocalPath(), expected_guard)))
4599
4600 return errors
4601
4602
Saagar Sanghavifceeaae2020-08-12 16:40:364603def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234604 """Check source code and known ascii text files for Windows style line
4605 endings.
4606 """
earthdok1b5e0ee2015-03-10 15:19:104607 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234608
4609 file_inclusion_pattern = (
4610 known_text_files,
4611 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4612 )
4613
mostynbb639aca52015-01-07 20:31:234614 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534615 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444616 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534617 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504618 include_file = False
4619 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234620 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504621 include_file = True
4622 if include_file:
4623 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234624
4625 if problems:
4626 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4627 'these files to contain Windows style line endings?\n' +
4628 '\n'.join(problems))]
4629
4630 return []
4631
Jose Magana2b456f22021-03-09 23:26:404632def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4633 """Check source code for use of Chrome App technologies being
4634 deprecated.
4635 """
4636
4637 def _CheckForDeprecatedTech(input_api, output_api,
4638 detection_list, files_to_check = None, files_to_skip = None):
4639
4640 if (files_to_check or files_to_skip):
4641 source_file_filter = lambda f: input_api.FilterSourceFile(
4642 f, files_to_check=files_to_check,
4643 files_to_skip=files_to_skip)
4644 else:
4645 source_file_filter = None
4646
4647 problems = []
4648
4649 for f in input_api.AffectedSourceFiles(source_file_filter):
4650 if f.Action() == 'D':
4651 continue
4652 for _, line in f.ChangedContents():
4653 if any( detect in line for detect in detection_list ):
4654 problems.append(f.LocalPath())
4655
4656 return problems
4657
4658 # to avoid this presubmit script triggering warnings
4659 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4660
4661 problems =[]
4662
4663 # NMF: any files with extensions .nmf or NMF
4664 _NMF_FILES = r'\.(nmf|NMF)$'
4665 problems += _CheckForDeprecatedTech(input_api, output_api,
4666 detection_list = [''], # any change to the file will trigger warning
4667 files_to_check = [ r'.+%s' % _NMF_FILES ])
4668
4669 # MANIFEST: any manifest.json that in its diff includes "app":
4670 _MANIFEST_FILES = r'(manifest\.json)$'
4671 problems += _CheckForDeprecatedTech(input_api, output_api,
4672 detection_list = ['"app":'],
4673 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4674
4675 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4676 problems += _CheckForDeprecatedTech(input_api, output_api,
4677 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4678 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4679
4680 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4681 problems += _CheckForDeprecatedTech(input_api, output_api,
4682 detection_list = ['#include "ppapi','#include <ppapi'],
4683 files_to_check = (
4684 r'.+%s' % _HEADER_EXTENSIONS,
4685 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4686 files_to_skip = [r"^ppapi[\\/]"] )
4687
Jose Magana2b456f22021-03-09 23:26:404688 if problems:
4689 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4690 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4691 ' PNaCl, PPAPI). See this blog post for more details:\n'
4692 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4693 'and this documentation for options to replace these technologies:\n'
4694 'https://developer.chrome.com/docs/apps/migration/\n'+
4695 '\n'.join(problems))]
4696
4697 return []
4698
mostynbb639aca52015-01-07 20:31:234699
Saagar Sanghavifceeaae2020-08-12 16:40:364700def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134701 """Checks that all source files use SYSLOG properly."""
4702 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364703 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564704 for line_number, line in f.ChangedContents():
4705 if 'SYSLOG' in line:
4706 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4707
pastarmovj89f7ee12016-09-20 14:58:134708 if syslog_files:
4709 return [output_api.PresubmitPromptWarning(
4710 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4711 ' calls.\nFiles to check:\n', items=syslog_files)]
4712 return []
4713
4714
[email protected]1f7b4172010-01-28 01:17:344715def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364716 if input_api.version < [2, 0, 0]:
4717 return [output_api.PresubmitError("Your depot_tools is out of date. "
4718 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4719 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344720 results = []
scottmg39b29952014-12-08 18:31:284721 results.extend(
jam93a6ee792017-02-08 23:59:224722 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544723 return results
[email protected]ca8d1982009-02-19 16:33:124724
4725
4726def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364727 if input_api.version < [2, 0, 0]:
4728 return [output_api.PresubmitError("Your depot_tools is out of date. "
4729 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4730 "but your version is %d.%d.%d" % tuple(input_api.version))]
4731
[email protected]fe5f57c52009-06-05 14:25:544732 results = []
[email protected]fe5f57c52009-06-05 14:25:544733 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274734 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344735 input_api,
4736 output_api,
[email protected]2fdd1f362013-01-16 03:56:034737 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274738
jam93a6ee792017-02-08 23:59:224739 results.extend(
4740 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544741 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4742 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384743 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4744 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414745 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4746 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544747 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144748
4749
Saagar Sanghavifceeaae2020-08-12 16:40:364750def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264751 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024752 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4753 # footer is set to true.
4754 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264755 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024756 footer.lower()
4757 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264758 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024759
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144760 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264761 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144762 import sys
4763 from io import StringIO
4764
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144765 new_or_added_paths = set(f.LocalPath()
4766 for f in input_api.AffectedFiles()
4767 if (f.Action() == 'A' or f.Action() == 'M'))
4768 removed_paths = set(f.LocalPath()
4769 for f in input_api.AffectedFiles(include_deletes=True)
4770 if f.Action() == 'D')
4771
Andrew Grieve0e8790c2020-09-03 17:27:324772 affected_grds = [
4773 f for f in input_api.AffectedFiles()
4774 if f.LocalPath().endswith(('.grd', '.grdp'))
4775 ]
4776 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164777 if not affected_grds:
4778 return []
4779
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144780 affected_png_paths = [f.AbsoluteLocalPath()
4781 for f in input_api.AffectedFiles()
4782 if (f.LocalPath().endswith('.png'))]
4783
4784 # Check for screenshots. Developers can upload screenshots using
4785 # tools/translation/upload_screenshots.py which finds and uploads
4786 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4787 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4788 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4789 #
4790 # The logic here is as follows:
4791 #
4792 # - If the CL has a .png file under the screenshots directory for a grd
4793 # file, warn the developer. Actual images should never be checked into the
4794 # Chrome repo.
4795 #
4796 # - If the CL contains modified or new messages in grd files and doesn't
4797 # contain the corresponding .sha1 files, warn the developer to add images
4798 # and upload them via tools/translation/upload_screenshots.py.
4799 #
4800 # - If the CL contains modified or new messages in grd files and the
4801 # corresponding .sha1 files, everything looks good.
4802 #
4803 # - If the CL contains removed messages in grd files but the corresponding
4804 # .sha1 files aren't removed, warn the developer to remove them.
4805 unnecessary_screenshots = []
4806 missing_sha1 = []
4807 unnecessary_sha1_files = []
4808
Rainhard Findlingfc31844c52020-05-15 09:58:264809 # This checks verifies that the ICU syntax of messages this CL touched is
4810 # valid, and reports any found syntax errors.
4811 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4812 # without developers being aware of them. Later on, such ICU syntax errors
4813 # break message extraction for translation, hence would block Chromium
4814 # translations until they are fixed.
4815 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144816
4817 def _CheckScreenshotAdded(screenshots_dir, message_id):
4818 sha1_path = input_api.os_path.join(
4819 screenshots_dir, message_id + '.png.sha1')
4820 if sha1_path not in new_or_added_paths:
4821 missing_sha1.append(sha1_path)
4822
4823
4824 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4825 sha1_path = input_api.os_path.join(
4826 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034827 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144828 unnecessary_sha1_files.append(sha1_path)
4829
Rainhard Findlingfc31844c52020-05-15 09:58:264830
4831 def _ValidateIcuSyntax(text, level, signatures):
4832 """Validates ICU syntax of a text string.
4833
4834 Check if text looks similar to ICU and checks for ICU syntax correctness
4835 in this case. Reports various issues with ICU syntax and values of
4836 variants. Supports checking of nested messages. Accumulate information of
4837 each ICU messages found in the text for further checking.
4838
4839 Args:
4840 text: a string to check.
4841 level: a number of current nesting level.
4842 signatures: an accumulator, a list of tuple of (level, variable,
4843 kind, variants).
4844
4845 Returns:
4846 None if a string is not ICU or no issue detected.
4847 A tuple of (message, start index, end index) if an issue detected.
4848 """
4849 valid_types = {
4850 'plural': (frozenset(
4851 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4852 frozenset(['=1', 'other'])),
4853 'selectordinal': (frozenset(
4854 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4855 frozenset(['one', 'other'])),
4856 'select': (frozenset(), frozenset(['other'])),
4857 }
4858
4859 # Check if the message looks like an attempt to use ICU
4860 # plural. If yes - check if its syntax strictly matches ICU format.
4861 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4862 if not like:
4863 signatures.append((level, None, None, None))
4864 return
4865
4866 # Check for valid prefix and suffix
4867 m = re.match(
4868 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4869 r'(plural|selectordinal|select),\s*'
4870 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4871 if not m:
4872 return (('This message looks like an ICU plural, '
4873 'but does not follow ICU syntax.'), like.start(), like.end())
4874 starting, variable, kind, variant_pairs = m.groups()
4875 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4876 if depth:
4877 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4878 len(text))
4879 first = text[0]
4880 ending = text[last_pos:]
4881 if not starting:
4882 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4883 last_pos)
4884 if not ending or '}' not in ending:
4885 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4886 last_pos)
4887 elif first != '{':
4888 return (
4889 ('Invalid ICU format. Extra characters at the start of a complex '
4890 'message (go/icu-message-migration): "%s"') %
4891 starting, 0, len(starting))
4892 elif ending != '}':
4893 return (('Invalid ICU format. Extra characters at the end of a complex '
4894 'message (go/icu-message-migration): "%s"')
4895 % ending, last_pos - 1, len(text) - 1)
4896 if kind not in valid_types:
4897 return (('Unknown ICU message type %s. '
4898 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4899 known, required = valid_types[kind]
4900 defined_variants = set()
4901 for variant, variant_range, value, value_range in variants:
4902 start, end = variant_range
4903 if variant in defined_variants:
4904 return ('Variant "%s" is defined more than once' % variant,
4905 start, end)
4906 elif known and variant not in known:
4907 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4908 start, end)
4909 defined_variants.add(variant)
4910 # Check for nested structure
4911 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4912 if res:
4913 return (res[0], res[1] + value_range[0] + 1,
4914 res[2] + value_range[0] + 1)
4915 missing = required - defined_variants
4916 if missing:
4917 return ('Required variants missing: %s' % ', '.join(missing), 0,
4918 len(text))
4919 signatures.append((level, variable, kind, defined_variants))
4920
4921
4922 def _ParseIcuVariants(text, offset=0):
4923 """Parse variants part of ICU complex message.
4924
4925 Builds a tuple of variant names and values, as well as
4926 their offsets in the input string.
4927
4928 Args:
4929 text: a string to parse
4930 offset: additional offset to add to positions in the text to get correct
4931 position in the complete ICU string.
4932
4933 Returns:
4934 List of tuples, each tuple consist of four fields: variant name,
4935 variant name span (tuple of two integers), variant value, value
4936 span (tuple of two integers).
4937 """
4938 depth, start, end = 0, -1, -1
4939 variants = []
4940 key = None
4941 for idx, char in enumerate(text):
4942 if char == '{':
4943 if not depth:
4944 start = idx
4945 chunk = text[end + 1:start]
4946 key = chunk.strip()
4947 pos = offset + end + 1 + chunk.find(key)
4948 span = (pos, pos + len(key))
4949 depth += 1
4950 elif char == '}':
4951 if not depth:
4952 return variants, depth, offset + idx
4953 depth -= 1
4954 if not depth:
4955 end = idx
4956 variants.append((key, span, text[start:end + 1], (offset + start,
4957 offset + end + 1)))
4958 return variants, depth, offset + end + 1
4959
meacer8c0d3832019-12-26 21:46:164960 try:
4961 old_sys_path = sys.path
4962 sys.path = sys.path + [input_api.os_path.join(
4963 input_api.PresubmitLocalPath(), 'tools', 'translation')]
4964 from helper import grd_helper
4965 finally:
4966 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144967
4968 for f in affected_grds:
4969 file_path = f.LocalPath()
4970 old_id_to_msg_map = {}
4971 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:384972 # Note that this code doesn't check if the file has been deleted. This is
4973 # OK because it only uses the old and new file contents and doesn't load
4974 # the file via its path.
4975 # It's also possible that a file's content refers to a renamed or deleted
4976 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
4977 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
4978 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144979 if file_path.endswith('.grdp'):
4980 if f.OldContents():
meacerff8a9b62019-12-10 19:43:584981 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394982 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144983 if f.NewContents():
meacerff8a9b62019-12-10 19:43:584984 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394985 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144986 else:
meacerff8a9b62019-12-10 19:43:584987 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144988 if f.OldContents():
meacerff8a9b62019-12-10 19:43:584989 old_id_to_msg_map = grd_helper.GetGrdMessages(
4990 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144991 if f.NewContents():
meacerff8a9b62019-12-10 19:43:584992 new_id_to_msg_map = grd_helper.GetGrdMessages(
4993 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144994
Rainhard Findlingd8d04372020-08-13 13:30:094995 grd_name, ext = input_api.os_path.splitext(
4996 input_api.os_path.basename(file_path))
4997 screenshots_dir = input_api.os_path.join(
4998 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
4999
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145000 # Compute added, removed and modified message IDs.
5001 old_ids = set(old_id_to_msg_map)
5002 new_ids = set(new_id_to_msg_map)
5003 added_ids = new_ids - old_ids
5004 removed_ids = old_ids - new_ids
5005 modified_ids = set([])
5006 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355007 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095008 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5009 # The message content itself changed. Require an updated screenshot.
5010 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355011 elif old_id_to_msg_map[key].attrs['meaning'] != \
5012 new_id_to_msg_map[key].attrs['meaning']:
5013 # The message meaning changed. Ensure there is a screenshot for it.
5014 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5015 if sha1_path not in new_or_added_paths and not \
5016 input_api.os_path.exists(sha1_path):
5017 # There is neither a previous screenshot nor is a new one added now.
5018 # Require a screenshot.
5019 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145020
Rainhard Findlingfc31844c52020-05-15 09:58:265021 if run_screenshot_check:
5022 # Check the screenshot directory for .png files. Warn if there is any.
5023 for png_path in affected_png_paths:
5024 if png_path.startswith(screenshots_dir):
5025 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145026
Rainhard Findlingfc31844c52020-05-15 09:58:265027 for added_id in added_ids:
5028 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145029
Rainhard Findlingfc31844c52020-05-15 09:58:265030 for modified_id in modified_ids:
5031 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145032
Rainhard Findlingfc31844c52020-05-15 09:58:265033 for removed_id in removed_ids:
5034 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5035
5036 # Check new and changed strings for ICU syntax errors.
5037 for key in added_ids.union(modified_ids):
5038 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5039 err = _ValidateIcuSyntax(msg, 0, [])
5040 if err is not None:
5041 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145042
5043 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265044 if run_screenshot_check:
5045 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005046 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265047 'Do not include actual screenshots in the changelist. Run '
5048 'tools/translate/upload_screenshots.py to upload them instead:',
5049 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145050
Rainhard Findlingfc31844c52020-05-15 09:58:265051 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005052 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265053 'You are adding or modifying UI strings.\n'
5054 'To ensure the best translations, take screenshots of the relevant UI '
5055 '(https://g.co/chrome/translation) and add these files to your '
5056 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145057
Rainhard Findlingfc31844c52020-05-15 09:58:265058 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005059 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265060 'You removed strings associated with these files. Remove:',
5061 sorted(unnecessary_sha1_files)))
5062 else:
5063 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5064 'screenshots check.'))
5065
5066 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075067 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265068 'ICU syntax errors were found in the following strings (problems or '
5069 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145070
5071 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125072
5073
Saagar Sanghavifceeaae2020-08-12 16:40:365074def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125075 repo_root=None,
5076 translation_expectations_path=None,
5077 grd_files=None):
5078 import sys
5079 affected_grds = [f for f in input_api.AffectedFiles()
5080 if (f.LocalPath().endswith('.grd') or
5081 f.LocalPath().endswith('.grdp'))]
5082 if not affected_grds:
5083 return []
5084
5085 try:
5086 old_sys_path = sys.path
5087 sys.path = sys.path + [
5088 input_api.os_path.join(
5089 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5090 from helper import git_helper
5091 from helper import translation_helper
5092 finally:
5093 sys.path = old_sys_path
5094
5095 # Check that translation expectations can be parsed and we can get a list of
5096 # translatable grd files. |repo_root| and |translation_expectations_path| are
5097 # only passed by tests.
5098 if not repo_root:
5099 repo_root = input_api.PresubmitLocalPath()
5100 if not translation_expectations_path:
5101 translation_expectations_path = input_api.os_path.join(
5102 repo_root, 'tools', 'gritsettings',
5103 'translation_expectations.pyl')
5104 if not grd_files:
5105 grd_files = git_helper.list_grds_in_repository(repo_root)
5106
dpapad8e21b472020-10-23 17:15:035107 # Ignore bogus grd files used only for testing
5108 # ui/webui/resoucres/tools/generate_grd.py.
5109 ignore_path = input_api.os_path.join(
5110 'ui', 'webui', 'resources', 'tools', 'tests')
5111 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5112
Mustafa Emre Acer51f2f742020-03-09 19:41:125113 try:
5114 translation_helper.get_translatable_grds(repo_root, grd_files,
5115 translation_expectations_path)
5116 except Exception as e:
5117 return [output_api.PresubmitNotifyResult(
5118 'Failed to get a list of translatable grd files. This happens when:\n'
5119 ' - One of the modified grd or grdp files cannot be parsed or\n'
5120 ' - %s is not updated.\n'
5121 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5122 return []
Ken Rockotc31f4832020-05-29 18:58:515123
5124
Saagar Sanghavifceeaae2020-08-12 16:40:365125def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515126 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095127 changed_mojoms = input_api.AffectedFiles(
5128 include_deletes=True,
5129 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515130 delta = []
5131 for mojom in changed_mojoms:
5132 old_contents = ''.join(mojom.OldContents()) or None
5133 new_contents = ''.join(mojom.NewContents()) or None
5134 delta.append({
5135 'filename': mojom.LocalPath(),
5136 'old': '\n'.join(mojom.OldContents()) or None,
5137 'new': '\n'.join(mojom.NewContents()) or None,
5138 })
5139
5140 process = input_api.subprocess.Popen(
5141 [input_api.python_executable,
5142 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5143 'public', 'tools', 'mojom',
5144 'check_stable_mojom_compatibility.py'),
5145 '--src-root', input_api.PresubmitLocalPath()],
5146 stdin=input_api.subprocess.PIPE,
5147 stdout=input_api.subprocess.PIPE,
5148 stderr=input_api.subprocess.PIPE,
5149 universal_newlines=True)
5150 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5151 if process.returncode:
5152 return [output_api.PresubmitError(
5153 'One or more [Stable] mojom definitions appears to have been changed '
5154 'in a way that is not backward-compatible.',
5155 long_text=error)]
5156 return []
Dominic Battre645d42342020-12-04 16:14:105157
5158def CheckDeprecationOfPreferences(input_api, output_api):
5159 """Removing a preference should come with a deprecation."""
5160
5161 def FilterFile(affected_file):
5162 """Accept only .cc files and the like."""
5163 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5164 files_to_skip = (_EXCLUDED_PATHS +
5165 _TEST_CODE_EXCLUDED_PATHS +
5166 input_api.DEFAULT_FILES_TO_SKIP)
5167 return input_api.FilterSourceFile(
5168 affected_file,
5169 files_to_check=file_inclusion_pattern,
5170 files_to_skip=files_to_skip)
5171
5172 def ModifiedLines(affected_file):
5173 """Returns a list of tuples (line number, line text) of added and removed
5174 lines.
5175
5176 Deleted lines share the same line number as the previous line.
5177
5178 This relies on the scm diff output describing each changed code section
5179 with a line of the form
5180
5181 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5182 """
5183 line_num = 0
5184 modified_lines = []
5185 for line in affected_file.GenerateScmDiff().splitlines():
5186 # Extract <new line num> of the patch fragment (see format above).
5187 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5188 if m:
5189 line_num = int(m.groups(1)[0])
5190 continue
5191 if ((line.startswith('+') and not line.startswith('++')) or
5192 (line.startswith('-') and not line.startswith('--'))):
5193 modified_lines.append((line_num, line))
5194
5195 if not line.startswith('-'):
5196 line_num += 1
5197 return modified_lines
5198
5199 def FindLineWith(lines, needle):
5200 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5201
5202 If 0 or >1 lines contain `needle`, -1 is returned.
5203 """
5204 matching_line_numbers = [
5205 # + 1 for 1-based counting of line numbers.
5206 i + 1 for i, line
5207 in enumerate(lines)
5208 if needle in line]
5209 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5210
5211 def ModifiedPrefMigration(affected_file):
5212 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5213 # Determine first and last lines of MigrateObsolete.*Pref functions.
5214 new_contents = affected_file.NewContents();
5215 range_1 = (
5216 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5217 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5218 range_2 = (
5219 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5220 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5221 if (-1 in range_1 + range_2):
5222 raise Exception(
5223 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5224
5225 # Check whether any of the modified lines are part of the
5226 # MigrateObsolete.*Pref functions.
5227 for line_nr, line in ModifiedLines(affected_file):
5228 if (range_1[0] <= line_nr <= range_1[1] or
5229 range_2[0] <= line_nr <= range_2[1]):
5230 return True
5231 return False
5232
5233 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5234 browser_prefs_file_pattern = input_api.re.compile(
5235 r'chrome/browser/prefs/browser_prefs.cc')
5236
5237 changes = input_api.AffectedFiles(include_deletes=True,
5238 file_filter=FilterFile)
5239 potential_problems = []
5240 for f in changes:
5241 for line in f.GenerateScmDiff().splitlines():
5242 # Check deleted lines for pref registrations.
5243 if (line.startswith('-') and not line.startswith('--') and
5244 register_pref_pattern.search(line)):
5245 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5246
5247 if browser_prefs_file_pattern.search(f.LocalPath()):
5248 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5249 # assume that they knew that they have to deprecate preferences and don't
5250 # warn.
5251 try:
5252 if ModifiedPrefMigration(f):
5253 return []
5254 except Exception as e:
5255 return [output_api.PresubmitError(str(e))]
5256
5257 if potential_problems:
5258 return [output_api.PresubmitPromptWarning(
5259 'Discovered possible removal of preference registrations.\n\n'
5260 'Please make sure to properly deprecate preferences by clearing their\n'
5261 'value for a couple of milestones before finally removing the code.\n'
5262 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195263 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5264 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105265 'This may be a false positive warning (e.g. if you move preference\n'
5266 'registrations to a different place).\n',
5267 potential_problems
5268 )]
5269 return []