blob: 74d22d55072870ff82775b923224fa653f45265f [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
danakj7a2b7082019-05-21 21:13:51330# Directories that contain deprecated Bind() or Callback types.
331# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36332# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51333# echo "-- $i"
Alexander Cooperd1244c582021-01-26 02:25:27334# (cd $i; git grep -nP \
335# 'base::(Bind\(|(Cancelable)?(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51336# done
337#
338# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
339# when they have been converted to modern callback types (OnceCallback,
340# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
341# checks for them and prevent regressions.
342_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51343 '^base/callback.h', # Intentional.
Alex Turnerb3ea38c2020-11-25 18:03:07344 '^base/cancelable_callback.h', # Intentional.
Alexander Cooperb3f1af662021-02-01 19:47:26345 "^chrome/browser/ash/accessibility/",
Alexander Cooperb3f1af662021-02-01 19:47:26346 "^chrome/browser/metrics/",
Alexander Cooperb3f1af662021-02-01 19:47:26347 "^chrome/browser/prefetch/no_state_prefetch/",
348 '^chrome/browser/previews/',
Alexander Cooper6b447b22020-07-22 00:47:18349 '^chrome/browser/resources/chromeos/accessibility/',
Alexander Cooper6b447b22020-07-22 00:47:18350 '^chrome/browser/sync_file_system/',
Alexander Cooperb3f1af662021-02-01 19:47:26351 "^components/browsing_data/content/",
Alexander Cooperb3f1af662021-02-01 19:47:26352 "^components/feature_engagement/internal/",
353 "^docs/callback\\.md", # Intentional
354 "^docs/webui_explainer\\.md",
355 "^docs/process/lsc/large_scale_changes\\.md", # Intentional
356 "^docs/security/mojo\\.md",
357 "^docs/threading_and_tasks\\.md",
358 "^docs/ui/learn/bestpractices/layout\\.md",
Alan Cutter04a00642020-03-02 01:45:20359 '^extensions/browser/',
360 '^extensions/renderer/',
Alexander Cooperb3f1af662021-02-01 19:47:26361 '^third_party/blink/PRESUBMIT_test.py', # Intentional.
362 '^third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py' # Intentional pylint: disable=line-too-long
danakj7a2b7082019-05-21 21:13:51363 '^tools/clang/base_bind_rewriters/', # Intentional.
364 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51365))
[email protected]127f18ec2012-06-16 05:05:59366
Daniel Bratell609102be2019-03-27 20:53:21367# Format: Sequence of tuples containing:
368# * String pattern or, if starting with a slash, a regular expression.
369# * Sequence of strings to show when the pattern matches.
370# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
371# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59372_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20373 (
Peter Kasting94a56c42019-10-25 21:54:04374 r'/\busing namespace ',
375 (
376 'Using directives ("using namespace x") are banned by the Google Style',
377 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
378 'Explicitly qualify symbols or use using declarations ("using x::foo").',
379 ),
380 True,
381 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
382 ),
Antonio Gomes07300d02019-03-13 20:59:57383 # Make sure that gtest's FRIEND_TEST() macro is not used; the
384 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
385 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53386 (
[email protected]23e6cbc2012-06-16 18:51:20387 'FRIEND_TEST(',
388 (
[email protected]e3c945502012-06-26 20:01:49389 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20390 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
391 ),
392 False,
[email protected]7345da02012-11-27 14:31:49393 (),
[email protected]23e6cbc2012-06-16 18:51:20394 ),
395 (
tomhudsone2c14d552016-05-26 17:07:46396 'setMatrixClip',
397 (
398 'Overriding setMatrixClip() is prohibited; ',
399 'the base function is deprecated. ',
400 ),
401 True,
402 (),
403 ),
404 (
[email protected]52657f62013-05-20 05:30:31405 'SkRefPtr',
406 (
407 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22408 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31409 ),
410 True,
411 (),
412 ),
413 (
414 'SkAutoRef',
415 (
416 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22417 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31418 ),
419 True,
420 (),
421 ),
422 (
423 'SkAutoTUnref',
424 (
425 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22426 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31427 ),
428 True,
429 (),
430 ),
431 (
432 'SkAutoUnref',
433 (
434 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
435 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22436 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31437 ),
438 True,
439 (),
440 ),
[email protected]d89eec82013-12-03 14:10:59441 (
442 r'/HANDLE_EINTR\(.*close',
443 (
444 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
445 'descriptor will be closed, and it is incorrect to retry the close.',
446 'Either call close directly and ignore its return value, or wrap close',
447 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
448 ),
449 True,
450 (),
451 ),
452 (
453 r'/IGNORE_EINTR\((?!.*close)',
454 (
455 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
456 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
457 ),
458 True,
459 (
460 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04461 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
462 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59463 ),
464 ),
[email protected]ec5b3f02014-04-04 18:43:43465 (
466 r'/v8::Extension\(',
467 (
468 'Do not introduce new v8::Extensions into the code base, use',
469 'gin::Wrappable instead. See http://crbug.com/334679',
470 ),
471 True,
[email protected]f55c90ee62014-04-12 00:50:03472 (
Egor Paskoce145c42018-09-28 19:31:04473 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03474 ),
[email protected]ec5b3f02014-04-04 18:43:43475 ),
skyostilf9469f72015-04-20 10:38:52476 (
jame2d1a952016-04-02 00:27:10477 '#pragma comment(lib,',
478 (
479 'Specify libraries to link with in build files and not in the source.',
480 ),
481 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41482 (
tzik3f295992018-12-04 20:32:23483 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04484 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41485 ),
jame2d1a952016-04-02 00:27:10486 ),
fdorayc4ac18d2017-05-01 21:39:59487 (
Gabriel Charette7cc6c432018-04-25 20:52:02488 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59489 (
490 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
491 ),
492 False,
493 (),
494 ),
495 (
Gabriel Charette7cc6c432018-04-25 20:52:02496 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59497 (
498 'Consider using THREAD_CHECKER macros instead of the class directly.',
499 ),
500 False,
501 (),
502 ),
dbeamb6f4fde2017-06-15 04:03:06503 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06504 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
505 (
506 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
507 'deprecated (http://crbug.com/634507). Please avoid converting away',
508 'from the Time types in Chromium code, especially if any math is',
509 'being done on time values. For interfacing with platform/library',
510 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
511 'type converter methods instead. For faking TimeXXX values (for unit',
512 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
513 'other use cases, please contact base/time/OWNERS.',
514 ),
515 False,
516 (),
517 ),
518 (
dbeamb6f4fde2017-06-15 04:03:06519 'CallJavascriptFunctionUnsafe',
520 (
521 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
522 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
523 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
524 ),
525 False,
526 (
Egor Paskoce145c42018-09-28 19:31:04527 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
528 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
529 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06530 ),
531 ),
dskiba1474c2bfd62017-07-20 02:19:24532 (
533 'leveldb::DB::Open',
534 (
535 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
536 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
537 "Chrome's tracing, making their memory usage visible.",
538 ),
539 True,
540 (
541 r'^third_party/leveldatabase/.*\.(cc|h)$',
542 ),
Gabriel Charette0592c3a2017-07-26 12:02:04543 ),
544 (
Chris Mumfordc38afb62017-10-09 17:55:08545 'leveldb::NewMemEnv',
546 (
547 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58548 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
549 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08550 ),
551 True,
552 (
553 r'^third_party/leveldatabase/.*\.(cc|h)$',
554 ),
555 ),
556 (
Gabriel Charetted9839bc2017-07-29 14:17:47557 'RunLoop::QuitCurrent',
558 (
Robert Liao64b7ab22017-08-04 23:03:43559 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
560 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47561 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41562 False,
Gabriel Charetted9839bc2017-07-29 14:17:47563 (),
Gabriel Charettea44975052017-08-21 23:14:04564 ),
565 (
566 'base::ScopedMockTimeMessageLoopTaskRunner',
567 (
Gabriel Charette87cc1af2018-04-25 20:52:51568 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11569 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51570 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
571 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
572 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04573 ),
Gabriel Charette87cc1af2018-04-25 20:52:51574 False,
Gabriel Charettea44975052017-08-21 23:14:04575 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57576 ),
577 (
Dave Tapuska98199b612019-07-10 13:30:44578 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57579 (
580 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02581 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57582 ),
583 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16584 # Abseil's benchmarks never linked into chrome.
585 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38586 ),
587 (
Peter Kasting991618a62019-06-17 22:00:09588 r'/\bstd::stoi\b',
589 (
590 'std::stoi uses exceptions to communicate results. ',
591 'Use base::StringToInt() instead.',
592 ),
593 True,
594 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
595 ),
596 (
597 r'/\bstd::stol\b',
598 (
599 'std::stol uses exceptions to communicate results. ',
600 'Use base::StringToInt() instead.',
601 ),
602 True,
603 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
604 ),
605 (
606 r'/\bstd::stoul\b',
607 (
608 'std::stoul uses exceptions to communicate results. ',
609 'Use base::StringToUint() instead.',
610 ),
611 True,
612 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
613 ),
614 (
615 r'/\bstd::stoll\b',
616 (
617 'std::stoll uses exceptions to communicate results. ',
618 'Use base::StringToInt64() instead.',
619 ),
620 True,
621 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
622 ),
623 (
624 r'/\bstd::stoull\b',
625 (
626 'std::stoull uses exceptions to communicate results. ',
627 'Use base::StringToUint64() instead.',
628 ),
629 True,
630 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
631 ),
632 (
633 r'/\bstd::stof\b',
634 (
635 'std::stof uses exceptions to communicate results. ',
636 'For locale-independent values, e.g. reading numbers from disk',
637 'profiles, use base::StringToDouble().',
638 'For user-visible values, parse using ICU.',
639 ),
640 True,
641 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
642 ),
643 (
644 r'/\bstd::stod\b',
645 (
646 'std::stod uses exceptions to communicate results. ',
647 'For locale-independent values, e.g. reading numbers from disk',
648 'profiles, use base::StringToDouble().',
649 'For user-visible values, parse using ICU.',
650 ),
651 True,
652 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
653 ),
654 (
655 r'/\bstd::stold\b',
656 (
657 'std::stold uses exceptions to communicate results. ',
658 'For locale-independent values, e.g. reading numbers from disk',
659 'profiles, use base::StringToDouble().',
660 'For user-visible values, parse using ICU.',
661 ),
662 True,
663 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
664 ),
665 (
Daniel Bratell69334cc2019-03-26 11:07:45666 r'/\bstd::to_string\b',
667 (
668 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09669 'For locale-independent strings, e.g. writing numbers to disk',
670 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45671 'For user-visible strings, use base::FormatNumber() and',
672 'the related functions in base/i18n/number_formatting.h.',
673 ),
Peter Kasting991618a62019-06-17 22:00:09674 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21675 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45676 ),
677 (
678 r'/\bstd::shared_ptr\b',
679 (
680 'std::shared_ptr should not be used. Use scoped_refptr instead.',
681 ),
682 True,
Ulan Degenbaev947043882021-02-10 14:02:31683 [
684 # Needed for interop with third-party library.
685 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57686 'array_buffer_contents\.(cc|h)',
Ulan Degenbaev947043882021-02-10 14:02:31687 'gin/array_buffer.cc',
688 'gin/array_buffer.h',
Alex Chau9eb03cdd52020-07-13 21:04:57689 'chrome/services/sharing/nearby/',
690 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21691 ),
692 (
Peter Kasting991618a62019-06-17 22:00:09693 r'/\bstd::weak_ptr\b',
694 (
695 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
696 ),
697 True,
698 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
699 ),
700 (
Daniel Bratell609102be2019-03-27 20:53:21701 r'/\blong long\b',
702 (
703 'long long is banned. Use stdint.h if you need a 64 bit number.',
704 ),
705 False, # Only a warning since it is already used.
706 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
707 ),
708 (
709 r'/\bstd::bind\b',
710 (
711 'std::bind is banned because of lifetime risks.',
712 'Use base::BindOnce or base::BindRepeating instead.',
713 ),
714 True,
715 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
716 ),
717 (
718 r'/\b#include <chrono>\b',
719 (
720 '<chrono> overlaps with Time APIs in base. Keep using',
721 'base classes.',
722 ),
723 True,
724 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
725 ),
726 (
727 r'/\b#include <exception>\b',
728 (
729 'Exceptions are banned and disabled in Chromium.',
730 ),
731 True,
732 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
733 ),
734 (
735 r'/\bstd::function\b',
736 (
737 'std::function is banned. Instead use base::Callback which directly',
738 'supports Chromium\'s weak pointers, ref counting and more.',
739 ),
Peter Kasting991618a62019-06-17 22:00:09740 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21741 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
742 ),
743 (
744 r'/\b#include <random>\b',
745 (
746 'Do not use any random number engines from <random>. Instead',
747 'use base::RandomBitGenerator.',
748 ),
749 True,
750 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
751 ),
752 (
Tom Andersona95e12042020-09-09 23:08:00753 r'/\b#include <X11/',
754 (
755 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
756 ),
757 True,
758 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
759 ),
760 (
Daniel Bratell609102be2019-03-27 20:53:21761 r'/\bstd::ratio\b',
762 (
763 'std::ratio is banned by the Google Style Guide.',
764 ),
765 True,
766 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45767 ),
768 (
Francois Doray43670e32017-09-27 12:40:38769 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
770 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
771 (
772 'Use the new API in base/threading/thread_restrictions.h.',
773 ),
Gabriel Charette04b138f2018-08-06 00:03:22774 False,
Francois Doray43670e32017-09-27 12:40:38775 (),
776 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38777 (
danakj7a2b7082019-05-21 21:13:51778 r'/\bbase::Bind\(',
779 (
780 'Please use base::Bind{Once,Repeating} instead',
781 'of base::Bind. (crbug.com/714018)',
782 ),
783 False,
Erik Staaba737d7602019-11-25 18:41:07784 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51785 ),
786 (
787 r'/\bbase::Callback[<:]',
788 (
789 'Please use base::{Once,Repeating}Callback instead',
790 'of base::Callback. (crbug.com/714018)',
791 ),
792 False,
Erik Staaba737d7602019-11-25 18:41:07793 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51794 ),
795 (
796 r'/\bbase::Closure\b',
797 (
798 'Please use base::{Once,Repeating}Closure instead',
799 'of base::Closure. (crbug.com/714018)',
800 ),
801 False,
Erik Staaba737d7602019-11-25 18:41:07802 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51803 ),
804 (
Alex Turnerb3ea38c2020-11-25 18:03:07805 r'/\bbase::CancelableCallback[<:]',
806 (
807 'Please use base::Cancelable{Once,Repeating}Callback instead',
808 'of base::CancelableCallback. (crbug.com/714018)',
809 ),
810 False,
811 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
812 ),
813 (
814 r'/\bbase::CancelableClosure\b',
815 (
816 'Please use base::Cancelable{Once,Repeating}Closure instead',
817 'of base::CancelableClosure. (crbug.com/714018)',
818 ),
819 False,
820 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
821 ),
822 (
Michael Giuffrida7f93d6922019-04-19 14:39:58823 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19824 (
825 'RunMessageLoop is deprecated, use RunLoop instead.',
826 ),
827 False,
828 (),
829 ),
830 (
Dave Tapuska98199b612019-07-10 13:30:44831 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19832 (
833 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
834 ),
835 False,
836 (),
837 ),
838 (
Dave Tapuska98199b612019-07-10 13:30:44839 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19840 (
841 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
842 "if you're convinced you need this.",
843 ),
844 False,
845 (),
846 ),
847 (
Dave Tapuska98199b612019-07-10 13:30:44848 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19849 (
850 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04851 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19852 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
853 'async events instead of flushing threads.',
854 ),
855 False,
856 (),
857 ),
858 (
859 r'MessageLoopRunner',
860 (
861 'MessageLoopRunner is deprecated, use RunLoop instead.',
862 ),
863 False,
864 (),
865 ),
866 (
Dave Tapuska98199b612019-07-10 13:30:44867 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19868 (
869 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
870 "gab@ if you found a use case where this is the only solution.",
871 ),
872 False,
873 (),
874 ),
875 (
Victor Costane48a2e82019-03-15 22:02:34876 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16877 (
Victor Costane48a2e82019-03-15 22:02:34878 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16879 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
880 ),
881 True,
882 (
883 r'^sql/initialization\.(cc|h)$',
884 r'^third_party/sqlite/.*\.(c|cc|h)$',
885 ),
886 ),
Matt Menke7f520a82018-03-28 21:38:37887 (
Dave Tapuska98199b612019-07-10 13:30:44888 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47889 (
890 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
891 'base::RandomShuffle instead.'
892 ),
893 True,
894 (),
895 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24896 (
897 'ios/web/public/test/http_server',
898 (
899 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
900 ),
901 False,
902 (),
903 ),
Robert Liao764c9492019-01-24 18:46:28904 (
905 'GetAddressOf',
906 (
907 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53908 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11909 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53910 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28911 ),
912 True,
913 (),
914 ),
Antonio Gomes07300d02019-03-13 20:59:57915 (
Ben Lewisa9514602019-04-29 17:53:05916 'SHFileOperation',
917 (
918 'SHFileOperation was deprecated in Windows Vista, and there are less ',
919 'complex functions to achieve the same goals. Use IFileOperation for ',
920 'any esoteric actions instead.'
921 ),
922 True,
923 (),
924 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18925 (
Cliff Smolinsky81951642019-04-30 21:39:51926 'StringFromGUID2',
927 (
928 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24929 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51930 ),
931 True,
932 (
933 r'/base/win/win_util_unittest.cc'
934 ),
935 ),
936 (
937 'StringFromCLSID',
938 (
939 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24940 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51941 ),
942 True,
943 (
944 r'/base/win/win_util_unittest.cc'
945 ),
946 ),
947 (
Avi Drissman7382afa02019-04-29 23:27:13948 'kCFAllocatorNull',
949 (
950 'The use of kCFAllocatorNull with the NoCopy creation of ',
951 'CoreFoundation types is prohibited.',
952 ),
953 True,
954 (),
955 ),
Oksana Zhuravlovafd247772019-05-16 16:57:29956 (
957 'mojo::ConvertTo',
958 (
959 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
960 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
961 'StringTraits if you would like to convert between custom types and',
962 'the wire format of mojom types.'
963 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22964 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29965 (
Wezf89dec092019-09-11 19:38:33966 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
967 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29968 r'^third_party/blink/.*\.(cc|h)$',
969 r'^content/renderer/.*\.(cc|h)$',
970 ),
971 ),
Robert Liao1d78df52019-11-11 20:02:01972 (
Oksana Zhuravlovac8222d22019-12-19 19:21:16973 'GetInterfaceProvider',
974 (
975 'InterfaceProvider is deprecated.',
976 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
977 'or Platform::GetBrowserInterfaceBroker.'
978 ),
979 False,
980 (),
981 ),
982 (
Robert Liao1d78df52019-11-11 20:02:01983 'CComPtr',
984 (
985 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
986 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
987 'details.'
988 ),
989 False,
990 (),
991 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:20992 (
993 r'/\b(IFACE|STD)METHOD_?\(',
994 (
995 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
996 'Instead, always use IFACEMETHODIMP in the declaration.'
997 ),
998 False,
999 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1000 ),
Allen Bauer53b43fb12020-03-12 17:21:471001 (
1002 'set_owned_by_client',
1003 (
1004 'set_owned_by_client is deprecated.',
1005 'views::View already owns the child views by default. This introduces ',
1006 'a competing ownership model which makes the code difficult to reason ',
1007 'about. See http://crbug.com/1044687 for more details.'
1008 ),
1009 False,
1010 (),
1011 ),
Eric Secklerbe6f48d2020-05-06 18:09:121012 (
1013 r'/\bTRACE_EVENT_ASYNC_',
1014 (
1015 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1016 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1017 ),
1018 False,
1019 (
1020 r'^base/trace_event/.*',
1021 r'^base/tracing/.*',
1022 ),
1023 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:261024 (
1025 r'/\bScopedObserver',
1026 (
1027 'ScopedObserver is deprecated.',
1028 'Please use base::ScopedObservation for observing a single source,',
1029 'or base::ScopedMultiSourceObservation for observing multple sources',
1030 ),
1031 False,
1032 (),
1033 ),
Jan Wilken Dörrie60df2362021-04-08 19:44:211034 (
1035 r'/\bASCIIToUTF16\("(\\.|[^\\"])*"\)',
1036 (
1037 'base::ASCIIToUTF16 should not be used with a string literal.',
1038 'Consider using a UTF16 string literal (u"...") instead.',
1039 ),
1040 False,
1041 (),
1042 ),
1043 (
1044 r'/\bUTF8ToUTF16\("(\\.|[^\\"])*"\)',
1045 (
1046 'base::UTF8ToUTF16 should not be used with a string literal.',
1047 'Consider using a UTF16 string literal (u"...") instead.',
1048 ),
1049 False,
1050 (),
1051 ),
[email protected]127f18ec2012-06-16 05:05:591052)
1053
Mario Sanchez Prada2472cab2019-09-18 10:58:311054# Format: Sequence of tuples containing:
1055# * String pattern or, if starting with a slash, a regular expression.
1056# * Sequence of strings to show when the pattern matches.
1057_DEPRECATED_MOJO_TYPES = (
1058 (
1059 r'/\bmojo::AssociatedBinding\b',
1060 (
1061 'mojo::AssociatedBinding<Interface> is deprecated.',
1062 'Use mojo::AssociatedReceiver<Interface> instead.',
1063 ),
1064 ),
1065 (
1066 r'/\bmojo::AssociatedBindingSet\b',
1067 (
1068 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1069 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1070 ),
1071 ),
1072 (
1073 r'/\bmojo::AssociatedInterfacePtr\b',
1074 (
1075 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1076 'Use mojo::AssociatedRemote<Interface> instead.',
1077 ),
1078 ),
1079 (
1080 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1081 (
1082 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1083 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1084 ),
1085 ),
1086 (
1087 r'/\bmojo::AssociatedInterfaceRequest\b',
1088 (
1089 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1090 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1091 ),
1092 ),
1093 (
1094 r'/\bmojo::Binding\b',
1095 (
1096 'mojo::Binding<Interface> is deprecated.',
1097 'Use mojo::Receiver<Interface> instead.',
1098 ),
1099 ),
1100 (
1101 r'/\bmojo::BindingSet\b',
1102 (
1103 'mojo::BindingSet<Interface> is deprecated.',
1104 'Use mojo::ReceiverSet<Interface> instead.',
1105 ),
1106 ),
1107 (
1108 r'/\bmojo::InterfacePtr\b',
1109 (
1110 'mojo::InterfacePtr<Interface> is deprecated.',
1111 'Use mojo::Remote<Interface> instead.',
1112 ),
1113 ),
1114 (
1115 r'/\bmojo::InterfacePtrInfo\b',
1116 (
1117 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1118 'Use mojo::PendingRemote<Interface> instead.',
1119 ),
1120 ),
1121 (
1122 r'/\bmojo::InterfaceRequest\b',
1123 (
1124 'mojo::InterfaceRequest<Interface> is deprecated.',
1125 'Use mojo::PendingReceiver<Interface> instead.',
1126 ),
1127 ),
1128 (
1129 r'/\bmojo::MakeRequest\b',
1130 (
1131 'mojo::MakeRequest is deprecated.',
1132 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1133 ),
1134 ),
1135 (
1136 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1137 (
1138 'mojo::MakeRequest is deprecated.',
1139 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181140 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311141 ),
1142 ),
1143 (
1144 r'/\bmojo::MakeStrongBinding\b',
1145 (
1146 'mojo::MakeStrongBinding is deprecated.',
1147 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1148 'mojo::MakeSelfOwnedReceiver() instead.',
1149 ),
1150 ),
1151 (
1152 r'/\bmojo::MakeStrongAssociatedBinding\b',
1153 (
1154 'mojo::MakeStrongAssociatedBinding is deprecated.',
1155 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1156 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1157 ),
1158 ),
1159 (
Gyuyoung Kim4952ba62020-07-07 07:33:441160 r'/\bmojo::StrongAssociatedBinding\b',
1161 (
1162 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1163 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1164 ),
1165 ),
1166 (
1167 r'/\bmojo::StrongBinding\b',
1168 (
1169 'mojo::StrongBinding<Interface> is deprecated.',
1170 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1171 ),
1172 ),
1173 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311174 r'/\bmojo::StrongAssociatedBindingSet\b',
1175 (
1176 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1177 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1178 ),
1179 ),
1180 (
1181 r'/\bmojo::StrongBindingSet\b',
1182 (
1183 'mojo::StrongBindingSet<Interface> is deprecated.',
1184 'Use mojo::UniqueReceiverSet<Interface> instead.',
1185 ),
1186 ),
1187)
wnwenbdc444e2016-05-25 13:44:151188
mlamouria82272622014-09-16 18:45:041189_IPC_ENUM_TRAITS_DEPRECATED = (
1190 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501191 'See http://www.chromium.org/Home/chromium-security/education/'
1192 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041193
Stephen Martinis97a394142018-06-07 23:06:051194_LONG_PATH_ERROR = (
1195 'Some files included in this CL have file names that are too long (> 200'
1196 ' characters). If committed, these files will cause issues on Windows. See'
1197 ' https://crbug.com/612667 for more details.'
1198)
1199
Shenghua Zhangbfaa38b82017-11-16 21:58:021200_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041201 r".*[\\/]BuildHooksAndroidImpl\.java",
1202 r".*[\\/]LicenseContentProvider\.java",
1203 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281204 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021205]
[email protected]127f18ec2012-06-16 05:05:591206
Mohamed Heikald048240a2019-11-12 16:57:371207# List of image extensions that are used as resources in chromium.
1208_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1209
Sean Kau46e29bc2017-08-28 16:31:161210# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401211_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041212 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401213 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041214 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1215 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041216 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431217 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161218]
1219
1220
[email protected]b00342e7f2013-03-26 16:21:541221_VALID_OS_MACROS = (
1222 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081223 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541224 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441225 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121226 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541227 'OS_BSD',
1228 'OS_CAT', # For testing.
1229 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041230 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541231 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371232 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541233 'OS_IOS',
1234 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441235 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541236 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211237 'OS_NACL_NONSFI',
1238 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121239 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541240 'OS_OPENBSD',
1241 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371242 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541243 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541244 'OS_WIN',
1245)
1246
1247
Andrew Grieveb773bad2020-06-05 18:00:381248# These are not checked on the public chromium-presubmit trybot.
1249# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041250# checkouts.
agrievef32bcc72016-04-04 14:57:401251_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381252 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381253]
1254
1255
1256_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041257 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361258 'base/android/jni_generator/jni_generator.pydeps',
1259 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361260 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041261 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361262 'build/android/gyp/aar.pydeps',
1263 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271264 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361265 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381266 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361267 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021268 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221269 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111270 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361271 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361272 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361273 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111274 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041275 'build/android/gyp/create_app_bundle_apks.pydeps',
1276 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361277 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121278 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091279 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221280 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001281 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361282 'build/android/gyp/desugar.pydeps',
1283 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421284 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041285 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361286 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361287 'build/android/gyp/filter_zip.pydeps',
1288 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361289 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361290 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581291 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361292 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141293 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261294 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011295 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041296 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361297 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361298 'build/android/gyp/merge_manifest.pydeps',
1299 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221300 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361301 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461302 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241303 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361304 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461305 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561306 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361307 'build/android/incremental_install/generate_android_manifest.pydeps',
1308 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041309 'build/android/resource_sizes.pydeps',
1310 'build/android/test_runner.pydeps',
1311 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361312 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361313 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321314 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271315 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1316 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041317 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001318 'components/cronet/tools/generate_javadoc.pydeps',
1319 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381320 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001321 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381322 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041323 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181324 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041325 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421326 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1327 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131328 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061329 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221330 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401331]
1332
wnwenbdc444e2016-05-25 13:44:151333
agrievef32bcc72016-04-04 14:57:401334_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1335
1336
Eric Boren6fd2b932018-01-25 15:05:081337# Bypass the AUTHORS check for these accounts.
1338_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591339 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451340 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591341 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521342 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071343 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041344 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271345 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041346 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301347 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081348
1349
Daniel Bratell65b033262019-04-23 08:17:061350def _IsCPlusPlusFile(input_api, file_path):
1351 """Returns True if this file contains C++-like code (and not Python,
1352 Go, Java, MarkDown, ...)"""
1353
1354 ext = input_api.os_path.splitext(file_path)[1]
1355 # This list is compatible with CppChecker.IsCppFile but we should
1356 # consider adding ".c" to it. If we do that we can use this function
1357 # at more places in the code.
1358 return ext in (
1359 '.h',
1360 '.cc',
1361 '.cpp',
1362 '.m',
1363 '.mm',
1364 )
1365
1366def _IsCPlusPlusHeaderFile(input_api, file_path):
1367 return input_api.os_path.splitext(file_path)[1] == ".h"
1368
1369
1370def _IsJavaFile(input_api, file_path):
1371 return input_api.os_path.splitext(file_path)[1] == ".java"
1372
1373
1374def _IsProtoFile(input_api, file_path):
1375 return input_api.os_path.splitext(file_path)[1] == ".proto"
1376
Mohamed Heikal5e5b7922020-10-29 18:57:591377
1378def CheckNoUpstreamDepsOnClank(input_api, output_api):
1379 """Prevent additions of dependencies from the upstream repo on //clank."""
1380 # clank can depend on clank
1381 if input_api.change.RepositoryRoot().endswith('clank'):
1382 return []
1383 build_file_patterns = [
1384 r'(.+/)?BUILD\.gn',
1385 r'.+\.gni',
1386 ]
1387 excluded_files = [
1388 r'build[/\\]config[/\\]android[/\\]config\.gni'
1389 ]
1390 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1391
1392 error_message = 'Disallowed import on //clank in an upstream build file:'
1393
1394 def FilterFile(affected_file):
1395 return input_api.FilterSourceFile(
1396 affected_file,
1397 files_to_check=build_file_patterns,
1398 files_to_skip=excluded_files)
1399
1400 problems = []
1401 for f in input_api.AffectedSourceFiles(FilterFile):
1402 local_path = f.LocalPath()
1403 for line_number, line in f.ChangedContents():
1404 if (bad_pattern.search(line)):
1405 problems.append(
1406 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1407 if problems:
1408 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1409 else:
1410 return []
1411
1412
Saagar Sanghavifceeaae2020-08-12 16:40:361413def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191414 """Attempts to prevent use of functions intended only for testing in
1415 non-testing code. For now this is just a best-effort implementation
1416 that ignores header files and may have some false positives. A
1417 better implementation would probably need a proper C++ parser.
1418 """
1419 # We only scan .cc files and the like, as the declaration of
1420 # for-testing functions in header files are hard to distinguish from
1421 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491422 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191423
jochenc0d4808c2015-07-27 09:25:421424 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191425 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091426 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131427 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191428 exclusion_pattern = input_api.re.compile(
1429 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1430 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131431 # Avoid a false positive in this case, where the method name, the ::, and
1432 # the closing { are all on different lines due to line wrapping.
1433 # HelperClassForTesting::
1434 # HelperClassForTesting(
1435 # args)
1436 # : member(0) {}
1437 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191438
1439 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441440 files_to_skip = (_EXCLUDED_PATHS +
1441 _TEST_CODE_EXCLUDED_PATHS +
1442 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191443 return input_api.FilterSourceFile(
1444 affected_file,
James Cook24a504192020-07-23 00:08:441445 files_to_check=file_inclusion_pattern,
1446 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191447
1448 problems = []
1449 for f in input_api.AffectedSourceFiles(FilterFile):
1450 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131451 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241452 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031453 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461454 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131455 not exclusion_pattern.search(line) and
1456 not allowlist_pattern.search(line) and
1457 not in_method_defn):
[email protected]55459852011-08-10 15:17:191458 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031459 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131460 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191461
1462 if problems:
[email protected]f7051d52013-04-02 18:31:421463 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031464 else:
1465 return []
[email protected]55459852011-08-10 15:17:191466
1467
Saagar Sanghavifceeaae2020-08-12 16:40:361468def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231469 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591470 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231471 """
1472 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1473 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1474 name_pattern = r'ForTest(s|ing)?'
1475 # Describes an occurrence of "ForTest*" inside a // comment.
1476 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501477 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551478 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231479 # Catch calls.
1480 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1481 # Ignore definitions. (Comments are ignored separately.)
1482 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1483
1484 problems = []
1485 sources = lambda x: input_api.FilterSourceFile(
1486 x,
James Cook24a504192020-07-23 00:08:441487 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1488 + input_api.DEFAULT_FILES_TO_SKIP),
1489 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231490 )
1491 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1492 local_path = f.LocalPath()
1493 is_inside_javadoc = False
1494 for line_number, line in f.ChangedContents():
1495 if is_inside_javadoc and javadoc_end_re.search(line):
1496 is_inside_javadoc = False
1497 if not is_inside_javadoc and javadoc_start_re.search(line):
1498 is_inside_javadoc = True
1499 if is_inside_javadoc:
1500 continue
1501 if (inclusion_re.search(line) and
1502 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501503 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231504 not exclusion_re.search(line)):
1505 problems.append(
1506 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1507
1508 if problems:
1509 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1510 else:
1511 return []
1512
1513
Saagar Sanghavifceeaae2020-08-12 16:40:361514def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541515 """Checks to make sure no .h files include <iostream>."""
1516 files = []
1517 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1518 input_api.re.MULTILINE)
1519 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1520 if not f.LocalPath().endswith('.h'):
1521 continue
1522 contents = input_api.ReadFile(f)
1523 if pattern.search(contents):
1524 files.append(f)
1525
1526 if len(files):
yolandyandaabc6d2016-04-18 18:29:391527 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061528 'Do not #include <iostream> in header files, since it inserts static '
1529 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541530 '#include <ostream>. See http://crbug.com/94794',
1531 files) ]
1532 return []
1533
Danil Chapovalov3518f362018-08-11 16:13:431534def _CheckNoStrCatRedefines(input_api, output_api):
1535 """Checks no windows headers with StrCat redefined are included directly."""
1536 files = []
1537 pattern_deny = input_api.re.compile(
1538 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1539 input_api.re.MULTILINE)
1540 pattern_allow = input_api.re.compile(
1541 r'^#include\s"base/win/windows_defines.inc"',
1542 input_api.re.MULTILINE)
1543 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1544 contents = input_api.ReadFile(f)
1545 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1546 files.append(f.LocalPath())
1547
1548 if len(files):
1549 return [output_api.PresubmitError(
1550 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1551 'directly since they pollute code with StrCat macro. Instead, '
1552 'include matching header from base/win. See http://crbug.com/856536',
1553 files) ]
1554 return []
1555
[email protected]10689ca2011-09-02 02:31:541556
Saagar Sanghavifceeaae2020-08-12 16:40:361557def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521558 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181559 problems = []
1560 for f in input_api.AffectedFiles():
1561 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1562 continue
1563
1564 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041565 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181566 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1567
1568 if not problems:
1569 return []
1570 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1571 '\n'.join(problems))]
1572
Saagar Sanghavifceeaae2020-08-12 16:40:361573def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341574 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1575
1576 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1577 instead of DISABLED_. To filter false positives, reports are only generated
1578 if a corresponding MAYBE_ line exists.
1579 """
1580 problems = []
1581
1582 # The following two patterns are looked for in tandem - is a test labeled
1583 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1584 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1585 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1586
1587 # This is for the case that a test is disabled on all platforms.
1588 full_disable_pattern = input_api.re.compile(
1589 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1590 input_api.re.MULTILINE)
1591
Katie Df13948e2018-09-25 07:33:441592 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341593 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1594 continue
1595
1596 # Search for MABYE_, DISABLE_ pairs.
1597 disable_lines = {} # Maps of test name to line number.
1598 maybe_lines = {}
1599 for line_num, line in f.ChangedContents():
1600 disable_match = disable_pattern.search(line)
1601 if disable_match:
1602 disable_lines[disable_match.group(1)] = line_num
1603 maybe_match = maybe_pattern.search(line)
1604 if maybe_match:
1605 maybe_lines[maybe_match.group(1)] = line_num
1606
1607 # Search for DISABLE_ occurrences within a TEST() macro.
1608 disable_tests = set(disable_lines.keys())
1609 maybe_tests = set(maybe_lines.keys())
1610 for test in disable_tests.intersection(maybe_tests):
1611 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1612
1613 contents = input_api.ReadFile(f)
1614 full_disable_match = full_disable_pattern.search(contents)
1615 if full_disable_match:
1616 problems.append(' %s' % f.LocalPath())
1617
1618 if not problems:
1619 return []
1620 return [
1621 output_api.PresubmitPromptWarning(
1622 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1623 '\n'.join(problems))
1624 ]
1625
[email protected]72df4e782012-06-21 16:28:181626
Saagar Sanghavifceeaae2020-08-12 16:40:361627def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571628 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521629 errors = []
Hans Wennborg944479f2020-06-25 21:39:251630 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521631 input_api.re.MULTILINE)
1632 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1633 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1634 continue
1635 for lnum, line in f.ChangedContents():
1636 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171637 errors.append(output_api.PresubmitError(
1638 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571639 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171640 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521641 return errors
1642
1643
Weilun Shia487fad2020-10-28 00:10:341644# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1645# more reliable way. See
1646# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191647
wnwenbdc444e2016-05-25 13:44:151648
Saagar Sanghavifceeaae2020-08-12 16:40:361649def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391650 """Check that FlakyTest annotation is our own instead of the android one"""
1651 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1652 files = []
1653 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1654 if f.LocalPath().endswith('Test.java'):
1655 if pattern.search(input_api.ReadFile(f)):
1656 files.append(f)
1657 if len(files):
1658 return [output_api.PresubmitError(
1659 'Use org.chromium.base.test.util.FlakyTest instead of '
1660 'android.test.FlakyTest',
1661 files)]
1662 return []
mcasasb7440c282015-02-04 14:52:191663
wnwenbdc444e2016-05-25 13:44:151664
Saagar Sanghavifceeaae2020-08-12 16:40:361665def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441666 """Make sure .DEPS.git is never modified manually."""
1667 if any(f.LocalPath().endswith('.DEPS.git') for f in
1668 input_api.AffectedFiles()):
1669 return [output_api.PresubmitError(
1670 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1671 'automated system based on what\'s in DEPS and your changes will be\n'
1672 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501673 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1674 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441675 'for more information')]
1676 return []
1677
1678
Saagar Sanghavifceeaae2020-08-12 16:40:361679def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471680 """Checks that DEPS file deps are from allowed_hosts."""
1681 # Run only if DEPS file has been modified to annoy fewer bystanders.
1682 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1683 return []
1684 # Outsource work to gclient verify
1685 try:
John Budorickf20c0042019-04-25 23:23:401686 gclient_path = input_api.os_path.join(
1687 input_api.PresubmitLocalPath(),
1688 'third_party', 'depot_tools', 'gclient.py')
1689 input_api.subprocess.check_output(
1690 [input_api.python_executable, gclient_path, 'verify'],
1691 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471692 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201693 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471694 return [output_api.PresubmitError(
1695 'DEPS file must have only git dependencies.',
1696 long_text=error.output)]
1697
1698
Mario Sanchez Prada2472cab2019-09-18 10:58:311699def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1700 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591701 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311702
1703 Returns an string composed of the name of the file, the line number where the
1704 match has been found and the additional text passed as |message| in case the
1705 target type name matches the text inside the line passed as parameter.
1706 """
Peng Huang9c5949a02020-06-11 19:20:541707 result = []
1708
danakjd18e8892020-12-17 17:42:011709 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1710 return result
1711 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541712 return result
1713
Mario Sanchez Prada2472cab2019-09-18 10:58:311714 matched = False
1715 if type_name[0:1] == '/':
1716 regex = type_name[1:]
1717 if input_api.re.search(regex, line):
1718 matched = True
1719 elif type_name in line:
1720 matched = True
1721
Mario Sanchez Prada2472cab2019-09-18 10:58:311722 if matched:
1723 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1724 for message_line in message:
1725 result.append(' %s' % message_line)
1726
1727 return result
1728
1729
Saagar Sanghavifceeaae2020-08-12 16:40:361730def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591731 """Make sure that banned functions are not used."""
1732 warnings = []
1733 errors = []
1734
James Cook24a504192020-07-23 00:08:441735 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151736 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441737 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151738 if input_api.re.match(item, local_path):
1739 return True
1740 return False
1741
Peter K. Lee6c03ccff2019-07-15 14:40:051742 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541743 local_path = affected_file.LocalPath()
1744 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1745 return False
1746 basename = input_api.os_path.basename(local_path)
1747 if 'ios' in basename.split('_'):
1748 return True
1749 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1750 if sep and 'ios' in local_path.split(sep):
1751 return True
1752 return False
1753
wnwenbdc444e2016-05-25 13:44:151754 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311755 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1756 func_name, message)
1757 if problems:
wnwenbdc444e2016-05-25 13:44:151758 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311759 errors.extend(problems)
1760 else:
1761 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151762
Eric Stevensona9a980972017-09-23 00:04:411763 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1764 for f in input_api.AffectedFiles(file_filter=file_filter):
1765 for line_num, line in f.ChangedContents():
1766 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1767 CheckForMatch(f, line_num, line, func_name, message, error)
1768
[email protected]127f18ec2012-06-16 05:05:591769 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1770 for f in input_api.AffectedFiles(file_filter=file_filter):
1771 for line_num, line in f.ChangedContents():
1772 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151773 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591774
Peter K. Lee6c03ccff2019-07-15 14:40:051775 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541776 for line_num, line in f.ChangedContents():
1777 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1778 CheckForMatch(f, line_num, line, func_name, message, error)
1779
Peter K. Lee6c03ccff2019-07-15 14:40:051780 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1781 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1782 for line_num, line in f.ChangedContents():
1783 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1784 CheckForMatch(f, line_num, line, func_name, message, error)
1785
[email protected]127f18ec2012-06-16 05:05:591786 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1787 for f in input_api.AffectedFiles(file_filter=file_filter):
1788 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491789 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441790 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491791 continue
wnwenbdc444e2016-05-25 13:44:151792 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591793
1794 result = []
1795 if (warnings):
1796 result.append(output_api.PresubmitPromptWarning(
1797 'Banned functions were used.\n' + '\n'.join(warnings)))
1798 if (errors):
1799 result.append(output_api.PresubmitError(
1800 'Banned functions were used.\n' + '\n'.join(errors)))
1801 return result
1802
1803
Michael Thiessen44457642020-02-06 00:24:151804def _CheckAndroidNoBannedImports(input_api, output_api):
1805 """Make sure that banned java imports are not used."""
1806 errors = []
1807
1808 def IsException(path, exceptions):
1809 for exception in exceptions:
1810 if (path.startswith(exception)):
1811 return True
1812 return False
1813
1814 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1815 for f in input_api.AffectedFiles(file_filter=file_filter):
1816 for line_num, line in f.ChangedContents():
1817 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1818 if IsException(f.LocalPath(), exceptions):
1819 continue;
1820 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1821 'import ' + import_name, message)
1822 if problems:
1823 errors.extend(problems)
1824 result = []
1825 if (errors):
1826 result.append(output_api.PresubmitError(
1827 'Banned imports were used.\n' + '\n'.join(errors)))
1828 return result
1829
1830
Saagar Sanghavifceeaae2020-08-12 16:40:361831def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311832 """Make sure that old Mojo types are not used."""
1833 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571834 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311835
Mario Sanchez Pradaaab91382019-12-19 08:57:091836 # For any path that is not an "ok" or an "error" path, a warning will be
1837 # raised if deprecated mojo types are found.
1838 ok_paths = ['components/arc']
1839 error_paths = ['third_party/blink', 'content']
1840
Mario Sanchez Prada2472cab2019-09-18 10:58:311841 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1842 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571843 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091844 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311845 continue
1846
1847 for line_num, line in f.ChangedContents():
1848 for func_name, message in _DEPRECATED_MOJO_TYPES:
1849 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1850 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571851
Mario Sanchez Prada2472cab2019-09-18 10:58:311852 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091853 # Raise errors inside |error_paths| and warnings everywhere else.
1854 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571855 errors.extend(problems)
1856 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311857 warnings.extend(problems)
1858
1859 result = []
1860 if (warnings):
1861 result.append(output_api.PresubmitPromptWarning(
1862 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571863 if (errors):
1864 result.append(output_api.PresubmitError(
1865 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311866 return result
1867
1868
Saagar Sanghavifceeaae2020-08-12 16:40:361869def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061870 """Make sure that banned functions are not used."""
1871 files = []
1872 pattern = input_api.re.compile(r'^#pragma\s+once',
1873 input_api.re.MULTILINE)
1874 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1875 if not f.LocalPath().endswith('.h'):
1876 continue
1877 contents = input_api.ReadFile(f)
1878 if pattern.search(contents):
1879 files.append(f)
1880
1881 if files:
1882 return [output_api.PresubmitError(
1883 'Do not use #pragma once in header files.\n'
1884 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1885 files)]
1886 return []
1887
[email protected]127f18ec2012-06-16 05:05:591888
Saagar Sanghavifceeaae2020-08-12 16:40:361889def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121890 """Checks to make sure we don't introduce use of foo ? true : false."""
1891 problems = []
1892 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1893 for f in input_api.AffectedFiles():
1894 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1895 continue
1896
1897 for line_num, line in f.ChangedContents():
1898 if pattern.match(line):
1899 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1900
1901 if not problems:
1902 return []
1903 return [output_api.PresubmitPromptWarning(
1904 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1905 '\n'.join(problems))]
1906
1907
Saagar Sanghavifceeaae2020-08-12 16:40:361908def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281909 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181910 change. Breaking - rules is an error, breaking ! rules is a
1911 warning.
1912 """
mohan.reddyf21db962014-10-16 12:26:471913 import sys
[email protected]55f9f382012-07-31 11:02:181914 # We need to wait until we have an input_api object and use this
1915 # roundabout construct to import checkdeps because this file is
1916 # eval-ed and thus doesn't have __file__.
1917 original_sys_path = sys.path
1918 try:
1919 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471920 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181921 import checkdeps
[email protected]55f9f382012-07-31 11:02:181922 from rules import Rule
1923 finally:
1924 # Restore sys.path to what it was before.
1925 sys.path = original_sys_path
1926
1927 added_includes = []
rhalavati08acd232017-04-03 07:23:281928 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241929 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181930 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061931 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501932 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081933 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061934 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501935 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081936 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061937 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501938 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081939 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181940
[email protected]26385172013-05-09 23:11:351941 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181942
1943 error_descriptions = []
1944 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281945 error_subjects = set()
1946 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361947
[email protected]55f9f382012-07-31 11:02:181948 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1949 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081950 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181951 description_with_path = '%s\n %s' % (path, rule_description)
1952 if rule_type == Rule.DISALLOW:
1953 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281954 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181955 else:
1956 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281957 warning_subjects.add("#includes")
1958
1959 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1960 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081961 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281962 description_with_path = '%s\n %s' % (path, rule_description)
1963 if rule_type == Rule.DISALLOW:
1964 error_descriptions.append(description_with_path)
1965 error_subjects.add("imports")
1966 else:
1967 warning_descriptions.append(description_with_path)
1968 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181969
Jinsuk Kim5a092672017-10-24 22:42:241970 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021971 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081972 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241973 description_with_path = '%s\n %s' % (path, rule_description)
1974 if rule_type == Rule.DISALLOW:
1975 error_descriptions.append(description_with_path)
1976 error_subjects.add("imports")
1977 else:
1978 warning_descriptions.append(description_with_path)
1979 warning_subjects.add("imports")
1980
[email protected]55f9f382012-07-31 11:02:181981 results = []
1982 if error_descriptions:
1983 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281984 'You added one or more %s that violate checkdeps rules.'
1985 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181986 error_descriptions))
1987 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421988 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281989 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181990 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281991 '%s? See relevant DEPS file(s) for details and contacts.' %
1992 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181993 warning_descriptions))
1994 return results
1995
1996
Saagar Sanghavifceeaae2020-08-12 16:40:361997def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:221998 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151999 if input_api.platform == 'win32':
2000 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292001 checkperms_tool = input_api.os_path.join(
2002 input_api.PresubmitLocalPath(),
2003 'tools', 'checkperms', 'checkperms.py')
2004 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472005 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392006 with input_api.CreateTemporaryFile() as file_list:
2007 for f in input_api.AffectedFiles():
2008 # checkperms.py file/directory arguments must be relative to the
2009 # repository.
2010 file_list.write(f.LocalPath() + '\n')
2011 file_list.close()
2012 args += ['--file-list', file_list.name]
2013 try:
2014 input_api.subprocess.check_output(args)
2015 return []
2016 except input_api.subprocess.CalledProcessError as error:
2017 return [output_api.PresubmitError(
2018 'checkperms.py failed:',
2019 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222020
2021
Saagar Sanghavifceeaae2020-08-12 16:40:362022def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492023 """Makes sure we don't include ui/aura/window_property.h
2024 in header files.
2025 """
2026 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2027 errors = []
2028 for f in input_api.AffectedFiles():
2029 if not f.LocalPath().endswith('.h'):
2030 continue
2031 for line_num, line in f.ChangedContents():
2032 if pattern.match(line):
2033 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2034
2035 results = []
2036 if errors:
2037 results.append(output_api.PresubmitError(
2038 'Header files should not include ui/aura/window_property.h', errors))
2039 return results
2040
2041
[email protected]70ca77752012-11-20 03:45:032042def _CheckForVersionControlConflictsInFile(input_api, f):
2043 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2044 errors = []
2045 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162046 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232047 # First-level headers in markdown look a lot like version control
2048 # conflict markers. http://daringfireball.net/projects/markdown/basics
2049 continue
[email protected]70ca77752012-11-20 03:45:032050 if pattern.match(line):
2051 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2052 return errors
2053
2054
Saagar Sanghavifceeaae2020-08-12 16:40:362055def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032056 """Usually this is not intentional and will cause a compile failure."""
2057 errors = []
2058 for f in input_api.AffectedFiles():
2059 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2060
2061 results = []
2062 if errors:
2063 results.append(output_api.PresubmitError(
2064 'Version control conflict markers found, please resolve.', errors))
2065 return results
2066
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202067
Saagar Sanghavifceeaae2020-08-12 16:40:362068def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162069 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2070 errors = []
2071 for f in input_api.AffectedFiles():
2072 for line_num, line in f.ChangedContents():
2073 if pattern.search(line):
2074 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2075
2076 results = []
2077 if errors:
2078 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502079 'Found Google support URL addressed by answer number. Please replace '
2080 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162081 return results
2082
[email protected]70ca77752012-11-20 03:45:032083
Saagar Sanghavifceeaae2020-08-12 16:40:362084def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442085 def FilterFile(affected_file):
2086 """Filter function for use with input_api.AffectedSourceFiles,
2087 below. This filters out everything except non-test files from
2088 top-level directories that generally speaking should not hard-code
2089 service URLs (e.g. src/android_webview/, src/content/ and others).
2090 """
2091 return input_api.FilterSourceFile(
2092 affected_file,
James Cook24a504192020-07-23 00:08:442093 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2094 files_to_skip=(_EXCLUDED_PATHS +
2095 _TEST_CODE_EXCLUDED_PATHS +
2096 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442097
reillyi38965732015-11-16 18:27:332098 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2099 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462100 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2101 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442102 problems = [] # items are (filename, line_number, line)
2103 for f in input_api.AffectedSourceFiles(FilterFile):
2104 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462105 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442106 problems.append((f.LocalPath(), line_num, line))
2107
2108 if problems:
[email protected]f7051d52013-04-02 18:31:422109 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442110 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582111 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442112 [' %s:%d: %s' % (
2113 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032114 else:
2115 return []
[email protected]06e6d0ff2012-12-11 01:36:442116
2117
Saagar Sanghavifceeaae2020-08-12 16:40:362118def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292119 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2120 def FileFilter(affected_file):
2121 """Includes directories known to be Chrome OS only."""
2122 return input_api.FilterSourceFile(
2123 affected_file,
James Cook24a504192020-07-23 00:08:442124 files_to_check=('^ash/',
2125 '^chromeos/', # Top-level src/chromeos.
2126 '/chromeos/', # Any path component.
2127 '^components/arc',
2128 '^components/exo'),
2129 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292130
2131 prefs = []
2132 priority_prefs = []
2133 for f in input_api.AffectedFiles(file_filter=FileFilter):
2134 for line_num, line in f.ChangedContents():
2135 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2136 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2137 prefs.append(' %s' % line)
2138 if input_api.re.search(
2139 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2140 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2141 priority_prefs.append(' %s' % line)
2142
2143 results = []
2144 if (prefs):
2145 results.append(output_api.PresubmitPromptWarning(
2146 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2147 'by browser sync settings. If these prefs should be controlled by OS '
2148 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2149 if (priority_prefs):
2150 results.append(output_api.PresubmitPromptWarning(
2151 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2152 'controlled by browser sync settings. If these prefs should be '
2153 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2154 'instead.\n' + '\n'.join(prefs)))
2155 return results
2156
2157
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492158# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362159def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272160 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312161 The native_client_sdk directory is excluded because it has auto-generated PNG
2162 files for documentation.
[email protected]d2530012013-01-25 16:39:272163 """
[email protected]d2530012013-01-25 16:39:272164 errors = []
James Cook24a504192020-07-23 00:08:442165 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2166 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312167 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442168 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312169 for f in input_api.AffectedFiles(include_deletes=False,
2170 file_filter=file_filter):
2171 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272172
2173 results = []
2174 if errors:
2175 results.append(output_api.PresubmitError(
2176 'The name of PNG files should not have abbreviations. \n'
2177 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2178 'Contact [email protected] if you have questions.', errors))
2179 return results
2180
2181
Daniel Cheng4dcdb6b2017-04-13 08:30:172182def _ExtractAddRulesFromParsedDeps(parsed_deps):
2183 """Extract the rules that add dependencies from a parsed DEPS file.
2184
2185 Args:
2186 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2187 add_rules = set()
2188 add_rules.update([
2189 rule[1:] for rule in parsed_deps.get('include_rules', [])
2190 if rule.startswith('+') or rule.startswith('!')
2191 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502192 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172193 {}).iteritems():
2194 add_rules.update([
2195 rule[1:] for rule in rules
2196 if rule.startswith('+') or rule.startswith('!')
2197 ])
2198 return add_rules
2199
2200
2201def _ParseDeps(contents):
2202 """Simple helper for parsing DEPS files."""
2203 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172204 class _VarImpl:
2205
2206 def __init__(self, local_scope):
2207 self._local_scope = local_scope
2208
2209 def Lookup(self, var_name):
2210 """Implements the Var syntax."""
2211 try:
2212 return self._local_scope['vars'][var_name]
2213 except KeyError:
2214 raise Exception('Var is not defined: %s' % var_name)
2215
2216 local_scope = {}
2217 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172218 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592219 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172220 }
2221 exec contents in global_scope, local_scope
2222 return local_scope
2223
2224
2225def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592226 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412227 a set of DEPS entries that we should look up.
2228
2229 For a directory (rather than a specific filename) we fake a path to
2230 a specific filename by adding /DEPS. This is chosen as a file that
2231 will seldom or never be subject to per-file include_rules.
2232 """
[email protected]2b438d62013-11-14 17:54:142233 # We ignore deps entries on auto-generated directories.
2234 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082235
Daniel Cheng4dcdb6b2017-04-13 08:30:172236 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2237 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2238
2239 added_deps = new_deps.difference(old_deps)
2240
[email protected]2b438d62013-11-14 17:54:142241 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172242 for added_dep in added_deps:
2243 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2244 continue
2245 # Assume that a rule that ends in .h is a rule for a specific file.
2246 if added_dep.endswith('.h'):
2247 results.add(added_dep)
2248 else:
2249 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082250 return results
2251
2252
Saagar Sanghavifceeaae2020-08-12 16:40:362253def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552254 """When a dependency prefixed with + is added to a DEPS file, we
2255 want to make sure that the change is reviewed by an OWNER of the
2256 target file or directory, to avoid layering violations from being
2257 introduced. This check verifies that this happens.
2258 """
Joey Mou57048132021-02-26 22:17:552259 # We rely on Gerrit's code-owners to check approvals.
2260 # input_api.gerrit is always set for Chromium, but other projects
2261 # might not use Gerrit.
2262 if not input_api.gerrit:
2263 return []
Edward Lesmes44feb2332021-03-19 01:27:522264 if (input_api.change.issue and
2265 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232266 # Skip OWNERS check when Owners-Override label is approved. This is intended
2267 # for global owners, trusted bots, and on-call sheriffs. Review is still
2268 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522269 return []
Edward Lesmes6fba51082021-01-20 04:20:232270
Daniel Cheng4dcdb6b2017-04-13 08:30:172271 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242272
2273 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492274 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242275 for f in input_api.AffectedFiles(include_deletes=False,
2276 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552277 filename = input_api.os_path.basename(f.LocalPath())
2278 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172279 virtual_depended_on_files.update(_CalculateAddedDeps(
2280 input_api.os_path,
2281 '\n'.join(f.OldContents()),
2282 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552283
[email protected]e871964c2013-05-13 14:14:552284 if not virtual_depended_on_files:
2285 return []
2286
2287 if input_api.is_committing:
2288 if input_api.tbr:
2289 return [output_api.PresubmitNotifyResult(
2290 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272291 if input_api.dry_run:
2292 return [output_api.PresubmitNotifyResult(
2293 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552294 if not input_api.change.issue:
2295 return [output_api.PresubmitError(
2296 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402297 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552298 output = output_api.PresubmitError
2299 else:
2300 output = output_api.PresubmitNotifyResult
2301
tandriied3b7e12016-05-12 14:38:502302 owner_email, reviewers = (
2303 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2304 input_api,
Edward Lesmesa3846442021-02-08 20:20:032305 None,
tandriied3b7e12016-05-12 14:38:502306 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552307
2308 owner_email = owner_email or input_api.change.author_email
2309
Edward Lesmesa3846442021-02-08 20:20:032310 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2311 virtual_depended_on_files, reviewers.union([owner_email]), [])
2312 missing_files = [
2313 f for f in virtual_depended_on_files
2314 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412315
2316 # We strip the /DEPS part that was added by
2317 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2318 # directory.
2319 def StripDeps(path):
2320 start_deps = path.rfind('/DEPS')
2321 if start_deps != -1:
2322 return path[:start_deps]
2323 else:
2324 return path
2325 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552326 for path in missing_files]
2327
2328 if unapproved_dependencies:
2329 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152330 output('You need LGTM from owners of depends-on paths in DEPS that were '
2331 'modified in this CL:\n %s' %
2332 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032333 suggested_owners = input_api.owners_client.SuggestOwners(
2334 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152335 output_list.append(output(
2336 'Suggested missing target path OWNERS:\n %s' %
2337 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552338 return output_list
2339
2340 return []
2341
2342
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492343# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362344def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492345 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442346 files_to_skip = (_EXCLUDED_PATHS +
2347 _TEST_CODE_EXCLUDED_PATHS +
2348 input_api.DEFAULT_FILES_TO_SKIP +
2349 (r"^base[\\/]logging\.h$",
2350 r"^base[\\/]logging\.cc$",
2351 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2352 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2353 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2354 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2355 r"startup_browser_creator\.cc$",
2356 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2357 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2358 r"diagnostics_writer\.cc$",
2359 r"^chrome[\\/]chrome_cleaner[\\/].*",
2360 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2361 r"dll_hash_main\.cc$",
2362 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2363 r"^chromecast[\\/]",
2364 r"^cloud_print[\\/]",
2365 r"^components[\\/]browser_watcher[\\/]"
2366 r"dump_stability_report_main_win.cc$",
2367 r"^components[\\/]media_control[\\/]renderer[\\/]"
2368 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352369 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2370 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442371 r"^components[\\/]zucchini[\\/].*",
2372 # TODO(peter): Remove exception. https://crbug.com/534537
2373 r"^content[\\/]browser[\\/]notifications[\\/]"
2374 r"notification_event_dispatcher_impl\.cc$",
2375 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2376 r"gl_helper_benchmark\.cc$",
2377 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2378 r"^courgette[\\/]courgette_tool\.cc$",
2379 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2380 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2381 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi1d4c7ee2021-03-10 21:24:082382 # TODO(https://crbug.com/1181062): Temporary debugging.
Alexei Svitkine64505a92021-03-11 22:00:542383 r"^fuchsia[\\/]engine[\\/]renderer[\\/]"
2384 r"web_engine_render_frame_observer.cc$",
James Cook24a504192020-07-23 00:08:442385 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2386 r"^ipc[\\/]ipc_logging\.cc$",
2387 r"^native_client_sdk[\\/]",
2388 r"^remoting[\\/]base[\\/]logging\.h$",
2389 r"^remoting[\\/]host[\\/].*",
2390 r"^sandbox[\\/]linux[\\/].*",
2391 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2392 r"dump_file_system.cc$",
2393 r"^tools[\\/]",
2394 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2395 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2396 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2397 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2398 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402399 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442400 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402401
thomasanderson625d3932017-03-29 07:16:582402 log_info = set([])
2403 printf = set([])
[email protected]85218562013-11-22 07:41:402404
2405 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582406 for _, line in f.ChangedContents():
2407 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2408 log_info.add(f.LocalPath())
2409 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2410 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372411
thomasanderson625d3932017-03-29 07:16:582412 if input_api.re.search(r"\bprintf\(", line):
2413 printf.add(f.LocalPath())
2414 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2415 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402416
2417 if log_info:
2418 return [output_api.PresubmitError(
2419 'These files spam the console log with LOG(INFO):',
2420 items=log_info)]
2421 if printf:
2422 return [output_api.PresubmitError(
2423 'These files spam the console log with printf/fprintf:',
2424 items=printf)]
2425 return []
2426
2427
Saagar Sanghavifceeaae2020-08-12 16:40:362428def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162429 """These types are all expected to hold locks while in scope and
2430 so should never be anonymous (which causes them to be immediately
2431 destroyed)."""
2432 they_who_must_be_named = [
2433 'base::AutoLock',
2434 'base::AutoReset',
2435 'base::AutoUnlock',
2436 'SkAutoAlphaRestore',
2437 'SkAutoBitmapShaderInstall',
2438 'SkAutoBlitterChoose',
2439 'SkAutoBounderCommit',
2440 'SkAutoCallProc',
2441 'SkAutoCanvasRestore',
2442 'SkAutoCommentBlock',
2443 'SkAutoDescriptor',
2444 'SkAutoDisableDirectionCheck',
2445 'SkAutoDisableOvalCheck',
2446 'SkAutoFree',
2447 'SkAutoGlyphCache',
2448 'SkAutoHDC',
2449 'SkAutoLockColors',
2450 'SkAutoLockPixels',
2451 'SkAutoMalloc',
2452 'SkAutoMaskFreeImage',
2453 'SkAutoMutexAcquire',
2454 'SkAutoPathBoundsUpdate',
2455 'SkAutoPDFRelease',
2456 'SkAutoRasterClipValidate',
2457 'SkAutoRef',
2458 'SkAutoTime',
2459 'SkAutoTrace',
2460 'SkAutoUnref',
2461 ]
2462 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2463 # bad: base::AutoLock(lock.get());
2464 # not bad: base::AutoLock lock(lock.get());
2465 bad_pattern = input_api.re.compile(anonymous)
2466 # good: new base::AutoLock(lock.get())
2467 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2468 errors = []
2469
2470 for f in input_api.AffectedFiles():
2471 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2472 continue
2473 for linenum, line in f.ChangedContents():
2474 if bad_pattern.search(line) and not good_pattern.search(line):
2475 errors.append('%s:%d' % (f.LocalPath(), linenum))
2476
2477 if errors:
2478 return [output_api.PresubmitError(
2479 'These lines create anonymous variables that need to be named:',
2480 items=errors)]
2481 return []
2482
2483
Saagar Sanghavifceeaae2020-08-12 16:40:362484def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532485 # Returns whether |template_str| is of the form <T, U...> for some types T
2486 # and U. Assumes that |template_str| is already in the form <...>.
2487 def HasMoreThanOneArg(template_str):
2488 # Level of <...> nesting.
2489 nesting = 0
2490 for c in template_str:
2491 if c == '<':
2492 nesting += 1
2493 elif c == '>':
2494 nesting -= 1
2495 elif c == ',' and nesting == 1:
2496 return True
2497 return False
2498
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492499 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102500 sources = lambda affected_file: input_api.FilterSourceFile(
2501 affected_file,
James Cook24a504192020-07-23 00:08:442502 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2503 input_api.DEFAULT_FILES_TO_SKIP),
2504 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552505
2506 # Pattern to capture a single "<...>" block of template arguments. It can
2507 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2508 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2509 # latter would likely require counting that < and > match, which is not
2510 # expressible in regular languages. Should the need arise, one can introduce
2511 # limited counting (matching up to a total number of nesting depth), which
2512 # should cover all practical cases for already a low nesting limit.
2513 template_arg_pattern = (
2514 r'<[^>]*' # Opening block of <.
2515 r'>([^<]*>)?') # Closing block of >.
2516 # Prefix expressing that whatever follows is not already inside a <...>
2517 # block.
2518 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102519 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552520 not_inside_template_arg_pattern
2521 + r'\bstd::unique_ptr'
2522 + template_arg_pattern
2523 + r'\(\)')
2524
2525 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2526 template_arg_no_array_pattern = (
2527 r'<[^>]*[^]]' # Opening block of <.
2528 r'>([^(<]*[^]]>)?') # Closing block of >.
2529 # Prefix saying that what follows is the start of an expression.
2530 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2531 # Suffix saying that what follows are call parentheses with a non-empty list
2532 # of arguments.
2533 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532534 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552535 return_construct_pattern = input_api.re.compile(
2536 start_of_expr_pattern
2537 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532538 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552539 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532540 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552541 + nonempty_arg_list_pattern)
2542
Vaclav Brozek851d9602018-04-04 16:13:052543 problems_constructor = []
2544 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102545 for f in input_api.AffectedSourceFiles(sources):
2546 for line_number, line in f.ChangedContents():
2547 # Disallow:
2548 # return std::unique_ptr<T>(foo);
2549 # bar = std::unique_ptr<T>(foo);
2550 # But allow:
2551 # return std::unique_ptr<T[]>(foo);
2552 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532553 # And also allow cases when the second template argument is present. Those
2554 # cases cannot be handled by std::make_unique:
2555 # return std::unique_ptr<T, U>(foo);
2556 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052557 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532558 return_construct_result = return_construct_pattern.search(line)
2559 if return_construct_result and not HasMoreThanOneArg(
2560 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052561 problems_constructor.append(
2562 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102563 # Disallow:
2564 # std::unique_ptr<T>()
2565 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052566 problems_nullptr.append(
2567 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2568
2569 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162570 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052571 errors.append(output_api.PresubmitError(
2572 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162573 problems_nullptr))
2574 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052575 errors.append(output_api.PresubmitError(
2576 'The following files use explicit std::unique_ptr constructor.'
2577 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162578 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102579 return errors
2580
2581
Saagar Sanghavifceeaae2020-08-12 16:40:362582def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082583 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522584 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082585 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522586 # If actions.xml is already included in the changelist, the PRESUBMIT
2587 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082588 return []
2589
Alexei Svitkine64505a92021-03-11 22:00:542590 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2591 files_to_skip = (_EXCLUDED_PATHS +
2592 _TEST_CODE_EXCLUDED_PATHS +
2593 input_api.DEFAULT_FILES_TO_SKIP )
2594 file_filter = lambda f: input_api.FilterSourceFile(
2595 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2596
[email protected]999261d2014-03-03 20:08:082597 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522598 current_actions = None
[email protected]999261d2014-03-03 20:08:082599 for f in input_api.AffectedFiles(file_filter=file_filter):
2600 for line_num, line in f.ChangedContents():
2601 match = input_api.re.search(action_re, line)
2602 if match:
[email protected]2f92dec2014-03-07 19:21:522603 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2604 # loaded only once.
2605 if not current_actions:
2606 with open('tools/metrics/actions/actions.xml') as actions_f:
2607 current_actions = actions_f.read()
2608 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082609 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522610 action = 'name="{0}"'.format(action_name)
2611 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082612 return [output_api.PresubmitPromptWarning(
2613 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522614 'tools/metrics/actions/actions.xml. Please run '
2615 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082616 % (f.LocalPath(), line_num, action_name))]
2617 return []
2618
2619
Daniel Cheng13ca61a882017-08-25 15:11:252620def _ImportJSONCommentEater(input_api):
2621 import sys
2622 sys.path = sys.path + [input_api.os_path.join(
2623 input_api.PresubmitLocalPath(),
2624 'tools', 'json_comment_eater')]
2625 import json_comment_eater
2626 return json_comment_eater
2627
2628
[email protected]99171a92014-06-03 08:44:472629def _GetJSONParseError(input_api, filename, eat_comments=True):
2630 try:
2631 contents = input_api.ReadFile(filename)
2632 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252633 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132634 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472635
2636 input_api.json.loads(contents)
2637 except ValueError as e:
2638 return e
2639 return None
2640
2641
2642def _GetIDLParseError(input_api, filename):
2643 try:
2644 contents = input_api.ReadFile(filename)
2645 idl_schema = input_api.os_path.join(
2646 input_api.PresubmitLocalPath(),
2647 'tools', 'json_schema_compiler', 'idl_schema.py')
2648 process = input_api.subprocess.Popen(
2649 [input_api.python_executable, idl_schema],
2650 stdin=input_api.subprocess.PIPE,
2651 stdout=input_api.subprocess.PIPE,
2652 stderr=input_api.subprocess.PIPE,
2653 universal_newlines=True)
2654 (_, error) = process.communicate(input=contents)
2655 return error or None
2656 except ValueError as e:
2657 return e
2658
2659
Saagar Sanghavifceeaae2020-08-12 16:40:362660def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472661 """Check that IDL and JSON files do not contain syntax errors."""
2662 actions = {
2663 '.idl': _GetIDLParseError,
2664 '.json': _GetJSONParseError,
2665 }
[email protected]99171a92014-06-03 08:44:472666 # Most JSON files are preprocessed and support comments, but these do not.
2667 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042668 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472669 ]
2670 # Only run IDL checker on files in these directories.
2671 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042672 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2673 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472674 ]
2675
2676 def get_action(affected_file):
2677 filename = affected_file.LocalPath()
2678 return actions.get(input_api.os_path.splitext(filename)[1])
2679
[email protected]99171a92014-06-03 08:44:472680 def FilterFile(affected_file):
2681 action = get_action(affected_file)
2682 if not action:
2683 return False
2684 path = affected_file.LocalPath()
2685
Erik Staab2dd72b12020-04-16 15:03:402686 if _MatchesFile(input_api,
2687 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2688 path):
[email protected]99171a92014-06-03 08:44:472689 return False
2690
2691 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162692 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472693 return False
2694 return True
2695
2696 results = []
2697 for affected_file in input_api.AffectedFiles(
2698 file_filter=FilterFile, include_deletes=False):
2699 action = get_action(affected_file)
2700 kwargs = {}
2701 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162702 _MatchesFile(input_api, json_no_comments_patterns,
2703 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472704 kwargs['eat_comments'] = False
2705 parse_error = action(input_api,
2706 affected_file.AbsoluteLocalPath(),
2707 **kwargs)
2708 if parse_error:
2709 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2710 (affected_file.LocalPath(), parse_error)))
2711 return results
2712
2713
Saagar Sanghavifceeaae2020-08-12 16:40:362714def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492715 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472716 import sys
[email protected]760deea2013-12-10 19:33:492717 original_sys_path = sys.path
2718 try:
2719 sys.path = sys.path + [input_api.os_path.join(
2720 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2721 import checkstyle
2722 finally:
2723 # Restore sys.path to what it was before.
2724 sys.path = original_sys_path
2725
2726 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092727 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442728 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492729
2730
Saagar Sanghavifceeaae2020-08-12 16:40:362731def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002732 """Checks to make sure devil is initialized correctly in python scripts."""
2733 script_common_initialize_pattern = input_api.re.compile(
2734 r'script_common\.InitializeEnvironment\(')
2735 devil_env_config_initialize = input_api.re.compile(
2736 r'devil_env\.config\.Initialize\(')
2737
2738 errors = []
2739
2740 sources = lambda affected_file: input_api.FilterSourceFile(
2741 affected_file,
James Cook24a504192020-07-23 00:08:442742 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2743 (r'^build[\\/]android[\\/]devil_chromium\.py',
2744 r'^third_party[\\/].*',)),
2745 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002746
2747 for f in input_api.AffectedSourceFiles(sources):
2748 for line_num, line in f.ChangedContents():
2749 if (script_common_initialize_pattern.search(line) or
2750 devil_env_config_initialize.search(line)):
2751 errors.append("%s:%d" % (f.LocalPath(), line_num))
2752
2753 results = []
2754
2755 if errors:
2756 results.append(output_api.PresubmitError(
2757 'Devil initialization should always be done using '
2758 'devil_chromium.Initialize() in the chromium project, to use better '
2759 'defaults for dependencies (ex. up-to-date version of adb).',
2760 errors))
2761
2762 return results
2763
2764
Sean Kau46e29bc2017-08-28 16:31:162765def _MatchesFile(input_api, patterns, path):
2766 for pattern in patterns:
2767 if input_api.re.search(pattern, path):
2768 return True
2769 return False
2770
2771
Daniel Cheng7052cdf2017-11-21 19:23:292772def _GetOwnersFilesToCheckForIpcOwners(input_api):
2773 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172774
Daniel Cheng7052cdf2017-11-21 19:23:292775 Returns:
2776 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2777 contain to cover IPC-related files with noparent reviewer rules.
2778 """
2779 # Whether or not a file affects IPC is (mostly) determined by a simple list
2780 # of filename patterns.
dchenge07de812016-06-20 19:27:172781 file_patterns = [
palmerb19a0932017-01-24 04:00:312782 # Legacy IPC:
dchenge07de812016-06-20 19:27:172783 '*_messages.cc',
2784 '*_messages*.h',
2785 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312786 # Mojo IPC:
dchenge07de812016-06-20 19:27:172787 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472788 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172789 '*_struct_traits*.*',
2790 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312791 '*.typemap',
2792 # Android native IPC:
2793 '*.aidl',
2794 # Blink uses a different file naming convention:
2795 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472796 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172797 '*StructTraits*.*',
2798 '*TypeConverter*.*',
2799 ]
2800
scottmg7a6ed5ba2016-11-04 18:22:042801 # These third_party directories do not contain IPCs, but contain files
2802 # matching the above patterns, which trigger false positives.
2803 exclude_paths = [
2804 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162805 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232806 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292807 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542808 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162809 # These files are just used to communicate between class loaders running
2810 # in the same process.
2811 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572812 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2813
scottmg7a6ed5ba2016-11-04 18:22:042814 ]
2815
dchenge07de812016-06-20 19:27:172816 # Dictionary mapping an OWNERS file path to Patterns.
2817 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2818 # rules ) to a PatternEntry.
2819 # PatternEntry is a dictionary with two keys:
2820 # - 'files': the files that are matched by this pattern
2821 # - 'rules': the per-file rules needed for this pattern
2822 # For example, if we expect OWNERS file to contain rules for *.mojom and
2823 # *_struct_traits*.*, Patterns might look like this:
2824 # {
2825 # '*.mojom': {
2826 # 'files': ...,
2827 # 'rules': [
2828 # 'per-file *.mojom=set noparent',
2829 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2830 # ],
2831 # },
2832 # '*_struct_traits*.*': {
2833 # 'files': ...,
2834 # 'rules': [
2835 # 'per-file *_struct_traits*.*=set noparent',
2836 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2837 # ],
2838 # },
2839 # }
2840 to_check = {}
2841
Daniel Cheng13ca61a882017-08-25 15:11:252842 def AddPatternToCheck(input_file, pattern):
2843 owners_file = input_api.os_path.join(
2844 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2845 if owners_file not in to_check:
2846 to_check[owners_file] = {}
2847 if pattern not in to_check[owners_file]:
2848 to_check[owners_file][pattern] = {
2849 'files': [],
2850 'rules': [
2851 'per-file %s=set noparent' % pattern,
2852 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2853 ]
2854 }
Vaclav Brozekd5de76a2018-03-17 07:57:502855 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252856
dchenge07de812016-06-20 19:27:172857 # Iterate through the affected files to see what we actually need to check
2858 # for. We should only nag patch authors about per-file rules if a file in that
2859 # directory would match that pattern. If a directory only contains *.mojom
2860 # files and no *_messages*.h files, we should only nag about rules for
2861 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252862 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262863 # Manifest files don't have a strong naming convention. Instead, try to find
2864 # affected .cc and .h files which look like they contain a manifest
2865 # definition.
2866 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2867 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2868 if (manifest_pattern.search(f.LocalPath()) and not
2869 test_manifest_pattern.search(f.LocalPath())):
2870 # We expect all actual service manifest files to contain at least one
2871 # qualified reference to service_manager::Manifest.
2872 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252873 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172874 for pattern in file_patterns:
2875 if input_api.fnmatch.fnmatch(
2876 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042877 skip = False
2878 for exclude in exclude_paths:
2879 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2880 skip = True
2881 break
2882 if skip:
2883 continue
Daniel Cheng13ca61a882017-08-25 15:11:252884 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172885 break
2886
Daniel Cheng7052cdf2017-11-21 19:23:292887 return to_check
2888
2889
Wez17c66962020-04-29 15:26:032890def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2891 """Adds OWNERS files to check for correct Fuchsia security owners."""
2892
2893 file_patterns = [
2894 # Component specifications.
2895 '*.cml', # Component Framework v2.
2896 '*.cmx', # Component Framework v1.
2897
2898 # Fuchsia IDL protocol specifications.
2899 '*.fidl',
2900 ]
2901
Joshua Peraza1ca6d392020-12-08 00:14:092902 # Don't check for owners files for changes in these directories.
2903 exclude_paths = [
2904 'third_party/crashpad/*',
2905 ]
2906
Wez17c66962020-04-29 15:26:032907 def AddPatternToCheck(input_file, pattern):
2908 owners_file = input_api.os_path.join(
2909 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2910 if owners_file not in to_check:
2911 to_check[owners_file] = {}
2912 if pattern not in to_check[owners_file]:
2913 to_check[owners_file][pattern] = {
2914 'files': [],
2915 'rules': [
2916 'per-file %s=set noparent' % pattern,
2917 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2918 ]
2919 }
2920 to_check[owners_file][pattern]['files'].append(input_file)
2921
2922 # Iterate through the affected files to see what we actually need to check
2923 # for. We should only nag patch authors about per-file rules if a file in that
2924 # directory would match that pattern.
2925 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092926 skip = False
2927 for exclude in exclude_paths:
2928 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2929 skip = True
2930 if skip:
2931 continue
2932
Wez17c66962020-04-29 15:26:032933 for pattern in file_patterns:
2934 if input_api.fnmatch.fnmatch(
2935 input_api.os_path.basename(f.LocalPath()), pattern):
2936 AddPatternToCheck(f, pattern)
2937 break
2938
2939 return to_check
2940
2941
Saagar Sanghavifceeaae2020-08-12 16:40:362942def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292943 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2944 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032945 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292946
2947 if to_check:
2948 # If there are any OWNERS files to check, there are IPC-related changes in
2949 # this CL. Auto-CC the review list.
2950 output_api.AppendCC('[email protected]')
2951
2952 # Go through the OWNERS files to check, filtering out rules that are already
2953 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172954 for owners_file, patterns in to_check.iteritems():
2955 try:
2956 with file(owners_file) as f:
2957 lines = set(f.read().splitlines())
2958 for entry in patterns.itervalues():
2959 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2960 ]
2961 except IOError:
2962 # No OWNERS file, so all the rules are definitely missing.
2963 continue
2964
2965 # All the remaining lines weren't found in OWNERS files, so emit an error.
2966 errors = []
2967 for owners_file, patterns in to_check.iteritems():
2968 missing_lines = []
2969 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502970 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172971 missing_lines.extend(entry['rules'])
2972 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2973 if missing_lines:
2974 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052975 'Because of the presence of files:\n%s\n\n'
2976 '%s needs the following %d lines added:\n\n%s' %
2977 ('\n'.join(files), owners_file, len(missing_lines),
2978 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172979
2980 results = []
2981 if errors:
vabrf5ce3bf92016-07-11 14:52:412982 if input_api.is_committing:
2983 output = output_api.PresubmitError
2984 else:
2985 output = output_api.PresubmitPromptWarning
2986 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592987 'Found OWNERS files that need to be updated for IPC security ' +
2988 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172989 long_text='\n\n'.join(errors)))
2990
2991 return results
2992
2993
Robert Sesek2c905332020-05-06 23:17:132994def _GetFilesUsingSecurityCriticalFunctions(input_api):
2995 """Checks affected files for changes to security-critical calls. This
2996 function checks the full change diff, to catch both additions/changes
2997 and removals.
2998
2999 Returns a dict keyed by file name, and the value is a set of detected
3000 functions.
3001 """
3002 # Map of function pretty name (displayed in an error) to the pattern to
3003 # match it with.
3004 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373005 'content::GetServiceSandboxType<>()':
3006 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133007 }
3008 _PATTERNS_TO_CHECK = {
3009 k: input_api.re.compile(v)
3010 for k, v in _PATTERNS_TO_CHECK.items()
3011 }
3012
3013 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3014 files_to_functions = {}
3015 for f in input_api.AffectedFiles():
3016 diff = f.GenerateScmDiff()
3017 for line in diff.split('\n'):
3018 # Not using just RightHandSideLines() because removing a
3019 # call to a security-critical function can be just as important
3020 # as adding or changing the arguments.
3021 if line.startswith('-') or (line.startswith('+') and
3022 not line.startswith('++')):
3023 for name, pattern in _PATTERNS_TO_CHECK.items():
3024 if pattern.search(line):
3025 path = f.LocalPath()
3026 if not path in files_to_functions:
3027 files_to_functions[path] = set()
3028 files_to_functions[path].add(name)
3029 return files_to_functions
3030
3031
Saagar Sanghavifceeaae2020-08-12 16:40:363032def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133033 """Checks that changes involving security-critical functions are reviewed
3034 by the security team.
3035 """
3036 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:123037 if not len(files_to_functions):
3038 return []
Robert Sesek2c905332020-05-06 23:17:133039
Edward Lesmes1e9fade2021-02-08 20:31:123040 owner_email, reviewers = (
3041 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3042 input_api,
3043 None,
3044 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:133045
Edward Lesmes1e9fade2021-02-08 20:31:123046 # Load the OWNERS file for security changes.
3047 owners_file = 'ipc/SECURITY_OWNERS'
3048 security_owners = input_api.owners_client.ListOwners(owners_file)
3049 has_security_owner = any([owner in reviewers for owner in security_owners])
3050 if has_security_owner:
3051 return []
Robert Sesek2c905332020-05-06 23:17:133052
Edward Lesmes1e9fade2021-02-08 20:31:123053 msg = 'The following files change calls to security-sensive functions\n' \
3054 'that need to be reviewed by {}.\n'.format(owners_file)
3055 for path, names in files_to_functions.items():
3056 msg += ' {}\n'.format(path)
3057 for name in names:
3058 msg += ' {}\n'.format(name)
3059 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133060
Edward Lesmes1e9fade2021-02-08 20:31:123061 if input_api.is_committing:
3062 output = output_api.PresubmitError
3063 else:
3064 output = output_api.PresubmitNotifyResult
3065 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133066
3067
Saagar Sanghavifceeaae2020-08-12 16:40:363068def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263069 """Checks that set noparent is only used together with an OWNERS file in
3070 //build/OWNERS.setnoparent (see also
3071 //docs/code_reviews.md#owners-files-details)
3072 """
3073 errors = []
3074
3075 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3076 allowed_owners_files = set()
3077 with open(allowed_owners_files_file, 'r') as f:
3078 for line in f:
3079 line = line.strip()
3080 if not line or line.startswith('#'):
3081 continue
3082 allowed_owners_files.add(line)
3083
3084 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3085
3086 for f in input_api.AffectedFiles(include_deletes=False):
3087 if not f.LocalPath().endswith('OWNERS'):
3088 continue
3089
3090 found_owners_files = set()
3091 found_set_noparent_lines = dict()
3092
3093 # Parse the OWNERS file.
3094 for lineno, line in enumerate(f.NewContents(), 1):
3095 line = line.strip()
3096 if line.startswith('set noparent'):
3097 found_set_noparent_lines[''] = lineno
3098 if line.startswith('file://'):
3099 if line in allowed_owners_files:
3100 found_owners_files.add('')
3101 if line.startswith('per-file'):
3102 match = per_file_pattern.match(line)
3103 if match:
3104 glob = match.group(1).strip()
3105 directive = match.group(2).strip()
3106 if directive == 'set noparent':
3107 found_set_noparent_lines[glob] = lineno
3108 if directive.startswith('file://'):
3109 if directive in allowed_owners_files:
3110 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153111
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263112 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403113 # listed in build/OWNERS.setnoparent. An exception is made for top level
3114 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143115 if (f.LocalPath().count('/') != 1 and
3116 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403117 for set_noparent_line in found_set_noparent_lines:
3118 if set_noparent_line in found_owners_files:
3119 continue
3120 errors.append(' %s:%d' % (f.LocalPath(),
3121 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263122
3123 results = []
3124 if errors:
3125 if input_api.is_committing:
3126 output = output_api.PresubmitError
3127 else:
3128 output = output_api.PresubmitPromptWarning
3129 results.append(output(
3130 'Found the following "set noparent" restrictions in OWNERS files that '
3131 'do not include owners from build/OWNERS.setnoparent:',
3132 long_text='\n\n'.join(errors)))
3133 return results
3134
3135
Saagar Sanghavifceeaae2020-08-12 16:40:363136def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313137 """Checks that added or removed lines in non third party affected
3138 header files do not lead to new useless class or struct forward
3139 declaration.
jbriance9e12f162016-11-25 07:57:503140 """
3141 results = []
3142 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3143 input_api.re.MULTILINE)
3144 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3145 input_api.re.MULTILINE)
3146 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313147 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193148 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493149 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313150 continue
3151
jbriance9e12f162016-11-25 07:57:503152 if not f.LocalPath().endswith('.h'):
3153 continue
3154
3155 contents = input_api.ReadFile(f)
3156 fwd_decls = input_api.re.findall(class_pattern, contents)
3157 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3158
3159 useless_fwd_decls = []
3160 for decl in fwd_decls:
3161 count = sum(1 for _ in input_api.re.finditer(
3162 r'\b%s\b' % input_api.re.escape(decl), contents))
3163 if count == 1:
3164 useless_fwd_decls.append(decl)
3165
3166 if not useless_fwd_decls:
3167 continue
3168
3169 for line in f.GenerateScmDiff().splitlines():
3170 if (line.startswith('-') and not line.startswith('--') or
3171 line.startswith('+') and not line.startswith('++')):
3172 for decl in useless_fwd_decls:
3173 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3174 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243175 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503176 (f.LocalPath(), decl)))
3177 useless_fwd_decls.remove(decl)
3178
3179 return results
3180
Jinsong Fan91ebbbd2019-04-16 14:57:173181def _CheckAndroidDebuggableBuild(input_api, output_api):
3182 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3183 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3184 this is a debuggable build of Android.
3185 """
3186 build_type_check_pattern = input_api.re.compile(
3187 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3188
3189 errors = []
3190
3191 sources = lambda affected_file: input_api.FilterSourceFile(
3192 affected_file,
James Cook24a504192020-07-23 00:08:443193 files_to_skip=(_EXCLUDED_PATHS +
3194 _TEST_CODE_EXCLUDED_PATHS +
3195 input_api.DEFAULT_FILES_TO_SKIP +
3196 (r"^android_webview[\\/]support_library[\\/]"
3197 "boundary_interfaces[\\/]",
3198 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3199 r'^third_party[\\/].*',
3200 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3201 r"webview[\\/]chromium[\\/]License.*",)),
3202 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173203
3204 for f in input_api.AffectedSourceFiles(sources):
3205 for line_num, line in f.ChangedContents():
3206 if build_type_check_pattern.search(line):
3207 errors.append("%s:%d" % (f.LocalPath(), line_num))
3208
3209 results = []
3210
3211 if errors:
3212 results.append(output_api.PresubmitPromptWarning(
3213 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3214 ' Please use BuildInfo.isDebugAndroid() instead.',
3215 errors))
3216
3217 return results
jbriance9e12f162016-11-25 07:57:503218
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493219# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293220def _CheckAndroidToastUsage(input_api, output_api):
3221 """Checks that code uses org.chromium.ui.widget.Toast instead of
3222 android.widget.Toast (Chromium Toast doesn't force hardware
3223 acceleration on low-end devices, saving memory).
3224 """
3225 toast_import_pattern = input_api.re.compile(
3226 r'^import android\.widget\.Toast;$')
3227
3228 errors = []
3229
3230 sources = lambda affected_file: input_api.FilterSourceFile(
3231 affected_file,
James Cook24a504192020-07-23 00:08:443232 files_to_skip=(_EXCLUDED_PATHS +
3233 _TEST_CODE_EXCLUDED_PATHS +
3234 input_api.DEFAULT_FILES_TO_SKIP +
3235 (r'^chromecast[\\/].*',
3236 r'^remoting[\\/].*')),
3237 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293238
3239 for f in input_api.AffectedSourceFiles(sources):
3240 for line_num, line in f.ChangedContents():
3241 if toast_import_pattern.search(line):
3242 errors.append("%s:%d" % (f.LocalPath(), line_num))
3243
3244 results = []
3245
3246 if errors:
3247 results.append(output_api.PresubmitError(
3248 'android.widget.Toast usage is detected. Android toasts use hardware'
3249 ' acceleration, and can be\ncostly on low-end devices. Please use'
3250 ' org.chromium.ui.widget.Toast instead.\n'
3251 'Contact [email protected] if you have any questions.',
3252 errors))
3253
3254 return results
3255
3256
dgnaa68d5e2015-06-10 10:08:223257def _CheckAndroidCrLogUsage(input_api, output_api):
3258 """Checks that new logs using org.chromium.base.Log:
3259 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513260 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223261 """
pkotwicza1dd0b002016-05-16 14:41:043262
torne89540622017-03-24 19:41:303263 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043264 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303265 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043266 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303267 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043268 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3269 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093270 # The customtabs_benchmark is a small app that does not depend on Chromium
3271 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043272 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043273 ]
3274
dgnaa68d5e2015-06-10 10:08:223275 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123276 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3277 class_in_base_pattern = input_api.re.compile(
3278 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3279 has_some_log_import_pattern = input_api.re.compile(
3280 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223281 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553282 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223283 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463284 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553285 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223286
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463287 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443288 sources = lambda x: input_api.FilterSourceFile(x,
3289 files_to_check=[r'.*\.java$'],
3290 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123291
dgnaa68d5e2015-06-10 10:08:223292 tag_decl_errors = []
3293 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123294 tag_errors = []
dgn38736db2015-09-18 19:20:513295 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123296 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223297
3298 for f in input_api.AffectedSourceFiles(sources):
3299 file_content = input_api.ReadFile(f)
3300 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223301 # Per line checks
dgn87d9fb62015-06-12 09:15:123302 if (cr_log_import_pattern.search(file_content) or
3303 (class_in_base_pattern.search(file_content) and
3304 not has_some_log_import_pattern.search(file_content))):
3305 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223306 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553307 if rough_log_decl_pattern.search(line):
3308 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223309
3310 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123311 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223312 if match:
3313 has_modified_logs = True
3314
3315 # Make sure it uses "TAG"
3316 if not match.group('tag') == 'TAG':
3317 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123318 else:
3319 # Report non cr Log function calls in changed lines
3320 for line_num, line in f.ChangedContents():
3321 if log_call_pattern.search(line):
3322 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223323
3324 # Per file checks
3325 if has_modified_logs:
3326 # Make sure the tag is using the "cr" prefix and is not too long
3327 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513328 tag_name = match.group('name') if match else None
3329 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223330 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513331 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223332 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513333 elif '.' in tag_name:
3334 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223335
3336 results = []
3337 if tag_decl_errors:
3338 results.append(output_api.PresubmitPromptWarning(
3339 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513340 '"private static final String TAG = "<package tag>".\n'
3341 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223342 tag_decl_errors))
3343
3344 if tag_length_errors:
3345 results.append(output_api.PresubmitError(
3346 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513347 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223348 tag_length_errors))
3349
3350 if tag_errors:
3351 results.append(output_api.PresubmitPromptWarning(
3352 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3353 tag_errors))
3354
dgn87d9fb62015-06-12 09:15:123355 if util_log_errors:
dgn4401aa52015-04-29 16:26:173356 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123357 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3358 util_log_errors))
3359
dgn38736db2015-09-18 19:20:513360 if tag_with_dot_errors:
3361 results.append(output_api.PresubmitPromptWarning(
3362 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3363 tag_with_dot_errors))
3364
dgn4401aa52015-04-29 16:26:173365 return results
3366
3367
Yoland Yanb92fa522017-08-28 17:37:063368def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3369 """Checks that junit.framework.* is no longer used."""
3370 deprecated_junit_framework_pattern = input_api.re.compile(
3371 r'^import junit\.framework\..*;',
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)
Yoland Yanb92fa522017-08-28 17:37:063375 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133376 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063377 for line_num, line in f.ChangedContents():
3378 if deprecated_junit_framework_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 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3385 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3386 ' if you have any question.', errors))
3387 return results
3388
3389
3390def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3391 """Checks that if new Java test classes have inheritance.
3392 Either the new test class is JUnit3 test or it is a JUnit4 test class
3393 with a base class, either case is undesirable.
3394 """
3395 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3396
3397 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443398 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063399 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133400 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063401 if not f.OldContents():
3402 class_declaration_start_flag = False
3403 for line_num, line in f.ChangedContents():
3404 if class_declaration_pattern.search(line):
3405 class_declaration_start_flag = True
3406 if class_declaration_start_flag and ' extends ' in line:
3407 errors.append('%s:%d' % (f.LocalPath(), line_num))
3408 if '{' in line:
3409 class_declaration_start_flag = False
3410
3411 results = []
3412 if errors:
3413 results.append(output_api.PresubmitPromptWarning(
3414 'The newly created files include Test classes that inherits from base'
3415 ' class. Please do not use inheritance in JUnit4 tests or add new'
3416 ' JUnit3 tests. Contact [email protected] if you have any'
3417 ' questions.', errors))
3418 return results
3419
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203420
yolandyan45001472016-12-21 21:12:423421def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3422 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3423 deprecated_annotation_import_pattern = input_api.re.compile(
3424 r'^import android\.test\.suitebuilder\.annotation\..*;',
3425 input_api.re.MULTILINE)
3426 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443427 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423428 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133429 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423430 for line_num, line in f.ChangedContents():
3431 if deprecated_annotation_import_pattern.search(line):
3432 errors.append("%s:%d" % (f.LocalPath(), line_num))
3433
3434 results = []
3435 if errors:
3436 results.append(output_api.PresubmitError(
3437 'Annotations in android.test.suitebuilder.annotation have been'
3438 ' deprecated since API level 24. Please use android.support.test.filters'
3439 ' from //third_party/android_support_test_runner:runner_java instead.'
3440 ' Contact [email protected] if you have any questions.', errors))
3441 return results
3442
3443
agrieve7b6479d82015-10-07 14:24:223444def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3445 """Checks if MDPI assets are placed in a correct directory."""
3446 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3447 ('/res/drawable/' in f.LocalPath() or
3448 '/res/drawable-ldrtl/' in f.LocalPath()))
3449 errors = []
3450 for f in input_api.AffectedFiles(include_deletes=False,
3451 file_filter=file_filter):
3452 errors.append(' %s' % f.LocalPath())
3453
3454 results = []
3455 if errors:
3456 results.append(output_api.PresubmitError(
3457 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3458 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3459 '/res/drawable-ldrtl/.\n'
3460 'Contact [email protected] if you have questions.', errors))
3461 return results
3462
3463
Nate Fischer535972b2017-09-16 01:06:183464def _CheckAndroidWebkitImports(input_api, output_api):
3465 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353466 android.webview.ValueCallback except in the WebView glue layer
3467 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183468 """
3469 valuecallback_import_pattern = input_api.re.compile(
3470 r'^import android\.webkit\.ValueCallback;$')
3471
3472 errors = []
3473
3474 sources = lambda affected_file: input_api.FilterSourceFile(
3475 affected_file,
James Cook24a504192020-07-23 00:08:443476 files_to_skip=(_EXCLUDED_PATHS +
3477 _TEST_CODE_EXCLUDED_PATHS +
3478 input_api.DEFAULT_FILES_TO_SKIP +
3479 (r'^android_webview[\\/]glue[\\/].*',
3480 r'^weblayer[\\/].*',)),
3481 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183482
3483 for f in input_api.AffectedSourceFiles(sources):
3484 for line_num, line in f.ChangedContents():
3485 if valuecallback_import_pattern.search(line):
3486 errors.append("%s:%d" % (f.LocalPath(), line_num))
3487
3488 results = []
3489
3490 if errors:
3491 results.append(output_api.PresubmitError(
3492 'android.webkit.ValueCallback usage is detected outside of the glue'
3493 ' layer. To stay compatible with the support library, android.webkit.*'
3494 ' classes should only be used inside the glue layer and'
3495 ' org.chromium.base.Callback should be used instead.',
3496 errors))
3497
3498 return results
3499
3500
Becky Zhou7c69b50992018-12-10 19:37:573501def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3502 """Checks Android XML styles """
3503 import sys
3504 original_sys_path = sys.path
3505 try:
3506 sys.path = sys.path + [input_api.os_path.join(
3507 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3508 import checkxmlstyle
3509 finally:
3510 # Restore sys.path to what it was before.
3511 sys.path = original_sys_path
3512
3513 if is_check_on_upload:
3514 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3515 else:
3516 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3517
3518
agrievef32bcc72016-04-04 14:57:403519class PydepsChecker(object):
3520 def __init__(self, input_api, pydeps_files):
3521 self._file_cache = {}
3522 self._input_api = input_api
3523 self._pydeps_files = pydeps_files
3524
3525 def _LoadFile(self, path):
3526 """Returns the list of paths within a .pydeps file relative to //."""
3527 if path not in self._file_cache:
3528 with open(path) as f:
3529 self._file_cache[path] = f.read()
3530 return self._file_cache[path]
3531
3532 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3533 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393534 pydeps_data = self._LoadFile(pydeps_path)
3535 uses_gn_paths = '--gn-paths' in pydeps_data
3536 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3537 if uses_gn_paths:
3538 # Paths look like: //foo/bar/baz
3539 return (e[2:] for e in entries)
3540 else:
3541 # Paths look like: path/relative/to/file.pydeps
3542 os_path = self._input_api.os_path
3543 pydeps_dir = os_path.dirname(pydeps_path)
3544 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403545
3546 def _CreateFilesToPydepsMap(self):
3547 """Returns a map of local_path -> list_of_pydeps."""
3548 ret = {}
3549 for pydep_local_path in self._pydeps_files:
3550 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3551 ret.setdefault(path, []).append(pydep_local_path)
3552 return ret
3553
3554 def ComputeAffectedPydeps(self):
3555 """Returns an iterable of .pydeps files that might need regenerating."""
3556 affected_pydeps = set()
3557 file_to_pydeps_map = None
3558 for f in self._input_api.AffectedFiles(include_deletes=True):
3559 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463560 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3561 # subrepositories. We can't figure out which files change, so re-check
3562 # all files.
3563 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383564 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3565 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403566 return self._pydeps_files
3567 elif local_path.endswith('.pydeps'):
3568 if local_path in self._pydeps_files:
3569 affected_pydeps.add(local_path)
3570 elif local_path.endswith('.py'):
3571 if file_to_pydeps_map is None:
3572 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3573 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3574 return affected_pydeps
3575
3576 def DetermineIfStale(self, pydeps_path):
3577 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413578 import difflib
John Budorick47ca3fe2018-02-10 00:53:103579 import os
3580
agrievef32bcc72016-04-04 14:57:403581 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033582 if old_pydeps_data:
3583 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393584 if '--output' not in cmd:
3585 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033586 old_contents = old_pydeps_data[2:]
3587 else:
3588 # A default cmd that should work in most cases (as long as pydeps filename
3589 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3590 # file is empty/new.
3591 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3592 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3593 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103594 env = dict(os.environ)
3595 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403596 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103597 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413598 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033599 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413600 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403601
3602
Tibor Goldschwendt360793f72019-06-25 18:23:493603def _ParseGclientArgs():
3604 args = {}
3605 with open('build/config/gclient_args.gni', 'r') as f:
3606 for line in f:
3607 line = line.strip()
3608 if not line or line.startswith('#'):
3609 continue
3610 attribute, value = line.split('=')
3611 args[attribute.strip()] = value.strip()
3612 return args
3613
3614
Saagar Sanghavifceeaae2020-08-12 16:40:363615def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403616 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403617 # This check is for Python dependency lists (.pydeps files), and involves
3618 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3619 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283620 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003621 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493622 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403623 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403624 results = []
3625 # First, check for new / deleted .pydeps.
3626 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033627 # Check whether we are running the presubmit check for a file in src.
3628 # f.LocalPath is relative to repo (src, or internal repo).
3629 # os_path.exists is relative to src repo.
3630 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3631 # to src and we can conclude that the pydeps is in src.
3632 if input_api.os_path.exists(f.LocalPath()):
3633 if f.LocalPath().endswith('.pydeps'):
3634 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3635 results.append(output_api.PresubmitError(
3636 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3637 'remove %s' % f.LocalPath()))
3638 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3639 results.append(output_api.PresubmitError(
3640 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3641 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403642
3643 if results:
3644 return results
3645
Mohamed Heikal7cd4d8312020-06-16 16:49:403646 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3647 affected_pydeps = set(checker.ComputeAffectedPydeps())
3648 affected_android_pydeps = affected_pydeps.intersection(
3649 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3650 if affected_android_pydeps and not is_android:
3651 results.append(output_api.PresubmitPromptOrNotify(
3652 'You have changed python files that may affect pydeps for android\n'
3653 'specific scripts. However, the relevant presumbit check cannot be\n'
3654 'run because you are not using an Android checkout. To validate that\n'
3655 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3656 'use the android-internal-presubmit optional trybot.\n'
3657 'Possibly stale pydeps files:\n{}'.format(
3658 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403659
Mohamed Heikal7cd4d8312020-06-16 16:49:403660 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3661 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403662 try:
phajdan.jr0d9878552016-11-04 10:49:413663 result = checker.DetermineIfStale(pydep_path)
3664 if result:
3665 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403666 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413667 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3668 'To regenerate, run:\n\n %s' %
3669 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403670 except input_api.subprocess.CalledProcessError as error:
3671 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3672 long_text=error.output)]
3673
3674 return results
3675
3676
Saagar Sanghavifceeaae2020-08-12 16:40:363677def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433678 """Checks to make sure no header files have |Singleton<|."""
3679 def FileFilter(affected_file):
3680 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443681 files_to_skip = (_EXCLUDED_PATHS +
3682 input_api.DEFAULT_FILES_TO_SKIP +
3683 (r"^base[\\/]memory[\\/]singleton\.h$",
3684 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3685 r"quic_singleton_impl\.h$"))
3686 return input_api.FilterSourceFile(affected_file,
3687 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433688
sergeyu34d21222015-09-16 00:11:443689 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433690 files = []
3691 for f in input_api.AffectedSourceFiles(FileFilter):
3692 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3693 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3694 contents = input_api.ReadFile(f)
3695 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243696 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433697 pattern.search(line)):
3698 files.append(f)
3699 break
3700
3701 if files:
yolandyandaabc6d2016-04-18 18:29:393702 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443703 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433704 'Please move them to an appropriate source file so that the ' +
3705 'template gets instantiated in a single compilation unit.',
3706 files) ]
3707 return []
3708
3709
[email protected]fd20b902014-05-09 02:14:533710_DEPRECATED_CSS = [
3711 # Values
3712 ( "-webkit-box", "flex" ),
3713 ( "-webkit-inline-box", "inline-flex" ),
3714 ( "-webkit-flex", "flex" ),
3715 ( "-webkit-inline-flex", "inline-flex" ),
3716 ( "-webkit-min-content", "min-content" ),
3717 ( "-webkit-max-content", "max-content" ),
3718
3719 # Properties
3720 ( "-webkit-background-clip", "background-clip" ),
3721 ( "-webkit-background-origin", "background-origin" ),
3722 ( "-webkit-background-size", "background-size" ),
3723 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443724 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533725
3726 # Functions
3727 ( "-webkit-gradient", "gradient" ),
3728 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3729 ( "-webkit-linear-gradient", "linear-gradient" ),
3730 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3731 ( "-webkit-radial-gradient", "radial-gradient" ),
3732 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3733]
3734
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203735
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493736# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363737def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533738 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253739 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343740 documentation and iOS CSS for dom distiller
3741 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253742 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533743 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493744 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443745 files_to_skip = (_EXCLUDED_PATHS +
3746 _TEST_CODE_EXCLUDED_PATHS +
3747 input_api.DEFAULT_FILES_TO_SKIP +
3748 (r"^chrome/common/extensions/docs",
3749 r"^chrome/docs",
3750 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3751 r"^components/neterror/resources/neterror.css",
3752 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253753 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443754 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533755 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3756 for line_num, line in fpath.ChangedContents():
3757 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023758 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533759 results.append(output_api.PresubmitError(
3760 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3761 (fpath.LocalPath(), line_num, deprecated_value, value)))
3762 return results
3763
mohan.reddyf21db962014-10-16 12:26:473764
Saagar Sanghavifceeaae2020-08-12 16:40:363765def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363766 bad_files = {}
3767 for f in input_api.AffectedFiles(include_deletes=False):
3768 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493769 not f.LocalPath().startswith('third_party/blink') and
3770 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363771 continue
3772
Daniel Bratell65b033262019-04-23 08:17:063773 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363774 continue
3775
Vaclav Brozekd5de76a2018-03-17 07:57:503776 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363777 if "#include" in line and "../" in line]
3778 if not relative_includes:
3779 continue
3780 bad_files[f.LocalPath()] = relative_includes
3781
3782 if not bad_files:
3783 return []
3784
3785 error_descriptions = []
3786 for file_path, bad_lines in bad_files.iteritems():
3787 error_description = file_path
3788 for line in bad_lines:
3789 error_description += '\n ' + line
3790 error_descriptions.append(error_description)
3791
3792 results = []
3793 results.append(output_api.PresubmitError(
3794 'You added one or more relative #include paths (including "../").\n'
3795 'These shouldn\'t be used because they can be used to include headers\n'
3796 'from code that\'s not correctly specified as a dependency in the\n'
3797 'relevant BUILD.gn file(s).',
3798 error_descriptions))
3799
3800 return results
3801
Takeshi Yoshinoe387aa32017-08-02 13:16:133802
Saagar Sanghavifceeaae2020-08-12 16:40:363803def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063804 """Check that nobody tries to include a cc file. It's a relatively
3805 common error which results in duplicate symbols in object
3806 files. This may not always break the build until someone later gets
3807 very confusing linking errors."""
3808 results = []
3809 for f in input_api.AffectedFiles(include_deletes=False):
3810 # We let third_party code do whatever it wants
3811 if (f.LocalPath().startswith('third_party') and
3812 not f.LocalPath().startswith('third_party/blink') and
3813 not f.LocalPath().startswith('third_party\\blink')):
3814 continue
3815
3816 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3817 continue
3818
3819 for _, line in f.ChangedContents():
3820 if line.startswith('#include "'):
3821 included_file = line.split('"')[1]
3822 if _IsCPlusPlusFile(input_api, included_file):
3823 # The most common naming for external files with C++ code,
3824 # apart from standard headers, is to call them foo.inc, but
3825 # Chromium sometimes uses foo-inc.cc so allow that as well.
3826 if not included_file.endswith(('.h', '-inc.cc')):
3827 results.append(output_api.PresubmitError(
3828 'Only header files or .inc files should be included in other\n'
3829 'C++ files. Compiling the contents of a cc file more than once\n'
3830 'will cause duplicate information in the build which may later\n'
3831 'result in strange link_errors.\n' +
3832 f.LocalPath() + ':\n ' +
3833 line))
3834
3835 return results
3836
3837
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203838def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3839 if not isinstance(key, ast.Str):
3840 return 'Key at line %d must be a string literal' % key.lineno
3841 if not isinstance(value, ast.Dict):
3842 return 'Value at line %d must be a dict' % value.lineno
3843 if len(value.keys) != 1:
3844 return 'Dict at line %d must have single entry' % value.lineno
3845 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3846 return (
3847 'Entry at line %d must have a string literal \'filepath\' as key' %
3848 value.lineno)
3849 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133850
Takeshi Yoshinoe387aa32017-08-02 13:16:133851
Sergey Ulanov4af16052018-11-08 02:41:463852def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203853 if not isinstance(key, ast.Str):
3854 return 'Key at line %d must be a string literal' % key.lineno
3855 if not isinstance(value, ast.List):
3856 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463857 for element in value.elts:
3858 if not isinstance(element, ast.Str):
3859 return 'Watchlist elements on line %d is not a string' % key.lineno
3860 if not email_regex.match(element.s):
3861 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3862 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203863 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133864
Takeshi Yoshinoe387aa32017-08-02 13:16:133865
Sergey Ulanov4af16052018-11-08 02:41:463866def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203867 mismatch_template = (
3868 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3869 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133870
Sergey Ulanov4af16052018-11-08 02:41:463871 email_regex = input_api.re.compile(
3872 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3873
3874 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203875 i = 0
3876 last_key = ''
3877 while True:
3878 if i >= len(wd_dict.keys):
3879 if i >= len(w_dict.keys):
3880 return None
3881 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3882 elif i >= len(w_dict.keys):
3883 return (
3884 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133885
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203886 wd_key = wd_dict.keys[i]
3887 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133888
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203889 result = _CheckWatchlistDefinitionsEntrySyntax(
3890 wd_key, wd_dict.values[i], ast)
3891 if result is not None:
3892 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133893
Sergey Ulanov4af16052018-11-08 02:41:463894 result = _CheckWatchlistsEntrySyntax(
3895 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203896 if result is not None:
3897 return 'Bad entry in WATCHLISTS dict: %s' % result
3898
3899 if wd_key.s != w_key.s:
3900 return mismatch_template % (
3901 '%s at line %d' % (wd_key.s, wd_key.lineno),
3902 '%s at line %d' % (w_key.s, w_key.lineno))
3903
3904 if wd_key.s < last_key:
3905 return (
3906 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3907 (wd_key.lineno, w_key.lineno))
3908 last_key = wd_key.s
3909
3910 i = i + 1
3911
3912
Sergey Ulanov4af16052018-11-08 02:41:463913def _CheckWATCHLISTSSyntax(expression, input_api):
3914 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203915 if not isinstance(expression, ast.Expression):
3916 return 'WATCHLISTS file must contain a valid expression'
3917 dictionary = expression.body
3918 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3919 return 'WATCHLISTS file must have single dict with exactly two entries'
3920
3921 first_key = dictionary.keys[0]
3922 first_value = dictionary.values[0]
3923 second_key = dictionary.keys[1]
3924 second_value = dictionary.values[1]
3925
3926 if (not isinstance(first_key, ast.Str) or
3927 first_key.s != 'WATCHLIST_DEFINITIONS' or
3928 not isinstance(first_value, ast.Dict)):
3929 return (
3930 'The first entry of the dict in WATCHLISTS file must be '
3931 'WATCHLIST_DEFINITIONS dict')
3932
3933 if (not isinstance(second_key, ast.Str) or
3934 second_key.s != 'WATCHLISTS' or
3935 not isinstance(second_value, ast.Dict)):
3936 return (
3937 'The second entry of the dict in WATCHLISTS file must be '
3938 'WATCHLISTS dict')
3939
Sergey Ulanov4af16052018-11-08 02:41:463940 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133941
3942
Saagar Sanghavifceeaae2020-08-12 16:40:363943def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133944 for f in input_api.AffectedFiles(include_deletes=False):
3945 if f.LocalPath() == 'WATCHLISTS':
3946 contents = input_api.ReadFile(f, 'r')
3947
3948 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203949 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133950 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203951 # Get an AST tree for it and scan the tree for detailed style checking.
3952 expression = input_api.ast.parse(
3953 contents, filename='WATCHLISTS', mode='eval')
3954 except ValueError as e:
3955 return [output_api.PresubmitError(
3956 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3957 except SyntaxError as e:
3958 return [output_api.PresubmitError(
3959 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3960 except TypeError as e:
3961 return [output_api.PresubmitError(
3962 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133963
Sergey Ulanov4af16052018-11-08 02:41:463964 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203965 if result is not None:
3966 return [output_api.PresubmitError(result)]
3967 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133968
3969 return []
3970
3971
Andrew Grieve1b290e4a22020-11-24 20:07:013972def CheckGnGlobForward(input_api, output_api):
3973 """Checks that forward_variables_from(invoker, "*") follows best practices.
3974
3975 As documented at //build/docs/writing_gn_templates.md
3976 """
3977 def gn_files(f):
3978 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3979
3980 problems = []
3981 for f in input_api.AffectedSourceFiles(gn_files):
3982 for line_num, line in f.ChangedContents():
3983 if 'forward_variables_from(invoker, "*")' in line:
3984 problems.append(
3985 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3986 f.LocalPath(), line_num))
3987
3988 if problems:
3989 return [output_api.PresubmitPromptWarning(
3990 'forward_variables_from("*") without exclusions',
3991 items=sorted(problems),
3992 long_text=('The variables "visibilty" and "test_only" should be '
3993 'explicitly listed in forward_variables_from(). For more '
3994 'details, see:\n'
3995 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
3996 'build/docs/writing_gn_templates.md'
3997 '#Using-forward_variables_from'))]
3998 return []
3999
4000
Saagar Sanghavifceeaae2020-08-12 16:40:364001def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194002 """Checks that newly added header files have corresponding GN changes.
4003 Note that this is only a heuristic. To be precise, run script:
4004 build/check_gn_headers.py.
4005 """
4006
4007 def headers(f):
4008 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444009 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194010
4011 new_headers = []
4012 for f in input_api.AffectedSourceFiles(headers):
4013 if f.Action() != 'A':
4014 continue
4015 new_headers.append(f.LocalPath())
4016
4017 def gn_files(f):
James Cook24a504192020-07-23 00:08:444018 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194019
4020 all_gn_changed_contents = ''
4021 for f in input_api.AffectedSourceFiles(gn_files):
4022 for _, line in f.ChangedContents():
4023 all_gn_changed_contents += line
4024
4025 problems = []
4026 for header in new_headers:
4027 basename = input_api.os_path.basename(header)
4028 if basename not in all_gn_changed_contents:
4029 problems.append(header)
4030
4031 if problems:
4032 return [output_api.PresubmitPromptWarning(
4033 'Missing GN changes for new header files', items=sorted(problems),
4034 long_text='Please double check whether newly added header files need '
4035 'corresponding changes in gn or gni files.\nThis checking is only a '
4036 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4037 'Read https://crbug.com/661774 for more info.')]
4038 return []
4039
4040
Saagar Sanghavifceeaae2020-08-12 16:40:364041def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024042 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4043
4044 This assumes we won't intentionally reference one product from the other
4045 product.
4046 """
4047 all_problems = []
4048 test_cases = [{
4049 "filename_postfix": "google_chrome_strings.grd",
4050 "correct_name": "Chrome",
4051 "incorrect_name": "Chromium",
4052 }, {
4053 "filename_postfix": "chromium_strings.grd",
4054 "correct_name": "Chromium",
4055 "incorrect_name": "Chrome",
4056 }]
4057
4058 for test_case in test_cases:
4059 problems = []
4060 filename_filter = lambda x: x.LocalPath().endswith(
4061 test_case["filename_postfix"])
4062
4063 # Check each new line. Can yield false positives in multiline comments, but
4064 # easier than trying to parse the XML because messages can have nested
4065 # children, and associating message elements with affected lines is hard.
4066 for f in input_api.AffectedSourceFiles(filename_filter):
4067 for line_num, line in f.ChangedContents():
4068 if "<message" in line or "<!--" in line or "-->" in line:
4069 continue
4070 if test_case["incorrect_name"] in line:
4071 problems.append(
4072 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4073
4074 if problems:
4075 message = (
4076 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4077 % (test_case["correct_name"], test_case["correct_name"],
4078 test_case["incorrect_name"]))
4079 all_problems.append(
4080 output_api.PresubmitPromptWarning(message, items=problems))
4081
4082 return all_problems
4083
4084
Saagar Sanghavifceeaae2020-08-12 16:40:364085def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364086 """Avoid large files, especially binary files, in the repository since
4087 git doesn't scale well for those. They will be in everyone's repo
4088 clones forever, forever making Chromium slower to clone and work
4089 with."""
4090
4091 # Uploading files to cloud storage is not trivial so we don't want
4092 # to set the limit too low, but the upper limit for "normal" large
4093 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4094 # anything over 20 MB is exceptional.
4095 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4096
4097 too_large_files = []
4098 for f in input_api.AffectedFiles():
4099 # Check both added and modified files (but not deleted files).
4100 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384101 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364102 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4103 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4104
4105 if too_large_files:
4106 message = (
4107 'Do not commit large files to git since git scales badly for those.\n' +
4108 'Instead put the large files in cloud storage and use DEPS to\n' +
4109 'fetch them.\n' + '\n'.join(too_large_files)
4110 )
4111 return [output_api.PresubmitError(
4112 'Too large files found in commit', long_text=message + '\n')]
4113 else:
4114 return []
4115
Max Morozb47503b2019-08-08 21:03:274116
Saagar Sanghavifceeaae2020-08-12 16:40:364117def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274118 """Checks specific for fuzz target sources."""
4119 EXPORTED_SYMBOLS = [
4120 'LLVMFuzzerInitialize',
4121 'LLVMFuzzerCustomMutator',
4122 'LLVMFuzzerCustomCrossOver',
4123 'LLVMFuzzerMutate',
4124 ]
4125
4126 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4127
4128 def FilterFile(affected_file):
4129 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444130 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4131 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274132
4133 return input_api.FilterSourceFile(
4134 affected_file,
James Cook24a504192020-07-23 00:08:444135 files_to_check=[files_to_check],
4136 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274137
4138 files_with_missing_header = []
4139 for f in input_api.AffectedSourceFiles(FilterFile):
4140 contents = input_api.ReadFile(f, 'r')
4141 if REQUIRED_HEADER in contents:
4142 continue
4143
4144 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4145 files_with_missing_header.append(f.LocalPath())
4146
4147 if not files_with_missing_header:
4148 return []
4149
4150 long_text = (
4151 'If you define any of the libFuzzer optional functions (%s), it is '
4152 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4153 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4154 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4155 'to access command line arguments passed to the fuzzer. Instead, prefer '
4156 'static initialization and shared resources as documented in '
4157 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4158 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4159 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4160 )
4161
4162 return [output_api.PresubmitPromptWarning(
4163 message="Missing '%s' in:" % REQUIRED_HEADER,
4164 items=files_with_missing_header,
4165 long_text=long_text)]
4166
4167
Mohamed Heikald048240a2019-11-12 16:57:374168def _CheckNewImagesWarning(input_api, output_api):
4169 """
4170 Warns authors who add images into the repo to make sure their images are
4171 optimized before committing.
4172 """
4173 images_added = False
4174 image_paths = []
4175 errors = []
4176 filter_lambda = lambda x: input_api.FilterSourceFile(
4177 x,
James Cook24a504192020-07-23 00:08:444178 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4179 + input_api.DEFAULT_FILES_TO_SKIP),
4180 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374181 )
4182 for f in input_api.AffectedFiles(
4183 include_deletes=False, file_filter=filter_lambda):
4184 local_path = f.LocalPath().lower()
4185 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4186 images_added = True
4187 image_paths.append(f)
4188 if images_added:
4189 errors.append(output_api.PresubmitPromptWarning(
4190 'It looks like you are trying to commit some images. If these are '
4191 'non-test-only images, please make sure to read and apply the tips in '
4192 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4193 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4194 'FYI only and will not block your CL on the CQ.', image_paths))
4195 return errors
4196
4197
Saagar Sanghavifceeaae2020-08-12 16:40:364198def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574199 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224200 results = []
dgnaa68d5e2015-06-10 10:08:224201 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174202 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224203 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294204 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064205 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4206 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424207 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184208 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574209 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374210 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154211 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574212 return results
4213
Saagar Sanghavifceeaae2020-08-12 16:40:364214def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574215 """Groups commit checks that target android code."""
4216 results = []
4217 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224218 return results
4219
Chris Hall59f8d0c72020-05-01 07:31:194220# TODO(chrishall): could we additionally match on any path owned by
4221# ui/accessibility/OWNERS ?
4222_ACCESSIBILITY_PATHS = (
4223 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4224 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4225 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4226 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4227 r"^content[\\/]browser[\\/]accessibility[\\/]",
4228 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4229 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4230 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4231 r"^ui[\\/]accessibility[\\/]",
4232 r"^ui[\\/]views[\\/]accessibility[\\/]",
4233)
4234
Saagar Sanghavifceeaae2020-08-12 16:40:364235def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194236 """Checks that commits to accessibility code contain an AX-Relnotes field in
4237 their commit message."""
4238 def FileFilter(affected_file):
4239 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444240 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194241
4242 # Only consider changes affecting accessibility paths.
4243 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4244 return []
4245
Akihiro Ota08108e542020-05-20 15:30:534246 # AX-Relnotes can appear in either the description or the footer.
4247 # When searching the description, require 'AX-Relnotes:' to appear at the
4248 # beginning of a line.
4249 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4250 description_has_relnotes = any(ax_regex.match(line)
4251 for line in input_api.change.DescriptionText().lower().splitlines())
4252
4253 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4254 'AX-Relnotes', [])
4255 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194256 return []
4257
4258 # TODO(chrishall): link to Relnotes documentation in message.
4259 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4260 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4261 "user-facing changes"
4262 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4263 "user-facing effects"
4264 "\n if this is confusing or annoying then please contact members "
4265 "of ui/accessibility/OWNERS.")
4266
4267 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224268
seanmccullough4a9356252021-04-08 19:54:094269# string pattern, sequence of strings to show when pattern matches,
4270# error flag. True if match is a presubmit error, otherwise it's a warning.
4271_NON_INCLUSIVE_TERMS = (
4272 (
4273 # Note that \b pattern in python re is pretty particular. In this
4274 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4275 # ...' will not. This may require some tweaking to catch these cases
4276 # without triggering a lot of false positives. Leaving it naive and
4277 # less matchy for now.
4278 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4279 (
4280 'Please don\'t use blacklist, whitelist, ' # nocheck
4281 'or slave in your', # nocheck
4282 'code and make every effort to use other terms. Using "// nocheck"',
4283 '"# nocheck" or "<!-- nocheck -->"',
4284 'at the end of the offending line will bypass this PRESUBMIT error',
4285 'but avoid using this whenever possible. Reach out to',
4286 '[email protected] if you have questions'),
4287 True),)
4288
Saagar Sanghavifceeaae2020-08-12 16:40:364289def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394290 """Checks common to both upload and commit."""
4291 results = []
4292 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384293 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544294 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084295
4296 author = input_api.change.author_email
4297 if author and author not in _KNOWN_ROBOTS:
4298 results.extend(
4299 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4300
[email protected]9f919cc2013-07-31 03:04:044301 results.extend(
4302 input_api.canned_checks.CheckChangeHasNoTabs(
4303 input_api,
4304 output_api,
4305 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434306 results.extend(input_api.RunTests(
4307 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244308
Edward Lesmesce51df52020-08-04 22:10:174309 dirmd_bin = input_api.os_path.join(
4310 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4311 results.extend(input_api.RunTests(
4312 input_api.canned_checks.CheckDirMetadataFormat(
4313 input_api, output_api, dirmd_bin)))
4314 results.extend(
4315 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4316 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554317 results.extend(
4318 input_api.canned_checks.CheckNoNewMetadataInOwners(
4319 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094320 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4321 input_api, output_api,
4322 excluded_directories_relative_path = [
4323 'infra',
4324 'inclusive_language_presubmit_exempt_dirs.txt'
4325 ],
4326 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174327
Vaclav Brozekcdc7defb2018-03-20 09:54:354328 for f in input_api.AffectedFiles():
4329 path, name = input_api.os_path.split(f.LocalPath())
4330 if name == 'PRESUBMIT.py':
4331 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004332 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4333 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074334 # The PRESUBMIT.py file (and the directory containing it) might
4335 # have been affected by being moved or removed, so only try to
4336 # run the tests if they still exist.
4337 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4338 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444339 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394340 return results
[email protected]1f7b4172010-01-28 01:17:344341
[email protected]b337cb5b2011-01-23 21:24:054342
Saagar Sanghavifceeaae2020-08-12 16:40:364343def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494344 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4345 if f.LocalPath().endswith(('.orig', '.rej'))]
4346 if problems:
4347 return [output_api.PresubmitError(
4348 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034349 else:
4350 return []
[email protected]b8079ae4a2012-12-05 19:56:494351
4352
Saagar Sanghavifceeaae2020-08-12 16:40:364353def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214354 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4355 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4356 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074357 include_re = input_api.re.compile(
4358 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4359 extension_re = input_api.re.compile(r'\.[a-z]+$')
4360 errors = []
4361 for f in input_api.AffectedFiles():
4362 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4363 continue
4364 found_line_number = None
4365 found_macro = None
4366 for line_num, line in f.ChangedContents():
4367 match = macro_re.search(line)
4368 if match:
4369 found_line_number = line_num
4370 found_macro = match.group(2)
4371 break
4372 if not found_line_number:
4373 continue
4374
4375 found_include = False
4376 for line in f.NewContents():
4377 if include_re.search(line):
4378 found_include = True
4379 break
4380 if found_include:
4381 continue
4382
4383 if not f.LocalPath().endswith('.h'):
4384 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4385 try:
4386 content = input_api.ReadFile(primary_header_path, 'r')
4387 if include_re.search(content):
4388 continue
4389 except IOError:
4390 pass
4391 errors.append('%s:%d %s macro is used without including build/'
4392 'build_config.h.'
4393 % (f.LocalPath(), found_line_number, found_macro))
4394 if errors:
4395 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4396 return []
4397
4398
[email protected]b00342e7f2013-03-26 16:21:544399def _DidYouMeanOSMacro(bad_macro):
4400 try:
4401 return {'A': 'OS_ANDROID',
4402 'B': 'OS_BSD',
4403 'C': 'OS_CHROMEOS',
4404 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444405 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544406 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444407 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544408 'N': 'OS_NACL',
4409 'O': 'OS_OPENBSD',
4410 'P': 'OS_POSIX',
4411 'S': 'OS_SOLARIS',
4412 'W': 'OS_WIN'}[bad_macro[3].upper()]
4413 except KeyError:
4414 return ''
4415
4416
4417def _CheckForInvalidOSMacrosInFile(input_api, f):
4418 """Check for sensible looking, totally invalid OS macros."""
4419 preprocessor_statement = input_api.re.compile(r'^\s*#')
4420 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4421 results = []
4422 for lnum, line in f.ChangedContents():
4423 if preprocessor_statement.search(line):
4424 for match in os_macro.finditer(line):
4425 if not match.group(1) in _VALID_OS_MACROS:
4426 good = _DidYouMeanOSMacro(match.group(1))
4427 did_you_mean = ' (did you mean %s?)' % good if good else ''
4428 results.append(' %s:%d %s%s' % (f.LocalPath(),
4429 lnum,
4430 match.group(1),
4431 did_you_mean))
4432 return results
4433
4434
Saagar Sanghavifceeaae2020-08-12 16:40:364435def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544436 """Check all affected files for invalid OS macros."""
4437 bad_macros = []
tzik3f295992018-12-04 20:32:234438 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474439 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544440 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4441
4442 if not bad_macros:
4443 return []
4444
4445 return [output_api.PresubmitError(
4446 'Possibly invalid OS macro[s] found. Please fix your code\n'
4447 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4448
lliabraa35bab3932014-10-01 12:16:444449
4450def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4451 """Check all affected files for invalid "if defined" macros."""
4452 ALWAYS_DEFINED_MACROS = (
4453 "TARGET_CPU_PPC",
4454 "TARGET_CPU_PPC64",
4455 "TARGET_CPU_68K",
4456 "TARGET_CPU_X86",
4457 "TARGET_CPU_ARM",
4458 "TARGET_CPU_MIPS",
4459 "TARGET_CPU_SPARC",
4460 "TARGET_CPU_ALPHA",
4461 "TARGET_IPHONE_SIMULATOR",
4462 "TARGET_OS_EMBEDDED",
4463 "TARGET_OS_IPHONE",
4464 "TARGET_OS_MAC",
4465 "TARGET_OS_UNIX",
4466 "TARGET_OS_WIN32",
4467 )
4468 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4469 results = []
4470 for lnum, line in f.ChangedContents():
4471 for match in ifdef_macro.finditer(line):
4472 if match.group(1) in ALWAYS_DEFINED_MACROS:
4473 always_defined = ' %s is always defined. ' % match.group(1)
4474 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4475 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4476 lnum,
4477 always_defined,
4478 did_you_mean))
4479 return results
4480
4481
Saagar Sanghavifceeaae2020-08-12 16:40:364482def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444483 """Check all affected files for invalid "if defined" macros."""
4484 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054485 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444486 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054487 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214488 continue
lliabraa35bab3932014-10-01 12:16:444489 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4490 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4491
4492 if not bad_macros:
4493 return []
4494
4495 return [output_api.PresubmitError(
4496 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4497 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4498 bad_macros)]
4499
4500
Saagar Sanghavifceeaae2020-08-12 16:40:364501def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044502 """Check for same IPC rules described in
4503 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4504 """
4505 base_pattern = r'IPC_ENUM_TRAITS\('
4506 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4507 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4508
4509 problems = []
4510 for f in input_api.AffectedSourceFiles(None):
4511 local_path = f.LocalPath()
4512 if not local_path.endswith('.h'):
4513 continue
4514 for line_number, line in f.ChangedContents():
4515 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4516 problems.append(
4517 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4518
4519 if problems:
4520 return [output_api.PresubmitPromptWarning(
4521 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4522 else:
4523 return []
4524
[email protected]b00342e7f2013-03-26 16:21:544525
Saagar Sanghavifceeaae2020-08-12 16:40:364526def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054527 """Check to make sure no files being submitted have long paths.
4528 This causes issues on Windows.
4529 """
4530 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194531 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054532 local_path = f.LocalPath()
4533 # Windows has a path limit of 260 characters. Limit path length to 200 so
4534 # that we have some extra for the prefix on dev machines and the bots.
4535 if len(local_path) > 200:
4536 problems.append(local_path)
4537
4538 if problems:
4539 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4540 else:
4541 return []
4542
4543
Saagar Sanghavifceeaae2020-08-12 16:40:364544def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144545 """Check that header files have proper guards against multiple inclusion.
4546 If a file should not have such guards (and it probably should) then it
4547 should include the string "no-include-guard-because-multiply-included".
4548 """
Daniel Bratell6a75baef62018-06-04 10:04:454549 def is_chromium_header_file(f):
4550 # We only check header files under the control of the Chromium
4551 # project. That is, those outside third_party apart from
4552 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324553 # We also exclude *_message_generator.h headers as they use
4554 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454555 file_with_path = input_api.os_path.normpath(f.LocalPath())
4556 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324557 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454558 (not file_with_path.startswith('third_party') or
4559 file_with_path.startswith(
4560 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144561
4562 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344563 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144564
4565 errors = []
4566
Daniel Bratell6a75baef62018-06-04 10:04:454567 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144568 guard_name = None
4569 guard_line_number = None
4570 seen_guard_end = False
4571
4572 file_with_path = input_api.os_path.normpath(f.LocalPath())
4573 base_file_name = input_api.os_path.splitext(
4574 input_api.os_path.basename(file_with_path))[0]
4575 upper_base_file_name = base_file_name.upper()
4576
4577 expected_guard = replace_special_with_underscore(
4578 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144579
4580 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574581 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4582 # are too many (1000+) files with slight deviations from the
4583 # coding style. The most important part is that the include guard
4584 # is there, and that it's unique, not the name so this check is
4585 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144586 #
4587 # As code becomes more uniform, this could be made stricter.
4588
4589 guard_name_pattern_list = [
4590 # Anything with the right suffix (maybe with an extra _).
4591 r'\w+_H__?',
4592
Daniel Bratell39b5b062018-05-16 18:09:574593 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144594 r'\w+_h',
4595
4596 # Anything including the uppercase name of the file.
4597 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4598 upper_base_file_name)) + r'\w*',
4599 ]
4600 guard_name_pattern = '|'.join(guard_name_pattern_list)
4601 guard_pattern = input_api.re.compile(
4602 r'#ifndef\s+(' + guard_name_pattern + ')')
4603
4604 for line_number, line in enumerate(f.NewContents()):
4605 if 'no-include-guard-because-multiply-included' in line:
4606 guard_name = 'DUMMY' # To not trigger check outside the loop.
4607 break
4608
4609 if guard_name is None:
4610 match = guard_pattern.match(line)
4611 if match:
4612 guard_name = match.group(1)
4613 guard_line_number = line_number
4614
Daniel Bratell39b5b062018-05-16 18:09:574615 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454616 # don't match the chromium style guide, but new files should
4617 # get it right.
4618 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574619 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144620 errors.append(output_api.PresubmitPromptWarning(
4621 'Header using the wrong include guard name %s' % guard_name,
4622 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574623 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144624 else:
4625 # The line after #ifndef should have a #define of the same name.
4626 if line_number == guard_line_number + 1:
4627 expected_line = '#define %s' % guard_name
4628 if line != expected_line:
4629 errors.append(output_api.PresubmitPromptWarning(
4630 'Missing "%s" for include guard' % expected_line,
4631 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4632 'Expected: %r\nGot: %r' % (expected_line, line)))
4633
4634 if not seen_guard_end and line == '#endif // %s' % guard_name:
4635 seen_guard_end = True
4636 elif seen_guard_end:
4637 if line.strip() != '':
4638 errors.append(output_api.PresubmitPromptWarning(
4639 'Include guard %s not covering the whole file' % (
4640 guard_name), [f.LocalPath()]))
4641 break # Nothing else to check and enough to warn once.
4642
4643 if guard_name is None:
4644 errors.append(output_api.PresubmitPromptWarning(
4645 'Missing include guard %s' % expected_guard,
4646 [f.LocalPath()],
4647 'Missing include guard in %s\n'
4648 'Recommended name: %s\n'
4649 'This check can be disabled by having the string\n'
4650 'no-include-guard-because-multiply-included in the header.' %
4651 (f.LocalPath(), expected_guard)))
4652
4653 return errors
4654
4655
Saagar Sanghavifceeaae2020-08-12 16:40:364656def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234657 """Check source code and known ascii text files for Windows style line
4658 endings.
4659 """
earthdok1b5e0ee2015-03-10 15:19:104660 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234661
4662 file_inclusion_pattern = (
4663 known_text_files,
4664 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4665 )
4666
mostynbb639aca52015-01-07 20:31:234667 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534668 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444669 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534670 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504671 include_file = False
4672 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234673 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504674 include_file = True
4675 if include_file:
4676 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234677
4678 if problems:
4679 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4680 'these files to contain Windows style line endings?\n' +
4681 '\n'.join(problems))]
4682
4683 return []
4684
Jose Magana2b456f22021-03-09 23:26:404685def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4686 """Check source code for use of Chrome App technologies being
4687 deprecated.
4688 """
4689
4690 def _CheckForDeprecatedTech(input_api, output_api,
4691 detection_list, files_to_check = None, files_to_skip = None):
4692
4693 if (files_to_check or files_to_skip):
4694 source_file_filter = lambda f: input_api.FilterSourceFile(
4695 f, files_to_check=files_to_check,
4696 files_to_skip=files_to_skip)
4697 else:
4698 source_file_filter = None
4699
4700 problems = []
4701
4702 for f in input_api.AffectedSourceFiles(source_file_filter):
4703 if f.Action() == 'D':
4704 continue
4705 for _, line in f.ChangedContents():
4706 if any( detect in line for detect in detection_list ):
4707 problems.append(f.LocalPath())
4708
4709 return problems
4710
4711 # to avoid this presubmit script triggering warnings
4712 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4713
4714 problems =[]
4715
4716 # NMF: any files with extensions .nmf or NMF
4717 _NMF_FILES = r'\.(nmf|NMF)$'
4718 problems += _CheckForDeprecatedTech(input_api, output_api,
4719 detection_list = [''], # any change to the file will trigger warning
4720 files_to_check = [ r'.+%s' % _NMF_FILES ])
4721
4722 # MANIFEST: any manifest.json that in its diff includes "app":
4723 _MANIFEST_FILES = r'(manifest\.json)$'
4724 problems += _CheckForDeprecatedTech(input_api, output_api,
4725 detection_list = ['"app":'],
4726 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4727
4728 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4729 problems += _CheckForDeprecatedTech(input_api, output_api,
4730 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4731 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4732
4733 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4734 problems += _CheckForDeprecatedTech(input_api, output_api,
4735 detection_list = ['#include "ppapi','#include <ppapi'],
4736 files_to_check = (
4737 r'.+%s' % _HEADER_EXTENSIONS,
4738 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4739 files_to_skip = [r"^ppapi[\\/]"] )
4740
4741 # Chrome Apps: any JS/TS file that references an API in the list below.
4742 # This should include the list of Chrome Apps APIs that are not Chrome
4743 # Extensions APIs as documented in:
4744 # https://developer.chrome.com/docs/apps/migration/
4745 detection_list_chrome_apps = [
4746 'chrome.accessibilityFeatures',
4747 'chrome.alarms',
4748 'chrome.app.runtime',
4749 'chrome.app.window',
4750 'chrome.audio',
4751 'chrome.bluetooth',
4752 'chrome.bluetoothLowEnergy',
4753 'chrome.bluetoothSocket',
4754 'chrome.browser',
4755 'chrome.commands',
4756 'chrome.contextMenus',
4757 'chrome.documentScan',
4758 'chrome.events',
4759 'chrome.extensionTypes',
4760 'chrome.fileSystem',
4761 'chrome.fileSystemProvider',
4762 'chrome.gcm',
4763 'chrome.hid',
4764 'chrome.i18n',
4765 'chrome.identity',
4766 'chrome.idle',
4767 'chrome.instanceID',
4768 'chrome.mdns',
4769 'chrome.mediaGalleries',
4770 'chrome.networking.onc',
4771 'chrome.notifications',
4772 'chrome.permissions',
4773 'chrome.power',
4774 'chrome.printerProvider',
4775 'chrome.runtime',
4776 'chrome.serial',
4777 'chrome.sockets.tcp',
4778 'chrome.sockets.tcpServer',
4779 'chrome.sockets.udp',
4780 'chrome.storage',
4781 'chrome.syncFileSystem',
4782 'chrome.system.cpu',
4783 'chrome.system.display',
4784 'chrome.system.memory',
4785 'chrome.system.network',
4786 'chrome.system.storage',
4787 'chrome.tts',
4788 'chrome.types',
4789 'chrome.usb',
4790 'chrome.virtualKeyboard',
4791 'chrome.vpnProvider',
4792 'chrome.wallpaper'
4793 ]
4794 _JS_FILES = r'\.(js|ts)$'
4795 problems += _CheckForDeprecatedTech(input_api, output_api,
4796 detection_list = detection_list_chrome_apps,
4797 files_to_check = [ r'.+%s' % _JS_FILES ],
4798 files_to_skip = files_to_skip)
4799
4800 if problems:
4801 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4802 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4803 ' PNaCl, PPAPI). See this blog post for more details:\n'
4804 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4805 'and this documentation for options to replace these technologies:\n'
4806 'https://developer.chrome.com/docs/apps/migration/\n'+
4807 '\n'.join(problems))]
4808
4809 return []
4810
mostynbb639aca52015-01-07 20:31:234811
Saagar Sanghavifceeaae2020-08-12 16:40:364812def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134813 """Checks that all source files use SYSLOG properly."""
4814 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364815 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564816 for line_number, line in f.ChangedContents():
4817 if 'SYSLOG' in line:
4818 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4819
pastarmovj89f7ee12016-09-20 14:58:134820 if syslog_files:
4821 return [output_api.PresubmitPromptWarning(
4822 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4823 ' calls.\nFiles to check:\n', items=syslog_files)]
4824 return []
4825
4826
[email protected]1f7b4172010-01-28 01:17:344827def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364828 if input_api.version < [2, 0, 0]:
4829 return [output_api.PresubmitError("Your depot_tools is out of date. "
4830 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4831 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344832 results = []
scottmg39b29952014-12-08 18:31:284833 results.extend(
jam93a6ee792017-02-08 23:59:224834 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544835 return results
[email protected]ca8d1982009-02-19 16:33:124836
4837
[email protected]1bfb8322014-04-23 01:02:414838def GetTryServerMasterForBot(bot):
4839 """Returns the Try Server master for the given bot.
4840
[email protected]0bb112362014-07-26 04:38:324841 It tries to guess the master from the bot name, but may still fail
4842 and return None. There is no longer a default master.
4843 """
4844 # Potentially ambiguous bot names are listed explicitly.
4845 master_map = {
tandriie5587792016-07-14 00:34:504846 'chromium_presubmit': 'master.tryserver.chromium.linux',
4847 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414848 }
[email protected]0bb112362014-07-26 04:38:324849 master = master_map.get(bot)
4850 if not master:
wnwen4fbaab82016-05-25 12:54:364851 if 'android' in bot:
tandriie5587792016-07-14 00:34:504852 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364853 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504854 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324855 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504856 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324857 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504858 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324859 return master
[email protected]1bfb8322014-04-23 01:02:414860
4861
[email protected]ca8d1982009-02-19 16:33:124862def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364863 if input_api.version < [2, 0, 0]:
4864 return [output_api.PresubmitError("Your depot_tools is out of date. "
4865 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4866 "but your version is %d.%d.%d" % tuple(input_api.version))]
4867
[email protected]fe5f57c52009-06-05 14:25:544868 results = []
[email protected]fe5f57c52009-06-05 14:25:544869 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274870 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344871 input_api,
4872 output_api,
[email protected]2fdd1f362013-01-16 03:56:034873 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274874
jam93a6ee792017-02-08 23:59:224875 results.extend(
4876 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544877 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4878 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384879 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4880 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414881 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4882 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544883 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144884
4885
Saagar Sanghavifceeaae2020-08-12 16:40:364886def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264887 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024888 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4889 # footer is set to true.
4890 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264891 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024892 footer.lower()
4893 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264894 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024895
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144896 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264897 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144898 import sys
4899 from io import StringIO
4900
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144901 new_or_added_paths = set(f.LocalPath()
4902 for f in input_api.AffectedFiles()
4903 if (f.Action() == 'A' or f.Action() == 'M'))
4904 removed_paths = set(f.LocalPath()
4905 for f in input_api.AffectedFiles(include_deletes=True)
4906 if f.Action() == 'D')
4907
Andrew Grieve0e8790c2020-09-03 17:27:324908 affected_grds = [
4909 f for f in input_api.AffectedFiles()
4910 if f.LocalPath().endswith(('.grd', '.grdp'))
4911 ]
4912 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164913 if not affected_grds:
4914 return []
4915
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144916 affected_png_paths = [f.AbsoluteLocalPath()
4917 for f in input_api.AffectedFiles()
4918 if (f.LocalPath().endswith('.png'))]
4919
4920 # Check for screenshots. Developers can upload screenshots using
4921 # tools/translation/upload_screenshots.py which finds and uploads
4922 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4923 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4924 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4925 #
4926 # The logic here is as follows:
4927 #
4928 # - If the CL has a .png file under the screenshots directory for a grd
4929 # file, warn the developer. Actual images should never be checked into the
4930 # Chrome repo.
4931 #
4932 # - If the CL contains modified or new messages in grd files and doesn't
4933 # contain the corresponding .sha1 files, warn the developer to add images
4934 # and upload them via tools/translation/upload_screenshots.py.
4935 #
4936 # - If the CL contains modified or new messages in grd files and the
4937 # corresponding .sha1 files, everything looks good.
4938 #
4939 # - If the CL contains removed messages in grd files but the corresponding
4940 # .sha1 files aren't removed, warn the developer to remove them.
4941 unnecessary_screenshots = []
4942 missing_sha1 = []
4943 unnecessary_sha1_files = []
4944
Rainhard Findlingfc31844c52020-05-15 09:58:264945 # This checks verifies that the ICU syntax of messages this CL touched is
4946 # valid, and reports any found syntax errors.
4947 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4948 # without developers being aware of them. Later on, such ICU syntax errors
4949 # break message extraction for translation, hence would block Chromium
4950 # translations until they are fixed.
4951 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144952
4953 def _CheckScreenshotAdded(screenshots_dir, message_id):
4954 sha1_path = input_api.os_path.join(
4955 screenshots_dir, message_id + '.png.sha1')
4956 if sha1_path not in new_or_added_paths:
4957 missing_sha1.append(sha1_path)
4958
4959
4960 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4961 sha1_path = input_api.os_path.join(
4962 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034963 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144964 unnecessary_sha1_files.append(sha1_path)
4965
Rainhard Findlingfc31844c52020-05-15 09:58:264966
4967 def _ValidateIcuSyntax(text, level, signatures):
4968 """Validates ICU syntax of a text string.
4969
4970 Check if text looks similar to ICU and checks for ICU syntax correctness
4971 in this case. Reports various issues with ICU syntax and values of
4972 variants. Supports checking of nested messages. Accumulate information of
4973 each ICU messages found in the text for further checking.
4974
4975 Args:
4976 text: a string to check.
4977 level: a number of current nesting level.
4978 signatures: an accumulator, a list of tuple of (level, variable,
4979 kind, variants).
4980
4981 Returns:
4982 None if a string is not ICU or no issue detected.
4983 A tuple of (message, start index, end index) if an issue detected.
4984 """
4985 valid_types = {
4986 'plural': (frozenset(
4987 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4988 frozenset(['=1', 'other'])),
4989 'selectordinal': (frozenset(
4990 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4991 frozenset(['one', 'other'])),
4992 'select': (frozenset(), frozenset(['other'])),
4993 }
4994
4995 # Check if the message looks like an attempt to use ICU
4996 # plural. If yes - check if its syntax strictly matches ICU format.
4997 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4998 if not like:
4999 signatures.append((level, None, None, None))
5000 return
5001
5002 # Check for valid prefix and suffix
5003 m = re.match(
5004 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5005 r'(plural|selectordinal|select),\s*'
5006 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5007 if not m:
5008 return (('This message looks like an ICU plural, '
5009 'but does not follow ICU syntax.'), like.start(), like.end())
5010 starting, variable, kind, variant_pairs = m.groups()
5011 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5012 if depth:
5013 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5014 len(text))
5015 first = text[0]
5016 ending = text[last_pos:]
5017 if not starting:
5018 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5019 last_pos)
5020 if not ending or '}' not in ending:
5021 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5022 last_pos)
5023 elif first != '{':
5024 return (
5025 ('Invalid ICU format. Extra characters at the start of a complex '
5026 'message (go/icu-message-migration): "%s"') %
5027 starting, 0, len(starting))
5028 elif ending != '}':
5029 return (('Invalid ICU format. Extra characters at the end of a complex '
5030 'message (go/icu-message-migration): "%s"')
5031 % ending, last_pos - 1, len(text) - 1)
5032 if kind not in valid_types:
5033 return (('Unknown ICU message type %s. '
5034 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5035 known, required = valid_types[kind]
5036 defined_variants = set()
5037 for variant, variant_range, value, value_range in variants:
5038 start, end = variant_range
5039 if variant in defined_variants:
5040 return ('Variant "%s" is defined more than once' % variant,
5041 start, end)
5042 elif known and variant not in known:
5043 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5044 start, end)
5045 defined_variants.add(variant)
5046 # Check for nested structure
5047 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5048 if res:
5049 return (res[0], res[1] + value_range[0] + 1,
5050 res[2] + value_range[0] + 1)
5051 missing = required - defined_variants
5052 if missing:
5053 return ('Required variants missing: %s' % ', '.join(missing), 0,
5054 len(text))
5055 signatures.append((level, variable, kind, defined_variants))
5056
5057
5058 def _ParseIcuVariants(text, offset=0):
5059 """Parse variants part of ICU complex message.
5060
5061 Builds a tuple of variant names and values, as well as
5062 their offsets in the input string.
5063
5064 Args:
5065 text: a string to parse
5066 offset: additional offset to add to positions in the text to get correct
5067 position in the complete ICU string.
5068
5069 Returns:
5070 List of tuples, each tuple consist of four fields: variant name,
5071 variant name span (tuple of two integers), variant value, value
5072 span (tuple of two integers).
5073 """
5074 depth, start, end = 0, -1, -1
5075 variants = []
5076 key = None
5077 for idx, char in enumerate(text):
5078 if char == '{':
5079 if not depth:
5080 start = idx
5081 chunk = text[end + 1:start]
5082 key = chunk.strip()
5083 pos = offset + end + 1 + chunk.find(key)
5084 span = (pos, pos + len(key))
5085 depth += 1
5086 elif char == '}':
5087 if not depth:
5088 return variants, depth, offset + idx
5089 depth -= 1
5090 if not depth:
5091 end = idx
5092 variants.append((key, span, text[start:end + 1], (offset + start,
5093 offset + end + 1)))
5094 return variants, depth, offset + end + 1
5095
meacer8c0d3832019-12-26 21:46:165096 try:
5097 old_sys_path = sys.path
5098 sys.path = sys.path + [input_api.os_path.join(
5099 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5100 from helper import grd_helper
5101 finally:
5102 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145103
5104 for f in affected_grds:
5105 file_path = f.LocalPath()
5106 old_id_to_msg_map = {}
5107 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385108 # Note that this code doesn't check if the file has been deleted. This is
5109 # OK because it only uses the old and new file contents and doesn't load
5110 # the file via its path.
5111 # It's also possible that a file's content refers to a renamed or deleted
5112 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5113 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5114 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145115 if file_path.endswith('.grdp'):
5116 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585117 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395118 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145119 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585120 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395121 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145122 else:
meacerff8a9b62019-12-10 19:43:585123 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145124 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585125 old_id_to_msg_map = grd_helper.GetGrdMessages(
5126 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145127 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585128 new_id_to_msg_map = grd_helper.GetGrdMessages(
5129 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145130
Rainhard Findlingd8d04372020-08-13 13:30:095131 grd_name, ext = input_api.os_path.splitext(
5132 input_api.os_path.basename(file_path))
5133 screenshots_dir = input_api.os_path.join(
5134 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5135
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145136 # Compute added, removed and modified message IDs.
5137 old_ids = set(old_id_to_msg_map)
5138 new_ids = set(new_id_to_msg_map)
5139 added_ids = new_ids - old_ids
5140 removed_ids = old_ids - new_ids
5141 modified_ids = set([])
5142 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355143 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095144 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5145 # The message content itself changed. Require an updated screenshot.
5146 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355147 elif old_id_to_msg_map[key].attrs['meaning'] != \
5148 new_id_to_msg_map[key].attrs['meaning']:
5149 # The message meaning changed. Ensure there is a screenshot for it.
5150 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5151 if sha1_path not in new_or_added_paths and not \
5152 input_api.os_path.exists(sha1_path):
5153 # There is neither a previous screenshot nor is a new one added now.
5154 # Require a screenshot.
5155 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145156
Rainhard Findlingfc31844c52020-05-15 09:58:265157 if run_screenshot_check:
5158 # Check the screenshot directory for .png files. Warn if there is any.
5159 for png_path in affected_png_paths:
5160 if png_path.startswith(screenshots_dir):
5161 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145162
Rainhard Findlingfc31844c52020-05-15 09:58:265163 for added_id in added_ids:
5164 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145165
Rainhard Findlingfc31844c52020-05-15 09:58:265166 for modified_id in modified_ids:
5167 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145168
Rainhard Findlingfc31844c52020-05-15 09:58:265169 for removed_id in removed_ids:
5170 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5171
5172 # Check new and changed strings for ICU syntax errors.
5173 for key in added_ids.union(modified_ids):
5174 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5175 err = _ValidateIcuSyntax(msg, 0, [])
5176 if err is not None:
5177 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145178
5179 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265180 if run_screenshot_check:
5181 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005182 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265183 'Do not include actual screenshots in the changelist. Run '
5184 'tools/translate/upload_screenshots.py to upload them instead:',
5185 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145186
Rainhard Findlingfc31844c52020-05-15 09:58:265187 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005188 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265189 'You are adding or modifying UI strings.\n'
5190 'To ensure the best translations, take screenshots of the relevant UI '
5191 '(https://g.co/chrome/translation) and add these files to your '
5192 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145193
Rainhard Findlingfc31844c52020-05-15 09:58:265194 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005195 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265196 'You removed strings associated with these files. Remove:',
5197 sorted(unnecessary_sha1_files)))
5198 else:
5199 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5200 'screenshots check.'))
5201
5202 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075203 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265204 'ICU syntax errors were found in the following strings (problems or '
5205 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145206
5207 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125208
5209
Saagar Sanghavifceeaae2020-08-12 16:40:365210def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125211 repo_root=None,
5212 translation_expectations_path=None,
5213 grd_files=None):
5214 import sys
5215 affected_grds = [f for f in input_api.AffectedFiles()
5216 if (f.LocalPath().endswith('.grd') or
5217 f.LocalPath().endswith('.grdp'))]
5218 if not affected_grds:
5219 return []
5220
5221 try:
5222 old_sys_path = sys.path
5223 sys.path = sys.path + [
5224 input_api.os_path.join(
5225 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5226 from helper import git_helper
5227 from helper import translation_helper
5228 finally:
5229 sys.path = old_sys_path
5230
5231 # Check that translation expectations can be parsed and we can get a list of
5232 # translatable grd files. |repo_root| and |translation_expectations_path| are
5233 # only passed by tests.
5234 if not repo_root:
5235 repo_root = input_api.PresubmitLocalPath()
5236 if not translation_expectations_path:
5237 translation_expectations_path = input_api.os_path.join(
5238 repo_root, 'tools', 'gritsettings',
5239 'translation_expectations.pyl')
5240 if not grd_files:
5241 grd_files = git_helper.list_grds_in_repository(repo_root)
5242
dpapad8e21b472020-10-23 17:15:035243 # Ignore bogus grd files used only for testing
5244 # ui/webui/resoucres/tools/generate_grd.py.
5245 ignore_path = input_api.os_path.join(
5246 'ui', 'webui', 'resources', 'tools', 'tests')
5247 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5248
Mustafa Emre Acer51f2f742020-03-09 19:41:125249 try:
5250 translation_helper.get_translatable_grds(repo_root, grd_files,
5251 translation_expectations_path)
5252 except Exception as e:
5253 return [output_api.PresubmitNotifyResult(
5254 'Failed to get a list of translatable grd files. This happens when:\n'
5255 ' - One of the modified grd or grdp files cannot be parsed or\n'
5256 ' - %s is not updated.\n'
5257 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5258 return []
Ken Rockotc31f4832020-05-29 18:58:515259
5260
Saagar Sanghavifceeaae2020-08-12 16:40:365261def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515262 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095263 changed_mojoms = input_api.AffectedFiles(
5264 include_deletes=True,
5265 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515266 delta = []
5267 for mojom in changed_mojoms:
5268 old_contents = ''.join(mojom.OldContents()) or None
5269 new_contents = ''.join(mojom.NewContents()) or None
5270 delta.append({
5271 'filename': mojom.LocalPath(),
5272 'old': '\n'.join(mojom.OldContents()) or None,
5273 'new': '\n'.join(mojom.NewContents()) or None,
5274 })
5275
5276 process = input_api.subprocess.Popen(
5277 [input_api.python_executable,
5278 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5279 'public', 'tools', 'mojom',
5280 'check_stable_mojom_compatibility.py'),
5281 '--src-root', input_api.PresubmitLocalPath()],
5282 stdin=input_api.subprocess.PIPE,
5283 stdout=input_api.subprocess.PIPE,
5284 stderr=input_api.subprocess.PIPE,
5285 universal_newlines=True)
5286 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5287 if process.returncode:
5288 return [output_api.PresubmitError(
5289 'One or more [Stable] mojom definitions appears to have been changed '
5290 'in a way that is not backward-compatible.',
5291 long_text=error)]
5292 return []
Dominic Battre645d42342020-12-04 16:14:105293
5294def CheckDeprecationOfPreferences(input_api, output_api):
5295 """Removing a preference should come with a deprecation."""
5296
5297 def FilterFile(affected_file):
5298 """Accept only .cc files and the like."""
5299 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5300 files_to_skip = (_EXCLUDED_PATHS +
5301 _TEST_CODE_EXCLUDED_PATHS +
5302 input_api.DEFAULT_FILES_TO_SKIP)
5303 return input_api.FilterSourceFile(
5304 affected_file,
5305 files_to_check=file_inclusion_pattern,
5306 files_to_skip=files_to_skip)
5307
5308 def ModifiedLines(affected_file):
5309 """Returns a list of tuples (line number, line text) of added and removed
5310 lines.
5311
5312 Deleted lines share the same line number as the previous line.
5313
5314 This relies on the scm diff output describing each changed code section
5315 with a line of the form
5316
5317 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5318 """
5319 line_num = 0
5320 modified_lines = []
5321 for line in affected_file.GenerateScmDiff().splitlines():
5322 # Extract <new line num> of the patch fragment (see format above).
5323 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5324 if m:
5325 line_num = int(m.groups(1)[0])
5326 continue
5327 if ((line.startswith('+') and not line.startswith('++')) or
5328 (line.startswith('-') and not line.startswith('--'))):
5329 modified_lines.append((line_num, line))
5330
5331 if not line.startswith('-'):
5332 line_num += 1
5333 return modified_lines
5334
5335 def FindLineWith(lines, needle):
5336 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5337
5338 If 0 or >1 lines contain `needle`, -1 is returned.
5339 """
5340 matching_line_numbers = [
5341 # + 1 for 1-based counting of line numbers.
5342 i + 1 for i, line
5343 in enumerate(lines)
5344 if needle in line]
5345 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5346
5347 def ModifiedPrefMigration(affected_file):
5348 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5349 # Determine first and last lines of MigrateObsolete.*Pref functions.
5350 new_contents = affected_file.NewContents();
5351 range_1 = (
5352 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5353 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5354 range_2 = (
5355 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5356 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5357 if (-1 in range_1 + range_2):
5358 raise Exception(
5359 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5360
5361 # Check whether any of the modified lines are part of the
5362 # MigrateObsolete.*Pref functions.
5363 for line_nr, line in ModifiedLines(affected_file):
5364 if (range_1[0] <= line_nr <= range_1[1] or
5365 range_2[0] <= line_nr <= range_2[1]):
5366 return True
5367 return False
5368
5369 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5370 browser_prefs_file_pattern = input_api.re.compile(
5371 r'chrome/browser/prefs/browser_prefs.cc')
5372
5373 changes = input_api.AffectedFiles(include_deletes=True,
5374 file_filter=FilterFile)
5375 potential_problems = []
5376 for f in changes:
5377 for line in f.GenerateScmDiff().splitlines():
5378 # Check deleted lines for pref registrations.
5379 if (line.startswith('-') and not line.startswith('--') and
5380 register_pref_pattern.search(line)):
5381 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5382
5383 if browser_prefs_file_pattern.search(f.LocalPath()):
5384 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5385 # assume that they knew that they have to deprecate preferences and don't
5386 # warn.
5387 try:
5388 if ModifiedPrefMigration(f):
5389 return []
5390 except Exception as e:
5391 return [output_api.PresubmitError(str(e))]
5392
5393 if potential_problems:
5394 return [output_api.PresubmitPromptWarning(
5395 'Discovered possible removal of preference registrations.\n\n'
5396 'Please make sure to properly deprecate preferences by clearing their\n'
5397 'value for a couple of milestones before finally removing the code.\n'
5398 'Otherwise data may stay in the preferences files forever. See\n'
5399 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5400 'This may be a false positive warning (e.g. if you move preference\n'
5401 'registrations to a different place).\n',
5402 potential_problems
5403 )]
5404 return []