blob: 47bace30856f43d2550473c6dc2c9697e2656fce [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
wnwenbdc444e2016-05-25 13:44:1538
[email protected]06e6d0ff2012-12-11 01:36:4439# Fragment of a regular expression that matches C++ and Objective-C++
40# implementation files.
41_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
42
wnwenbdc444e2016-05-25 13:44:1543
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1944# Fragment of a regular expression that matches C++ and Objective-C++
45# header files.
46_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
47
48
[email protected]06e6d0ff2012-12-11 01:36:4449# Regular expression that matches code only used for test binaries
50# (best effort).
51_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0452 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4453 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4454 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1255 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1856 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4457 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0458 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4359 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0460 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4361 # Web test harness.
62 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4763 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0464 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0865 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0466 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4167 # EarlGrey app side code for tests.
68 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1769 # Views Examples code
70 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4171 # Chromium Codelab
72 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4473)
[email protected]ca8d1982009-02-19 16:33:1274
Daniel Bratell609102be2019-03-27 20:53:2175_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1576
[email protected]eea609a2011-11-18 13:10:1277_TEST_ONLY_WARNING = (
78 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5579 'production code. If you are doing this from inside another method\n'
80 'named as *ForTesting(), then consider exposing things to have tests\n'
81 'make that same call directly.\n'
82 'If that is not possible, you may put a comment on the same line with\n'
83 ' // IN-TEST \n'
84 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
85 'method and can be ignored. Do not do this inside production code.\n'
86 'The android-binary-size trybot will block if the method exists in the\n'
87 'release apk.')
[email protected]eea609a2011-11-18 13:10:1288
89
[email protected]cf9b78f2012-11-14 11:40:2890_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4091 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2192 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
93 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2894
Michael Thiessen44457642020-02-06 00:24:1595# Format: Sequence of tuples containing:
96# * Full import path.
97# * Sequence of strings to show when the pattern matches.
98# * Sequence of path or filename exceptions to this rule
99_BANNED_JAVA_IMPORTS = (
100 (
Colin Blundell170d78c82020-03-12 13:56:04101 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15102 (
103 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
104 ),
105 (
106 'net/android/javatests/src/org/chromium/net/'
107 'AndroidProxySelectorTest.java',
108 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04109 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15110 ),
111 ),
Michael Thiessened631912020-08-07 19:01:31112 (
113 'android.support.test.rule.UiThreadTestRule;',
114 (
115 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43116 '@org.chromium.base.test.UiThreadTest on test methods that should run '
117 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31118 ),
119 (),
120 ),
121 (
122 'android.support.test.annotation.UiThreadTest;',
123 (
124 'Do not use android.support.test.annotation.UiThreadTest, use '
125 'org.chromium.base.test.UiThreadTest instead. See '
126 'https://crbug.com/1111893.',
127 ),
128 ()
129 )
Michael Thiessen44457642020-02-06 00:24:15130)
wnwenbdc444e2016-05-25 13:44:15131
Daniel Bratell609102be2019-03-27 20:53:21132# Format: Sequence of tuples containing:
133# * String pattern or, if starting with a slash, a regular expression.
134# * Sequence of strings to show when the pattern matches.
135# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41136_BANNED_JAVA_FUNCTIONS = (
137 (
138 'StrictMode.allowThreadDiskReads()',
139 (
140 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
141 'directly.',
142 ),
143 False,
144 ),
145 (
146 'StrictMode.allowThreadDiskWrites()',
147 (
148 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
149 'directly.',
150 ),
151 False,
152 ),
Michael Thiessen0f2547e2020-07-27 21:55:36153 (
154 '.waitForIdleSync()',
155 (
156 'Do not use waitForIdleSync as it masks underlying issues. There is '
157 'almost always something else you should wait on instead.',
158 ),
159 False,
160 ),
Eric Stevensona9a980972017-09-23 00:04:41161)
162
Daniel Bratell609102be2019-03-27 20:53:21163# Format: Sequence of tuples containing:
164# * String pattern or, if starting with a slash, a regular expression.
165# * Sequence of strings to show when the pattern matches.
166# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59167_BANNED_OBJC_FUNCTIONS = (
168 (
169 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20170 (
171 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59172 'prohibited. Please use CrTrackingArea instead.',
173 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
174 ),
175 False,
176 ),
177 (
[email protected]eaae1972014-04-16 04:17:26178 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20179 (
180 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59181 'instead.',
182 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
183 ),
184 False,
185 ),
186 (
187 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20188 (
189 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59190 'Please use |convertPoint:(point) fromView:nil| instead.',
191 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
192 ),
193 True,
194 ),
195 (
196 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20197 (
198 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59199 'Please use |convertPoint:(point) toView:nil| instead.',
200 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
201 ),
202 True,
203 ),
204 (
205 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20206 (
207 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59208 'Please use |convertRect:(point) fromView:nil| instead.',
209 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
210 ),
211 True,
212 ),
213 (
214 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20215 (
216 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59217 'Please use |convertRect:(point) toView:nil| instead.',
218 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
219 ),
220 True,
221 ),
222 (
223 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20224 (
225 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59226 'Please use |convertSize:(point) fromView:nil| instead.',
227 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
228 ),
229 True,
230 ),
231 (
232 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20233 (
234 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59235 'Please use |convertSize:(point) toView:nil| instead.',
236 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
237 ),
238 True,
239 ),
jif65398702016-10-27 10:19:48240 (
241 r"/\s+UTF8String\s*]",
242 (
243 'The use of -[NSString UTF8String] is dangerous as it can return null',
244 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
245 'Please use |SysNSStringToUTF8| instead.',
246 ),
247 True,
248 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34249 (
250 r'__unsafe_unretained',
251 (
252 'The use of __unsafe_unretained is almost certainly wrong, unless',
253 'when interacting with NSFastEnumeration or NSInvocation.',
254 'Please use __weak in files build with ARC, nothing otherwise.',
255 ),
256 False,
257 ),
Avi Drissman7382afa02019-04-29 23:27:13258 (
259 'freeWhenDone:NO',
260 (
261 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
262 'Foundation types is prohibited.',
263 ),
264 True,
265 ),
[email protected]127f18ec2012-06-16 05:05:59266)
267
Daniel Bratell609102be2019-03-27 20:53:21268# Format: Sequence of tuples containing:
269# * String pattern or, if starting with a slash, a regular expression.
270# * Sequence of strings to show when the pattern matches.
271# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54272_BANNED_IOS_OBJC_FUNCTIONS = (
273 (
274 r'/\bTEST[(]',
275 (
276 'TEST() macro should not be used in Objective-C++ code as it does not ',
277 'drain the autorelease pool at the end of the test. Use TEST_F() ',
278 'macro instead with a fixture inheriting from PlatformTest (or a ',
279 'typedef).'
280 ),
281 True,
282 ),
283 (
284 r'/\btesting::Test\b',
285 (
286 'testing::Test should not be used in Objective-C++ code as it does ',
287 'not drain the autorelease pool at the end of the test. Use ',
288 'PlatformTest instead.'
289 ),
290 True,
291 ),
292)
293
Peter K. Lee6c03ccff2019-07-15 14:40:05294# Format: Sequence of tuples containing:
295# * String pattern or, if starting with a slash, a regular expression.
296# * Sequence of strings to show when the pattern matches.
297# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
298_BANNED_IOS_EGTEST_FUNCTIONS = (
299 (
300 r'/\bEXPECT_OCMOCK_VERIFY\b',
301 (
302 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
303 'it is meant for GTests. Use [mock verify] instead.'
304 ),
305 True,
306 ),
307)
308
danakj7a2b7082019-05-21 21:13:51309# Directories that contain deprecated Bind() or Callback types.
310# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36311# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51312# echo "-- $i"
danakj710b4c02019-11-28 16:08:45313# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51314# done
315#
316# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
317# when they have been converted to modern callback types (OnceCallback,
318# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
319# checks for them and prevent regressions.
320_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51321 '^base/callback.h', # Intentional.
Alexander Cooper6b447b22020-07-22 00:47:18322 '^chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc',
323 '^chrome/browser/apps/guest_view/',
Alexander Cooper6b447b22020-07-22 00:47:18324 '^chrome/browser/browsing_data/',
325 '^chrome/browser/captive_portal/captive_portal_browsertest.cc',
326 '^chrome/browser/chromeos/',
327 '^chrome/browser/component_updater/',
Peter Wen6367b882020-08-05 16:55:50328 '^chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc', # pylint: disable=line-too-long
Alexander Cooper6b447b22020-07-22 00:47:18329 '^chrome/browser/devtools/',
330 '^chrome/browser/download/',
331 '^chrome/browser/extensions/',
Alexander Cooper6b447b22020-07-22 00:47:18332 '^chrome/browser/history/',
Alexander Cooper6b447b22020-07-22 00:47:18333 '^chrome/browser/lifetime/',
334 '^chrome/browser/media_galleries/',
335 '^chrome/browser/media/',
336 '^chrome/browser/metrics/',
Alexander Cooper6b447b22020-07-22 00:47:18337 '^chrome/browser/net/',
338 '^chrome/browser/notifications/',
339 '^chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc',
340 '^chrome/browser/offline_pages/',
Peter Wen6367b882020-08-05 16:55:50341 '^chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc', # pylint: disable=line-too-long
Alexander Cooper6b447b22020-07-22 00:47:18342 '^chrome/browser/payments/payment_manifest_parser_browsertest.cc',
343 '^chrome/browser/pdf/pdf_extension_test.cc',
344 '^chrome/browser/plugins/',
345 '^chrome/browser/policy/',
346 '^chrome/browser/portal/portal_browsertest.cc',
347 '^chrome/browser/prefs/profile_pref_store_manager_unittest.cc',
348 '^chrome/browser/prerender/',
349 '^chrome/browser/previews/',
350 '^chrome/browser/printing/printing_message_filter.cc',
351 '^chrome/browser/profiles/',
352 '^chrome/browser/profiling_host/profiling_process_host.cc',
353 '^chrome/browser/push_messaging/',
354 '^chrome/browser/recovery/recovery_install_global_error.cc',
355 '^chrome/browser/renderer_context_menu/',
356 '^chrome/browser/renderer_host/pepper/',
357 '^chrome/browser/resource_coordinator/',
358 '^chrome/browser/resources/chromeos/accessibility/',
359 '^chrome/browser/rlz/chrome_rlz_tracker_delegate.cc',
360 '^chrome/browser/safe_browsing/',
361 '^chrome/browser/search_engines/',
362 '^chrome/browser/service_process/',
363 '^chrome/browser/signin/',
364 '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
365 '^chrome/browser/ssl/',
366 '^chrome/browser/subresource_filter/',
367 '^chrome/browser/supervised_user/',
368 '^chrome/browser/sync_file_system/',
369 '^chrome/browser/sync/',
370 '^chrome/browser/themes/theme_service.cc',
371 '^chrome/browser/thumbnail/cc/',
Alexander Cooper6b447b22020-07-22 00:47:18372 '^chrome/browser/translate/',
373 '^chrome/browser/ui/',
Alexander Cooper6b447b22020-07-22 00:47:18374 '^chrome/browser/web_applications/',
375 '^chrome/browser/win/',
danakj7a2b7082019-05-21 21:13:51376 '^chrome/services/',
377 '^chrome/test/',
378 '^chrome/tools/',
danakj7a2b7082019-05-21 21:13:51379 '^chromecast/media/',
danakj7a2b7082019-05-21 21:13:51380 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51381 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51382 '^components/arc/',
danakj7a2b7082019-05-21 21:13:51383 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51384 '^components/component_updater/',
385 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51386 '^components/drive/',
danakj7a2b7082019-05-21 21:13:51387 '^components/nacl/',
388 '^components/navigation_interception/',
danakj7a2b7082019-05-21 21:13:51389 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51390 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51391 '^components/search_engines/',
danakj7a2b7082019-05-21 21:13:51392 '^components/security_interstitials/',
danakj7a2b7082019-05-21 21:13:51393 '^components/signin/',
danakj7a2b7082019-05-21 21:13:51394 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51395 '^components/ukm/',
danakj7a2b7082019-05-21 21:13:51396 '^components/webcrypto/',
Alan Cutter04a00642020-03-02 01:45:20397 '^extensions/browser/',
398 '^extensions/renderer/',
Alexander Cooper922f2112020-07-22 16:27:43399 '^google_apis/drive/',
danakj7a2b7082019-05-21 21:13:51400 '^ios/chrome/',
401 '^ios/components/',
402 '^ios/net/',
403 '^ios/web/',
404 '^ios/web_view/',
405 '^ipc/',
danakjc8576092019-11-26 19:01:36406 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51407 '^media/cast/',
408 '^media/cdm/',
danakj7a2b7082019-05-21 21:13:51409 '^media/filters/',
danakj7a2b7082019-05-21 21:13:51410 '^media/gpu/',
411 '^media/mojo/',
Steve Kobes334b6ed2020-07-09 07:26:31412 '^net/http/',
413 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51414 '^ppapi/proxy/',
danakj7a2b7082019-05-21 21:13:51415 '^services/',
danakj7a2b7082019-05-21 21:13:51416 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51417 '^tools/clang/base_bind_rewriters/', # Intentional.
418 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51419))
[email protected]127f18ec2012-06-16 05:05:59420
Daniel Bratell609102be2019-03-27 20:53:21421# Format: Sequence of tuples containing:
422# * String pattern or, if starting with a slash, a regular expression.
423# * Sequence of strings to show when the pattern matches.
424# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
425# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59426_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20427 (
Dave Tapuska98199b612019-07-10 13:30:44428 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53429 (
430 'New code should not use NULL. Use nullptr instead.',
431 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20432 False,
thomasandersone7caaa9b2017-03-29 19:22:53433 (),
434 ),
Peter Kasting94a56c42019-10-25 21:54:04435 (
436 r'/\busing namespace ',
437 (
438 'Using directives ("using namespace x") are banned by the Google Style',
439 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
440 'Explicitly qualify symbols or use using declarations ("using x::foo").',
441 ),
442 True,
443 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
444 ),
Antonio Gomes07300d02019-03-13 20:59:57445 # Make sure that gtest's FRIEND_TEST() macro is not used; the
446 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
447 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53448 (
[email protected]23e6cbc2012-06-16 18:51:20449 'FRIEND_TEST(',
450 (
[email protected]e3c945502012-06-26 20:01:49451 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20452 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
453 ),
454 False,
[email protected]7345da02012-11-27 14:31:49455 (),
[email protected]23e6cbc2012-06-16 18:51:20456 ),
457 (
tomhudsone2c14d552016-05-26 17:07:46458 'setMatrixClip',
459 (
460 'Overriding setMatrixClip() is prohibited; ',
461 'the base function is deprecated. ',
462 ),
463 True,
464 (),
465 ),
466 (
[email protected]52657f62013-05-20 05:30:31467 'SkRefPtr',
468 (
469 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22470 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31471 ),
472 True,
473 (),
474 ),
475 (
476 'SkAutoRef',
477 (
478 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22479 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31480 ),
481 True,
482 (),
483 ),
484 (
485 'SkAutoTUnref',
486 (
487 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22488 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31489 ),
490 True,
491 (),
492 ),
493 (
494 'SkAutoUnref',
495 (
496 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
497 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22498 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31499 ),
500 True,
501 (),
502 ),
[email protected]d89eec82013-12-03 14:10:59503 (
504 r'/HANDLE_EINTR\(.*close',
505 (
506 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
507 'descriptor will be closed, and it is incorrect to retry the close.',
508 'Either call close directly and ignore its return value, or wrap close',
509 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
510 ),
511 True,
512 (),
513 ),
514 (
515 r'/IGNORE_EINTR\((?!.*close)',
516 (
517 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
518 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
519 ),
520 True,
521 (
522 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04523 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
524 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59525 ),
526 ),
[email protected]ec5b3f02014-04-04 18:43:43527 (
528 r'/v8::Extension\(',
529 (
530 'Do not introduce new v8::Extensions into the code base, use',
531 'gin::Wrappable instead. See http://crbug.com/334679',
532 ),
533 True,
[email protected]f55c90ee62014-04-12 00:50:03534 (
Egor Paskoce145c42018-09-28 19:31:04535 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03536 ),
[email protected]ec5b3f02014-04-04 18:43:43537 ),
skyostilf9469f72015-04-20 10:38:52538 (
jame2d1a952016-04-02 00:27:10539 '#pragma comment(lib,',
540 (
541 'Specify libraries to link with in build files and not in the source.',
542 ),
543 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41544 (
tzik3f295992018-12-04 20:32:23545 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04546 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41547 ),
jame2d1a952016-04-02 00:27:10548 ),
fdorayc4ac18d2017-05-01 21:39:59549 (
Gabriel Charette7cc6c432018-04-25 20:52:02550 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59551 (
552 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
553 ),
554 False,
555 (),
556 ),
557 (
Gabriel Charette7cc6c432018-04-25 20:52:02558 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59559 (
560 'Consider using THREAD_CHECKER macros instead of the class directly.',
561 ),
562 False,
563 (),
564 ),
dbeamb6f4fde2017-06-15 04:03:06565 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06566 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
567 (
568 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
569 'deprecated (http://crbug.com/634507). Please avoid converting away',
570 'from the Time types in Chromium code, especially if any math is',
571 'being done on time values. For interfacing with platform/library',
572 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
573 'type converter methods instead. For faking TimeXXX values (for unit',
574 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
575 'other use cases, please contact base/time/OWNERS.',
576 ),
577 False,
578 (),
579 ),
580 (
dbeamb6f4fde2017-06-15 04:03:06581 'CallJavascriptFunctionUnsafe',
582 (
583 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
584 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
585 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
586 ),
587 False,
588 (
Egor Paskoce145c42018-09-28 19:31:04589 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
590 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
591 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06592 ),
593 ),
dskiba1474c2bfd62017-07-20 02:19:24594 (
595 'leveldb::DB::Open',
596 (
597 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
598 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
599 "Chrome's tracing, making their memory usage visible.",
600 ),
601 True,
602 (
603 r'^third_party/leveldatabase/.*\.(cc|h)$',
604 ),
Gabriel Charette0592c3a2017-07-26 12:02:04605 ),
606 (
Chris Mumfordc38afb62017-10-09 17:55:08607 'leveldb::NewMemEnv',
608 (
609 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58610 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
611 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08612 ),
613 True,
614 (
615 r'^third_party/leveldatabase/.*\.(cc|h)$',
616 ),
617 ),
618 (
Gabriel Charetted9839bc2017-07-29 14:17:47619 'RunLoop::QuitCurrent',
620 (
Robert Liao64b7ab22017-08-04 23:03:43621 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
622 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47623 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41624 False,
Gabriel Charetted9839bc2017-07-29 14:17:47625 (),
Gabriel Charettea44975052017-08-21 23:14:04626 ),
627 (
628 'base::ScopedMockTimeMessageLoopTaskRunner',
629 (
Gabriel Charette87cc1af2018-04-25 20:52:51630 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11631 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51632 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
633 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
634 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04635 ),
Gabriel Charette87cc1af2018-04-25 20:52:51636 False,
Gabriel Charettea44975052017-08-21 23:14:04637 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57638 ),
639 (
Dave Tapuska98199b612019-07-10 13:30:44640 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57641 (
642 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02643 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57644 ),
645 True,
646 (),
Francois Doray43670e32017-09-27 12:40:38647 ),
648 (
Peter Kasting991618a62019-06-17 22:00:09649 r'/\bstd::stoi\b',
650 (
651 'std::stoi uses exceptions to communicate results. ',
652 'Use base::StringToInt() instead.',
653 ),
654 True,
655 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
656 ),
657 (
658 r'/\bstd::stol\b',
659 (
660 'std::stol uses exceptions to communicate results. ',
661 'Use base::StringToInt() instead.',
662 ),
663 True,
664 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
665 ),
666 (
667 r'/\bstd::stoul\b',
668 (
669 'std::stoul uses exceptions to communicate results. ',
670 'Use base::StringToUint() instead.',
671 ),
672 True,
673 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
674 ),
675 (
676 r'/\bstd::stoll\b',
677 (
678 'std::stoll uses exceptions to communicate results. ',
679 'Use base::StringToInt64() instead.',
680 ),
681 True,
682 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
683 ),
684 (
685 r'/\bstd::stoull\b',
686 (
687 'std::stoull uses exceptions to communicate results. ',
688 'Use base::StringToUint64() instead.',
689 ),
690 True,
691 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
692 ),
693 (
694 r'/\bstd::stof\b',
695 (
696 'std::stof uses exceptions to communicate results. ',
697 'For locale-independent values, e.g. reading numbers from disk',
698 'profiles, use base::StringToDouble().',
699 'For user-visible values, parse using ICU.',
700 ),
701 True,
702 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
703 ),
704 (
705 r'/\bstd::stod\b',
706 (
707 'std::stod uses exceptions to communicate results. ',
708 'For locale-independent values, e.g. reading numbers from disk',
709 'profiles, use base::StringToDouble().',
710 'For user-visible values, parse using ICU.',
711 ),
712 True,
713 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
714 ),
715 (
716 r'/\bstd::stold\b',
717 (
718 'std::stold uses exceptions to communicate results. ',
719 'For locale-independent values, e.g. reading numbers from disk',
720 'profiles, use base::StringToDouble().',
721 'For user-visible values, parse using ICU.',
722 ),
723 True,
724 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
725 ),
726 (
Daniel Bratell69334cc2019-03-26 11:07:45727 r'/\bstd::to_string\b',
728 (
729 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09730 'For locale-independent strings, e.g. writing numbers to disk',
731 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45732 'For user-visible strings, use base::FormatNumber() and',
733 'the related functions in base/i18n/number_formatting.h.',
734 ),
Peter Kasting991618a62019-06-17 22:00:09735 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21736 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45737 ),
738 (
739 r'/\bstd::shared_ptr\b',
740 (
741 'std::shared_ptr should not be used. Use scoped_refptr instead.',
742 ),
743 True,
Alex Chau9eb03cdd52020-07-13 21:04:57744 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
745 'array_buffer_contents\.(cc|h)',
746 # Needed for interop with third-party library
747 'chrome/services/sharing/nearby/',
748 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21749 ),
750 (
Peter Kasting991618a62019-06-17 22:00:09751 r'/\bstd::weak_ptr\b',
752 (
753 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
754 ),
755 True,
756 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
757 ),
758 (
Daniel Bratell609102be2019-03-27 20:53:21759 r'/\blong long\b',
760 (
761 'long long is banned. Use stdint.h if you need a 64 bit number.',
762 ),
763 False, # Only a warning since it is already used.
764 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
765 ),
766 (
767 r'/\bstd::bind\b',
768 (
769 'std::bind is banned because of lifetime risks.',
770 'Use base::BindOnce or base::BindRepeating instead.',
771 ),
772 True,
773 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
774 ),
775 (
776 r'/\b#include <chrono>\b',
777 (
778 '<chrono> overlaps with Time APIs in base. Keep using',
779 'base classes.',
780 ),
781 True,
782 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
783 ),
784 (
785 r'/\b#include <exception>\b',
786 (
787 'Exceptions are banned and disabled in Chromium.',
788 ),
789 True,
790 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
791 ),
792 (
793 r'/\bstd::function\b',
794 (
795 'std::function is banned. Instead use base::Callback which directly',
796 'supports Chromium\'s weak pointers, ref counting and more.',
797 ),
Peter Kasting991618a62019-06-17 22:00:09798 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21799 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
800 ),
801 (
802 r'/\b#include <random>\b',
803 (
804 'Do not use any random number engines from <random>. Instead',
805 'use base::RandomBitGenerator.',
806 ),
807 True,
808 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
809 ),
810 (
Tom Andersona95e12042020-09-09 23:08:00811 r'/\b#include <X11/',
812 (
813 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
814 ),
815 True,
816 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
817 ),
818 (
Daniel Bratell609102be2019-03-27 20:53:21819 r'/\bstd::ratio\b',
820 (
821 'std::ratio is banned by the Google Style Guide.',
822 ),
823 True,
824 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45825 ),
826 (
Francois Doray43670e32017-09-27 12:40:38827 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
828 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
829 (
830 'Use the new API in base/threading/thread_restrictions.h.',
831 ),
Gabriel Charette04b138f2018-08-06 00:03:22832 False,
Francois Doray43670e32017-09-27 12:40:38833 (),
834 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38835 (
danakj7a2b7082019-05-21 21:13:51836 r'/\bbase::Bind\(',
837 (
838 'Please use base::Bind{Once,Repeating} instead',
839 'of base::Bind. (crbug.com/714018)',
840 ),
841 False,
Erik Staaba737d7602019-11-25 18:41:07842 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51843 ),
844 (
845 r'/\bbase::Callback[<:]',
846 (
847 'Please use base::{Once,Repeating}Callback instead',
848 'of base::Callback. (crbug.com/714018)',
849 ),
850 False,
Erik Staaba737d7602019-11-25 18:41:07851 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51852 ),
853 (
854 r'/\bbase::Closure\b',
855 (
856 'Please use base::{Once,Repeating}Closure instead',
857 'of base::Closure. (crbug.com/714018)',
858 ),
859 False,
Erik Staaba737d7602019-11-25 18:41:07860 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51861 ),
862 (
Michael Giuffrida7f93d6922019-04-19 14:39:58863 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19864 (
865 'RunMessageLoop is deprecated, use RunLoop instead.',
866 ),
867 False,
868 (),
869 ),
870 (
Dave Tapuska98199b612019-07-10 13:30:44871 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19872 (
873 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
874 ),
875 False,
876 (),
877 ),
878 (
Dave Tapuska98199b612019-07-10 13:30:44879 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19880 (
881 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
882 "if you're convinced you need this.",
883 ),
884 False,
885 (),
886 ),
887 (
Dave Tapuska98199b612019-07-10 13:30:44888 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19889 (
890 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04891 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19892 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
893 'async events instead of flushing threads.',
894 ),
895 False,
896 (),
897 ),
898 (
899 r'MessageLoopRunner',
900 (
901 'MessageLoopRunner is deprecated, use RunLoop instead.',
902 ),
903 False,
904 (),
905 ),
906 (
Dave Tapuska98199b612019-07-10 13:30:44907 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19908 (
909 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
910 "gab@ if you found a use case where this is the only solution.",
911 ),
912 False,
913 (),
914 ),
915 (
Victor Costane48a2e82019-03-15 22:02:34916 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16917 (
Victor Costane48a2e82019-03-15 22:02:34918 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16919 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
920 ),
921 True,
922 (
923 r'^sql/initialization\.(cc|h)$',
924 r'^third_party/sqlite/.*\.(c|cc|h)$',
925 ),
926 ),
Matt Menke7f520a82018-03-28 21:38:37927 (
Dave Tapuska98199b612019-07-10 13:30:44928 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47929 (
930 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
931 'base::RandomShuffle instead.'
932 ),
933 True,
934 (),
935 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24936 (
937 'ios/web/public/test/http_server',
938 (
939 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
940 ),
941 False,
942 (),
943 ),
Robert Liao764c9492019-01-24 18:46:28944 (
945 'GetAddressOf',
946 (
947 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53948 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11949 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53950 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28951 ),
952 True,
953 (),
954 ),
Antonio Gomes07300d02019-03-13 20:59:57955 (
956 'DEFINE_TYPE_CASTS',
957 (
958 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
959 '//third_party/blink/renderer/platform/casting.h.'
960 ),
961 True,
962 (
963 r'^third_party/blink/renderer/.*\.(cc|h)$',
964 ),
965 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38966 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45967 r'/\bIsHTML.+Element\(\b',
968 (
969 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
970 ' helpers IsA<HTMLXXXXElement> from ',
971 '//third_party/blink/renderer/platform/casting.h.'
972 ),
973 False,
974 (
975 r'^third_party/blink/renderer/.*\.(cc|h)$',
976 ),
977 ),
978 (
979 r'/\bToHTML.+Element(|OrNull)\(\b',
980 (
981 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
982 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
983 'and DynamicTo<HTMLXXXXElement> from ',
984 '//third_party/blink/renderer/platform/casting.h.'
985 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
986 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
987 ),
988 False,
989 (
990 r'^third_party/blink/renderer/.*\.(cc|h)$',
991 ),
992 ),
993 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37994 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38995 (
996 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
997 ),
998 True,
999 (),
1000 ),
Ben Lewisa9514602019-04-29 17:53:051001 (
1002 'SHFileOperation',
1003 (
1004 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1005 'complex functions to achieve the same goals. Use IFileOperation for ',
1006 'any esoteric actions instead.'
1007 ),
1008 True,
1009 (),
1010 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181011 (
Cliff Smolinsky81951642019-04-30 21:39:511012 'StringFromGUID2',
1013 (
1014 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241015 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511016 ),
1017 True,
1018 (
1019 r'/base/win/win_util_unittest.cc'
1020 ),
1021 ),
1022 (
1023 'StringFromCLSID',
1024 (
1025 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241026 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511027 ),
1028 True,
1029 (
1030 r'/base/win/win_util_unittest.cc'
1031 ),
1032 ),
1033 (
Avi Drissman7382afa02019-04-29 23:27:131034 'kCFAllocatorNull',
1035 (
1036 'The use of kCFAllocatorNull with the NoCopy creation of ',
1037 'CoreFoundation types is prohibited.',
1038 ),
1039 True,
1040 (),
1041 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291042 (
1043 'mojo::ConvertTo',
1044 (
1045 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1046 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1047 'StringTraits if you would like to convert between custom types and',
1048 'the wire format of mojom types.'
1049 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221050 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291051 (
Wezf89dec092019-09-11 19:38:331052 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1053 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291054 r'^third_party/blink/.*\.(cc|h)$',
1055 r'^content/renderer/.*\.(cc|h)$',
1056 ),
1057 ),
Robert Liao1d78df52019-11-11 20:02:011058 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161059 'GetInterfaceProvider',
1060 (
1061 'InterfaceProvider is deprecated.',
1062 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1063 'or Platform::GetBrowserInterfaceBroker.'
1064 ),
1065 False,
1066 (),
1067 ),
1068 (
Robert Liao1d78df52019-11-11 20:02:011069 'CComPtr',
1070 (
1071 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1072 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1073 'details.'
1074 ),
1075 False,
1076 (),
1077 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201078 (
1079 r'/\b(IFACE|STD)METHOD_?\(',
1080 (
1081 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1082 'Instead, always use IFACEMETHODIMP in the declaration.'
1083 ),
1084 False,
1085 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1086 ),
Allen Bauer53b43fb12020-03-12 17:21:471087 (
1088 'set_owned_by_client',
1089 (
1090 'set_owned_by_client is deprecated.',
1091 'views::View already owns the child views by default. This introduces ',
1092 'a competing ownership model which makes the code difficult to reason ',
1093 'about. See http://crbug.com/1044687 for more details.'
1094 ),
1095 False,
1096 (),
1097 ),
Eric Secklerbe6f48d2020-05-06 18:09:121098 (
1099 r'/\bTRACE_EVENT_ASYNC_',
1100 (
1101 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1102 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1103 ),
1104 False,
1105 (
1106 r'^base/trace_event/.*',
1107 r'^base/tracing/.*',
1108 ),
1109 ),
[email protected]127f18ec2012-06-16 05:05:591110)
1111
Mario Sanchez Prada2472cab2019-09-18 10:58:311112# Format: Sequence of tuples containing:
1113# * String pattern or, if starting with a slash, a regular expression.
1114# * Sequence of strings to show when the pattern matches.
1115_DEPRECATED_MOJO_TYPES = (
1116 (
1117 r'/\bmojo::AssociatedBinding\b',
1118 (
1119 'mojo::AssociatedBinding<Interface> is deprecated.',
1120 'Use mojo::AssociatedReceiver<Interface> instead.',
1121 ),
1122 ),
1123 (
1124 r'/\bmojo::AssociatedBindingSet\b',
1125 (
1126 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1127 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1128 ),
1129 ),
1130 (
1131 r'/\bmojo::AssociatedInterfacePtr\b',
1132 (
1133 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1134 'Use mojo::AssociatedRemote<Interface> instead.',
1135 ),
1136 ),
1137 (
1138 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1139 (
1140 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1141 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1142 ),
1143 ),
1144 (
1145 r'/\bmojo::AssociatedInterfaceRequest\b',
1146 (
1147 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1148 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1149 ),
1150 ),
1151 (
1152 r'/\bmojo::Binding\b',
1153 (
1154 'mojo::Binding<Interface> is deprecated.',
1155 'Use mojo::Receiver<Interface> instead.',
1156 ),
1157 ),
1158 (
1159 r'/\bmojo::BindingSet\b',
1160 (
1161 'mojo::BindingSet<Interface> is deprecated.',
1162 'Use mojo::ReceiverSet<Interface> instead.',
1163 ),
1164 ),
1165 (
1166 r'/\bmojo::InterfacePtr\b',
1167 (
1168 'mojo::InterfacePtr<Interface> is deprecated.',
1169 'Use mojo::Remote<Interface> instead.',
1170 ),
1171 ),
1172 (
1173 r'/\bmojo::InterfacePtrInfo\b',
1174 (
1175 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1176 'Use mojo::PendingRemote<Interface> instead.',
1177 ),
1178 ),
1179 (
1180 r'/\bmojo::InterfaceRequest\b',
1181 (
1182 'mojo::InterfaceRequest<Interface> is deprecated.',
1183 'Use mojo::PendingReceiver<Interface> instead.',
1184 ),
1185 ),
1186 (
1187 r'/\bmojo::MakeRequest\b',
1188 (
1189 'mojo::MakeRequest is deprecated.',
1190 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1191 ),
1192 ),
1193 (
1194 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1195 (
1196 'mojo::MakeRequest is deprecated.',
1197 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181198 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311199 ),
1200 ),
1201 (
1202 r'/\bmojo::MakeStrongBinding\b',
1203 (
1204 'mojo::MakeStrongBinding is deprecated.',
1205 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1206 'mojo::MakeSelfOwnedReceiver() instead.',
1207 ),
1208 ),
1209 (
1210 r'/\bmojo::MakeStrongAssociatedBinding\b',
1211 (
1212 'mojo::MakeStrongAssociatedBinding is deprecated.',
1213 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1214 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1215 ),
1216 ),
1217 (
Gyuyoung Kim4952ba62020-07-07 07:33:441218 r'/\bmojo::StrongAssociatedBinding\b',
1219 (
1220 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1221 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1222 ),
1223 ),
1224 (
1225 r'/\bmojo::StrongBinding\b',
1226 (
1227 'mojo::StrongBinding<Interface> is deprecated.',
1228 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1229 ),
1230 ),
1231 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311232 r'/\bmojo::StrongAssociatedBindingSet\b',
1233 (
1234 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1235 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1236 ),
1237 ),
1238 (
1239 r'/\bmojo::StrongBindingSet\b',
1240 (
1241 'mojo::StrongBindingSet<Interface> is deprecated.',
1242 'Use mojo::UniqueReceiverSet<Interface> instead.',
1243 ),
1244 ),
1245)
wnwenbdc444e2016-05-25 13:44:151246
mlamouria82272622014-09-16 18:45:041247_IPC_ENUM_TRAITS_DEPRECATED = (
1248 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501249 'See http://www.chromium.org/Home/chromium-security/education/'
1250 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041251
Stephen Martinis97a394142018-06-07 23:06:051252_LONG_PATH_ERROR = (
1253 'Some files included in this CL have file names that are too long (> 200'
1254 ' characters). If committed, these files will cause issues on Windows. See'
1255 ' https://crbug.com/612667 for more details.'
1256)
1257
Shenghua Zhangbfaa38b82017-11-16 21:58:021258_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041259 r".*[\\/]BuildHooksAndroidImpl\.java",
1260 r".*[\\/]LicenseContentProvider\.java",
1261 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281262 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021263]
[email protected]127f18ec2012-06-16 05:05:591264
Mohamed Heikald048240a2019-11-12 16:57:371265# List of image extensions that are used as resources in chromium.
1266_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1267
Sean Kau46e29bc2017-08-28 16:31:161268# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401269_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041270 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401271 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041272 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1273 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041274 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431275 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161276]
1277
1278
[email protected]b00342e7f2013-03-26 16:21:541279_VALID_OS_MACROS = (
1280 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081281 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541282 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441283 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121284 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541285 'OS_BSD',
1286 'OS_CAT', # For testing.
1287 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041288 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541289 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371290 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541291 'OS_IOS',
1292 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441293 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541294 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211295 'OS_NACL_NONSFI',
1296 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121297 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541298 'OS_OPENBSD',
1299 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371300 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541301 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541302 'OS_WIN',
1303)
1304
1305
Andrew Grieveb773bad2020-06-05 18:00:381306# These are not checked on the public chromium-presubmit trybot.
1307# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041308# checkouts.
agrievef32bcc72016-04-04 14:57:401309_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381310 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381311]
1312
1313
1314_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041315 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361316 'base/android/jni_generator/jni_generator.pydeps',
1317 'base/android/jni_generator/jni_registration_generator.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041318 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361319 'build/android/gyp/aar.pydeps',
1320 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271321 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361322 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381323 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111325 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361326 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361327 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361328 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111329 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041330 'build/android/gyp/create_app_bundle_apks.pydeps',
1331 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361332 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121333 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221334 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001335 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361336 'build/android/gyp/desugar.pydeps',
1337 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421338 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041339 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361340 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361341 'build/android/gyp/filter_zip.pydeps',
1342 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361343 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361344 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581345 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361346 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141347 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261348 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011349 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041350 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361351 'build/android/gyp/lint.pydeps',
1352 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/gyp/merge_manifest.pydeps',
1354 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221355 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361356 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461357 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241358 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361359 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461360 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561361 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361362 'build/android/incremental_install/generate_android_manifest.pydeps',
1363 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041364 'build/android/resource_sizes.pydeps',
1365 'build/android/test_runner.pydeps',
1366 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361367 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361368 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271369 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1370 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001371 'components/cronet/tools/generate_javadoc.pydeps',
1372 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381373 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001374 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381375 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041376 'testing/scripts/run_android_wpt.pydeps',
1377 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421378 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1379 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131380 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191381 ('third_party/blink/renderer/bindings/scripts/'
1382 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061383 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221384 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401385]
1386
wnwenbdc444e2016-05-25 13:44:151387
agrievef32bcc72016-04-04 14:57:401388_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1389
1390
Eric Boren6fd2b932018-01-25 15:05:081391# Bypass the AUTHORS check for these accounts.
1392_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591393 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451394 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591395 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521396 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071397 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041398 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271399 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041400 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301401 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081402
1403
Daniel Bratell65b033262019-04-23 08:17:061404def _IsCPlusPlusFile(input_api, file_path):
1405 """Returns True if this file contains C++-like code (and not Python,
1406 Go, Java, MarkDown, ...)"""
1407
1408 ext = input_api.os_path.splitext(file_path)[1]
1409 # This list is compatible with CppChecker.IsCppFile but we should
1410 # consider adding ".c" to it. If we do that we can use this function
1411 # at more places in the code.
1412 return ext in (
1413 '.h',
1414 '.cc',
1415 '.cpp',
1416 '.m',
1417 '.mm',
1418 )
1419
1420def _IsCPlusPlusHeaderFile(input_api, file_path):
1421 return input_api.os_path.splitext(file_path)[1] == ".h"
1422
1423
1424def _IsJavaFile(input_api, file_path):
1425 return input_api.os_path.splitext(file_path)[1] == ".java"
1426
1427
1428def _IsProtoFile(input_api, file_path):
1429 return input_api.os_path.splitext(file_path)[1] == ".proto"
1430
Saagar Sanghavifceeaae2020-08-12 16:40:361431def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191432 """Attempts to prevent use of functions intended only for testing in
1433 non-testing code. For now this is just a best-effort implementation
1434 that ignores header files and may have some false positives. A
1435 better implementation would probably need a proper C++ parser.
1436 """
1437 # We only scan .cc files and the like, as the declaration of
1438 # for-testing functions in header files are hard to distinguish from
1439 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491440 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191441
jochenc0d4808c2015-07-27 09:25:421442 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191443 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091444 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131445 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191446 exclusion_pattern = input_api.re.compile(
1447 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1448 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131449 # Avoid a false positive in this case, where the method name, the ::, and
1450 # the closing { are all on different lines due to line wrapping.
1451 # HelperClassForTesting::
1452 # HelperClassForTesting(
1453 # args)
1454 # : member(0) {}
1455 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191456
1457 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441458 files_to_skip = (_EXCLUDED_PATHS +
1459 _TEST_CODE_EXCLUDED_PATHS +
1460 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191461 return input_api.FilterSourceFile(
1462 affected_file,
James Cook24a504192020-07-23 00:08:441463 files_to_check=file_inclusion_pattern,
1464 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191465
1466 problems = []
1467 for f in input_api.AffectedSourceFiles(FilterFile):
1468 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131469 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241470 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031471 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461472 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131473 not exclusion_pattern.search(line) and
1474 not allowlist_pattern.search(line) and
1475 not in_method_defn):
[email protected]55459852011-08-10 15:17:191476 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031477 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131478 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191479
1480 if problems:
[email protected]f7051d52013-04-02 18:31:421481 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031482 else:
1483 return []
[email protected]55459852011-08-10 15:17:191484
1485
Saagar Sanghavifceeaae2020-08-12 16:40:361486def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231487 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591488 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231489 """
1490 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1491 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1492 name_pattern = r'ForTest(s|ing)?'
1493 # Describes an occurrence of "ForTest*" inside a // comment.
1494 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501495 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551496 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231497 # Catch calls.
1498 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1499 # Ignore definitions. (Comments are ignored separately.)
1500 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1501
1502 problems = []
1503 sources = lambda x: input_api.FilterSourceFile(
1504 x,
James Cook24a504192020-07-23 00:08:441505 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1506 + input_api.DEFAULT_FILES_TO_SKIP),
1507 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231508 )
1509 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1510 local_path = f.LocalPath()
1511 is_inside_javadoc = False
1512 for line_number, line in f.ChangedContents():
1513 if is_inside_javadoc and javadoc_end_re.search(line):
1514 is_inside_javadoc = False
1515 if not is_inside_javadoc and javadoc_start_re.search(line):
1516 is_inside_javadoc = True
1517 if is_inside_javadoc:
1518 continue
1519 if (inclusion_re.search(line) and
1520 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501521 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231522 not exclusion_re.search(line)):
1523 problems.append(
1524 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1525
1526 if problems:
1527 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1528 else:
1529 return []
1530
1531
Saagar Sanghavifceeaae2020-08-12 16:40:361532def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541533 """Checks to make sure no .h files include <iostream>."""
1534 files = []
1535 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1536 input_api.re.MULTILINE)
1537 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1538 if not f.LocalPath().endswith('.h'):
1539 continue
1540 contents = input_api.ReadFile(f)
1541 if pattern.search(contents):
1542 files.append(f)
1543
1544 if len(files):
yolandyandaabc6d2016-04-18 18:29:391545 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061546 'Do not #include <iostream> in header files, since it inserts static '
1547 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541548 '#include <ostream>. See http://crbug.com/94794',
1549 files) ]
1550 return []
1551
Danil Chapovalov3518f362018-08-11 16:13:431552def _CheckNoStrCatRedefines(input_api, output_api):
1553 """Checks no windows headers with StrCat redefined are included directly."""
1554 files = []
1555 pattern_deny = input_api.re.compile(
1556 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1557 input_api.re.MULTILINE)
1558 pattern_allow = input_api.re.compile(
1559 r'^#include\s"base/win/windows_defines.inc"',
1560 input_api.re.MULTILINE)
1561 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1562 contents = input_api.ReadFile(f)
1563 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1564 files.append(f.LocalPath())
1565
1566 if len(files):
1567 return [output_api.PresubmitError(
1568 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1569 'directly since they pollute code with StrCat macro. Instead, '
1570 'include matching header from base/win. See http://crbug.com/856536',
1571 files) ]
1572 return []
1573
[email protected]10689ca2011-09-02 02:31:541574
Saagar Sanghavifceeaae2020-08-12 16:40:361575def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521576 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181577 problems = []
1578 for f in input_api.AffectedFiles():
1579 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1580 continue
1581
1582 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041583 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181584 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1585
1586 if not problems:
1587 return []
1588 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1589 '\n'.join(problems))]
1590
Saagar Sanghavifceeaae2020-08-12 16:40:361591def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341592 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1593
1594 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1595 instead of DISABLED_. To filter false positives, reports are only generated
1596 if a corresponding MAYBE_ line exists.
1597 """
1598 problems = []
1599
1600 # The following two patterns are looked for in tandem - is a test labeled
1601 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1602 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1603 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1604
1605 # This is for the case that a test is disabled on all platforms.
1606 full_disable_pattern = input_api.re.compile(
1607 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1608 input_api.re.MULTILINE)
1609
Katie Df13948e2018-09-25 07:33:441610 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341611 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1612 continue
1613
1614 # Search for MABYE_, DISABLE_ pairs.
1615 disable_lines = {} # Maps of test name to line number.
1616 maybe_lines = {}
1617 for line_num, line in f.ChangedContents():
1618 disable_match = disable_pattern.search(line)
1619 if disable_match:
1620 disable_lines[disable_match.group(1)] = line_num
1621 maybe_match = maybe_pattern.search(line)
1622 if maybe_match:
1623 maybe_lines[maybe_match.group(1)] = line_num
1624
1625 # Search for DISABLE_ occurrences within a TEST() macro.
1626 disable_tests = set(disable_lines.keys())
1627 maybe_tests = set(maybe_lines.keys())
1628 for test in disable_tests.intersection(maybe_tests):
1629 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1630
1631 contents = input_api.ReadFile(f)
1632 full_disable_match = full_disable_pattern.search(contents)
1633 if full_disable_match:
1634 problems.append(' %s' % f.LocalPath())
1635
1636 if not problems:
1637 return []
1638 return [
1639 output_api.PresubmitPromptWarning(
1640 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1641 '\n'.join(problems))
1642 ]
1643
[email protected]72df4e782012-06-21 16:28:181644
Saagar Sanghavifceeaae2020-08-12 16:40:361645def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571646 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521647 errors = []
Hans Wennborg944479f2020-06-25 21:39:251648 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521649 input_api.re.MULTILINE)
1650 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1651 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1652 continue
1653 for lnum, line in f.ChangedContents():
1654 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171655 errors.append(output_api.PresubmitError(
1656 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571657 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171658 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521659 return errors
1660
1661
Makoto Shimazu3ad422cd2019-05-08 02:35:141662def _FindHistogramNameInChunk(histogram_name, chunk):
1663 """Tries to find a histogram name or prefix in a line.
1664
1665 Returns the existence of the histogram name, or None if it needs more chunk
1666 to determine."""
mcasasb7440c282015-02-04 14:52:191667 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1668 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141669 if '<affected-histogram' in chunk:
1670 # If the tag is not completed, needs more chunk to get the name.
1671 if not '>' in chunk:
1672 return None
1673 if not 'name="' in chunk:
1674 return False
1675 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1676 # expect the only attribute is the name.
1677 histogram_prefix = chunk.split('"')[1]
1678 return histogram_prefix in histogram_name
1679 # Typically the whole histogram name should in the line.
1680 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191681
1682
Saagar Sanghavifceeaae2020-08-12 16:40:361683def CheckUmaHistogramChangesOnUpload(input_api, output_api):
mcasasb7440c282015-02-04 14:52:191684 """Check that UMA histogram names in touched lines can still be found in other
1685 lines of the patch or in histograms.xml. Note that this check would not catch
1686 the reverse: changes in histograms.xml not matched in the code itself."""
1687 touched_histograms = []
1688 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471689 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1690 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1691 name_pattern = r'"(.*?)"'
1692 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1693 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1694 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1695 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1696 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171697 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191698 for f in input_api.AffectedFiles():
1699 # If histograms.xml itself is modified, keep the modified lines for later.
1700 if f.LocalPath().endswith(('histograms.xml')):
1701 histograms_xml_modifications = f.ChangedContents()
1702 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471703 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1704 single_line_re = single_line_c_re
1705 split_line_prefix_re = split_line_c_prefix_re
1706 elif f.LocalPath().endswith(('java')):
1707 single_line_re = single_line_java_re
1708 split_line_prefix_re = split_line_java_prefix_re
1709 else:
mcasasb7440c282015-02-04 14:52:191710 continue
1711 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171712 if last_line_matched_prefix:
1713 suffix_found = split_line_suffix_re.search(line)
1714 if suffix_found :
1715 touched_histograms.append([suffix_found.group(1), f, line_num])
1716 last_line_matched_prefix = False
1717 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061718 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191719 if found:
1720 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171721 continue
1722 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191723
1724 # Search for the touched histogram names in the local modifications to
1725 # histograms.xml, and, if not found, on the base histograms.xml file.
1726 unmatched_histograms = []
1727 for histogram_info in touched_histograms:
1728 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141729 chunk = ''
mcasasb7440c282015-02-04 14:52:191730 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141731 chunk += line
1732 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1733 if histogram_name_found is None:
1734 continue
1735 chunk = ''
mcasasb7440c282015-02-04 14:52:191736 if histogram_name_found:
1737 break
1738 if not histogram_name_found:
1739 unmatched_histograms.append(histogram_info)
1740
eromanb90c82e7e32015-04-01 15:13:491741 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191742 problems = []
1743 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491744 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191745 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451746 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191747 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141748 chunk = ''
mcasasb7440c282015-02-04 14:52:191749 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141750 chunk += line
1751 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1752 chunk)
1753 if histogram_name_found is None:
1754 continue
1755 chunk = ''
mcasasb7440c282015-02-04 14:52:191756 if histogram_name_found:
1757 break
1758 if not histogram_name_found:
1759 problems.append(' [%s:%d] %s' %
1760 (f.LocalPath(), line_num, histogram_name))
1761
1762 if not problems:
1763 return []
1764 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1765 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491766 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191767
wnwenbdc444e2016-05-25 13:44:151768
Saagar Sanghavifceeaae2020-08-12 16:40:361769def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391770 """Check that FlakyTest annotation is our own instead of the android one"""
1771 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1772 files = []
1773 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1774 if f.LocalPath().endswith('Test.java'):
1775 if pattern.search(input_api.ReadFile(f)):
1776 files.append(f)
1777 if len(files):
1778 return [output_api.PresubmitError(
1779 'Use org.chromium.base.test.util.FlakyTest instead of '
1780 'android.test.FlakyTest',
1781 files)]
1782 return []
mcasasb7440c282015-02-04 14:52:191783
wnwenbdc444e2016-05-25 13:44:151784
Saagar Sanghavifceeaae2020-08-12 16:40:361785def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221786 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271787 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221788 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201789 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571790 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341791 '/win/' in f.LocalPath() or
1792 'chrome_elf' in f.LocalPath() or
1793 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201794 continue
[email protected]8ea5d4b2011-09-13 21:49:221795
[email protected]a11dbe9b2012-08-07 01:32:581796 allowWString = False
[email protected]b5c24292011-11-28 14:38:201797 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581798 if 'presubmit: allow wstring' in line:
1799 allowWString = True
1800 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271801 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581802 allowWString = False
1803 else:
1804 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221805
[email protected]55463aa62011-10-12 00:48:271806 if not problems:
1807 return []
1808 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581809 ' If you are calling a cross-platform API that accepts a wstring, '
1810 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271811 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221812
1813
Saagar Sanghavifceeaae2020-08-12 16:40:361814def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441815 """Make sure .DEPS.git is never modified manually."""
1816 if any(f.LocalPath().endswith('.DEPS.git') for f in
1817 input_api.AffectedFiles()):
1818 return [output_api.PresubmitError(
1819 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1820 'automated system based on what\'s in DEPS and your changes will be\n'
1821 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501822 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1823 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441824 'for more information')]
1825 return []
1826
1827
Saagar Sanghavifceeaae2020-08-12 16:40:361828def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471829 """Checks that DEPS file deps are from allowed_hosts."""
1830 # Run only if DEPS file has been modified to annoy fewer bystanders.
1831 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1832 return []
1833 # Outsource work to gclient verify
1834 try:
John Budorickf20c0042019-04-25 23:23:401835 gclient_path = input_api.os_path.join(
1836 input_api.PresubmitLocalPath(),
1837 'third_party', 'depot_tools', 'gclient.py')
1838 input_api.subprocess.check_output(
1839 [input_api.python_executable, gclient_path, 'verify'],
1840 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471841 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201842 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471843 return [output_api.PresubmitError(
1844 'DEPS file must have only git dependencies.',
1845 long_text=error.output)]
1846
1847
Mario Sanchez Prada2472cab2019-09-18 10:58:311848def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1849 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591850 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311851
1852 Returns an string composed of the name of the file, the line number where the
1853 match has been found and the additional text passed as |message| in case the
1854 target type name matches the text inside the line passed as parameter.
1855 """
Peng Huang9c5949a02020-06-11 19:20:541856 result = []
1857
1858 if line.endswith(" nocheck"):
1859 return result
1860
Mario Sanchez Prada2472cab2019-09-18 10:58:311861 matched = False
1862 if type_name[0:1] == '/':
1863 regex = type_name[1:]
1864 if input_api.re.search(regex, line):
1865 matched = True
1866 elif type_name in line:
1867 matched = True
1868
Mario Sanchez Prada2472cab2019-09-18 10:58:311869 if matched:
1870 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1871 for message_line in message:
1872 result.append(' %s' % message_line)
1873
1874 return result
1875
1876
Saagar Sanghavifceeaae2020-08-12 16:40:361877def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591878 """Make sure that banned functions are not used."""
1879 warnings = []
1880 errors = []
1881
James Cook24a504192020-07-23 00:08:441882 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151883 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441884 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151885 if input_api.re.match(item, local_path):
1886 return True
1887 return False
1888
Peter K. Lee6c03ccff2019-07-15 14:40:051889 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541890 local_path = affected_file.LocalPath()
1891 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1892 return False
1893 basename = input_api.os_path.basename(local_path)
1894 if 'ios' in basename.split('_'):
1895 return True
1896 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1897 if sep and 'ios' in local_path.split(sep):
1898 return True
1899 return False
1900
wnwenbdc444e2016-05-25 13:44:151901 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311902 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1903 func_name, message)
1904 if problems:
wnwenbdc444e2016-05-25 13:44:151905 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311906 errors.extend(problems)
1907 else:
1908 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151909
Eric Stevensona9a980972017-09-23 00:04:411910 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1911 for f in input_api.AffectedFiles(file_filter=file_filter):
1912 for line_num, line in f.ChangedContents():
1913 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1914 CheckForMatch(f, line_num, line, func_name, message, error)
1915
[email protected]127f18ec2012-06-16 05:05:591916 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1917 for f in input_api.AffectedFiles(file_filter=file_filter):
1918 for line_num, line in f.ChangedContents():
1919 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151920 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591921
Peter K. Lee6c03ccff2019-07-15 14:40:051922 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541923 for line_num, line in f.ChangedContents():
1924 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1925 CheckForMatch(f, line_num, line, func_name, message, error)
1926
Peter K. Lee6c03ccff2019-07-15 14:40:051927 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1928 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1929 for line_num, line in f.ChangedContents():
1930 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1931 CheckForMatch(f, line_num, line, func_name, message, error)
1932
[email protected]127f18ec2012-06-16 05:05:591933 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1934 for f in input_api.AffectedFiles(file_filter=file_filter):
1935 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491936 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441937 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491938 continue
wnwenbdc444e2016-05-25 13:44:151939 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591940
1941 result = []
1942 if (warnings):
1943 result.append(output_api.PresubmitPromptWarning(
1944 'Banned functions were used.\n' + '\n'.join(warnings)))
1945 if (errors):
1946 result.append(output_api.PresubmitError(
1947 'Banned functions were used.\n' + '\n'.join(errors)))
1948 return result
1949
1950
Michael Thiessen44457642020-02-06 00:24:151951def _CheckAndroidNoBannedImports(input_api, output_api):
1952 """Make sure that banned java imports are not used."""
1953 errors = []
1954
1955 def IsException(path, exceptions):
1956 for exception in exceptions:
1957 if (path.startswith(exception)):
1958 return True
1959 return False
1960
1961 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1962 for f in input_api.AffectedFiles(file_filter=file_filter):
1963 for line_num, line in f.ChangedContents():
1964 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1965 if IsException(f.LocalPath(), exceptions):
1966 continue;
1967 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1968 'import ' + import_name, message)
1969 if problems:
1970 errors.extend(problems)
1971 result = []
1972 if (errors):
1973 result.append(output_api.PresubmitError(
1974 'Banned imports were used.\n' + '\n'.join(errors)))
1975 return result
1976
1977
Saagar Sanghavifceeaae2020-08-12 16:40:361978def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311979 """Make sure that old Mojo types are not used."""
1980 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571981 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311982
Mario Sanchez Pradaaab91382019-12-19 08:57:091983 # For any path that is not an "ok" or an "error" path, a warning will be
1984 # raised if deprecated mojo types are found.
1985 ok_paths = ['components/arc']
1986 error_paths = ['third_party/blink', 'content']
1987
Mario Sanchez Prada2472cab2019-09-18 10:58:311988 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1989 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571990 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091991 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311992 continue
1993
1994 for line_num, line in f.ChangedContents():
1995 for func_name, message in _DEPRECATED_MOJO_TYPES:
1996 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1997 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571998
Mario Sanchez Prada2472cab2019-09-18 10:58:311999 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:092000 # Raise errors inside |error_paths| and warnings everywhere else.
2001 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:572002 errors.extend(problems)
2003 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:312004 warnings.extend(problems)
2005
2006 result = []
2007 if (warnings):
2008 result.append(output_api.PresubmitPromptWarning(
2009 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:572010 if (errors):
2011 result.append(output_api.PresubmitError(
2012 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:312013 return result
2014
2015
Saagar Sanghavifceeaae2020-08-12 16:40:362016def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:062017 """Make sure that banned functions are not used."""
2018 files = []
2019 pattern = input_api.re.compile(r'^#pragma\s+once',
2020 input_api.re.MULTILINE)
2021 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2022 if not f.LocalPath().endswith('.h'):
2023 continue
2024 contents = input_api.ReadFile(f)
2025 if pattern.search(contents):
2026 files.append(f)
2027
2028 if files:
2029 return [output_api.PresubmitError(
2030 'Do not use #pragma once in header files.\n'
2031 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2032 files)]
2033 return []
2034
[email protected]127f18ec2012-06-16 05:05:592035
Saagar Sanghavifceeaae2020-08-12 16:40:362036def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:122037 """Checks to make sure we don't introduce use of foo ? true : false."""
2038 problems = []
2039 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2040 for f in input_api.AffectedFiles():
2041 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2042 continue
2043
2044 for line_num, line in f.ChangedContents():
2045 if pattern.match(line):
2046 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2047
2048 if not problems:
2049 return []
2050 return [output_api.PresubmitPromptWarning(
2051 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2052 '\n'.join(problems))]
2053
2054
Saagar Sanghavifceeaae2020-08-12 16:40:362055def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282056 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182057 change. Breaking - rules is an error, breaking ! rules is a
2058 warning.
2059 """
mohan.reddyf21db962014-10-16 12:26:472060 import sys
[email protected]55f9f382012-07-31 11:02:182061 # We need to wait until we have an input_api object and use this
2062 # roundabout construct to import checkdeps because this file is
2063 # eval-ed and thus doesn't have __file__.
2064 original_sys_path = sys.path
2065 try:
2066 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472067 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182068 import checkdeps
[email protected]55f9f382012-07-31 11:02:182069 from rules import Rule
2070 finally:
2071 # Restore sys.path to what it was before.
2072 sys.path = original_sys_path
2073
2074 added_includes = []
rhalavati08acd232017-04-03 07:23:282075 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242076 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182077 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062078 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502079 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082080 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062081 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502082 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082083 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062084 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502085 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082086 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182087
[email protected]26385172013-05-09 23:11:352088 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182089
2090 error_descriptions = []
2091 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282092 error_subjects = set()
2093 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362094
[email protected]55f9f382012-07-31 11:02:182095 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2096 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082097 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182098 description_with_path = '%s\n %s' % (path, rule_description)
2099 if rule_type == Rule.DISALLOW:
2100 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282101 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182102 else:
2103 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282104 warning_subjects.add("#includes")
2105
2106 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2107 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082108 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282109 description_with_path = '%s\n %s' % (path, rule_description)
2110 if rule_type == Rule.DISALLOW:
2111 error_descriptions.append(description_with_path)
2112 error_subjects.add("imports")
2113 else:
2114 warning_descriptions.append(description_with_path)
2115 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182116
Jinsuk Kim5a092672017-10-24 22:42:242117 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022118 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082119 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242120 description_with_path = '%s\n %s' % (path, rule_description)
2121 if rule_type == Rule.DISALLOW:
2122 error_descriptions.append(description_with_path)
2123 error_subjects.add("imports")
2124 else:
2125 warning_descriptions.append(description_with_path)
2126 warning_subjects.add("imports")
2127
[email protected]55f9f382012-07-31 11:02:182128 results = []
2129 if error_descriptions:
2130 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282131 'You added one or more %s that violate checkdeps rules.'
2132 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182133 error_descriptions))
2134 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422135 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282136 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182137 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282138 '%s? See relevant DEPS file(s) for details and contacts.' %
2139 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182140 warning_descriptions))
2141 return results
2142
2143
Saagar Sanghavifceeaae2020-08-12 16:40:362144def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222145 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152146 if input_api.platform == 'win32':
2147 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292148 checkperms_tool = input_api.os_path.join(
2149 input_api.PresubmitLocalPath(),
2150 'tools', 'checkperms', 'checkperms.py')
2151 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472152 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392153 with input_api.CreateTemporaryFile() as file_list:
2154 for f in input_api.AffectedFiles():
2155 # checkperms.py file/directory arguments must be relative to the
2156 # repository.
2157 file_list.write(f.LocalPath() + '\n')
2158 file_list.close()
2159 args += ['--file-list', file_list.name]
2160 try:
2161 input_api.subprocess.check_output(args)
2162 return []
2163 except input_api.subprocess.CalledProcessError as error:
2164 return [output_api.PresubmitError(
2165 'checkperms.py failed:',
2166 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222167
2168
Saagar Sanghavifceeaae2020-08-12 16:40:362169def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492170 """Makes sure we don't include ui/aura/window_property.h
2171 in header files.
2172 """
2173 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2174 errors = []
2175 for f in input_api.AffectedFiles():
2176 if not f.LocalPath().endswith('.h'):
2177 continue
2178 for line_num, line in f.ChangedContents():
2179 if pattern.match(line):
2180 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2181
2182 results = []
2183 if errors:
2184 results.append(output_api.PresubmitError(
2185 'Header files should not include ui/aura/window_property.h', errors))
2186 return results
2187
2188
[email protected]70ca77752012-11-20 03:45:032189def _CheckForVersionControlConflictsInFile(input_api, f):
2190 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2191 errors = []
2192 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162193 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232194 # First-level headers in markdown look a lot like version control
2195 # conflict markers. http://daringfireball.net/projects/markdown/basics
2196 continue
[email protected]70ca77752012-11-20 03:45:032197 if pattern.match(line):
2198 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2199 return errors
2200
2201
Saagar Sanghavifceeaae2020-08-12 16:40:362202def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032203 """Usually this is not intentional and will cause a compile failure."""
2204 errors = []
2205 for f in input_api.AffectedFiles():
2206 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2207
2208 results = []
2209 if errors:
2210 results.append(output_api.PresubmitError(
2211 'Version control conflict markers found, please resolve.', errors))
2212 return results
2213
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202214
Saagar Sanghavifceeaae2020-08-12 16:40:362215def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162216 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2217 errors = []
2218 for f in input_api.AffectedFiles():
2219 for line_num, line in f.ChangedContents():
2220 if pattern.search(line):
2221 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2222
2223 results = []
2224 if errors:
2225 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502226 'Found Google support URL addressed by answer number. Please replace '
2227 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162228 return results
2229
[email protected]70ca77752012-11-20 03:45:032230
Saagar Sanghavifceeaae2020-08-12 16:40:362231def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442232 def FilterFile(affected_file):
2233 """Filter function for use with input_api.AffectedSourceFiles,
2234 below. This filters out everything except non-test files from
2235 top-level directories that generally speaking should not hard-code
2236 service URLs (e.g. src/android_webview/, src/content/ and others).
2237 """
2238 return input_api.FilterSourceFile(
2239 affected_file,
James Cook24a504192020-07-23 00:08:442240 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2241 files_to_skip=(_EXCLUDED_PATHS +
2242 _TEST_CODE_EXCLUDED_PATHS +
2243 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442244
reillyi38965732015-11-16 18:27:332245 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2246 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462247 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2248 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442249 problems = [] # items are (filename, line_number, line)
2250 for f in input_api.AffectedSourceFiles(FilterFile):
2251 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462252 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442253 problems.append((f.LocalPath(), line_num, line))
2254
2255 if problems:
[email protected]f7051d52013-04-02 18:31:422256 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442257 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582258 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442259 [' %s:%d: %s' % (
2260 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032261 else:
2262 return []
[email protected]06e6d0ff2012-12-11 01:36:442263
2264
Saagar Sanghavifceeaae2020-08-12 16:40:362265def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292266 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2267 def FileFilter(affected_file):
2268 """Includes directories known to be Chrome OS only."""
2269 return input_api.FilterSourceFile(
2270 affected_file,
James Cook24a504192020-07-23 00:08:442271 files_to_check=('^ash/',
2272 '^chromeos/', # Top-level src/chromeos.
2273 '/chromeos/', # Any path component.
2274 '^components/arc',
2275 '^components/exo'),
2276 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292277
2278 prefs = []
2279 priority_prefs = []
2280 for f in input_api.AffectedFiles(file_filter=FileFilter):
2281 for line_num, line in f.ChangedContents():
2282 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2283 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2284 prefs.append(' %s' % line)
2285 if input_api.re.search(
2286 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2287 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2288 priority_prefs.append(' %s' % line)
2289
2290 results = []
2291 if (prefs):
2292 results.append(output_api.PresubmitPromptWarning(
2293 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2294 'by browser sync settings. If these prefs should be controlled by OS '
2295 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2296 if (priority_prefs):
2297 results.append(output_api.PresubmitPromptWarning(
2298 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2299 'controlled by browser sync settings. If these prefs should be '
2300 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2301 'instead.\n' + '\n'.join(prefs)))
2302 return results
2303
2304
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492305# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362306def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272307 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312308 The native_client_sdk directory is excluded because it has auto-generated PNG
2309 files for documentation.
[email protected]d2530012013-01-25 16:39:272310 """
[email protected]d2530012013-01-25 16:39:272311 errors = []
James Cook24a504192020-07-23 00:08:442312 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2313 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312314 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442315 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312316 for f in input_api.AffectedFiles(include_deletes=False,
2317 file_filter=file_filter):
2318 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272319
2320 results = []
2321 if errors:
2322 results.append(output_api.PresubmitError(
2323 'The name of PNG files should not have abbreviations. \n'
2324 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2325 'Contact [email protected] if you have questions.', errors))
2326 return results
2327
2328
Daniel Cheng4dcdb6b2017-04-13 08:30:172329def _ExtractAddRulesFromParsedDeps(parsed_deps):
2330 """Extract the rules that add dependencies from a parsed DEPS file.
2331
2332 Args:
2333 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2334 add_rules = set()
2335 add_rules.update([
2336 rule[1:] for rule in parsed_deps.get('include_rules', [])
2337 if rule.startswith('+') or rule.startswith('!')
2338 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502339 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172340 {}).iteritems():
2341 add_rules.update([
2342 rule[1:] for rule in rules
2343 if rule.startswith('+') or rule.startswith('!')
2344 ])
2345 return add_rules
2346
2347
2348def _ParseDeps(contents):
2349 """Simple helper for parsing DEPS files."""
2350 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172351 class _VarImpl:
2352
2353 def __init__(self, local_scope):
2354 self._local_scope = local_scope
2355
2356 def Lookup(self, var_name):
2357 """Implements the Var syntax."""
2358 try:
2359 return self._local_scope['vars'][var_name]
2360 except KeyError:
2361 raise Exception('Var is not defined: %s' % var_name)
2362
2363 local_scope = {}
2364 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172365 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592366 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172367 }
2368 exec contents in global_scope, local_scope
2369 return local_scope
2370
2371
2372def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592373 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412374 a set of DEPS entries that we should look up.
2375
2376 For a directory (rather than a specific filename) we fake a path to
2377 a specific filename by adding /DEPS. This is chosen as a file that
2378 will seldom or never be subject to per-file include_rules.
2379 """
[email protected]2b438d62013-11-14 17:54:142380 # We ignore deps entries on auto-generated directories.
2381 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082382
Daniel Cheng4dcdb6b2017-04-13 08:30:172383 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2384 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2385
2386 added_deps = new_deps.difference(old_deps)
2387
[email protected]2b438d62013-11-14 17:54:142388 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172389 for added_dep in added_deps:
2390 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2391 continue
2392 # Assume that a rule that ends in .h is a rule for a specific file.
2393 if added_dep.endswith('.h'):
2394 results.add(added_dep)
2395 else:
2396 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082397 return results
2398
2399
Saagar Sanghavifceeaae2020-08-12 16:40:362400def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552401 """When a dependency prefixed with + is added to a DEPS file, we
2402 want to make sure that the change is reviewed by an OWNER of the
2403 target file or directory, to avoid layering violations from being
2404 introduced. This check verifies that this happens.
2405 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172406 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242407
2408 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492409 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242410 for f in input_api.AffectedFiles(include_deletes=False,
2411 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552412 filename = input_api.os_path.basename(f.LocalPath())
2413 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172414 virtual_depended_on_files.update(_CalculateAddedDeps(
2415 input_api.os_path,
2416 '\n'.join(f.OldContents()),
2417 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552418
[email protected]e871964c2013-05-13 14:14:552419 if not virtual_depended_on_files:
2420 return []
2421
2422 if input_api.is_committing:
2423 if input_api.tbr:
2424 return [output_api.PresubmitNotifyResult(
2425 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272426 if input_api.dry_run:
2427 return [output_api.PresubmitNotifyResult(
2428 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552429 if not input_api.change.issue:
2430 return [output_api.PresubmitError(
2431 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402432 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552433 output = output_api.PresubmitError
2434 else:
2435 output = output_api.PresubmitNotifyResult
2436
2437 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502438 owner_email, reviewers = (
2439 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2440 input_api,
2441 owners_db.email_regexp,
2442 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552443
2444 owner_email = owner_email or input_api.change.author_email
2445
[email protected]de4f7d22013-05-23 14:27:462446 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512447 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462448 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552449 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2450 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412451
2452 # We strip the /DEPS part that was added by
2453 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2454 # directory.
2455 def StripDeps(path):
2456 start_deps = path.rfind('/DEPS')
2457 if start_deps != -1:
2458 return path[:start_deps]
2459 else:
2460 return path
2461 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552462 for path in missing_files]
2463
2464 if unapproved_dependencies:
2465 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152466 output('You need LGTM from owners of depends-on paths in DEPS that were '
2467 'modified in this CL:\n %s' %
2468 '\n '.join(sorted(unapproved_dependencies)))]
2469 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2470 output_list.append(output(
2471 'Suggested missing target path OWNERS:\n %s' %
2472 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552473 return output_list
2474
2475 return []
2476
2477
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492478# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362479def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492480 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442481 files_to_skip = (_EXCLUDED_PATHS +
2482 _TEST_CODE_EXCLUDED_PATHS +
2483 input_api.DEFAULT_FILES_TO_SKIP +
2484 (r"^base[\\/]logging\.h$",
2485 r"^base[\\/]logging\.cc$",
2486 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2487 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2488 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2489 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2490 r"startup_browser_creator\.cc$",
2491 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2492 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2493 r"diagnostics_writer\.cc$",
2494 r"^chrome[\\/]chrome_cleaner[\\/].*",
2495 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2496 r"dll_hash_main\.cc$",
2497 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2498 r"^chromecast[\\/]",
2499 r"^cloud_print[\\/]",
2500 r"^components[\\/]browser_watcher[\\/]"
2501 r"dump_stability_report_main_win.cc$",
2502 r"^components[\\/]media_control[\\/]renderer[\\/]"
2503 r"media_playback_options\.cc$",
2504 r"^components[\\/]zucchini[\\/].*",
2505 # TODO(peter): Remove exception. https://crbug.com/534537
2506 r"^content[\\/]browser[\\/]notifications[\\/]"
2507 r"notification_event_dispatcher_impl\.cc$",
2508 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2509 r"gl_helper_benchmark\.cc$",
2510 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2511 r"^courgette[\\/]courgette_tool\.cc$",
2512 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2513 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2514 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2515 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2516 r"^ipc[\\/]ipc_logging\.cc$",
2517 r"^native_client_sdk[\\/]",
2518 r"^remoting[\\/]base[\\/]logging\.h$",
2519 r"^remoting[\\/]host[\\/].*",
2520 r"^sandbox[\\/]linux[\\/].*",
2521 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2522 r"dump_file_system.cc$",
2523 r"^tools[\\/]",
2524 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2525 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2526 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2527 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2528 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402529 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442530 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402531
thomasanderson625d3932017-03-29 07:16:582532 log_info = set([])
2533 printf = set([])
[email protected]85218562013-11-22 07:41:402534
2535 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582536 for _, line in f.ChangedContents():
2537 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2538 log_info.add(f.LocalPath())
2539 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2540 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372541
thomasanderson625d3932017-03-29 07:16:582542 if input_api.re.search(r"\bprintf\(", line):
2543 printf.add(f.LocalPath())
2544 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2545 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402546
2547 if log_info:
2548 return [output_api.PresubmitError(
2549 'These files spam the console log with LOG(INFO):',
2550 items=log_info)]
2551 if printf:
2552 return [output_api.PresubmitError(
2553 'These files spam the console log with printf/fprintf:',
2554 items=printf)]
2555 return []
2556
2557
Saagar Sanghavifceeaae2020-08-12 16:40:362558def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162559 """These types are all expected to hold locks while in scope and
2560 so should never be anonymous (which causes them to be immediately
2561 destroyed)."""
2562 they_who_must_be_named = [
2563 'base::AutoLock',
2564 'base::AutoReset',
2565 'base::AutoUnlock',
2566 'SkAutoAlphaRestore',
2567 'SkAutoBitmapShaderInstall',
2568 'SkAutoBlitterChoose',
2569 'SkAutoBounderCommit',
2570 'SkAutoCallProc',
2571 'SkAutoCanvasRestore',
2572 'SkAutoCommentBlock',
2573 'SkAutoDescriptor',
2574 'SkAutoDisableDirectionCheck',
2575 'SkAutoDisableOvalCheck',
2576 'SkAutoFree',
2577 'SkAutoGlyphCache',
2578 'SkAutoHDC',
2579 'SkAutoLockColors',
2580 'SkAutoLockPixels',
2581 'SkAutoMalloc',
2582 'SkAutoMaskFreeImage',
2583 'SkAutoMutexAcquire',
2584 'SkAutoPathBoundsUpdate',
2585 'SkAutoPDFRelease',
2586 'SkAutoRasterClipValidate',
2587 'SkAutoRef',
2588 'SkAutoTime',
2589 'SkAutoTrace',
2590 'SkAutoUnref',
2591 ]
2592 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2593 # bad: base::AutoLock(lock.get());
2594 # not bad: base::AutoLock lock(lock.get());
2595 bad_pattern = input_api.re.compile(anonymous)
2596 # good: new base::AutoLock(lock.get())
2597 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2598 errors = []
2599
2600 for f in input_api.AffectedFiles():
2601 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2602 continue
2603 for linenum, line in f.ChangedContents():
2604 if bad_pattern.search(line) and not good_pattern.search(line):
2605 errors.append('%s:%d' % (f.LocalPath(), linenum))
2606
2607 if errors:
2608 return [output_api.PresubmitError(
2609 'These lines create anonymous variables that need to be named:',
2610 items=errors)]
2611 return []
2612
2613
Saagar Sanghavifceeaae2020-08-12 16:40:362614def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532615 # Returns whether |template_str| is of the form <T, U...> for some types T
2616 # and U. Assumes that |template_str| is already in the form <...>.
2617 def HasMoreThanOneArg(template_str):
2618 # Level of <...> nesting.
2619 nesting = 0
2620 for c in template_str:
2621 if c == '<':
2622 nesting += 1
2623 elif c == '>':
2624 nesting -= 1
2625 elif c == ',' and nesting == 1:
2626 return True
2627 return False
2628
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492629 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102630 sources = lambda affected_file: input_api.FilterSourceFile(
2631 affected_file,
James Cook24a504192020-07-23 00:08:442632 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2633 input_api.DEFAULT_FILES_TO_SKIP),
2634 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552635
2636 # Pattern to capture a single "<...>" block of template arguments. It can
2637 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2638 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2639 # latter would likely require counting that < and > match, which is not
2640 # expressible in regular languages. Should the need arise, one can introduce
2641 # limited counting (matching up to a total number of nesting depth), which
2642 # should cover all practical cases for already a low nesting limit.
2643 template_arg_pattern = (
2644 r'<[^>]*' # Opening block of <.
2645 r'>([^<]*>)?') # Closing block of >.
2646 # Prefix expressing that whatever follows is not already inside a <...>
2647 # block.
2648 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102649 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552650 not_inside_template_arg_pattern
2651 + r'\bstd::unique_ptr'
2652 + template_arg_pattern
2653 + r'\(\)')
2654
2655 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2656 template_arg_no_array_pattern = (
2657 r'<[^>]*[^]]' # Opening block of <.
2658 r'>([^(<]*[^]]>)?') # Closing block of >.
2659 # Prefix saying that what follows is the start of an expression.
2660 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2661 # Suffix saying that what follows are call parentheses with a non-empty list
2662 # of arguments.
2663 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532664 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552665 return_construct_pattern = input_api.re.compile(
2666 start_of_expr_pattern
2667 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532668 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552669 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532670 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552671 + nonempty_arg_list_pattern)
2672
Vaclav Brozek851d9602018-04-04 16:13:052673 problems_constructor = []
2674 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102675 for f in input_api.AffectedSourceFiles(sources):
2676 for line_number, line in f.ChangedContents():
2677 # Disallow:
2678 # return std::unique_ptr<T>(foo);
2679 # bar = std::unique_ptr<T>(foo);
2680 # But allow:
2681 # return std::unique_ptr<T[]>(foo);
2682 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532683 # And also allow cases when the second template argument is present. Those
2684 # cases cannot be handled by std::make_unique:
2685 # return std::unique_ptr<T, U>(foo);
2686 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052687 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532688 return_construct_result = return_construct_pattern.search(line)
2689 if return_construct_result and not HasMoreThanOneArg(
2690 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052691 problems_constructor.append(
2692 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102693 # Disallow:
2694 # std::unique_ptr<T>()
2695 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052696 problems_nullptr.append(
2697 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2698
2699 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162700 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052701 errors.append(output_api.PresubmitError(
2702 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162703 problems_nullptr))
2704 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052705 errors.append(output_api.PresubmitError(
2706 'The following files use explicit std::unique_ptr constructor.'
2707 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162708 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102709 return errors
2710
2711
Saagar Sanghavifceeaae2020-08-12 16:40:362712def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082713 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522714 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082715 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522716 # If actions.xml is already included in the changelist, the PRESUBMIT
2717 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082718 return []
2719
[email protected]999261d2014-03-03 20:08:082720 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2721 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522722 current_actions = None
[email protected]999261d2014-03-03 20:08:082723 for f in input_api.AffectedFiles(file_filter=file_filter):
2724 for line_num, line in f.ChangedContents():
2725 match = input_api.re.search(action_re, line)
2726 if match:
[email protected]2f92dec2014-03-07 19:21:522727 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2728 # loaded only once.
2729 if not current_actions:
2730 with open('tools/metrics/actions/actions.xml') as actions_f:
2731 current_actions = actions_f.read()
2732 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082733 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522734 action = 'name="{0}"'.format(action_name)
2735 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082736 return [output_api.PresubmitPromptWarning(
2737 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522738 'tools/metrics/actions/actions.xml. Please run '
2739 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082740 % (f.LocalPath(), line_num, action_name))]
2741 return []
2742
2743
Daniel Cheng13ca61a882017-08-25 15:11:252744def _ImportJSONCommentEater(input_api):
2745 import sys
2746 sys.path = sys.path + [input_api.os_path.join(
2747 input_api.PresubmitLocalPath(),
2748 'tools', 'json_comment_eater')]
2749 import json_comment_eater
2750 return json_comment_eater
2751
2752
[email protected]99171a92014-06-03 08:44:472753def _GetJSONParseError(input_api, filename, eat_comments=True):
2754 try:
2755 contents = input_api.ReadFile(filename)
2756 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252757 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132758 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472759
2760 input_api.json.loads(contents)
2761 except ValueError as e:
2762 return e
2763 return None
2764
2765
2766def _GetIDLParseError(input_api, filename):
2767 try:
2768 contents = input_api.ReadFile(filename)
2769 idl_schema = input_api.os_path.join(
2770 input_api.PresubmitLocalPath(),
2771 'tools', 'json_schema_compiler', 'idl_schema.py')
2772 process = input_api.subprocess.Popen(
2773 [input_api.python_executable, idl_schema],
2774 stdin=input_api.subprocess.PIPE,
2775 stdout=input_api.subprocess.PIPE,
2776 stderr=input_api.subprocess.PIPE,
2777 universal_newlines=True)
2778 (_, error) = process.communicate(input=contents)
2779 return error or None
2780 except ValueError as e:
2781 return e
2782
2783
Saagar Sanghavifceeaae2020-08-12 16:40:362784def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472785 """Check that IDL and JSON files do not contain syntax errors."""
2786 actions = {
2787 '.idl': _GetIDLParseError,
2788 '.json': _GetJSONParseError,
2789 }
[email protected]99171a92014-06-03 08:44:472790 # Most JSON files are preprocessed and support comments, but these do not.
2791 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042792 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472793 ]
2794 # Only run IDL checker on files in these directories.
2795 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042796 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2797 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472798 ]
2799
2800 def get_action(affected_file):
2801 filename = affected_file.LocalPath()
2802 return actions.get(input_api.os_path.splitext(filename)[1])
2803
[email protected]99171a92014-06-03 08:44:472804 def FilterFile(affected_file):
2805 action = get_action(affected_file)
2806 if not action:
2807 return False
2808 path = affected_file.LocalPath()
2809
Erik Staab2dd72b12020-04-16 15:03:402810 if _MatchesFile(input_api,
2811 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2812 path):
[email protected]99171a92014-06-03 08:44:472813 return False
2814
2815 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162816 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472817 return False
2818 return True
2819
2820 results = []
2821 for affected_file in input_api.AffectedFiles(
2822 file_filter=FilterFile, include_deletes=False):
2823 action = get_action(affected_file)
2824 kwargs = {}
2825 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162826 _MatchesFile(input_api, json_no_comments_patterns,
2827 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472828 kwargs['eat_comments'] = False
2829 parse_error = action(input_api,
2830 affected_file.AbsoluteLocalPath(),
2831 **kwargs)
2832 if parse_error:
2833 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2834 (affected_file.LocalPath(), parse_error)))
2835 return results
2836
2837
Saagar Sanghavifceeaae2020-08-12 16:40:362838def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492839 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472840 import sys
[email protected]760deea2013-12-10 19:33:492841 original_sys_path = sys.path
2842 try:
2843 sys.path = sys.path + [input_api.os_path.join(
2844 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2845 import checkstyle
2846 finally:
2847 # Restore sys.path to what it was before.
2848 sys.path = original_sys_path
2849
2850 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092851 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442852 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492853
2854
Saagar Sanghavifceeaae2020-08-12 16:40:362855def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002856 """Checks to make sure devil is initialized correctly in python scripts."""
2857 script_common_initialize_pattern = input_api.re.compile(
2858 r'script_common\.InitializeEnvironment\(')
2859 devil_env_config_initialize = input_api.re.compile(
2860 r'devil_env\.config\.Initialize\(')
2861
2862 errors = []
2863
2864 sources = lambda affected_file: input_api.FilterSourceFile(
2865 affected_file,
James Cook24a504192020-07-23 00:08:442866 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2867 (r'^build[\\/]android[\\/]devil_chromium\.py',
2868 r'^third_party[\\/].*',)),
2869 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002870
2871 for f in input_api.AffectedSourceFiles(sources):
2872 for line_num, line in f.ChangedContents():
2873 if (script_common_initialize_pattern.search(line) or
2874 devil_env_config_initialize.search(line)):
2875 errors.append("%s:%d" % (f.LocalPath(), line_num))
2876
2877 results = []
2878
2879 if errors:
2880 results.append(output_api.PresubmitError(
2881 'Devil initialization should always be done using '
2882 'devil_chromium.Initialize() in the chromium project, to use better '
2883 'defaults for dependencies (ex. up-to-date version of adb).',
2884 errors))
2885
2886 return results
2887
2888
Sean Kau46e29bc2017-08-28 16:31:162889def _MatchesFile(input_api, patterns, path):
2890 for pattern in patterns:
2891 if input_api.re.search(pattern, path):
2892 return True
2893 return False
2894
2895
Daniel Cheng7052cdf2017-11-21 19:23:292896def _GetOwnersFilesToCheckForIpcOwners(input_api):
2897 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172898
Daniel Cheng7052cdf2017-11-21 19:23:292899 Returns:
2900 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2901 contain to cover IPC-related files with noparent reviewer rules.
2902 """
2903 # Whether or not a file affects IPC is (mostly) determined by a simple list
2904 # of filename patterns.
dchenge07de812016-06-20 19:27:172905 file_patterns = [
palmerb19a0932017-01-24 04:00:312906 # Legacy IPC:
dchenge07de812016-06-20 19:27:172907 '*_messages.cc',
2908 '*_messages*.h',
2909 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312910 # Mojo IPC:
dchenge07de812016-06-20 19:27:172911 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472912 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172913 '*_struct_traits*.*',
2914 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312915 '*.typemap',
2916 # Android native IPC:
2917 '*.aidl',
2918 # Blink uses a different file naming convention:
2919 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472920 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172921 '*StructTraits*.*',
2922 '*TypeConverter*.*',
2923 ]
2924
scottmg7a6ed5ba2016-11-04 18:22:042925 # These third_party directories do not contain IPCs, but contain files
2926 # matching the above patterns, which trigger false positives.
2927 exclude_paths = [
2928 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162929 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232930 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292931 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542932 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162933 # These files are just used to communicate between class loaders running
2934 # in the same process.
2935 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572936 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2937
scottmg7a6ed5ba2016-11-04 18:22:042938 ]
2939
dchenge07de812016-06-20 19:27:172940 # Dictionary mapping an OWNERS file path to Patterns.
2941 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2942 # rules ) to a PatternEntry.
2943 # PatternEntry is a dictionary with two keys:
2944 # - 'files': the files that are matched by this pattern
2945 # - 'rules': the per-file rules needed for this pattern
2946 # For example, if we expect OWNERS file to contain rules for *.mojom and
2947 # *_struct_traits*.*, Patterns might look like this:
2948 # {
2949 # '*.mojom': {
2950 # 'files': ...,
2951 # 'rules': [
2952 # 'per-file *.mojom=set noparent',
2953 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2954 # ],
2955 # },
2956 # '*_struct_traits*.*': {
2957 # 'files': ...,
2958 # 'rules': [
2959 # 'per-file *_struct_traits*.*=set noparent',
2960 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2961 # ],
2962 # },
2963 # }
2964 to_check = {}
2965
Daniel Cheng13ca61a882017-08-25 15:11:252966 def AddPatternToCheck(input_file, pattern):
2967 owners_file = input_api.os_path.join(
2968 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2969 if owners_file not in to_check:
2970 to_check[owners_file] = {}
2971 if pattern not in to_check[owners_file]:
2972 to_check[owners_file][pattern] = {
2973 'files': [],
2974 'rules': [
2975 'per-file %s=set noparent' % pattern,
2976 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2977 ]
2978 }
Vaclav Brozekd5de76a2018-03-17 07:57:502979 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252980
dchenge07de812016-06-20 19:27:172981 # Iterate through the affected files to see what we actually need to check
2982 # for. We should only nag patch authors about per-file rules if a file in that
2983 # directory would match that pattern. If a directory only contains *.mojom
2984 # files and no *_messages*.h files, we should only nag about rules for
2985 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252986 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262987 # Manifest files don't have a strong naming convention. Instead, try to find
2988 # affected .cc and .h files which look like they contain a manifest
2989 # definition.
2990 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2991 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2992 if (manifest_pattern.search(f.LocalPath()) and not
2993 test_manifest_pattern.search(f.LocalPath())):
2994 # We expect all actual service manifest files to contain at least one
2995 # qualified reference to service_manager::Manifest.
2996 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252997 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172998 for pattern in file_patterns:
2999 if input_api.fnmatch.fnmatch(
3000 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:043001 skip = False
3002 for exclude in exclude_paths:
3003 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
3004 skip = True
3005 break
3006 if skip:
3007 continue
Daniel Cheng13ca61a882017-08-25 15:11:253008 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173009 break
3010
Daniel Cheng7052cdf2017-11-21 19:23:293011 return to_check
3012
3013
Wez17c66962020-04-29 15:26:033014def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3015 """Adds OWNERS files to check for correct Fuchsia security owners."""
3016
3017 file_patterns = [
3018 # Component specifications.
3019 '*.cml', # Component Framework v2.
3020 '*.cmx', # Component Framework v1.
3021
3022 # Fuchsia IDL protocol specifications.
3023 '*.fidl',
3024 ]
3025
3026 def AddPatternToCheck(input_file, pattern):
3027 owners_file = input_api.os_path.join(
3028 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3029 if owners_file not in to_check:
3030 to_check[owners_file] = {}
3031 if pattern not in to_check[owners_file]:
3032 to_check[owners_file][pattern] = {
3033 'files': [],
3034 'rules': [
3035 'per-file %s=set noparent' % pattern,
3036 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3037 ]
3038 }
3039 to_check[owners_file][pattern]['files'].append(input_file)
3040
3041 # Iterate through the affected files to see what we actually need to check
3042 # for. We should only nag patch authors about per-file rules if a file in that
3043 # directory would match that pattern.
3044 for f in input_api.AffectedFiles(include_deletes=False):
3045 for pattern in file_patterns:
3046 if input_api.fnmatch.fnmatch(
3047 input_api.os_path.basename(f.LocalPath()), pattern):
3048 AddPatternToCheck(f, pattern)
3049 break
3050
3051 return to_check
3052
3053
Saagar Sanghavifceeaae2020-08-12 16:40:363054def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293055 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3056 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033057 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293058
3059 if to_check:
3060 # If there are any OWNERS files to check, there are IPC-related changes in
3061 # this CL. Auto-CC the review list.
3062 output_api.AppendCC('[email protected]')
3063
3064 # Go through the OWNERS files to check, filtering out rules that are already
3065 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173066 for owners_file, patterns in to_check.iteritems():
3067 try:
3068 with file(owners_file) as f:
3069 lines = set(f.read().splitlines())
3070 for entry in patterns.itervalues():
3071 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3072 ]
3073 except IOError:
3074 # No OWNERS file, so all the rules are definitely missing.
3075 continue
3076
3077 # All the remaining lines weren't found in OWNERS files, so emit an error.
3078 errors = []
3079 for owners_file, patterns in to_check.iteritems():
3080 missing_lines = []
3081 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503082 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173083 missing_lines.extend(entry['rules'])
3084 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3085 if missing_lines:
3086 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053087 'Because of the presence of files:\n%s\n\n'
3088 '%s needs the following %d lines added:\n\n%s' %
3089 ('\n'.join(files), owners_file, len(missing_lines),
3090 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173091
3092 results = []
3093 if errors:
vabrf5ce3bf92016-07-11 14:52:413094 if input_api.is_committing:
3095 output = output_api.PresubmitError
3096 else:
3097 output = output_api.PresubmitPromptWarning
3098 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593099 'Found OWNERS files that need to be updated for IPC security ' +
3100 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173101 long_text='\n\n'.join(errors)))
3102
3103 return results
3104
3105
Robert Sesek2c905332020-05-06 23:17:133106def _GetFilesUsingSecurityCriticalFunctions(input_api):
3107 """Checks affected files for changes to security-critical calls. This
3108 function checks the full change diff, to catch both additions/changes
3109 and removals.
3110
3111 Returns a dict keyed by file name, and the value is a set of detected
3112 functions.
3113 """
3114 # Map of function pretty name (displayed in an error) to the pattern to
3115 # match it with.
3116 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373117 'content::GetServiceSandboxType<>()':
3118 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133119 }
3120 _PATTERNS_TO_CHECK = {
3121 k: input_api.re.compile(v)
3122 for k, v in _PATTERNS_TO_CHECK.items()
3123 }
3124
3125 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3126 files_to_functions = {}
3127 for f in input_api.AffectedFiles():
3128 diff = f.GenerateScmDiff()
3129 for line in diff.split('\n'):
3130 # Not using just RightHandSideLines() because removing a
3131 # call to a security-critical function can be just as important
3132 # as adding or changing the arguments.
3133 if line.startswith('-') or (line.startswith('+') and
3134 not line.startswith('++')):
3135 for name, pattern in _PATTERNS_TO_CHECK.items():
3136 if pattern.search(line):
3137 path = f.LocalPath()
3138 if not path in files_to_functions:
3139 files_to_functions[path] = set()
3140 files_to_functions[path].add(name)
3141 return files_to_functions
3142
3143
Saagar Sanghavifceeaae2020-08-12 16:40:363144def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133145 """Checks that changes involving security-critical functions are reviewed
3146 by the security team.
3147 """
3148 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3149 if len(files_to_functions):
3150 owners_db = input_api.owners_db
3151 owner_email, reviewers = (
3152 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3153 input_api,
3154 owners_db.email_regexp,
3155 approval_needed=input_api.is_committing))
3156
3157 # Load the OWNERS file for security changes.
3158 owners_file = 'ipc/SECURITY_OWNERS'
3159 security_owners = owners_db.owners_rooted_at_file(owners_file)
3160
3161 has_security_owner = any([owner in reviewers for owner in security_owners])
3162 if not has_security_owner:
3163 msg = 'The following files change calls to security-sensive functions\n' \
3164 'that need to be reviewed by {}.\n'.format(owners_file)
3165 for path, names in files_to_functions.items():
3166 msg += ' {}\n'.format(path)
3167 for name in names:
3168 msg += ' {}\n'.format(name)
3169 msg += '\n'
3170
3171 if input_api.is_committing:
3172 output = output_api.PresubmitError
3173 else:
3174 output = output_api.PresubmitNotifyResult
3175 return [output(msg)]
3176
3177 return []
3178
3179
Saagar Sanghavifceeaae2020-08-12 16:40:363180def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263181 """Checks that set noparent is only used together with an OWNERS file in
3182 //build/OWNERS.setnoparent (see also
3183 //docs/code_reviews.md#owners-files-details)
3184 """
3185 errors = []
3186
3187 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3188 allowed_owners_files = set()
3189 with open(allowed_owners_files_file, 'r') as f:
3190 for line in f:
3191 line = line.strip()
3192 if not line or line.startswith('#'):
3193 continue
3194 allowed_owners_files.add(line)
3195
3196 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3197
3198 for f in input_api.AffectedFiles(include_deletes=False):
3199 if not f.LocalPath().endswith('OWNERS'):
3200 continue
3201
3202 found_owners_files = set()
3203 found_set_noparent_lines = dict()
3204
3205 # Parse the OWNERS file.
3206 for lineno, line in enumerate(f.NewContents(), 1):
3207 line = line.strip()
3208 if line.startswith('set noparent'):
3209 found_set_noparent_lines[''] = lineno
3210 if line.startswith('file://'):
3211 if line in allowed_owners_files:
3212 found_owners_files.add('')
3213 if line.startswith('per-file'):
3214 match = per_file_pattern.match(line)
3215 if match:
3216 glob = match.group(1).strip()
3217 directive = match.group(2).strip()
3218 if directive == 'set noparent':
3219 found_set_noparent_lines[glob] = lineno
3220 if directive.startswith('file://'):
3221 if directive in allowed_owners_files:
3222 found_owners_files.add(glob)
3223
3224 # Check that every set noparent line has a corresponding file:// line
3225 # listed in build/OWNERS.setnoparent.
3226 for set_noparent_line in found_set_noparent_lines:
3227 if set_noparent_line in found_owners_files:
3228 continue
3229 errors.append(' %s:%d' % (f.LocalPath(),
3230 found_set_noparent_lines[set_noparent_line]))
3231
3232 results = []
3233 if errors:
3234 if input_api.is_committing:
3235 output = output_api.PresubmitError
3236 else:
3237 output = output_api.PresubmitPromptWarning
3238 results.append(output(
3239 'Found the following "set noparent" restrictions in OWNERS files that '
3240 'do not include owners from build/OWNERS.setnoparent:',
3241 long_text='\n\n'.join(errors)))
3242 return results
3243
3244
Saagar Sanghavifceeaae2020-08-12 16:40:363245def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313246 """Checks that added or removed lines in non third party affected
3247 header files do not lead to new useless class or struct forward
3248 declaration.
jbriance9e12f162016-11-25 07:57:503249 """
3250 results = []
3251 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3252 input_api.re.MULTILINE)
3253 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3254 input_api.re.MULTILINE)
3255 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313256 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193257 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493258 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313259 continue
3260
jbriance9e12f162016-11-25 07:57:503261 if not f.LocalPath().endswith('.h'):
3262 continue
3263
3264 contents = input_api.ReadFile(f)
3265 fwd_decls = input_api.re.findall(class_pattern, contents)
3266 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3267
3268 useless_fwd_decls = []
3269 for decl in fwd_decls:
3270 count = sum(1 for _ in input_api.re.finditer(
3271 r'\b%s\b' % input_api.re.escape(decl), contents))
3272 if count == 1:
3273 useless_fwd_decls.append(decl)
3274
3275 if not useless_fwd_decls:
3276 continue
3277
3278 for line in f.GenerateScmDiff().splitlines():
3279 if (line.startswith('-') and not line.startswith('--') or
3280 line.startswith('+') and not line.startswith('++')):
3281 for decl in useless_fwd_decls:
3282 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3283 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243284 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503285 (f.LocalPath(), decl)))
3286 useless_fwd_decls.remove(decl)
3287
3288 return results
3289
Jinsong Fan91ebbbd2019-04-16 14:57:173290def _CheckAndroidDebuggableBuild(input_api, output_api):
3291 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3292 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3293 this is a debuggable build of Android.
3294 """
3295 build_type_check_pattern = input_api.re.compile(
3296 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3297
3298 errors = []
3299
3300 sources = lambda affected_file: input_api.FilterSourceFile(
3301 affected_file,
James Cook24a504192020-07-23 00:08:443302 files_to_skip=(_EXCLUDED_PATHS +
3303 _TEST_CODE_EXCLUDED_PATHS +
3304 input_api.DEFAULT_FILES_TO_SKIP +
3305 (r"^android_webview[\\/]support_library[\\/]"
3306 "boundary_interfaces[\\/]",
3307 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3308 r'^third_party[\\/].*',
3309 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3310 r"webview[\\/]chromium[\\/]License.*",)),
3311 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173312
3313 for f in input_api.AffectedSourceFiles(sources):
3314 for line_num, line in f.ChangedContents():
3315 if build_type_check_pattern.search(line):
3316 errors.append("%s:%d" % (f.LocalPath(), line_num))
3317
3318 results = []
3319
3320 if errors:
3321 results.append(output_api.PresubmitPromptWarning(
3322 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3323 ' Please use BuildInfo.isDebugAndroid() instead.',
3324 errors))
3325
3326 return results
jbriance9e12f162016-11-25 07:57:503327
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493328# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293329def _CheckAndroidToastUsage(input_api, output_api):
3330 """Checks that code uses org.chromium.ui.widget.Toast instead of
3331 android.widget.Toast (Chromium Toast doesn't force hardware
3332 acceleration on low-end devices, saving memory).
3333 """
3334 toast_import_pattern = input_api.re.compile(
3335 r'^import android\.widget\.Toast;$')
3336
3337 errors = []
3338
3339 sources = lambda affected_file: input_api.FilterSourceFile(
3340 affected_file,
James Cook24a504192020-07-23 00:08:443341 files_to_skip=(_EXCLUDED_PATHS +
3342 _TEST_CODE_EXCLUDED_PATHS +
3343 input_api.DEFAULT_FILES_TO_SKIP +
3344 (r'^chromecast[\\/].*',
3345 r'^remoting[\\/].*')),
3346 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293347
3348 for f in input_api.AffectedSourceFiles(sources):
3349 for line_num, line in f.ChangedContents():
3350 if toast_import_pattern.search(line):
3351 errors.append("%s:%d" % (f.LocalPath(), line_num))
3352
3353 results = []
3354
3355 if errors:
3356 results.append(output_api.PresubmitError(
3357 'android.widget.Toast usage is detected. Android toasts use hardware'
3358 ' acceleration, and can be\ncostly on low-end devices. Please use'
3359 ' org.chromium.ui.widget.Toast instead.\n'
3360 'Contact [email protected] if you have any questions.',
3361 errors))
3362
3363 return results
3364
3365
dgnaa68d5e2015-06-10 10:08:223366def _CheckAndroidCrLogUsage(input_api, output_api):
3367 """Checks that new logs using org.chromium.base.Log:
3368 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513369 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223370 """
pkotwicza1dd0b002016-05-16 14:41:043371
torne89540622017-03-24 19:41:303372 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043373 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303374 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043375 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303376 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043377 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3378 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093379 # The customtabs_benchmark is a small app that does not depend on Chromium
3380 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043381 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043382 ]
3383
dgnaa68d5e2015-06-10 10:08:223384 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123385 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3386 class_in_base_pattern = input_api.re.compile(
3387 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3388 has_some_log_import_pattern = input_api.re.compile(
3389 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223390 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553391 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223392 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463393 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553394 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223395
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463396 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443397 sources = lambda x: input_api.FilterSourceFile(x,
3398 files_to_check=[r'.*\.java$'],
3399 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123400
dgnaa68d5e2015-06-10 10:08:223401 tag_decl_errors = []
3402 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123403 tag_errors = []
dgn38736db2015-09-18 19:20:513404 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123405 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223406
3407 for f in input_api.AffectedSourceFiles(sources):
3408 file_content = input_api.ReadFile(f)
3409 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223410 # Per line checks
dgn87d9fb62015-06-12 09:15:123411 if (cr_log_import_pattern.search(file_content) or
3412 (class_in_base_pattern.search(file_content) and
3413 not has_some_log_import_pattern.search(file_content))):
3414 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223415 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553416 if rough_log_decl_pattern.search(line):
3417 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223418
3419 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123420 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223421 if match:
3422 has_modified_logs = True
3423
3424 # Make sure it uses "TAG"
3425 if not match.group('tag') == 'TAG':
3426 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123427 else:
3428 # Report non cr Log function calls in changed lines
3429 for line_num, line in f.ChangedContents():
3430 if log_call_pattern.search(line):
3431 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223432
3433 # Per file checks
3434 if has_modified_logs:
3435 # Make sure the tag is using the "cr" prefix and is not too long
3436 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513437 tag_name = match.group('name') if match else None
3438 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223439 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513440 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223441 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513442 elif '.' in tag_name:
3443 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223444
3445 results = []
3446 if tag_decl_errors:
3447 results.append(output_api.PresubmitPromptWarning(
3448 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513449 '"private static final String TAG = "<package tag>".\n'
3450 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223451 tag_decl_errors))
3452
3453 if tag_length_errors:
3454 results.append(output_api.PresubmitError(
3455 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513456 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223457 tag_length_errors))
3458
3459 if tag_errors:
3460 results.append(output_api.PresubmitPromptWarning(
3461 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3462 tag_errors))
3463
dgn87d9fb62015-06-12 09:15:123464 if util_log_errors:
dgn4401aa52015-04-29 16:26:173465 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123466 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3467 util_log_errors))
3468
dgn38736db2015-09-18 19:20:513469 if tag_with_dot_errors:
3470 results.append(output_api.PresubmitPromptWarning(
3471 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3472 tag_with_dot_errors))
3473
dgn4401aa52015-04-29 16:26:173474 return results
3475
3476
Yoland Yanb92fa522017-08-28 17:37:063477def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3478 """Checks that junit.framework.* is no longer used."""
3479 deprecated_junit_framework_pattern = input_api.re.compile(
3480 r'^import junit\.framework\..*;',
3481 input_api.re.MULTILINE)
3482 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443483 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063484 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133485 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063486 for line_num, line in f.ChangedContents():
3487 if deprecated_junit_framework_pattern.search(line):
3488 errors.append("%s:%d" % (f.LocalPath(), line_num))
3489
3490 results = []
3491 if errors:
3492 results.append(output_api.PresubmitError(
3493 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3494 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3495 ' if you have any question.', errors))
3496 return results
3497
3498
3499def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3500 """Checks that if new Java test classes have inheritance.
3501 Either the new test class is JUnit3 test or it is a JUnit4 test class
3502 with a base class, either case is undesirable.
3503 """
3504 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3505
3506 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443507 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063508 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133509 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063510 if not f.OldContents():
3511 class_declaration_start_flag = False
3512 for line_num, line in f.ChangedContents():
3513 if class_declaration_pattern.search(line):
3514 class_declaration_start_flag = True
3515 if class_declaration_start_flag and ' extends ' in line:
3516 errors.append('%s:%d' % (f.LocalPath(), line_num))
3517 if '{' in line:
3518 class_declaration_start_flag = False
3519
3520 results = []
3521 if errors:
3522 results.append(output_api.PresubmitPromptWarning(
3523 'The newly created files include Test classes that inherits from base'
3524 ' class. Please do not use inheritance in JUnit4 tests or add new'
3525 ' JUnit3 tests. Contact [email protected] if you have any'
3526 ' questions.', errors))
3527 return results
3528
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203529
yolandyan45001472016-12-21 21:12:423530def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3531 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3532 deprecated_annotation_import_pattern = input_api.re.compile(
3533 r'^import android\.test\.suitebuilder\.annotation\..*;',
3534 input_api.re.MULTILINE)
3535 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443536 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423537 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133538 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423539 for line_num, line in f.ChangedContents():
3540 if deprecated_annotation_import_pattern.search(line):
3541 errors.append("%s:%d" % (f.LocalPath(), line_num))
3542
3543 results = []
3544 if errors:
3545 results.append(output_api.PresubmitError(
3546 'Annotations in android.test.suitebuilder.annotation have been'
3547 ' deprecated since API level 24. Please use android.support.test.filters'
3548 ' from //third_party/android_support_test_runner:runner_java instead.'
3549 ' Contact [email protected] if you have any questions.', errors))
3550 return results
3551
3552
agrieve7b6479d82015-10-07 14:24:223553def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3554 """Checks if MDPI assets are placed in a correct directory."""
3555 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3556 ('/res/drawable/' in f.LocalPath() or
3557 '/res/drawable-ldrtl/' in f.LocalPath()))
3558 errors = []
3559 for f in input_api.AffectedFiles(include_deletes=False,
3560 file_filter=file_filter):
3561 errors.append(' %s' % f.LocalPath())
3562
3563 results = []
3564 if errors:
3565 results.append(output_api.PresubmitError(
3566 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3567 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3568 '/res/drawable-ldrtl/.\n'
3569 'Contact [email protected] if you have questions.', errors))
3570 return results
3571
3572
Nate Fischer535972b2017-09-16 01:06:183573def _CheckAndroidWebkitImports(input_api, output_api):
3574 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353575 android.webview.ValueCallback except in the WebView glue layer
3576 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183577 """
3578 valuecallback_import_pattern = input_api.re.compile(
3579 r'^import android\.webkit\.ValueCallback;$')
3580
3581 errors = []
3582
3583 sources = lambda affected_file: input_api.FilterSourceFile(
3584 affected_file,
James Cook24a504192020-07-23 00:08:443585 files_to_skip=(_EXCLUDED_PATHS +
3586 _TEST_CODE_EXCLUDED_PATHS +
3587 input_api.DEFAULT_FILES_TO_SKIP +
3588 (r'^android_webview[\\/]glue[\\/].*',
3589 r'^weblayer[\\/].*',)),
3590 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183591
3592 for f in input_api.AffectedSourceFiles(sources):
3593 for line_num, line in f.ChangedContents():
3594 if valuecallback_import_pattern.search(line):
3595 errors.append("%s:%d" % (f.LocalPath(), line_num))
3596
3597 results = []
3598
3599 if errors:
3600 results.append(output_api.PresubmitError(
3601 'android.webkit.ValueCallback usage is detected outside of the glue'
3602 ' layer. To stay compatible with the support library, android.webkit.*'
3603 ' classes should only be used inside the glue layer and'
3604 ' org.chromium.base.Callback should be used instead.',
3605 errors))
3606
3607 return results
3608
3609
Becky Zhou7c69b50992018-12-10 19:37:573610def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3611 """Checks Android XML styles """
3612 import sys
3613 original_sys_path = sys.path
3614 try:
3615 sys.path = sys.path + [input_api.os_path.join(
3616 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3617 import checkxmlstyle
3618 finally:
3619 # Restore sys.path to what it was before.
3620 sys.path = original_sys_path
3621
3622 if is_check_on_upload:
3623 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3624 else:
3625 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3626
3627
agrievef32bcc72016-04-04 14:57:403628class PydepsChecker(object):
3629 def __init__(self, input_api, pydeps_files):
3630 self._file_cache = {}
3631 self._input_api = input_api
3632 self._pydeps_files = pydeps_files
3633
3634 def _LoadFile(self, path):
3635 """Returns the list of paths within a .pydeps file relative to //."""
3636 if path not in self._file_cache:
3637 with open(path) as f:
3638 self._file_cache[path] = f.read()
3639 return self._file_cache[path]
3640
3641 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3642 """Returns an interable of paths within the .pydep, relativized to //."""
3643 os_path = self._input_api.os_path
3644 pydeps_dir = os_path.dirname(pydeps_path)
3645 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3646 if not l.startswith('*'))
3647 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3648
3649 def _CreateFilesToPydepsMap(self):
3650 """Returns a map of local_path -> list_of_pydeps."""
3651 ret = {}
3652 for pydep_local_path in self._pydeps_files:
3653 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3654 ret.setdefault(path, []).append(pydep_local_path)
3655 return ret
3656
3657 def ComputeAffectedPydeps(self):
3658 """Returns an iterable of .pydeps files that might need regenerating."""
3659 affected_pydeps = set()
3660 file_to_pydeps_map = None
3661 for f in self._input_api.AffectedFiles(include_deletes=True):
3662 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463663 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3664 # subrepositories. We can't figure out which files change, so re-check
3665 # all files.
3666 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383667 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3668 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403669 return self._pydeps_files
3670 elif local_path.endswith('.pydeps'):
3671 if local_path in self._pydeps_files:
3672 affected_pydeps.add(local_path)
3673 elif local_path.endswith('.py'):
3674 if file_to_pydeps_map is None:
3675 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3676 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3677 return affected_pydeps
3678
3679 def DetermineIfStale(self, pydeps_path):
3680 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413681 import difflib
John Budorick47ca3fe2018-02-10 00:53:103682 import os
3683
agrievef32bcc72016-04-04 14:57:403684 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033685 if old_pydeps_data:
3686 cmd = old_pydeps_data[1][1:].strip()
3687 old_contents = old_pydeps_data[2:]
3688 else:
3689 # A default cmd that should work in most cases (as long as pydeps filename
3690 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3691 # file is empty/new.
3692 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3693 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3694 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103695 env = dict(os.environ)
3696 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403697 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103698 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413699 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033700 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413701 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403702
3703
Tibor Goldschwendt360793f72019-06-25 18:23:493704def _ParseGclientArgs():
3705 args = {}
3706 with open('build/config/gclient_args.gni', 'r') as f:
3707 for line in f:
3708 line = line.strip()
3709 if not line or line.startswith('#'):
3710 continue
3711 attribute, value = line.split('=')
3712 args[attribute.strip()] = value.strip()
3713 return args
3714
3715
Saagar Sanghavifceeaae2020-08-12 16:40:363716def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403717 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403718 # This check is for Python dependency lists (.pydeps files), and involves
3719 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3720 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283721 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003722 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493723 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403724 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403725 results = []
3726 # First, check for new / deleted .pydeps.
3727 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033728 # Check whether we are running the presubmit check for a file in src.
3729 # f.LocalPath is relative to repo (src, or internal repo).
3730 # os_path.exists is relative to src repo.
3731 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3732 # to src and we can conclude that the pydeps is in src.
3733 if input_api.os_path.exists(f.LocalPath()):
3734 if f.LocalPath().endswith('.pydeps'):
3735 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3736 results.append(output_api.PresubmitError(
3737 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3738 'remove %s' % f.LocalPath()))
3739 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3740 results.append(output_api.PresubmitError(
3741 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3742 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403743
3744 if results:
3745 return results
3746
Mohamed Heikal7cd4d8312020-06-16 16:49:403747 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3748 affected_pydeps = set(checker.ComputeAffectedPydeps())
3749 affected_android_pydeps = affected_pydeps.intersection(
3750 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3751 if affected_android_pydeps and not is_android:
3752 results.append(output_api.PresubmitPromptOrNotify(
3753 'You have changed python files that may affect pydeps for android\n'
3754 'specific scripts. However, the relevant presumbit check cannot be\n'
3755 'run because you are not using an Android checkout. To validate that\n'
3756 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3757 'use the android-internal-presubmit optional trybot.\n'
3758 'Possibly stale pydeps files:\n{}'.format(
3759 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403760
Mohamed Heikal7cd4d8312020-06-16 16:49:403761 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3762 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403763 try:
phajdan.jr0d9878552016-11-04 10:49:413764 result = checker.DetermineIfStale(pydep_path)
3765 if result:
3766 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403767 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413768 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3769 'To regenerate, run:\n\n %s' %
3770 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403771 except input_api.subprocess.CalledProcessError as error:
3772 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3773 long_text=error.output)]
3774
3775 return results
3776
3777
Saagar Sanghavifceeaae2020-08-12 16:40:363778def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433779 """Checks to make sure no header files have |Singleton<|."""
3780 def FileFilter(affected_file):
3781 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443782 files_to_skip = (_EXCLUDED_PATHS +
3783 input_api.DEFAULT_FILES_TO_SKIP +
3784 (r"^base[\\/]memory[\\/]singleton\.h$",
3785 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3786 r"quic_singleton_impl\.h$"))
3787 return input_api.FilterSourceFile(affected_file,
3788 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433789
sergeyu34d21222015-09-16 00:11:443790 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433791 files = []
3792 for f in input_api.AffectedSourceFiles(FileFilter):
3793 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3794 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3795 contents = input_api.ReadFile(f)
3796 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243797 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433798 pattern.search(line)):
3799 files.append(f)
3800 break
3801
3802 if files:
yolandyandaabc6d2016-04-18 18:29:393803 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443804 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433805 'Please move them to an appropriate source file so that the ' +
3806 'template gets instantiated in a single compilation unit.',
3807 files) ]
3808 return []
3809
3810
[email protected]fd20b902014-05-09 02:14:533811_DEPRECATED_CSS = [
3812 # Values
3813 ( "-webkit-box", "flex" ),
3814 ( "-webkit-inline-box", "inline-flex" ),
3815 ( "-webkit-flex", "flex" ),
3816 ( "-webkit-inline-flex", "inline-flex" ),
3817 ( "-webkit-min-content", "min-content" ),
3818 ( "-webkit-max-content", "max-content" ),
3819
3820 # Properties
3821 ( "-webkit-background-clip", "background-clip" ),
3822 ( "-webkit-background-origin", "background-origin" ),
3823 ( "-webkit-background-size", "background-size" ),
3824 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443825 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533826
3827 # Functions
3828 ( "-webkit-gradient", "gradient" ),
3829 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3830 ( "-webkit-linear-gradient", "linear-gradient" ),
3831 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3832 ( "-webkit-radial-gradient", "radial-gradient" ),
3833 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3834]
3835
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203836
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493837# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363838def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533839 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253840 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343841 documentation and iOS CSS for dom distiller
3842 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253843 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533844 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493845 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443846 files_to_skip = (_EXCLUDED_PATHS +
3847 _TEST_CODE_EXCLUDED_PATHS +
3848 input_api.DEFAULT_FILES_TO_SKIP +
3849 (r"^chrome/common/extensions/docs",
3850 r"^chrome/docs",
3851 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3852 r"^components/neterror/resources/neterror.css",
3853 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253854 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443855 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533856 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3857 for line_num, line in fpath.ChangedContents():
3858 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023859 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533860 results.append(output_api.PresubmitError(
3861 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3862 (fpath.LocalPath(), line_num, deprecated_value, value)))
3863 return results
3864
mohan.reddyf21db962014-10-16 12:26:473865
Saagar Sanghavifceeaae2020-08-12 16:40:363866def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363867 bad_files = {}
3868 for f in input_api.AffectedFiles(include_deletes=False):
3869 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493870 not f.LocalPath().startswith('third_party/blink') and
3871 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363872 continue
3873
Daniel Bratell65b033262019-04-23 08:17:063874 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363875 continue
3876
Vaclav Brozekd5de76a2018-03-17 07:57:503877 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363878 if "#include" in line and "../" in line]
3879 if not relative_includes:
3880 continue
3881 bad_files[f.LocalPath()] = relative_includes
3882
3883 if not bad_files:
3884 return []
3885
3886 error_descriptions = []
3887 for file_path, bad_lines in bad_files.iteritems():
3888 error_description = file_path
3889 for line in bad_lines:
3890 error_description += '\n ' + line
3891 error_descriptions.append(error_description)
3892
3893 results = []
3894 results.append(output_api.PresubmitError(
3895 'You added one or more relative #include paths (including "../").\n'
3896 'These shouldn\'t be used because they can be used to include headers\n'
3897 'from code that\'s not correctly specified as a dependency in the\n'
3898 'relevant BUILD.gn file(s).',
3899 error_descriptions))
3900
3901 return results
3902
Takeshi Yoshinoe387aa32017-08-02 13:16:133903
Saagar Sanghavifceeaae2020-08-12 16:40:363904def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063905 """Check that nobody tries to include a cc file. It's a relatively
3906 common error which results in duplicate symbols in object
3907 files. This may not always break the build until someone later gets
3908 very confusing linking errors."""
3909 results = []
3910 for f in input_api.AffectedFiles(include_deletes=False):
3911 # We let third_party code do whatever it wants
3912 if (f.LocalPath().startswith('third_party') and
3913 not f.LocalPath().startswith('third_party/blink') and
3914 not f.LocalPath().startswith('third_party\\blink')):
3915 continue
3916
3917 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3918 continue
3919
3920 for _, line in f.ChangedContents():
3921 if line.startswith('#include "'):
3922 included_file = line.split('"')[1]
3923 if _IsCPlusPlusFile(input_api, included_file):
3924 # The most common naming for external files with C++ code,
3925 # apart from standard headers, is to call them foo.inc, but
3926 # Chromium sometimes uses foo-inc.cc so allow that as well.
3927 if not included_file.endswith(('.h', '-inc.cc')):
3928 results.append(output_api.PresubmitError(
3929 'Only header files or .inc files should be included in other\n'
3930 'C++ files. Compiling the contents of a cc file more than once\n'
3931 'will cause duplicate information in the build which may later\n'
3932 'result in strange link_errors.\n' +
3933 f.LocalPath() + ':\n ' +
3934 line))
3935
3936 return results
3937
3938
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203939def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3940 if not isinstance(key, ast.Str):
3941 return 'Key at line %d must be a string literal' % key.lineno
3942 if not isinstance(value, ast.Dict):
3943 return 'Value at line %d must be a dict' % value.lineno
3944 if len(value.keys) != 1:
3945 return 'Dict at line %d must have single entry' % value.lineno
3946 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3947 return (
3948 'Entry at line %d must have a string literal \'filepath\' as key' %
3949 value.lineno)
3950 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133951
Takeshi Yoshinoe387aa32017-08-02 13:16:133952
Sergey Ulanov4af16052018-11-08 02:41:463953def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203954 if not isinstance(key, ast.Str):
3955 return 'Key at line %d must be a string literal' % key.lineno
3956 if not isinstance(value, ast.List):
3957 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463958 for element in value.elts:
3959 if not isinstance(element, ast.Str):
3960 return 'Watchlist elements on line %d is not a string' % key.lineno
3961 if not email_regex.match(element.s):
3962 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3963 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203964 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133965
Takeshi Yoshinoe387aa32017-08-02 13:16:133966
Sergey Ulanov4af16052018-11-08 02:41:463967def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203968 mismatch_template = (
3969 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3970 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133971
Sergey Ulanov4af16052018-11-08 02:41:463972 email_regex = input_api.re.compile(
3973 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3974
3975 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203976 i = 0
3977 last_key = ''
3978 while True:
3979 if i >= len(wd_dict.keys):
3980 if i >= len(w_dict.keys):
3981 return None
3982 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3983 elif i >= len(w_dict.keys):
3984 return (
3985 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133986
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203987 wd_key = wd_dict.keys[i]
3988 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133989
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203990 result = _CheckWatchlistDefinitionsEntrySyntax(
3991 wd_key, wd_dict.values[i], ast)
3992 if result is not None:
3993 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133994
Sergey Ulanov4af16052018-11-08 02:41:463995 result = _CheckWatchlistsEntrySyntax(
3996 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203997 if result is not None:
3998 return 'Bad entry in WATCHLISTS dict: %s' % result
3999
4000 if wd_key.s != w_key.s:
4001 return mismatch_template % (
4002 '%s at line %d' % (wd_key.s, wd_key.lineno),
4003 '%s at line %d' % (w_key.s, w_key.lineno))
4004
4005 if wd_key.s < last_key:
4006 return (
4007 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4008 (wd_key.lineno, w_key.lineno))
4009 last_key = wd_key.s
4010
4011 i = i + 1
4012
4013
Sergey Ulanov4af16052018-11-08 02:41:464014def _CheckWATCHLISTSSyntax(expression, input_api):
4015 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204016 if not isinstance(expression, ast.Expression):
4017 return 'WATCHLISTS file must contain a valid expression'
4018 dictionary = expression.body
4019 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4020 return 'WATCHLISTS file must have single dict with exactly two entries'
4021
4022 first_key = dictionary.keys[0]
4023 first_value = dictionary.values[0]
4024 second_key = dictionary.keys[1]
4025 second_value = dictionary.values[1]
4026
4027 if (not isinstance(first_key, ast.Str) or
4028 first_key.s != 'WATCHLIST_DEFINITIONS' or
4029 not isinstance(first_value, ast.Dict)):
4030 return (
4031 'The first entry of the dict in WATCHLISTS file must be '
4032 'WATCHLIST_DEFINITIONS dict')
4033
4034 if (not isinstance(second_key, ast.Str) or
4035 second_key.s != 'WATCHLISTS' or
4036 not isinstance(second_value, ast.Dict)):
4037 return (
4038 'The second entry of the dict in WATCHLISTS file must be '
4039 'WATCHLISTS dict')
4040
Sergey Ulanov4af16052018-11-08 02:41:464041 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134042
4043
Saagar Sanghavifceeaae2020-08-12 16:40:364044def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:134045 for f in input_api.AffectedFiles(include_deletes=False):
4046 if f.LocalPath() == 'WATCHLISTS':
4047 contents = input_api.ReadFile(f, 'r')
4048
4049 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204050 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134051 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204052 # Get an AST tree for it and scan the tree for detailed style checking.
4053 expression = input_api.ast.parse(
4054 contents, filename='WATCHLISTS', mode='eval')
4055 except ValueError as e:
4056 return [output_api.PresubmitError(
4057 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4058 except SyntaxError as e:
4059 return [output_api.PresubmitError(
4060 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4061 except TypeError as e:
4062 return [output_api.PresubmitError(
4063 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134064
Sergey Ulanov4af16052018-11-08 02:41:464065 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204066 if result is not None:
4067 return [output_api.PresubmitError(result)]
4068 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134069
4070 return []
4071
4072
Saagar Sanghavifceeaae2020-08-12 16:40:364073def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194074 """Checks that newly added header files have corresponding GN changes.
4075 Note that this is only a heuristic. To be precise, run script:
4076 build/check_gn_headers.py.
4077 """
4078
4079 def headers(f):
4080 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444081 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194082
4083 new_headers = []
4084 for f in input_api.AffectedSourceFiles(headers):
4085 if f.Action() != 'A':
4086 continue
4087 new_headers.append(f.LocalPath())
4088
4089 def gn_files(f):
James Cook24a504192020-07-23 00:08:444090 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194091
4092 all_gn_changed_contents = ''
4093 for f in input_api.AffectedSourceFiles(gn_files):
4094 for _, line in f.ChangedContents():
4095 all_gn_changed_contents += line
4096
4097 problems = []
4098 for header in new_headers:
4099 basename = input_api.os_path.basename(header)
4100 if basename not in all_gn_changed_contents:
4101 problems.append(header)
4102
4103 if problems:
4104 return [output_api.PresubmitPromptWarning(
4105 'Missing GN changes for new header files', items=sorted(problems),
4106 long_text='Please double check whether newly added header files need '
4107 'corresponding changes in gn or gni files.\nThis checking is only a '
4108 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4109 'Read https://crbug.com/661774 for more info.')]
4110 return []
4111
4112
Saagar Sanghavifceeaae2020-08-12 16:40:364113def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024114 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4115
4116 This assumes we won't intentionally reference one product from the other
4117 product.
4118 """
4119 all_problems = []
4120 test_cases = [{
4121 "filename_postfix": "google_chrome_strings.grd",
4122 "correct_name": "Chrome",
4123 "incorrect_name": "Chromium",
4124 }, {
4125 "filename_postfix": "chromium_strings.grd",
4126 "correct_name": "Chromium",
4127 "incorrect_name": "Chrome",
4128 }]
4129
4130 for test_case in test_cases:
4131 problems = []
4132 filename_filter = lambda x: x.LocalPath().endswith(
4133 test_case["filename_postfix"])
4134
4135 # Check each new line. Can yield false positives in multiline comments, but
4136 # easier than trying to parse the XML because messages can have nested
4137 # children, and associating message elements with affected lines is hard.
4138 for f in input_api.AffectedSourceFiles(filename_filter):
4139 for line_num, line in f.ChangedContents():
4140 if "<message" in line or "<!--" in line or "-->" in line:
4141 continue
4142 if test_case["incorrect_name"] in line:
4143 problems.append(
4144 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4145
4146 if problems:
4147 message = (
4148 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4149 % (test_case["correct_name"], test_case["correct_name"],
4150 test_case["incorrect_name"]))
4151 all_problems.append(
4152 output_api.PresubmitPromptWarning(message, items=problems))
4153
4154 return all_problems
4155
4156
Saagar Sanghavifceeaae2020-08-12 16:40:364157def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514158 # TODO(crbug.com/941824): We need to make sure the entries in
4159 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4160 # so that users of //buildtools in other projects get the same tooling
4161 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4162 # support to gclient, we can eliminate the duplication and delete
4163 # this presubmit check.
4164
4165 # Update this regexp if new revisions are added to the files.
4166 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264167 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514168
4169 # If a user is changing one revision, they need to change the same
4170 # line in both files. This means that any given change should contain
4171 # exactly the same list of changed lines that match the regexps. The
4172 # replace(' ', '') call allows us to ignore whitespace changes to the
4173 # lines. The 'long_text' parameter to the error will contain the
4174 # list of changed lines in both files, which should make it easy enough
4175 # to spot the error without going overboard in this implementation.
4176 revs_changes = {
4177 'DEPS': {},
4178 'buildtools/DEPS': {},
4179 }
4180 long_text = ''
4181
4182 for f in input_api.AffectedFiles(
4183 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4184 for line_num, line in f.ChangedContents():
4185 if rev_regexp.search(line):
4186 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4187 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4188
4189 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4190 return [output_api.PresubmitError(
4191 'Change buildtools revisions in sync in both //DEPS and '
4192 '//buildtools/DEPS.', long_text=long_text + '\n')]
4193 else:
4194 return []
4195
4196
Saagar Sanghavifceeaae2020-08-12 16:40:364197def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364198 """Avoid large files, especially binary files, in the repository since
4199 git doesn't scale well for those. They will be in everyone's repo
4200 clones forever, forever making Chromium slower to clone and work
4201 with."""
4202
4203 # Uploading files to cloud storage is not trivial so we don't want
4204 # to set the limit too low, but the upper limit for "normal" large
4205 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4206 # anything over 20 MB is exceptional.
4207 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4208
4209 too_large_files = []
4210 for f in input_api.AffectedFiles():
4211 # Check both added and modified files (but not deleted files).
4212 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384213 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364214 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4215 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4216
4217 if too_large_files:
4218 message = (
4219 'Do not commit large files to git since git scales badly for those.\n' +
4220 'Instead put the large files in cloud storage and use DEPS to\n' +
4221 'fetch them.\n' + '\n'.join(too_large_files)
4222 )
4223 return [output_api.PresubmitError(
4224 'Too large files found in commit', long_text=message + '\n')]
4225 else:
4226 return []
4227
Max Morozb47503b2019-08-08 21:03:274228
Saagar Sanghavifceeaae2020-08-12 16:40:364229def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274230 """Checks specific for fuzz target sources."""
4231 EXPORTED_SYMBOLS = [
4232 'LLVMFuzzerInitialize',
4233 'LLVMFuzzerCustomMutator',
4234 'LLVMFuzzerCustomCrossOver',
4235 'LLVMFuzzerMutate',
4236 ]
4237
4238 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4239
4240 def FilterFile(affected_file):
4241 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444242 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4243 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274244
4245 return input_api.FilterSourceFile(
4246 affected_file,
James Cook24a504192020-07-23 00:08:444247 files_to_check=[files_to_check],
4248 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274249
4250 files_with_missing_header = []
4251 for f in input_api.AffectedSourceFiles(FilterFile):
4252 contents = input_api.ReadFile(f, 'r')
4253 if REQUIRED_HEADER in contents:
4254 continue
4255
4256 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4257 files_with_missing_header.append(f.LocalPath())
4258
4259 if not files_with_missing_header:
4260 return []
4261
4262 long_text = (
4263 'If you define any of the libFuzzer optional functions (%s), it is '
4264 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4265 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4266 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4267 'to access command line arguments passed to the fuzzer. Instead, prefer '
4268 'static initialization and shared resources as documented in '
4269 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4270 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4271 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4272 )
4273
4274 return [output_api.PresubmitPromptWarning(
4275 message="Missing '%s' in:" % REQUIRED_HEADER,
4276 items=files_with_missing_header,
4277 long_text=long_text)]
4278
4279
Mohamed Heikald048240a2019-11-12 16:57:374280def _CheckNewImagesWarning(input_api, output_api):
4281 """
4282 Warns authors who add images into the repo to make sure their images are
4283 optimized before committing.
4284 """
4285 images_added = False
4286 image_paths = []
4287 errors = []
4288 filter_lambda = lambda x: input_api.FilterSourceFile(
4289 x,
James Cook24a504192020-07-23 00:08:444290 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4291 + input_api.DEFAULT_FILES_TO_SKIP),
4292 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374293 )
4294 for f in input_api.AffectedFiles(
4295 include_deletes=False, file_filter=filter_lambda):
4296 local_path = f.LocalPath().lower()
4297 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4298 images_added = True
4299 image_paths.append(f)
4300 if images_added:
4301 errors.append(output_api.PresubmitPromptWarning(
4302 'It looks like you are trying to commit some images. If these are '
4303 'non-test-only images, please make sure to read and apply the tips in '
4304 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4305 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4306 'FYI only and will not block your CL on the CQ.', image_paths))
4307 return errors
4308
4309
Saagar Sanghavifceeaae2020-08-12 16:40:364310def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574311 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224312 results = []
dgnaa68d5e2015-06-10 10:08:224313 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174314 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224315 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294316 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064317 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4318 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424319 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184320 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574321 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374322 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154323 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574324 return results
4325
Saagar Sanghavifceeaae2020-08-12 16:40:364326def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574327 """Groups commit checks that target android code."""
4328 results = []
4329 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224330 return results
4331
Chris Hall59f8d0c72020-05-01 07:31:194332# TODO(chrishall): could we additionally match on any path owned by
4333# ui/accessibility/OWNERS ?
4334_ACCESSIBILITY_PATHS = (
4335 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4336 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4337 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4338 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4339 r"^content[\\/]browser[\\/]accessibility[\\/]",
4340 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4341 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4342 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4343 r"^ui[\\/]accessibility[\\/]",
4344 r"^ui[\\/]views[\\/]accessibility[\\/]",
4345)
4346
Saagar Sanghavifceeaae2020-08-12 16:40:364347def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194348 """Checks that commits to accessibility code contain an AX-Relnotes field in
4349 their commit message."""
4350 def FileFilter(affected_file):
4351 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444352 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194353
4354 # Only consider changes affecting accessibility paths.
4355 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4356 return []
4357
Akihiro Ota08108e542020-05-20 15:30:534358 # AX-Relnotes can appear in either the description or the footer.
4359 # When searching the description, require 'AX-Relnotes:' to appear at the
4360 # beginning of a line.
4361 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4362 description_has_relnotes = any(ax_regex.match(line)
4363 for line in input_api.change.DescriptionText().lower().splitlines())
4364
4365 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4366 'AX-Relnotes', [])
4367 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194368 return []
4369
4370 # TODO(chrishall): link to Relnotes documentation in message.
4371 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4372 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4373 "user-facing changes"
4374 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4375 "user-facing effects"
4376 "\n if this is confusing or annoying then please contact members "
4377 "of ui/accessibility/OWNERS.")
4378
4379 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224380
Saagar Sanghavifceeaae2020-08-12 16:40:364381def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394382 """Checks common to both upload and commit."""
4383 results = []
4384 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384385 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544386 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084387
4388 author = input_api.change.author_email
4389 if author and author not in _KNOWN_ROBOTS:
4390 results.extend(
4391 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4392
[email protected]9f919cc2013-07-31 03:04:044393 results.extend(
4394 input_api.canned_checks.CheckChangeHasNoTabs(
4395 input_api,
4396 output_api,
4397 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434398 results.extend(input_api.RunTests(
4399 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244400
Edward Lesmesce51df52020-08-04 22:10:174401 dirmd_bin = input_api.os_path.join(
4402 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4403 results.extend(input_api.RunTests(
4404 input_api.canned_checks.CheckDirMetadataFormat(
4405 input_api, output_api, dirmd_bin)))
4406 results.extend(
4407 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4408 input_api, output_api))
4409
Vaclav Brozekcdc7defb2018-03-20 09:54:354410 for f in input_api.AffectedFiles():
4411 path, name = input_api.os_path.split(f.LocalPath())
4412 if name == 'PRESUBMIT.py':
4413 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004414 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4415 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074416 # The PRESUBMIT.py file (and the directory containing it) might
4417 # have been affected by being moved or removed, so only try to
4418 # run the tests if they still exist.
4419 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4420 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444421 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394422 return results
[email protected]1f7b4172010-01-28 01:17:344423
[email protected]b337cb5b2011-01-23 21:24:054424
Saagar Sanghavifceeaae2020-08-12 16:40:364425def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494426 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4427 if f.LocalPath().endswith(('.orig', '.rej'))]
4428 if problems:
4429 return [output_api.PresubmitError(
4430 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034431 else:
4432 return []
[email protected]b8079ae4a2012-12-05 19:56:494433
4434
Saagar Sanghavifceeaae2020-08-12 16:40:364435def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214436 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4437 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4438 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074439 include_re = input_api.re.compile(
4440 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4441 extension_re = input_api.re.compile(r'\.[a-z]+$')
4442 errors = []
4443 for f in input_api.AffectedFiles():
4444 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4445 continue
4446 found_line_number = None
4447 found_macro = None
4448 for line_num, line in f.ChangedContents():
4449 match = macro_re.search(line)
4450 if match:
4451 found_line_number = line_num
4452 found_macro = match.group(2)
4453 break
4454 if not found_line_number:
4455 continue
4456
4457 found_include = False
4458 for line in f.NewContents():
4459 if include_re.search(line):
4460 found_include = True
4461 break
4462 if found_include:
4463 continue
4464
4465 if not f.LocalPath().endswith('.h'):
4466 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4467 try:
4468 content = input_api.ReadFile(primary_header_path, 'r')
4469 if include_re.search(content):
4470 continue
4471 except IOError:
4472 pass
4473 errors.append('%s:%d %s macro is used without including build/'
4474 'build_config.h.'
4475 % (f.LocalPath(), found_line_number, found_macro))
4476 if errors:
4477 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4478 return []
4479
4480
[email protected]b00342e7f2013-03-26 16:21:544481def _DidYouMeanOSMacro(bad_macro):
4482 try:
4483 return {'A': 'OS_ANDROID',
4484 'B': 'OS_BSD',
4485 'C': 'OS_CHROMEOS',
4486 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444487 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544488 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444489 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544490 'N': 'OS_NACL',
4491 'O': 'OS_OPENBSD',
4492 'P': 'OS_POSIX',
4493 'S': 'OS_SOLARIS',
4494 'W': 'OS_WIN'}[bad_macro[3].upper()]
4495 except KeyError:
4496 return ''
4497
4498
4499def _CheckForInvalidOSMacrosInFile(input_api, f):
4500 """Check for sensible looking, totally invalid OS macros."""
4501 preprocessor_statement = input_api.re.compile(r'^\s*#')
4502 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4503 results = []
4504 for lnum, line in f.ChangedContents():
4505 if preprocessor_statement.search(line):
4506 for match in os_macro.finditer(line):
4507 if not match.group(1) in _VALID_OS_MACROS:
4508 good = _DidYouMeanOSMacro(match.group(1))
4509 did_you_mean = ' (did you mean %s?)' % good if good else ''
4510 results.append(' %s:%d %s%s' % (f.LocalPath(),
4511 lnum,
4512 match.group(1),
4513 did_you_mean))
4514 return results
4515
4516
Saagar Sanghavifceeaae2020-08-12 16:40:364517def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544518 """Check all affected files for invalid OS macros."""
4519 bad_macros = []
tzik3f295992018-12-04 20:32:234520 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474521 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544522 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4523
4524 if not bad_macros:
4525 return []
4526
4527 return [output_api.PresubmitError(
4528 'Possibly invalid OS macro[s] found. Please fix your code\n'
4529 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4530
lliabraa35bab3932014-10-01 12:16:444531
4532def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4533 """Check all affected files for invalid "if defined" macros."""
4534 ALWAYS_DEFINED_MACROS = (
4535 "TARGET_CPU_PPC",
4536 "TARGET_CPU_PPC64",
4537 "TARGET_CPU_68K",
4538 "TARGET_CPU_X86",
4539 "TARGET_CPU_ARM",
4540 "TARGET_CPU_MIPS",
4541 "TARGET_CPU_SPARC",
4542 "TARGET_CPU_ALPHA",
4543 "TARGET_IPHONE_SIMULATOR",
4544 "TARGET_OS_EMBEDDED",
4545 "TARGET_OS_IPHONE",
4546 "TARGET_OS_MAC",
4547 "TARGET_OS_UNIX",
4548 "TARGET_OS_WIN32",
4549 )
4550 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4551 results = []
4552 for lnum, line in f.ChangedContents():
4553 for match in ifdef_macro.finditer(line):
4554 if match.group(1) in ALWAYS_DEFINED_MACROS:
4555 always_defined = ' %s is always defined. ' % match.group(1)
4556 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4557 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4558 lnum,
4559 always_defined,
4560 did_you_mean))
4561 return results
4562
4563
Saagar Sanghavifceeaae2020-08-12 16:40:364564def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444565 """Check all affected files for invalid "if defined" macros."""
4566 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054567 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444568 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054569 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214570 continue
lliabraa35bab3932014-10-01 12:16:444571 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4572 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4573
4574 if not bad_macros:
4575 return []
4576
4577 return [output_api.PresubmitError(
4578 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4579 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4580 bad_macros)]
4581
4582
Saagar Sanghavifceeaae2020-08-12 16:40:364583def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044584 """Check for same IPC rules described in
4585 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4586 """
4587 base_pattern = r'IPC_ENUM_TRAITS\('
4588 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4589 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4590
4591 problems = []
4592 for f in input_api.AffectedSourceFiles(None):
4593 local_path = f.LocalPath()
4594 if not local_path.endswith('.h'):
4595 continue
4596 for line_number, line in f.ChangedContents():
4597 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4598 problems.append(
4599 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4600
4601 if problems:
4602 return [output_api.PresubmitPromptWarning(
4603 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4604 else:
4605 return []
4606
[email protected]b00342e7f2013-03-26 16:21:544607
Saagar Sanghavifceeaae2020-08-12 16:40:364608def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054609 """Check to make sure no files being submitted have long paths.
4610 This causes issues on Windows.
4611 """
4612 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194613 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054614 local_path = f.LocalPath()
4615 # Windows has a path limit of 260 characters. Limit path length to 200 so
4616 # that we have some extra for the prefix on dev machines and the bots.
4617 if len(local_path) > 200:
4618 problems.append(local_path)
4619
4620 if problems:
4621 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4622 else:
4623 return []
4624
4625
Saagar Sanghavifceeaae2020-08-12 16:40:364626def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144627 """Check that header files have proper guards against multiple inclusion.
4628 If a file should not have such guards (and it probably should) then it
4629 should include the string "no-include-guard-because-multiply-included".
4630 """
Daniel Bratell6a75baef62018-06-04 10:04:454631 def is_chromium_header_file(f):
4632 # We only check header files under the control of the Chromium
4633 # project. That is, those outside third_party apart from
4634 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324635 # We also exclude *_message_generator.h headers as they use
4636 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454637 file_with_path = input_api.os_path.normpath(f.LocalPath())
4638 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324639 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454640 (not file_with_path.startswith('third_party') or
4641 file_with_path.startswith(
4642 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144643
4644 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344645 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144646
4647 errors = []
4648
Daniel Bratell6a75baef62018-06-04 10:04:454649 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144650 guard_name = None
4651 guard_line_number = None
4652 seen_guard_end = False
4653
4654 file_with_path = input_api.os_path.normpath(f.LocalPath())
4655 base_file_name = input_api.os_path.splitext(
4656 input_api.os_path.basename(file_with_path))[0]
4657 upper_base_file_name = base_file_name.upper()
4658
4659 expected_guard = replace_special_with_underscore(
4660 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144661
4662 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574663 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4664 # are too many (1000+) files with slight deviations from the
4665 # coding style. The most important part is that the include guard
4666 # is there, and that it's unique, not the name so this check is
4667 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144668 #
4669 # As code becomes more uniform, this could be made stricter.
4670
4671 guard_name_pattern_list = [
4672 # Anything with the right suffix (maybe with an extra _).
4673 r'\w+_H__?',
4674
Daniel Bratell39b5b062018-05-16 18:09:574675 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144676 r'\w+_h',
4677
4678 # Anything including the uppercase name of the file.
4679 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4680 upper_base_file_name)) + r'\w*',
4681 ]
4682 guard_name_pattern = '|'.join(guard_name_pattern_list)
4683 guard_pattern = input_api.re.compile(
4684 r'#ifndef\s+(' + guard_name_pattern + ')')
4685
4686 for line_number, line in enumerate(f.NewContents()):
4687 if 'no-include-guard-because-multiply-included' in line:
4688 guard_name = 'DUMMY' # To not trigger check outside the loop.
4689 break
4690
4691 if guard_name is None:
4692 match = guard_pattern.match(line)
4693 if match:
4694 guard_name = match.group(1)
4695 guard_line_number = line_number
4696
Daniel Bratell39b5b062018-05-16 18:09:574697 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454698 # don't match the chromium style guide, but new files should
4699 # get it right.
4700 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574701 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144702 errors.append(output_api.PresubmitPromptWarning(
4703 'Header using the wrong include guard name %s' % guard_name,
4704 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574705 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144706 else:
4707 # The line after #ifndef should have a #define of the same name.
4708 if line_number == guard_line_number + 1:
4709 expected_line = '#define %s' % guard_name
4710 if line != expected_line:
4711 errors.append(output_api.PresubmitPromptWarning(
4712 'Missing "%s" for include guard' % expected_line,
4713 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4714 'Expected: %r\nGot: %r' % (expected_line, line)))
4715
4716 if not seen_guard_end and line == '#endif // %s' % guard_name:
4717 seen_guard_end = True
4718 elif seen_guard_end:
4719 if line.strip() != '':
4720 errors.append(output_api.PresubmitPromptWarning(
4721 'Include guard %s not covering the whole file' % (
4722 guard_name), [f.LocalPath()]))
4723 break # Nothing else to check and enough to warn once.
4724
4725 if guard_name is None:
4726 errors.append(output_api.PresubmitPromptWarning(
4727 'Missing include guard %s' % expected_guard,
4728 [f.LocalPath()],
4729 'Missing include guard in %s\n'
4730 'Recommended name: %s\n'
4731 'This check can be disabled by having the string\n'
4732 'no-include-guard-because-multiply-included in the header.' %
4733 (f.LocalPath(), expected_guard)))
4734
4735 return errors
4736
4737
Saagar Sanghavifceeaae2020-08-12 16:40:364738def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234739 """Check source code and known ascii text files for Windows style line
4740 endings.
4741 """
earthdok1b5e0ee2015-03-10 15:19:104742 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234743
4744 file_inclusion_pattern = (
4745 known_text_files,
4746 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4747 )
4748
mostynbb639aca52015-01-07 20:31:234749 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534750 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444751 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534752 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504753 include_file = False
4754 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234755 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504756 include_file = True
4757 if include_file:
4758 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234759
4760 if problems:
4761 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4762 'these files to contain Windows style line endings?\n' +
4763 '\n'.join(problems))]
4764
4765 return []
4766
4767
Saagar Sanghavifceeaae2020-08-12 16:40:364768def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134769 """Checks that all source files use SYSLOG properly."""
4770 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364771 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564772 for line_number, line in f.ChangedContents():
4773 if 'SYSLOG' in line:
4774 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4775
pastarmovj89f7ee12016-09-20 14:58:134776 if syslog_files:
4777 return [output_api.PresubmitPromptWarning(
4778 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4779 ' calls.\nFiles to check:\n', items=syslog_files)]
4780 return []
4781
4782
[email protected]1f7b4172010-01-28 01:17:344783def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364784 if input_api.version < [2, 0, 0]:
4785 return [output_api.PresubmitError("Your depot_tools is out of date. "
4786 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4787 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344788 results = []
scottmg39b29952014-12-08 18:31:284789 results.extend(
jam93a6ee792017-02-08 23:59:224790 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544791 return results
[email protected]ca8d1982009-02-19 16:33:124792
4793
[email protected]1bfb8322014-04-23 01:02:414794def GetTryServerMasterForBot(bot):
4795 """Returns the Try Server master for the given bot.
4796
[email protected]0bb112362014-07-26 04:38:324797 It tries to guess the master from the bot name, but may still fail
4798 and return None. There is no longer a default master.
4799 """
4800 # Potentially ambiguous bot names are listed explicitly.
4801 master_map = {
tandriie5587792016-07-14 00:34:504802 'chromium_presubmit': 'master.tryserver.chromium.linux',
4803 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414804 }
[email protected]0bb112362014-07-26 04:38:324805 master = master_map.get(bot)
4806 if not master:
wnwen4fbaab82016-05-25 12:54:364807 if 'android' in bot:
tandriie5587792016-07-14 00:34:504808 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364809 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504810 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324811 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504812 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324813 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504814 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324815 return master
[email protected]1bfb8322014-04-23 01:02:414816
4817
[email protected]ca8d1982009-02-19 16:33:124818def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364819 if input_api.version < [2, 0, 0]:
4820 return [output_api.PresubmitError("Your depot_tools is out of date. "
4821 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4822 "but your version is %d.%d.%d" % tuple(input_api.version))]
4823
[email protected]fe5f57c52009-06-05 14:25:544824 results = []
[email protected]fe5f57c52009-06-05 14:25:544825 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274826 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344827 input_api,
4828 output_api,
[email protected]2fdd1f362013-01-16 03:56:034829 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274830
jam93a6ee792017-02-08 23:59:224831 results.extend(
4832 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544833 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4834 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384835 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4836 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414837 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4838 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544839 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144840
4841
Saagar Sanghavifceeaae2020-08-12 16:40:364842def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264843 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024844 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4845 # footer is set to true.
4846 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264847 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024848 footer.lower()
4849 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264850 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024851
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144852 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264853 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144854 import sys
4855 from io import StringIO
4856
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144857 new_or_added_paths = set(f.LocalPath()
4858 for f in input_api.AffectedFiles()
4859 if (f.Action() == 'A' or f.Action() == 'M'))
4860 removed_paths = set(f.LocalPath()
4861 for f in input_api.AffectedFiles(include_deletes=True)
4862 if f.Action() == 'D')
4863
Andrew Grieve0e8790c2020-09-03 17:27:324864 affected_grds = [
4865 f for f in input_api.AffectedFiles()
4866 if f.LocalPath().endswith(('.grd', '.grdp'))
4867 ]
4868 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164869 if not affected_grds:
4870 return []
4871
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144872 affected_png_paths = [f.AbsoluteLocalPath()
4873 for f in input_api.AffectedFiles()
4874 if (f.LocalPath().endswith('.png'))]
4875
4876 # Check for screenshots. Developers can upload screenshots using
4877 # tools/translation/upload_screenshots.py which finds and uploads
4878 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4879 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4880 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4881 #
4882 # The logic here is as follows:
4883 #
4884 # - If the CL has a .png file under the screenshots directory for a grd
4885 # file, warn the developer. Actual images should never be checked into the
4886 # Chrome repo.
4887 #
4888 # - If the CL contains modified or new messages in grd files and doesn't
4889 # contain the corresponding .sha1 files, warn the developer to add images
4890 # and upload them via tools/translation/upload_screenshots.py.
4891 #
4892 # - If the CL contains modified or new messages in grd files and the
4893 # corresponding .sha1 files, everything looks good.
4894 #
4895 # - If the CL contains removed messages in grd files but the corresponding
4896 # .sha1 files aren't removed, warn the developer to remove them.
4897 unnecessary_screenshots = []
4898 missing_sha1 = []
4899 unnecessary_sha1_files = []
4900
Rainhard Findlingfc31844c52020-05-15 09:58:264901 # This checks verifies that the ICU syntax of messages this CL touched is
4902 # valid, and reports any found syntax errors.
4903 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4904 # without developers being aware of them. Later on, such ICU syntax errors
4905 # break message extraction for translation, hence would block Chromium
4906 # translations until they are fixed.
4907 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144908
4909 def _CheckScreenshotAdded(screenshots_dir, message_id):
4910 sha1_path = input_api.os_path.join(
4911 screenshots_dir, message_id + '.png.sha1')
4912 if sha1_path not in new_or_added_paths:
4913 missing_sha1.append(sha1_path)
4914
4915
4916 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4917 sha1_path = input_api.os_path.join(
4918 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034919 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144920 unnecessary_sha1_files.append(sha1_path)
4921
Rainhard Findlingfc31844c52020-05-15 09:58:264922
4923 def _ValidateIcuSyntax(text, level, signatures):
4924 """Validates ICU syntax of a text string.
4925
4926 Check if text looks similar to ICU and checks for ICU syntax correctness
4927 in this case. Reports various issues with ICU syntax and values of
4928 variants. Supports checking of nested messages. Accumulate information of
4929 each ICU messages found in the text for further checking.
4930
4931 Args:
4932 text: a string to check.
4933 level: a number of current nesting level.
4934 signatures: an accumulator, a list of tuple of (level, variable,
4935 kind, variants).
4936
4937 Returns:
4938 None if a string is not ICU or no issue detected.
4939 A tuple of (message, start index, end index) if an issue detected.
4940 """
4941 valid_types = {
4942 'plural': (frozenset(
4943 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4944 frozenset(['=1', 'other'])),
4945 'selectordinal': (frozenset(
4946 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4947 frozenset(['one', 'other'])),
4948 'select': (frozenset(), frozenset(['other'])),
4949 }
4950
4951 # Check if the message looks like an attempt to use ICU
4952 # plural. If yes - check if its syntax strictly matches ICU format.
4953 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4954 if not like:
4955 signatures.append((level, None, None, None))
4956 return
4957
4958 # Check for valid prefix and suffix
4959 m = re.match(
4960 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4961 r'(plural|selectordinal|select),\s*'
4962 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4963 if not m:
4964 return (('This message looks like an ICU plural, '
4965 'but does not follow ICU syntax.'), like.start(), like.end())
4966 starting, variable, kind, variant_pairs = m.groups()
4967 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4968 if depth:
4969 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4970 len(text))
4971 first = text[0]
4972 ending = text[last_pos:]
4973 if not starting:
4974 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4975 last_pos)
4976 if not ending or '}' not in ending:
4977 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4978 last_pos)
4979 elif first != '{':
4980 return (
4981 ('Invalid ICU format. Extra characters at the start of a complex '
4982 'message (go/icu-message-migration): "%s"') %
4983 starting, 0, len(starting))
4984 elif ending != '}':
4985 return (('Invalid ICU format. Extra characters at the end of a complex '
4986 'message (go/icu-message-migration): "%s"')
4987 % ending, last_pos - 1, len(text) - 1)
4988 if kind not in valid_types:
4989 return (('Unknown ICU message type %s. '
4990 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4991 known, required = valid_types[kind]
4992 defined_variants = set()
4993 for variant, variant_range, value, value_range in variants:
4994 start, end = variant_range
4995 if variant in defined_variants:
4996 return ('Variant "%s" is defined more than once' % variant,
4997 start, end)
4998 elif known and variant not in known:
4999 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5000 start, end)
5001 defined_variants.add(variant)
5002 # Check for nested structure
5003 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5004 if res:
5005 return (res[0], res[1] + value_range[0] + 1,
5006 res[2] + value_range[0] + 1)
5007 missing = required - defined_variants
5008 if missing:
5009 return ('Required variants missing: %s' % ', '.join(missing), 0,
5010 len(text))
5011 signatures.append((level, variable, kind, defined_variants))
5012
5013
5014 def _ParseIcuVariants(text, offset=0):
5015 """Parse variants part of ICU complex message.
5016
5017 Builds a tuple of variant names and values, as well as
5018 their offsets in the input string.
5019
5020 Args:
5021 text: a string to parse
5022 offset: additional offset to add to positions in the text to get correct
5023 position in the complete ICU string.
5024
5025 Returns:
5026 List of tuples, each tuple consist of four fields: variant name,
5027 variant name span (tuple of two integers), variant value, value
5028 span (tuple of two integers).
5029 """
5030 depth, start, end = 0, -1, -1
5031 variants = []
5032 key = None
5033 for idx, char in enumerate(text):
5034 if char == '{':
5035 if not depth:
5036 start = idx
5037 chunk = text[end + 1:start]
5038 key = chunk.strip()
5039 pos = offset + end + 1 + chunk.find(key)
5040 span = (pos, pos + len(key))
5041 depth += 1
5042 elif char == '}':
5043 if not depth:
5044 return variants, depth, offset + idx
5045 depth -= 1
5046 if not depth:
5047 end = idx
5048 variants.append((key, span, text[start:end + 1], (offset + start,
5049 offset + end + 1)))
5050 return variants, depth, offset + end + 1
5051
meacer8c0d3832019-12-26 21:46:165052 try:
5053 old_sys_path = sys.path
5054 sys.path = sys.path + [input_api.os_path.join(
5055 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5056 from helper import grd_helper
5057 finally:
5058 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145059
5060 for f in affected_grds:
5061 file_path = f.LocalPath()
5062 old_id_to_msg_map = {}
5063 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385064 # Note that this code doesn't check if the file has been deleted. This is
5065 # OK because it only uses the old and new file contents and doesn't load
5066 # the file via its path.
5067 # It's also possible that a file's content refers to a renamed or deleted
5068 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5069 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5070 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145071 if file_path.endswith('.grdp'):
5072 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585073 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395074 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145075 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585076 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395077 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145078 else:
meacerff8a9b62019-12-10 19:43:585079 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145080 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585081 old_id_to_msg_map = grd_helper.GetGrdMessages(
5082 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145083 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585084 new_id_to_msg_map = grd_helper.GetGrdMessages(
5085 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145086
Rainhard Findlingd8d04372020-08-13 13:30:095087 grd_name, ext = input_api.os_path.splitext(
5088 input_api.os_path.basename(file_path))
5089 screenshots_dir = input_api.os_path.join(
5090 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5091
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145092 # Compute added, removed and modified message IDs.
5093 old_ids = set(old_id_to_msg_map)
5094 new_ids = set(new_id_to_msg_map)
5095 added_ids = new_ids - old_ids
5096 removed_ids = old_ids - new_ids
5097 modified_ids = set([])
5098 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355099 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095100 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5101 # The message content itself changed. Require an updated screenshot.
5102 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355103 elif old_id_to_msg_map[key].attrs['meaning'] != \
5104 new_id_to_msg_map[key].attrs['meaning']:
5105 # The message meaning changed. Ensure there is a screenshot for it.
5106 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5107 if sha1_path not in new_or_added_paths and not \
5108 input_api.os_path.exists(sha1_path):
5109 # There is neither a previous screenshot nor is a new one added now.
5110 # Require a screenshot.
5111 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145112
Rainhard Findlingfc31844c52020-05-15 09:58:265113 if run_screenshot_check:
5114 # Check the screenshot directory for .png files. Warn if there is any.
5115 for png_path in affected_png_paths:
5116 if png_path.startswith(screenshots_dir):
5117 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145118
Rainhard Findlingfc31844c52020-05-15 09:58:265119 for added_id in added_ids:
5120 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145121
Rainhard Findlingfc31844c52020-05-15 09:58:265122 for modified_id in modified_ids:
5123 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145124
Rainhard Findlingfc31844c52020-05-15 09:58:265125 for removed_id in removed_ids:
5126 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5127
5128 # Check new and changed strings for ICU syntax errors.
5129 for key in added_ids.union(modified_ids):
5130 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5131 err = _ValidateIcuSyntax(msg, 0, [])
5132 if err is not None:
5133 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145134
5135 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265136 if run_screenshot_check:
5137 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005138 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265139 'Do not include actual screenshots in the changelist. Run '
5140 'tools/translate/upload_screenshots.py to upload them instead:',
5141 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145142
Rainhard Findlingfc31844c52020-05-15 09:58:265143 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005144 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265145 'You are adding or modifying UI strings.\n'
5146 'To ensure the best translations, take screenshots of the relevant UI '
5147 '(https://g.co/chrome/translation) and add these files to your '
5148 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145149
Rainhard Findlingfc31844c52020-05-15 09:58:265150 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005151 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265152 'You removed strings associated with these files. Remove:',
5153 sorted(unnecessary_sha1_files)))
5154 else:
5155 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5156 'screenshots check.'))
5157
5158 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075159 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265160 'ICU syntax errors were found in the following strings (problems or '
5161 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145162
5163 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125164
5165
Saagar Sanghavifceeaae2020-08-12 16:40:365166def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125167 repo_root=None,
5168 translation_expectations_path=None,
5169 grd_files=None):
5170 import sys
5171 affected_grds = [f for f in input_api.AffectedFiles()
5172 if (f.LocalPath().endswith('.grd') or
5173 f.LocalPath().endswith('.grdp'))]
5174 if not affected_grds:
5175 return []
5176
5177 try:
5178 old_sys_path = sys.path
5179 sys.path = sys.path + [
5180 input_api.os_path.join(
5181 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5182 from helper import git_helper
5183 from helper import translation_helper
5184 finally:
5185 sys.path = old_sys_path
5186
5187 # Check that translation expectations can be parsed and we can get a list of
5188 # translatable grd files. |repo_root| and |translation_expectations_path| are
5189 # only passed by tests.
5190 if not repo_root:
5191 repo_root = input_api.PresubmitLocalPath()
5192 if not translation_expectations_path:
5193 translation_expectations_path = input_api.os_path.join(
5194 repo_root, 'tools', 'gritsettings',
5195 'translation_expectations.pyl')
5196 if not grd_files:
5197 grd_files = git_helper.list_grds_in_repository(repo_root)
5198
5199 try:
5200 translation_helper.get_translatable_grds(repo_root, grd_files,
5201 translation_expectations_path)
5202 except Exception as e:
5203 return [output_api.PresubmitNotifyResult(
5204 'Failed to get a list of translatable grd files. This happens when:\n'
5205 ' - One of the modified grd or grdp files cannot be parsed or\n'
5206 ' - %s is not updated.\n'
5207 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5208 return []
Ken Rockotc31f4832020-05-29 18:58:515209
5210
Saagar Sanghavifceeaae2020-08-12 16:40:365211def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515212 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095213 changed_mojoms = input_api.AffectedFiles(
5214 include_deletes=True,
5215 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515216 delta = []
5217 for mojom in changed_mojoms:
5218 old_contents = ''.join(mojom.OldContents()) or None
5219 new_contents = ''.join(mojom.NewContents()) or None
5220 delta.append({
5221 'filename': mojom.LocalPath(),
5222 'old': '\n'.join(mojom.OldContents()) or None,
5223 'new': '\n'.join(mojom.NewContents()) or None,
5224 })
5225
5226 process = input_api.subprocess.Popen(
5227 [input_api.python_executable,
5228 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5229 'public', 'tools', 'mojom',
5230 'check_stable_mojom_compatibility.py'),
5231 '--src-root', input_api.PresubmitLocalPath()],
5232 stdin=input_api.subprocess.PIPE,
5233 stdout=input_api.subprocess.PIPE,
5234 stderr=input_api.subprocess.PIPE,
5235 universal_newlines=True)
5236 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5237 if process.returncode:
5238 return [output_api.PresubmitError(
5239 'One or more [Stable] mojom definitions appears to have been changed '
5240 'in a way that is not backward-compatible.',
5241 long_text=error)]
5242 return []