blob: 9f54921197ad1d668921494d70ece9455ebda420 [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/',
Alexander Cooper6b447b22020-07-22 00:47:18366 '^chrome/browser/supervised_user/',
367 '^chrome/browser/sync_file_system/',
368 '^chrome/browser/sync/',
Alexander Cooper6b447b22020-07-22 00:47:18369 '^chrome/browser/thumbnail/cc/',
Alexander Cooper6b447b22020-07-22 00:47:18370 '^chrome/browser/translate/',
371 '^chrome/browser/ui/',
Alexander Cooper6b447b22020-07-22 00:47:18372 '^chrome/browser/web_applications/',
373 '^chrome/browser/win/',
danakj7a2b7082019-05-21 21:13:51374 '^chrome/services/',
Alex Turner1dc2e1022020-10-22 16:31:54375 '^chrome/test/chromedriver/server/http_handler.cc',
danakj7a2b7082019-05-21 21:13:51376 '^chrome/tools/',
danakj7a2b7082019-05-21 21:13:51377 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51378 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51379 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51380 '^components/component_updater/',
381 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51382 '^components/drive/',
danakj7a2b7082019-05-21 21:13:51383 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51384 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51385 '^components/search_engines/',
danakj7a2b7082019-05-21 21:13:51386 '^components/security_interstitials/',
danakj7a2b7082019-05-21 21:13:51387 '^components/signin/',
danakj7a2b7082019-05-21 21:13:51388 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51389 '^components/ukm/',
danakj7a2b7082019-05-21 21:13:51390 '^components/webcrypto/',
Alan Cutter04a00642020-03-02 01:45:20391 '^extensions/browser/',
392 '^extensions/renderer/',
Alexander Cooper922f2112020-07-22 16:27:43393 '^google_apis/drive/',
danakj7a2b7082019-05-21 21:13:51394 '^ios/chrome/',
395 '^ios/components/',
396 '^ios/net/',
397 '^ios/web/',
398 '^ios/web_view/',
399 '^ipc/',
danakjc8576092019-11-26 19:01:36400 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51401 '^media/cast/',
402 '^media/cdm/',
danakj7a2b7082019-05-21 21:13:51403 '^media/filters/',
danakj7a2b7082019-05-21 21:13:51404 '^media/gpu/',
405 '^media/mojo/',
Steve Kobes334b6ed2020-07-09 07:26:31406 '^net/http/',
407 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51408 '^ppapi/proxy/',
danakj7a2b7082019-05-21 21:13:51409 '^services/',
danakj7a2b7082019-05-21 21:13:51410 '^tools/clang/base_bind_rewriters/', # Intentional.
411 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51412))
[email protected]127f18ec2012-06-16 05:05:59413
Daniel Bratell609102be2019-03-27 20:53:21414# Format: Sequence of tuples containing:
415# * String pattern or, if starting with a slash, a regular expression.
416# * Sequence of strings to show when the pattern matches.
417# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
418# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59419_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20420 (
Dave Tapuska98199b612019-07-10 13:30:44421 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53422 (
423 'New code should not use NULL. Use nullptr instead.',
424 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20425 False,
thomasandersone7caaa9b2017-03-29 19:22:53426 (),
427 ),
Peter Kasting94a56c42019-10-25 21:54:04428 (
429 r'/\busing namespace ',
430 (
431 'Using directives ("using namespace x") are banned by the Google Style',
432 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
433 'Explicitly qualify symbols or use using declarations ("using x::foo").',
434 ),
435 True,
436 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
437 ),
Antonio Gomes07300d02019-03-13 20:59:57438 # Make sure that gtest's FRIEND_TEST() macro is not used; the
439 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
440 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53441 (
[email protected]23e6cbc2012-06-16 18:51:20442 'FRIEND_TEST(',
443 (
[email protected]e3c945502012-06-26 20:01:49444 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20445 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
446 ),
447 False,
[email protected]7345da02012-11-27 14:31:49448 (),
[email protected]23e6cbc2012-06-16 18:51:20449 ),
450 (
tomhudsone2c14d552016-05-26 17:07:46451 'setMatrixClip',
452 (
453 'Overriding setMatrixClip() is prohibited; ',
454 'the base function is deprecated. ',
455 ),
456 True,
457 (),
458 ),
459 (
[email protected]52657f62013-05-20 05:30:31460 'SkRefPtr',
461 (
462 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22463 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31464 ),
465 True,
466 (),
467 ),
468 (
469 'SkAutoRef',
470 (
471 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22472 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31473 ),
474 True,
475 (),
476 ),
477 (
478 'SkAutoTUnref',
479 (
480 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22481 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31482 ),
483 True,
484 (),
485 ),
486 (
487 'SkAutoUnref',
488 (
489 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
490 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22491 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31492 ),
493 True,
494 (),
495 ),
[email protected]d89eec82013-12-03 14:10:59496 (
497 r'/HANDLE_EINTR\(.*close',
498 (
499 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
500 'descriptor will be closed, and it is incorrect to retry the close.',
501 'Either call close directly and ignore its return value, or wrap close',
502 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
503 ),
504 True,
505 (),
506 ),
507 (
508 r'/IGNORE_EINTR\((?!.*close)',
509 (
510 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
511 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
512 ),
513 True,
514 (
515 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04516 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
517 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59518 ),
519 ),
[email protected]ec5b3f02014-04-04 18:43:43520 (
521 r'/v8::Extension\(',
522 (
523 'Do not introduce new v8::Extensions into the code base, use',
524 'gin::Wrappable instead. See http://crbug.com/334679',
525 ),
526 True,
[email protected]f55c90ee62014-04-12 00:50:03527 (
Egor Paskoce145c42018-09-28 19:31:04528 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03529 ),
[email protected]ec5b3f02014-04-04 18:43:43530 ),
skyostilf9469f72015-04-20 10:38:52531 (
jame2d1a952016-04-02 00:27:10532 '#pragma comment(lib,',
533 (
534 'Specify libraries to link with in build files and not in the source.',
535 ),
536 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41537 (
tzik3f295992018-12-04 20:32:23538 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04539 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41540 ),
jame2d1a952016-04-02 00:27:10541 ),
fdorayc4ac18d2017-05-01 21:39:59542 (
Gabriel Charette7cc6c432018-04-25 20:52:02543 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59544 (
545 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
546 ),
547 False,
548 (),
549 ),
550 (
Gabriel Charette7cc6c432018-04-25 20:52:02551 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59552 (
553 'Consider using THREAD_CHECKER macros instead of the class directly.',
554 ),
555 False,
556 (),
557 ),
dbeamb6f4fde2017-06-15 04:03:06558 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06559 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
560 (
561 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
562 'deprecated (http://crbug.com/634507). Please avoid converting away',
563 'from the Time types in Chromium code, especially if any math is',
564 'being done on time values. For interfacing with platform/library',
565 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
566 'type converter methods instead. For faking TimeXXX values (for unit',
567 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
568 'other use cases, please contact base/time/OWNERS.',
569 ),
570 False,
571 (),
572 ),
573 (
dbeamb6f4fde2017-06-15 04:03:06574 'CallJavascriptFunctionUnsafe',
575 (
576 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
577 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
578 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
579 ),
580 False,
581 (
Egor Paskoce145c42018-09-28 19:31:04582 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
583 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
584 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06585 ),
586 ),
dskiba1474c2bfd62017-07-20 02:19:24587 (
588 'leveldb::DB::Open',
589 (
590 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
591 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
592 "Chrome's tracing, making their memory usage visible.",
593 ),
594 True,
595 (
596 r'^third_party/leveldatabase/.*\.(cc|h)$',
597 ),
Gabriel Charette0592c3a2017-07-26 12:02:04598 ),
599 (
Chris Mumfordc38afb62017-10-09 17:55:08600 'leveldb::NewMemEnv',
601 (
602 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58603 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
604 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08605 ),
606 True,
607 (
608 r'^third_party/leveldatabase/.*\.(cc|h)$',
609 ),
610 ),
611 (
Gabriel Charetted9839bc2017-07-29 14:17:47612 'RunLoop::QuitCurrent',
613 (
Robert Liao64b7ab22017-08-04 23:03:43614 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
615 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47616 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41617 False,
Gabriel Charetted9839bc2017-07-29 14:17:47618 (),
Gabriel Charettea44975052017-08-21 23:14:04619 ),
620 (
621 'base::ScopedMockTimeMessageLoopTaskRunner',
622 (
Gabriel Charette87cc1af2018-04-25 20:52:51623 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11624 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51625 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
626 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
627 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04628 ),
Gabriel Charette87cc1af2018-04-25 20:52:51629 False,
Gabriel Charettea44975052017-08-21 23:14:04630 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57631 ),
632 (
Dave Tapuska98199b612019-07-10 13:30:44633 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57634 (
635 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02636 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57637 ),
638 True,
639 (),
Francois Doray43670e32017-09-27 12:40:38640 ),
641 (
Peter Kasting991618a62019-06-17 22:00:09642 r'/\bstd::stoi\b',
643 (
644 'std::stoi uses exceptions to communicate results. ',
645 'Use base::StringToInt() instead.',
646 ),
647 True,
648 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
649 ),
650 (
651 r'/\bstd::stol\b',
652 (
653 'std::stol uses exceptions to communicate results. ',
654 'Use base::StringToInt() instead.',
655 ),
656 True,
657 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
658 ),
659 (
660 r'/\bstd::stoul\b',
661 (
662 'std::stoul uses exceptions to communicate results. ',
663 'Use base::StringToUint() instead.',
664 ),
665 True,
666 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
667 ),
668 (
669 r'/\bstd::stoll\b',
670 (
671 'std::stoll uses exceptions to communicate results. ',
672 'Use base::StringToInt64() instead.',
673 ),
674 True,
675 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
676 ),
677 (
678 r'/\bstd::stoull\b',
679 (
680 'std::stoull uses exceptions to communicate results. ',
681 'Use base::StringToUint64() instead.',
682 ),
683 True,
684 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
685 ),
686 (
687 r'/\bstd::stof\b',
688 (
689 'std::stof uses exceptions to communicate results. ',
690 'For locale-independent values, e.g. reading numbers from disk',
691 'profiles, use base::StringToDouble().',
692 'For user-visible values, parse using ICU.',
693 ),
694 True,
695 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
696 ),
697 (
698 r'/\bstd::stod\b',
699 (
700 'std::stod uses exceptions to communicate results. ',
701 'For locale-independent values, e.g. reading numbers from disk',
702 'profiles, use base::StringToDouble().',
703 'For user-visible values, parse using ICU.',
704 ),
705 True,
706 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
707 ),
708 (
709 r'/\bstd::stold\b',
710 (
711 'std::stold uses exceptions to communicate results. ',
712 'For locale-independent values, e.g. reading numbers from disk',
713 'profiles, use base::StringToDouble().',
714 'For user-visible values, parse using ICU.',
715 ),
716 True,
717 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
718 ),
719 (
Daniel Bratell69334cc2019-03-26 11:07:45720 r'/\bstd::to_string\b',
721 (
722 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09723 'For locale-independent strings, e.g. writing numbers to disk',
724 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45725 'For user-visible strings, use base::FormatNumber() and',
726 'the related functions in base/i18n/number_formatting.h.',
727 ),
Peter Kasting991618a62019-06-17 22:00:09728 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21729 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45730 ),
731 (
732 r'/\bstd::shared_ptr\b',
733 (
734 'std::shared_ptr should not be used. Use scoped_refptr instead.',
735 ),
736 True,
Alex Chau9eb03cdd52020-07-13 21:04:57737 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
738 'array_buffer_contents\.(cc|h)',
739 # Needed for interop with third-party library
740 'chrome/services/sharing/nearby/',
741 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21742 ),
743 (
Peter Kasting991618a62019-06-17 22:00:09744 r'/\bstd::weak_ptr\b',
745 (
746 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
747 ),
748 True,
749 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
750 ),
751 (
Daniel Bratell609102be2019-03-27 20:53:21752 r'/\blong long\b',
753 (
754 'long long is banned. Use stdint.h if you need a 64 bit number.',
755 ),
756 False, # Only a warning since it is already used.
757 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
758 ),
759 (
760 r'/\bstd::bind\b',
761 (
762 'std::bind is banned because of lifetime risks.',
763 'Use base::BindOnce or base::BindRepeating instead.',
764 ),
765 True,
766 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
767 ),
768 (
769 r'/\b#include <chrono>\b',
770 (
771 '<chrono> overlaps with Time APIs in base. Keep using',
772 'base classes.',
773 ),
774 True,
775 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
776 ),
777 (
778 r'/\b#include <exception>\b',
779 (
780 'Exceptions are banned and disabled in Chromium.',
781 ),
782 True,
783 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
784 ),
785 (
786 r'/\bstd::function\b',
787 (
788 'std::function is banned. Instead use base::Callback which directly',
789 'supports Chromium\'s weak pointers, ref counting and more.',
790 ),
Peter Kasting991618a62019-06-17 22:00:09791 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21792 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
793 ),
794 (
795 r'/\b#include <random>\b',
796 (
797 'Do not use any random number engines from <random>. Instead',
798 'use base::RandomBitGenerator.',
799 ),
800 True,
801 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
802 ),
803 (
Tom Andersona95e12042020-09-09 23:08:00804 r'/\b#include <X11/',
805 (
806 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
807 ),
808 True,
809 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
810 ),
811 (
Daniel Bratell609102be2019-03-27 20:53:21812 r'/\bstd::ratio\b',
813 (
814 'std::ratio is banned by the Google Style Guide.',
815 ),
816 True,
817 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45818 ),
819 (
Francois Doray43670e32017-09-27 12:40:38820 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
821 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
822 (
823 'Use the new API in base/threading/thread_restrictions.h.',
824 ),
Gabriel Charette04b138f2018-08-06 00:03:22825 False,
Francois Doray43670e32017-09-27 12:40:38826 (),
827 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38828 (
danakj7a2b7082019-05-21 21:13:51829 r'/\bbase::Bind\(',
830 (
831 'Please use base::Bind{Once,Repeating} instead',
832 'of base::Bind. (crbug.com/714018)',
833 ),
834 False,
Erik Staaba737d7602019-11-25 18:41:07835 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51836 ),
837 (
838 r'/\bbase::Callback[<:]',
839 (
840 'Please use base::{Once,Repeating}Callback instead',
841 'of base::Callback. (crbug.com/714018)',
842 ),
843 False,
Erik Staaba737d7602019-11-25 18:41:07844 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51845 ),
846 (
847 r'/\bbase::Closure\b',
848 (
849 'Please use base::{Once,Repeating}Closure instead',
850 'of base::Closure. (crbug.com/714018)',
851 ),
852 False,
Erik Staaba737d7602019-11-25 18:41:07853 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51854 ),
855 (
Michael Giuffrida7f93d6922019-04-19 14:39:58856 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19857 (
858 'RunMessageLoop is deprecated, use RunLoop instead.',
859 ),
860 False,
861 (),
862 ),
863 (
Dave Tapuska98199b612019-07-10 13:30:44864 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19865 (
866 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
867 ),
868 False,
869 (),
870 ),
871 (
Dave Tapuska98199b612019-07-10 13:30:44872 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19873 (
874 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
875 "if you're convinced you need this.",
876 ),
877 False,
878 (),
879 ),
880 (
Dave Tapuska98199b612019-07-10 13:30:44881 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19882 (
883 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04884 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19885 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
886 'async events instead of flushing threads.',
887 ),
888 False,
889 (),
890 ),
891 (
892 r'MessageLoopRunner',
893 (
894 'MessageLoopRunner is deprecated, use RunLoop instead.',
895 ),
896 False,
897 (),
898 ),
899 (
Dave Tapuska98199b612019-07-10 13:30:44900 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19901 (
902 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
903 "gab@ if you found a use case where this is the only solution.",
904 ),
905 False,
906 (),
907 ),
908 (
Victor Costane48a2e82019-03-15 22:02:34909 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16910 (
Victor Costane48a2e82019-03-15 22:02:34911 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16912 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
913 ),
914 True,
915 (
916 r'^sql/initialization\.(cc|h)$',
917 r'^third_party/sqlite/.*\.(c|cc|h)$',
918 ),
919 ),
Matt Menke7f520a82018-03-28 21:38:37920 (
Dave Tapuska98199b612019-07-10 13:30:44921 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47922 (
923 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
924 'base::RandomShuffle instead.'
925 ),
926 True,
927 (),
928 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24929 (
930 'ios/web/public/test/http_server',
931 (
932 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
933 ),
934 False,
935 (),
936 ),
Robert Liao764c9492019-01-24 18:46:28937 (
938 'GetAddressOf',
939 (
940 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53941 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11942 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53943 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28944 ),
945 True,
946 (),
947 ),
Antonio Gomes07300d02019-03-13 20:59:57948 (
949 'DEFINE_TYPE_CASTS',
950 (
951 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
952 '//third_party/blink/renderer/platform/casting.h.'
953 ),
954 True,
955 (
956 r'^third_party/blink/renderer/.*\.(cc|h)$',
957 ),
958 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38959 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45960 r'/\bIsHTML.+Element\(\b',
961 (
962 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
963 ' helpers IsA<HTMLXXXXElement> from ',
964 '//third_party/blink/renderer/platform/casting.h.'
965 ),
966 False,
967 (
968 r'^third_party/blink/renderer/.*\.(cc|h)$',
969 ),
970 ),
971 (
972 r'/\bToHTML.+Element(|OrNull)\(\b',
973 (
974 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
975 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
976 'and DynamicTo<HTMLXXXXElement> from ',
977 '//third_party/blink/renderer/platform/casting.h.'
978 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
979 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
980 ),
981 False,
982 (
983 r'^third_party/blink/renderer/.*\.(cc|h)$',
984 ),
985 ),
986 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37987 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38988 (
989 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
990 ),
991 True,
992 (),
993 ),
Ben Lewisa9514602019-04-29 17:53:05994 (
995 'SHFileOperation',
996 (
997 'SHFileOperation was deprecated in Windows Vista, and there are less ',
998 'complex functions to achieve the same goals. Use IFileOperation for ',
999 'any esoteric actions instead.'
1000 ),
1001 True,
1002 (),
1003 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181004 (
Cliff Smolinsky81951642019-04-30 21:39:511005 'StringFromGUID2',
1006 (
1007 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241008 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511009 ),
1010 True,
1011 (
1012 r'/base/win/win_util_unittest.cc'
1013 ),
1014 ),
1015 (
1016 'StringFromCLSID',
1017 (
1018 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241019 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511020 ),
1021 True,
1022 (
1023 r'/base/win/win_util_unittest.cc'
1024 ),
1025 ),
1026 (
Avi Drissman7382afa02019-04-29 23:27:131027 'kCFAllocatorNull',
1028 (
1029 'The use of kCFAllocatorNull with the NoCopy creation of ',
1030 'CoreFoundation types is prohibited.',
1031 ),
1032 True,
1033 (),
1034 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291035 (
1036 'mojo::ConvertTo',
1037 (
1038 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1039 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1040 'StringTraits if you would like to convert between custom types and',
1041 'the wire format of mojom types.'
1042 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221043 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291044 (
Wezf89dec092019-09-11 19:38:331045 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1046 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291047 r'^third_party/blink/.*\.(cc|h)$',
1048 r'^content/renderer/.*\.(cc|h)$',
1049 ),
1050 ),
Robert Liao1d78df52019-11-11 20:02:011051 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161052 'GetInterfaceProvider',
1053 (
1054 'InterfaceProvider is deprecated.',
1055 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1056 'or Platform::GetBrowserInterfaceBroker.'
1057 ),
1058 False,
1059 (),
1060 ),
1061 (
Robert Liao1d78df52019-11-11 20:02:011062 'CComPtr',
1063 (
1064 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1065 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1066 'details.'
1067 ),
1068 False,
1069 (),
1070 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201071 (
1072 r'/\b(IFACE|STD)METHOD_?\(',
1073 (
1074 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1075 'Instead, always use IFACEMETHODIMP in the declaration.'
1076 ),
1077 False,
1078 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1079 ),
Allen Bauer53b43fb12020-03-12 17:21:471080 (
1081 'set_owned_by_client',
1082 (
1083 'set_owned_by_client is deprecated.',
1084 'views::View already owns the child views by default. This introduces ',
1085 'a competing ownership model which makes the code difficult to reason ',
1086 'about. See http://crbug.com/1044687 for more details.'
1087 ),
1088 False,
1089 (),
1090 ),
Eric Secklerbe6f48d2020-05-06 18:09:121091 (
1092 r'/\bTRACE_EVENT_ASYNC_',
1093 (
1094 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1095 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1096 ),
1097 False,
1098 (
1099 r'^base/trace_event/.*',
1100 r'^base/tracing/.*',
1101 ),
1102 ),
[email protected]127f18ec2012-06-16 05:05:591103)
1104
Mario Sanchez Prada2472cab2019-09-18 10:58:311105# Format: Sequence of tuples containing:
1106# * String pattern or, if starting with a slash, a regular expression.
1107# * Sequence of strings to show when the pattern matches.
1108_DEPRECATED_MOJO_TYPES = (
1109 (
1110 r'/\bmojo::AssociatedBinding\b',
1111 (
1112 'mojo::AssociatedBinding<Interface> is deprecated.',
1113 'Use mojo::AssociatedReceiver<Interface> instead.',
1114 ),
1115 ),
1116 (
1117 r'/\bmojo::AssociatedBindingSet\b',
1118 (
1119 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1120 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1121 ),
1122 ),
1123 (
1124 r'/\bmojo::AssociatedInterfacePtr\b',
1125 (
1126 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1127 'Use mojo::AssociatedRemote<Interface> instead.',
1128 ),
1129 ),
1130 (
1131 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1132 (
1133 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1134 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1135 ),
1136 ),
1137 (
1138 r'/\bmojo::AssociatedInterfaceRequest\b',
1139 (
1140 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1141 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1142 ),
1143 ),
1144 (
1145 r'/\bmojo::Binding\b',
1146 (
1147 'mojo::Binding<Interface> is deprecated.',
1148 'Use mojo::Receiver<Interface> instead.',
1149 ),
1150 ),
1151 (
1152 r'/\bmojo::BindingSet\b',
1153 (
1154 'mojo::BindingSet<Interface> is deprecated.',
1155 'Use mojo::ReceiverSet<Interface> instead.',
1156 ),
1157 ),
1158 (
1159 r'/\bmojo::InterfacePtr\b',
1160 (
1161 'mojo::InterfacePtr<Interface> is deprecated.',
1162 'Use mojo::Remote<Interface> instead.',
1163 ),
1164 ),
1165 (
1166 r'/\bmojo::InterfacePtrInfo\b',
1167 (
1168 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1169 'Use mojo::PendingRemote<Interface> instead.',
1170 ),
1171 ),
1172 (
1173 r'/\bmojo::InterfaceRequest\b',
1174 (
1175 'mojo::InterfaceRequest<Interface> is deprecated.',
1176 'Use mojo::PendingReceiver<Interface> instead.',
1177 ),
1178 ),
1179 (
1180 r'/\bmojo::MakeRequest\b',
1181 (
1182 'mojo::MakeRequest is deprecated.',
1183 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1184 ),
1185 ),
1186 (
1187 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1188 (
1189 'mojo::MakeRequest is deprecated.',
1190 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181191 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311192 ),
1193 ),
1194 (
1195 r'/\bmojo::MakeStrongBinding\b',
1196 (
1197 'mojo::MakeStrongBinding is deprecated.',
1198 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1199 'mojo::MakeSelfOwnedReceiver() instead.',
1200 ),
1201 ),
1202 (
1203 r'/\bmojo::MakeStrongAssociatedBinding\b',
1204 (
1205 'mojo::MakeStrongAssociatedBinding is deprecated.',
1206 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1207 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1208 ),
1209 ),
1210 (
Gyuyoung Kim4952ba62020-07-07 07:33:441211 r'/\bmojo::StrongAssociatedBinding\b',
1212 (
1213 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1214 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1215 ),
1216 ),
1217 (
1218 r'/\bmojo::StrongBinding\b',
1219 (
1220 'mojo::StrongBinding<Interface> is deprecated.',
1221 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1222 ),
1223 ),
1224 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311225 r'/\bmojo::StrongAssociatedBindingSet\b',
1226 (
1227 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1228 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1229 ),
1230 ),
1231 (
1232 r'/\bmojo::StrongBindingSet\b',
1233 (
1234 'mojo::StrongBindingSet<Interface> is deprecated.',
1235 'Use mojo::UniqueReceiverSet<Interface> instead.',
1236 ),
1237 ),
1238)
wnwenbdc444e2016-05-25 13:44:151239
mlamouria82272622014-09-16 18:45:041240_IPC_ENUM_TRAITS_DEPRECATED = (
1241 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501242 'See http://www.chromium.org/Home/chromium-security/education/'
1243 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041244
Stephen Martinis97a394142018-06-07 23:06:051245_LONG_PATH_ERROR = (
1246 'Some files included in this CL have file names that are too long (> 200'
1247 ' characters). If committed, these files will cause issues on Windows. See'
1248 ' https://crbug.com/612667 for more details.'
1249)
1250
Shenghua Zhangbfaa38b82017-11-16 21:58:021251_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041252 r".*[\\/]BuildHooksAndroidImpl\.java",
1253 r".*[\\/]LicenseContentProvider\.java",
1254 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281255 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021256]
[email protected]127f18ec2012-06-16 05:05:591257
Mohamed Heikald048240a2019-11-12 16:57:371258# List of image extensions that are used as resources in chromium.
1259_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1260
Sean Kau46e29bc2017-08-28 16:31:161261# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401262_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041263 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401264 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041265 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1266 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041267 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431268 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161269]
1270
1271
[email protected]b00342e7f2013-03-26 16:21:541272_VALID_OS_MACROS = (
1273 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081274 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541275 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441276 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121277 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541278 'OS_BSD',
1279 'OS_CAT', # For testing.
1280 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041281 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541282 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371283 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541284 'OS_IOS',
1285 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441286 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541287 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211288 'OS_NACL_NONSFI',
1289 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121290 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541291 'OS_OPENBSD',
1292 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371293 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541294 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541295 'OS_WIN',
1296)
1297
1298
Andrew Grieveb773bad2020-06-05 18:00:381299# These are not checked on the public chromium-presubmit trybot.
1300# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041301# checkouts.
agrievef32bcc72016-04-04 14:57:401302_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381303 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381304]
1305
1306
1307_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041308 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361309 'base/android/jni_generator/jni_generator.pydeps',
1310 'base/android/jni_generator/jni_registration_generator.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041311 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361312 'build/android/gyp/aar.pydeps',
1313 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271314 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361315 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381316 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361317 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111318 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361319 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361320 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361321 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111322 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041323 'build/android/gyp/create_app_bundle_apks.pydeps',
1324 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361325 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121326 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221327 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001328 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361329 'build/android/gyp/desugar.pydeps',
1330 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421331 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041332 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361333 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361334 'build/android/gyp/filter_zip.pydeps',
1335 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361336 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361337 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581338 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361339 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141340 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261341 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011342 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041343 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361344 'build/android/gyp/lint.pydeps',
1345 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361346 'build/android/gyp/merge_manifest.pydeps',
1347 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221348 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361349 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461350 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241351 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361352 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461353 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561354 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361355 'build/android/incremental_install/generate_android_manifest.pydeps',
1356 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041357 'build/android/resource_sizes.pydeps',
1358 'build/android/test_runner.pydeps',
1359 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361360 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361361 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321362 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271363 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1364 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001365 'components/cronet/tools/generate_javadoc.pydeps',
1366 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381367 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001368 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381369 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041370 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181371 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041372 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421373 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1374 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131375 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191376 ('third_party/blink/renderer/bindings/scripts/'
1377 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061378 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221379 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401380]
1381
wnwenbdc444e2016-05-25 13:44:151382
agrievef32bcc72016-04-04 14:57:401383_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1384
1385
Eric Boren6fd2b932018-01-25 15:05:081386# Bypass the AUTHORS check for these accounts.
1387_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591388 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451389 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591390 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521391 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071392 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041393 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271394 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041395 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301396 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081397
1398
Daniel Bratell65b033262019-04-23 08:17:061399def _IsCPlusPlusFile(input_api, file_path):
1400 """Returns True if this file contains C++-like code (and not Python,
1401 Go, Java, MarkDown, ...)"""
1402
1403 ext = input_api.os_path.splitext(file_path)[1]
1404 # This list is compatible with CppChecker.IsCppFile but we should
1405 # consider adding ".c" to it. If we do that we can use this function
1406 # at more places in the code.
1407 return ext in (
1408 '.h',
1409 '.cc',
1410 '.cpp',
1411 '.m',
1412 '.mm',
1413 )
1414
1415def _IsCPlusPlusHeaderFile(input_api, file_path):
1416 return input_api.os_path.splitext(file_path)[1] == ".h"
1417
1418
1419def _IsJavaFile(input_api, file_path):
1420 return input_api.os_path.splitext(file_path)[1] == ".java"
1421
1422
1423def _IsProtoFile(input_api, file_path):
1424 return input_api.os_path.splitext(file_path)[1] == ".proto"
1425
Saagar Sanghavifceeaae2020-08-12 16:40:361426def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191427 """Attempts to prevent use of functions intended only for testing in
1428 non-testing code. For now this is just a best-effort implementation
1429 that ignores header files and may have some false positives. A
1430 better implementation would probably need a proper C++ parser.
1431 """
1432 # We only scan .cc files and the like, as the declaration of
1433 # for-testing functions in header files are hard to distinguish from
1434 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491435 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191436
jochenc0d4808c2015-07-27 09:25:421437 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191438 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091439 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131440 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191441 exclusion_pattern = input_api.re.compile(
1442 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1443 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131444 # Avoid a false positive in this case, where the method name, the ::, and
1445 # the closing { are all on different lines due to line wrapping.
1446 # HelperClassForTesting::
1447 # HelperClassForTesting(
1448 # args)
1449 # : member(0) {}
1450 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191451
1452 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441453 files_to_skip = (_EXCLUDED_PATHS +
1454 _TEST_CODE_EXCLUDED_PATHS +
1455 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191456 return input_api.FilterSourceFile(
1457 affected_file,
James Cook24a504192020-07-23 00:08:441458 files_to_check=file_inclusion_pattern,
1459 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191460
1461 problems = []
1462 for f in input_api.AffectedSourceFiles(FilterFile):
1463 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131464 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241465 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031466 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461467 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131468 not exclusion_pattern.search(line) and
1469 not allowlist_pattern.search(line) and
1470 not in_method_defn):
[email protected]55459852011-08-10 15:17:191471 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031472 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131473 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191474
1475 if problems:
[email protected]f7051d52013-04-02 18:31:421476 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031477 else:
1478 return []
[email protected]55459852011-08-10 15:17:191479
1480
Saagar Sanghavifceeaae2020-08-12 16:40:361481def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231482 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591483 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231484 """
1485 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1486 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1487 name_pattern = r'ForTest(s|ing)?'
1488 # Describes an occurrence of "ForTest*" inside a // comment.
1489 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501490 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551491 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231492 # Catch calls.
1493 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1494 # Ignore definitions. (Comments are ignored separately.)
1495 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1496
1497 problems = []
1498 sources = lambda x: input_api.FilterSourceFile(
1499 x,
James Cook24a504192020-07-23 00:08:441500 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1501 + input_api.DEFAULT_FILES_TO_SKIP),
1502 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231503 )
1504 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1505 local_path = f.LocalPath()
1506 is_inside_javadoc = False
1507 for line_number, line in f.ChangedContents():
1508 if is_inside_javadoc and javadoc_end_re.search(line):
1509 is_inside_javadoc = False
1510 if not is_inside_javadoc and javadoc_start_re.search(line):
1511 is_inside_javadoc = True
1512 if is_inside_javadoc:
1513 continue
1514 if (inclusion_re.search(line) and
1515 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501516 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231517 not exclusion_re.search(line)):
1518 problems.append(
1519 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1520
1521 if problems:
1522 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1523 else:
1524 return []
1525
1526
Saagar Sanghavifceeaae2020-08-12 16:40:361527def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541528 """Checks to make sure no .h files include <iostream>."""
1529 files = []
1530 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1531 input_api.re.MULTILINE)
1532 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1533 if not f.LocalPath().endswith('.h'):
1534 continue
1535 contents = input_api.ReadFile(f)
1536 if pattern.search(contents):
1537 files.append(f)
1538
1539 if len(files):
yolandyandaabc6d2016-04-18 18:29:391540 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061541 'Do not #include <iostream> in header files, since it inserts static '
1542 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541543 '#include <ostream>. See http://crbug.com/94794',
1544 files) ]
1545 return []
1546
Danil Chapovalov3518f362018-08-11 16:13:431547def _CheckNoStrCatRedefines(input_api, output_api):
1548 """Checks no windows headers with StrCat redefined are included directly."""
1549 files = []
1550 pattern_deny = input_api.re.compile(
1551 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1552 input_api.re.MULTILINE)
1553 pattern_allow = input_api.re.compile(
1554 r'^#include\s"base/win/windows_defines.inc"',
1555 input_api.re.MULTILINE)
1556 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1557 contents = input_api.ReadFile(f)
1558 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1559 files.append(f.LocalPath())
1560
1561 if len(files):
1562 return [output_api.PresubmitError(
1563 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1564 'directly since they pollute code with StrCat macro. Instead, '
1565 'include matching header from base/win. See http://crbug.com/856536',
1566 files) ]
1567 return []
1568
[email protected]10689ca2011-09-02 02:31:541569
Saagar Sanghavifceeaae2020-08-12 16:40:361570def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521571 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181572 problems = []
1573 for f in input_api.AffectedFiles():
1574 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1575 continue
1576
1577 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041578 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181579 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1580
1581 if not problems:
1582 return []
1583 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1584 '\n'.join(problems))]
1585
Saagar Sanghavifceeaae2020-08-12 16:40:361586def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341587 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1588
1589 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1590 instead of DISABLED_. To filter false positives, reports are only generated
1591 if a corresponding MAYBE_ line exists.
1592 """
1593 problems = []
1594
1595 # The following two patterns are looked for in tandem - is a test labeled
1596 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1597 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1598 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1599
1600 # This is for the case that a test is disabled on all platforms.
1601 full_disable_pattern = input_api.re.compile(
1602 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1603 input_api.re.MULTILINE)
1604
Katie Df13948e2018-09-25 07:33:441605 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341606 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1607 continue
1608
1609 # Search for MABYE_, DISABLE_ pairs.
1610 disable_lines = {} # Maps of test name to line number.
1611 maybe_lines = {}
1612 for line_num, line in f.ChangedContents():
1613 disable_match = disable_pattern.search(line)
1614 if disable_match:
1615 disable_lines[disable_match.group(1)] = line_num
1616 maybe_match = maybe_pattern.search(line)
1617 if maybe_match:
1618 maybe_lines[maybe_match.group(1)] = line_num
1619
1620 # Search for DISABLE_ occurrences within a TEST() macro.
1621 disable_tests = set(disable_lines.keys())
1622 maybe_tests = set(maybe_lines.keys())
1623 for test in disable_tests.intersection(maybe_tests):
1624 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1625
1626 contents = input_api.ReadFile(f)
1627 full_disable_match = full_disable_pattern.search(contents)
1628 if full_disable_match:
1629 problems.append(' %s' % f.LocalPath())
1630
1631 if not problems:
1632 return []
1633 return [
1634 output_api.PresubmitPromptWarning(
1635 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1636 '\n'.join(problems))
1637 ]
1638
[email protected]72df4e782012-06-21 16:28:181639
Saagar Sanghavifceeaae2020-08-12 16:40:361640def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571641 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521642 errors = []
Hans Wennborg944479f2020-06-25 21:39:251643 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521644 input_api.re.MULTILINE)
1645 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1646 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1647 continue
1648 for lnum, line in f.ChangedContents():
1649 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171650 errors.append(output_api.PresubmitError(
1651 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571652 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171653 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521654 return errors
1655
1656
Makoto Shimazu3ad422cd2019-05-08 02:35:141657def _FindHistogramNameInChunk(histogram_name, chunk):
1658 """Tries to find a histogram name or prefix in a line.
1659
1660 Returns the existence of the histogram name, or None if it needs more chunk
1661 to determine."""
mcasasb7440c282015-02-04 14:52:191662 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1663 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141664 if '<affected-histogram' in chunk:
1665 # If the tag is not completed, needs more chunk to get the name.
1666 if not '>' in chunk:
1667 return None
1668 if not 'name="' in chunk:
1669 return False
1670 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1671 # expect the only attribute is the name.
1672 histogram_prefix = chunk.split('"')[1]
1673 return histogram_prefix in histogram_name
1674 # Typically the whole histogram name should in the line.
1675 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191676
1677
Saagar Sanghavifceeaae2020-08-12 16:40:361678def CheckUmaHistogramChangesOnUpload(input_api, output_api):
mcasasb7440c282015-02-04 14:52:191679 """Check that UMA histogram names in touched lines can still be found in other
1680 lines of the patch or in histograms.xml. Note that this check would not catch
1681 the reverse: changes in histograms.xml not matched in the code itself."""
1682 touched_histograms = []
1683 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471684 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1685 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1686 name_pattern = r'"(.*?)"'
1687 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1688 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1689 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1690 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1691 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171692 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191693 for f in input_api.AffectedFiles():
1694 # If histograms.xml itself is modified, keep the modified lines for later.
1695 if f.LocalPath().endswith(('histograms.xml')):
1696 histograms_xml_modifications = f.ChangedContents()
1697 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471698 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1699 single_line_re = single_line_c_re
1700 split_line_prefix_re = split_line_c_prefix_re
1701 elif f.LocalPath().endswith(('java')):
1702 single_line_re = single_line_java_re
1703 split_line_prefix_re = split_line_java_prefix_re
1704 else:
mcasasb7440c282015-02-04 14:52:191705 continue
1706 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171707 if last_line_matched_prefix:
1708 suffix_found = split_line_suffix_re.search(line)
1709 if suffix_found :
1710 touched_histograms.append([suffix_found.group(1), f, line_num])
1711 last_line_matched_prefix = False
1712 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061713 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191714 if found:
1715 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171716 continue
1717 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191718
1719 # Search for the touched histogram names in the local modifications to
1720 # histograms.xml, and, if not found, on the base histograms.xml file.
1721 unmatched_histograms = []
1722 for histogram_info in touched_histograms:
1723 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141724 chunk = ''
mcasasb7440c282015-02-04 14:52:191725 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141726 chunk += line
1727 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1728 if histogram_name_found is None:
1729 continue
1730 chunk = ''
mcasasb7440c282015-02-04 14:52:191731 if histogram_name_found:
1732 break
1733 if not histogram_name_found:
1734 unmatched_histograms.append(histogram_info)
1735
eromanb90c82e7e32015-04-01 15:13:491736 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191737 problems = []
1738 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491739 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191740 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451741 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191742 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141743 chunk = ''
mcasasb7440c282015-02-04 14:52:191744 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141745 chunk += line
1746 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1747 chunk)
1748 if histogram_name_found is None:
1749 continue
1750 chunk = ''
mcasasb7440c282015-02-04 14:52:191751 if histogram_name_found:
1752 break
1753 if not histogram_name_found:
1754 problems.append(' [%s:%d] %s' %
1755 (f.LocalPath(), line_num, histogram_name))
1756
1757 if not problems:
1758 return []
1759 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1760 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491761 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191762
wnwenbdc444e2016-05-25 13:44:151763
Saagar Sanghavifceeaae2020-08-12 16:40:361764def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391765 """Check that FlakyTest annotation is our own instead of the android one"""
1766 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1767 files = []
1768 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1769 if f.LocalPath().endswith('Test.java'):
1770 if pattern.search(input_api.ReadFile(f)):
1771 files.append(f)
1772 if len(files):
1773 return [output_api.PresubmitError(
1774 'Use org.chromium.base.test.util.FlakyTest instead of '
1775 'android.test.FlakyTest',
1776 files)]
1777 return []
mcasasb7440c282015-02-04 14:52:191778
wnwenbdc444e2016-05-25 13:44:151779
Saagar Sanghavifceeaae2020-08-12 16:40:361780def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221781 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271782 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221783 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201784 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571785 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341786 '/win/' in f.LocalPath() or
1787 'chrome_elf' in f.LocalPath() or
1788 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201789 continue
[email protected]8ea5d4b2011-09-13 21:49:221790
[email protected]a11dbe9b2012-08-07 01:32:581791 allowWString = False
[email protected]b5c24292011-11-28 14:38:201792 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581793 if 'presubmit: allow wstring' in line:
1794 allowWString = True
1795 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271796 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581797 allowWString = False
1798 else:
1799 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221800
[email protected]55463aa62011-10-12 00:48:271801 if not problems:
1802 return []
1803 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581804 ' If you are calling a cross-platform API that accepts a wstring, '
1805 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271806 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221807
1808
Saagar Sanghavifceeaae2020-08-12 16:40:361809def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441810 """Make sure .DEPS.git is never modified manually."""
1811 if any(f.LocalPath().endswith('.DEPS.git') for f in
1812 input_api.AffectedFiles()):
1813 return [output_api.PresubmitError(
1814 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1815 'automated system based on what\'s in DEPS and your changes will be\n'
1816 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501817 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1818 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441819 'for more information')]
1820 return []
1821
1822
Saagar Sanghavifceeaae2020-08-12 16:40:361823def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471824 """Checks that DEPS file deps are from allowed_hosts."""
1825 # Run only if DEPS file has been modified to annoy fewer bystanders.
1826 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1827 return []
1828 # Outsource work to gclient verify
1829 try:
John Budorickf20c0042019-04-25 23:23:401830 gclient_path = input_api.os_path.join(
1831 input_api.PresubmitLocalPath(),
1832 'third_party', 'depot_tools', 'gclient.py')
1833 input_api.subprocess.check_output(
1834 [input_api.python_executable, gclient_path, 'verify'],
1835 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471836 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201837 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471838 return [output_api.PresubmitError(
1839 'DEPS file must have only git dependencies.',
1840 long_text=error.output)]
1841
1842
Mario Sanchez Prada2472cab2019-09-18 10:58:311843def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1844 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591845 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311846
1847 Returns an string composed of the name of the file, the line number where the
1848 match has been found and the additional text passed as |message| in case the
1849 target type name matches the text inside the line passed as parameter.
1850 """
Peng Huang9c5949a02020-06-11 19:20:541851 result = []
1852
1853 if line.endswith(" nocheck"):
1854 return result
1855
Mario Sanchez Prada2472cab2019-09-18 10:58:311856 matched = False
1857 if type_name[0:1] == '/':
1858 regex = type_name[1:]
1859 if input_api.re.search(regex, line):
1860 matched = True
1861 elif type_name in line:
1862 matched = True
1863
Mario Sanchez Prada2472cab2019-09-18 10:58:311864 if matched:
1865 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1866 for message_line in message:
1867 result.append(' %s' % message_line)
1868
1869 return result
1870
1871
Saagar Sanghavifceeaae2020-08-12 16:40:361872def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591873 """Make sure that banned functions are not used."""
1874 warnings = []
1875 errors = []
1876
James Cook24a504192020-07-23 00:08:441877 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151878 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441879 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151880 if input_api.re.match(item, local_path):
1881 return True
1882 return False
1883
Peter K. Lee6c03ccff2019-07-15 14:40:051884 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541885 local_path = affected_file.LocalPath()
1886 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1887 return False
1888 basename = input_api.os_path.basename(local_path)
1889 if 'ios' in basename.split('_'):
1890 return True
1891 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1892 if sep and 'ios' in local_path.split(sep):
1893 return True
1894 return False
1895
wnwenbdc444e2016-05-25 13:44:151896 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311897 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1898 func_name, message)
1899 if problems:
wnwenbdc444e2016-05-25 13:44:151900 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311901 errors.extend(problems)
1902 else:
1903 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151904
Eric Stevensona9a980972017-09-23 00:04:411905 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1906 for f in input_api.AffectedFiles(file_filter=file_filter):
1907 for line_num, line in f.ChangedContents():
1908 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1909 CheckForMatch(f, line_num, line, func_name, message, error)
1910
[email protected]127f18ec2012-06-16 05:05:591911 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1912 for f in input_api.AffectedFiles(file_filter=file_filter):
1913 for line_num, line in f.ChangedContents():
1914 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151915 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591916
Peter K. Lee6c03ccff2019-07-15 14:40:051917 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541918 for line_num, line in f.ChangedContents():
1919 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1920 CheckForMatch(f, line_num, line, func_name, message, error)
1921
Peter K. Lee6c03ccff2019-07-15 14:40:051922 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1923 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1924 for line_num, line in f.ChangedContents():
1925 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1926 CheckForMatch(f, line_num, line, func_name, message, error)
1927
[email protected]127f18ec2012-06-16 05:05:591928 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1929 for f in input_api.AffectedFiles(file_filter=file_filter):
1930 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491931 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441932 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491933 continue
wnwenbdc444e2016-05-25 13:44:151934 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591935
1936 result = []
1937 if (warnings):
1938 result.append(output_api.PresubmitPromptWarning(
1939 'Banned functions were used.\n' + '\n'.join(warnings)))
1940 if (errors):
1941 result.append(output_api.PresubmitError(
1942 'Banned functions were used.\n' + '\n'.join(errors)))
1943 return result
1944
1945
Michael Thiessen44457642020-02-06 00:24:151946def _CheckAndroidNoBannedImports(input_api, output_api):
1947 """Make sure that banned java imports are not used."""
1948 errors = []
1949
1950 def IsException(path, exceptions):
1951 for exception in exceptions:
1952 if (path.startswith(exception)):
1953 return True
1954 return False
1955
1956 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1957 for f in input_api.AffectedFiles(file_filter=file_filter):
1958 for line_num, line in f.ChangedContents():
1959 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1960 if IsException(f.LocalPath(), exceptions):
1961 continue;
1962 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1963 'import ' + import_name, message)
1964 if problems:
1965 errors.extend(problems)
1966 result = []
1967 if (errors):
1968 result.append(output_api.PresubmitError(
1969 'Banned imports were used.\n' + '\n'.join(errors)))
1970 return result
1971
1972
Saagar Sanghavifceeaae2020-08-12 16:40:361973def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311974 """Make sure that old Mojo types are not used."""
1975 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571976 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311977
Mario Sanchez Pradaaab91382019-12-19 08:57:091978 # For any path that is not an "ok" or an "error" path, a warning will be
1979 # raised if deprecated mojo types are found.
1980 ok_paths = ['components/arc']
1981 error_paths = ['third_party/blink', 'content']
1982
Mario Sanchez Prada2472cab2019-09-18 10:58:311983 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1984 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571985 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091986 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311987 continue
1988
1989 for line_num, line in f.ChangedContents():
1990 for func_name, message in _DEPRECATED_MOJO_TYPES:
1991 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1992 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571993
Mario Sanchez Prada2472cab2019-09-18 10:58:311994 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091995 # Raise errors inside |error_paths| and warnings everywhere else.
1996 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571997 errors.extend(problems)
1998 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311999 warnings.extend(problems)
2000
2001 result = []
2002 if (warnings):
2003 result.append(output_api.PresubmitPromptWarning(
2004 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:572005 if (errors):
2006 result.append(output_api.PresubmitError(
2007 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:312008 return result
2009
2010
Saagar Sanghavifceeaae2020-08-12 16:40:362011def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:062012 """Make sure that banned functions are not used."""
2013 files = []
2014 pattern = input_api.re.compile(r'^#pragma\s+once',
2015 input_api.re.MULTILINE)
2016 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2017 if not f.LocalPath().endswith('.h'):
2018 continue
2019 contents = input_api.ReadFile(f)
2020 if pattern.search(contents):
2021 files.append(f)
2022
2023 if files:
2024 return [output_api.PresubmitError(
2025 'Do not use #pragma once in header files.\n'
2026 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2027 files)]
2028 return []
2029
[email protected]127f18ec2012-06-16 05:05:592030
Saagar Sanghavifceeaae2020-08-12 16:40:362031def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:122032 """Checks to make sure we don't introduce use of foo ? true : false."""
2033 problems = []
2034 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2035 for f in input_api.AffectedFiles():
2036 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2037 continue
2038
2039 for line_num, line in f.ChangedContents():
2040 if pattern.match(line):
2041 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2042
2043 if not problems:
2044 return []
2045 return [output_api.PresubmitPromptWarning(
2046 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2047 '\n'.join(problems))]
2048
2049
Saagar Sanghavifceeaae2020-08-12 16:40:362050def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282051 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182052 change. Breaking - rules is an error, breaking ! rules is a
2053 warning.
2054 """
mohan.reddyf21db962014-10-16 12:26:472055 import sys
[email protected]55f9f382012-07-31 11:02:182056 # We need to wait until we have an input_api object and use this
2057 # roundabout construct to import checkdeps because this file is
2058 # eval-ed and thus doesn't have __file__.
2059 original_sys_path = sys.path
2060 try:
2061 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472062 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182063 import checkdeps
[email protected]55f9f382012-07-31 11:02:182064 from rules import Rule
2065 finally:
2066 # Restore sys.path to what it was before.
2067 sys.path = original_sys_path
2068
2069 added_includes = []
rhalavati08acd232017-04-03 07:23:282070 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242071 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182072 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062073 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502074 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082075 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062076 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502077 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082078 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062079 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502080 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082081 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182082
[email protected]26385172013-05-09 23:11:352083 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182084
2085 error_descriptions = []
2086 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282087 error_subjects = set()
2088 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362089
[email protected]55f9f382012-07-31 11:02:182090 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2091 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082092 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182093 description_with_path = '%s\n %s' % (path, rule_description)
2094 if rule_type == Rule.DISALLOW:
2095 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282096 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182097 else:
2098 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282099 warning_subjects.add("#includes")
2100
2101 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2102 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082103 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282104 description_with_path = '%s\n %s' % (path, rule_description)
2105 if rule_type == Rule.DISALLOW:
2106 error_descriptions.append(description_with_path)
2107 error_subjects.add("imports")
2108 else:
2109 warning_descriptions.append(description_with_path)
2110 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182111
Jinsuk Kim5a092672017-10-24 22:42:242112 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022113 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082114 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242115 description_with_path = '%s\n %s' % (path, rule_description)
2116 if rule_type == Rule.DISALLOW:
2117 error_descriptions.append(description_with_path)
2118 error_subjects.add("imports")
2119 else:
2120 warning_descriptions.append(description_with_path)
2121 warning_subjects.add("imports")
2122
[email protected]55f9f382012-07-31 11:02:182123 results = []
2124 if error_descriptions:
2125 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282126 'You added one or more %s that violate checkdeps rules.'
2127 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182128 error_descriptions))
2129 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422130 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282131 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182132 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282133 '%s? See relevant DEPS file(s) for details and contacts.' %
2134 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182135 warning_descriptions))
2136 return results
2137
2138
Saagar Sanghavifceeaae2020-08-12 16:40:362139def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222140 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152141 if input_api.platform == 'win32':
2142 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292143 checkperms_tool = input_api.os_path.join(
2144 input_api.PresubmitLocalPath(),
2145 'tools', 'checkperms', 'checkperms.py')
2146 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472147 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392148 with input_api.CreateTemporaryFile() as file_list:
2149 for f in input_api.AffectedFiles():
2150 # checkperms.py file/directory arguments must be relative to the
2151 # repository.
2152 file_list.write(f.LocalPath() + '\n')
2153 file_list.close()
2154 args += ['--file-list', file_list.name]
2155 try:
2156 input_api.subprocess.check_output(args)
2157 return []
2158 except input_api.subprocess.CalledProcessError as error:
2159 return [output_api.PresubmitError(
2160 'checkperms.py failed:',
2161 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222162
2163
Saagar Sanghavifceeaae2020-08-12 16:40:362164def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492165 """Makes sure we don't include ui/aura/window_property.h
2166 in header files.
2167 """
2168 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2169 errors = []
2170 for f in input_api.AffectedFiles():
2171 if not f.LocalPath().endswith('.h'):
2172 continue
2173 for line_num, line in f.ChangedContents():
2174 if pattern.match(line):
2175 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2176
2177 results = []
2178 if errors:
2179 results.append(output_api.PresubmitError(
2180 'Header files should not include ui/aura/window_property.h', errors))
2181 return results
2182
2183
[email protected]70ca77752012-11-20 03:45:032184def _CheckForVersionControlConflictsInFile(input_api, f):
2185 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2186 errors = []
2187 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162188 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232189 # First-level headers in markdown look a lot like version control
2190 # conflict markers. http://daringfireball.net/projects/markdown/basics
2191 continue
[email protected]70ca77752012-11-20 03:45:032192 if pattern.match(line):
2193 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2194 return errors
2195
2196
Saagar Sanghavifceeaae2020-08-12 16:40:362197def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032198 """Usually this is not intentional and will cause a compile failure."""
2199 errors = []
2200 for f in input_api.AffectedFiles():
2201 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2202
2203 results = []
2204 if errors:
2205 results.append(output_api.PresubmitError(
2206 'Version control conflict markers found, please resolve.', errors))
2207 return results
2208
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202209
Saagar Sanghavifceeaae2020-08-12 16:40:362210def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162211 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2212 errors = []
2213 for f in input_api.AffectedFiles():
2214 for line_num, line in f.ChangedContents():
2215 if pattern.search(line):
2216 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2217
2218 results = []
2219 if errors:
2220 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502221 'Found Google support URL addressed by answer number. Please replace '
2222 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162223 return results
2224
[email protected]70ca77752012-11-20 03:45:032225
Saagar Sanghavifceeaae2020-08-12 16:40:362226def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442227 def FilterFile(affected_file):
2228 """Filter function for use with input_api.AffectedSourceFiles,
2229 below. This filters out everything except non-test files from
2230 top-level directories that generally speaking should not hard-code
2231 service URLs (e.g. src/android_webview/, src/content/ and others).
2232 """
2233 return input_api.FilterSourceFile(
2234 affected_file,
James Cook24a504192020-07-23 00:08:442235 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2236 files_to_skip=(_EXCLUDED_PATHS +
2237 _TEST_CODE_EXCLUDED_PATHS +
2238 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442239
reillyi38965732015-11-16 18:27:332240 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2241 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462242 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2243 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442244 problems = [] # items are (filename, line_number, line)
2245 for f in input_api.AffectedSourceFiles(FilterFile):
2246 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462247 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442248 problems.append((f.LocalPath(), line_num, line))
2249
2250 if problems:
[email protected]f7051d52013-04-02 18:31:422251 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442252 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582253 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442254 [' %s:%d: %s' % (
2255 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032256 else:
2257 return []
[email protected]06e6d0ff2012-12-11 01:36:442258
2259
Saagar Sanghavifceeaae2020-08-12 16:40:362260def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292261 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2262 def FileFilter(affected_file):
2263 """Includes directories known to be Chrome OS only."""
2264 return input_api.FilterSourceFile(
2265 affected_file,
James Cook24a504192020-07-23 00:08:442266 files_to_check=('^ash/',
2267 '^chromeos/', # Top-level src/chromeos.
2268 '/chromeos/', # Any path component.
2269 '^components/arc',
2270 '^components/exo'),
2271 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292272
2273 prefs = []
2274 priority_prefs = []
2275 for f in input_api.AffectedFiles(file_filter=FileFilter):
2276 for line_num, line in f.ChangedContents():
2277 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2278 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2279 prefs.append(' %s' % line)
2280 if input_api.re.search(
2281 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2282 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2283 priority_prefs.append(' %s' % line)
2284
2285 results = []
2286 if (prefs):
2287 results.append(output_api.PresubmitPromptWarning(
2288 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2289 'by browser sync settings. If these prefs should be controlled by OS '
2290 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2291 if (priority_prefs):
2292 results.append(output_api.PresubmitPromptWarning(
2293 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2294 'controlled by browser sync settings. If these prefs should be '
2295 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2296 'instead.\n' + '\n'.join(prefs)))
2297 return results
2298
2299
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492300# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362301def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272302 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312303 The native_client_sdk directory is excluded because it has auto-generated PNG
2304 files for documentation.
[email protected]d2530012013-01-25 16:39:272305 """
[email protected]d2530012013-01-25 16:39:272306 errors = []
James Cook24a504192020-07-23 00:08:442307 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2308 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312309 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442310 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312311 for f in input_api.AffectedFiles(include_deletes=False,
2312 file_filter=file_filter):
2313 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272314
2315 results = []
2316 if errors:
2317 results.append(output_api.PresubmitError(
2318 'The name of PNG files should not have abbreviations. \n'
2319 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2320 'Contact [email protected] if you have questions.', errors))
2321 return results
2322
2323
Daniel Cheng4dcdb6b2017-04-13 08:30:172324def _ExtractAddRulesFromParsedDeps(parsed_deps):
2325 """Extract the rules that add dependencies from a parsed DEPS file.
2326
2327 Args:
2328 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2329 add_rules = set()
2330 add_rules.update([
2331 rule[1:] for rule in parsed_deps.get('include_rules', [])
2332 if rule.startswith('+') or rule.startswith('!')
2333 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502334 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172335 {}).iteritems():
2336 add_rules.update([
2337 rule[1:] for rule in rules
2338 if rule.startswith('+') or rule.startswith('!')
2339 ])
2340 return add_rules
2341
2342
2343def _ParseDeps(contents):
2344 """Simple helper for parsing DEPS files."""
2345 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172346 class _VarImpl:
2347
2348 def __init__(self, local_scope):
2349 self._local_scope = local_scope
2350
2351 def Lookup(self, var_name):
2352 """Implements the Var syntax."""
2353 try:
2354 return self._local_scope['vars'][var_name]
2355 except KeyError:
2356 raise Exception('Var is not defined: %s' % var_name)
2357
2358 local_scope = {}
2359 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172360 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592361 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172362 }
2363 exec contents in global_scope, local_scope
2364 return local_scope
2365
2366
2367def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592368 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412369 a set of DEPS entries that we should look up.
2370
2371 For a directory (rather than a specific filename) we fake a path to
2372 a specific filename by adding /DEPS. This is chosen as a file that
2373 will seldom or never be subject to per-file include_rules.
2374 """
[email protected]2b438d62013-11-14 17:54:142375 # We ignore deps entries on auto-generated directories.
2376 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082377
Daniel Cheng4dcdb6b2017-04-13 08:30:172378 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2379 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2380
2381 added_deps = new_deps.difference(old_deps)
2382
[email protected]2b438d62013-11-14 17:54:142383 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172384 for added_dep in added_deps:
2385 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2386 continue
2387 # Assume that a rule that ends in .h is a rule for a specific file.
2388 if added_dep.endswith('.h'):
2389 results.add(added_dep)
2390 else:
2391 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082392 return results
2393
2394
Saagar Sanghavifceeaae2020-08-12 16:40:362395def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552396 """When a dependency prefixed with + is added to a DEPS file, we
2397 want to make sure that the change is reviewed by an OWNER of the
2398 target file or directory, to avoid layering violations from being
2399 introduced. This check verifies that this happens.
2400 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172401 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242402
2403 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492404 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242405 for f in input_api.AffectedFiles(include_deletes=False,
2406 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552407 filename = input_api.os_path.basename(f.LocalPath())
2408 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172409 virtual_depended_on_files.update(_CalculateAddedDeps(
2410 input_api.os_path,
2411 '\n'.join(f.OldContents()),
2412 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552413
[email protected]e871964c2013-05-13 14:14:552414 if not virtual_depended_on_files:
2415 return []
2416
2417 if input_api.is_committing:
2418 if input_api.tbr:
2419 return [output_api.PresubmitNotifyResult(
2420 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272421 if input_api.dry_run:
2422 return [output_api.PresubmitNotifyResult(
2423 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552424 if not input_api.change.issue:
2425 return [output_api.PresubmitError(
2426 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402427 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552428 output = output_api.PresubmitError
2429 else:
2430 output = output_api.PresubmitNotifyResult
2431
2432 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502433 owner_email, reviewers = (
2434 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2435 input_api,
2436 owners_db.email_regexp,
2437 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552438
2439 owner_email = owner_email or input_api.change.author_email
2440
[email protected]de4f7d22013-05-23 14:27:462441 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512442 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462443 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552444 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2445 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412446
2447 # We strip the /DEPS part that was added by
2448 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2449 # directory.
2450 def StripDeps(path):
2451 start_deps = path.rfind('/DEPS')
2452 if start_deps != -1:
2453 return path[:start_deps]
2454 else:
2455 return path
2456 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552457 for path in missing_files]
2458
2459 if unapproved_dependencies:
2460 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152461 output('You need LGTM from owners of depends-on paths in DEPS that were '
2462 'modified in this CL:\n %s' %
2463 '\n '.join(sorted(unapproved_dependencies)))]
2464 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2465 output_list.append(output(
2466 'Suggested missing target path OWNERS:\n %s' %
2467 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552468 return output_list
2469
2470 return []
2471
2472
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492473# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362474def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492475 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442476 files_to_skip = (_EXCLUDED_PATHS +
2477 _TEST_CODE_EXCLUDED_PATHS +
2478 input_api.DEFAULT_FILES_TO_SKIP +
2479 (r"^base[\\/]logging\.h$",
2480 r"^base[\\/]logging\.cc$",
2481 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2482 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2483 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2484 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2485 r"startup_browser_creator\.cc$",
2486 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2487 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2488 r"diagnostics_writer\.cc$",
2489 r"^chrome[\\/]chrome_cleaner[\\/].*",
2490 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2491 r"dll_hash_main\.cc$",
2492 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2493 r"^chromecast[\\/]",
2494 r"^cloud_print[\\/]",
2495 r"^components[\\/]browser_watcher[\\/]"
2496 r"dump_stability_report_main_win.cc$",
2497 r"^components[\\/]media_control[\\/]renderer[\\/]"
2498 r"media_playback_options\.cc$",
2499 r"^components[\\/]zucchini[\\/].*",
2500 # TODO(peter): Remove exception. https://crbug.com/534537
2501 r"^content[\\/]browser[\\/]notifications[\\/]"
2502 r"notification_event_dispatcher_impl\.cc$",
2503 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2504 r"gl_helper_benchmark\.cc$",
2505 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2506 r"^courgette[\\/]courgette_tool\.cc$",
2507 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2508 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2509 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2510 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2511 r"^ipc[\\/]ipc_logging\.cc$",
2512 r"^native_client_sdk[\\/]",
2513 r"^remoting[\\/]base[\\/]logging\.h$",
2514 r"^remoting[\\/]host[\\/].*",
2515 r"^sandbox[\\/]linux[\\/].*",
2516 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2517 r"dump_file_system.cc$",
2518 r"^tools[\\/]",
2519 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2520 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2521 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2522 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2523 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402524 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442525 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402526
thomasanderson625d3932017-03-29 07:16:582527 log_info = set([])
2528 printf = set([])
[email protected]85218562013-11-22 07:41:402529
2530 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582531 for _, line in f.ChangedContents():
2532 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2533 log_info.add(f.LocalPath())
2534 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2535 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372536
thomasanderson625d3932017-03-29 07:16:582537 if input_api.re.search(r"\bprintf\(", line):
2538 printf.add(f.LocalPath())
2539 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2540 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402541
2542 if log_info:
2543 return [output_api.PresubmitError(
2544 'These files spam the console log with LOG(INFO):',
2545 items=log_info)]
2546 if printf:
2547 return [output_api.PresubmitError(
2548 'These files spam the console log with printf/fprintf:',
2549 items=printf)]
2550 return []
2551
2552
Saagar Sanghavifceeaae2020-08-12 16:40:362553def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162554 """These types are all expected to hold locks while in scope and
2555 so should never be anonymous (which causes them to be immediately
2556 destroyed)."""
2557 they_who_must_be_named = [
2558 'base::AutoLock',
2559 'base::AutoReset',
2560 'base::AutoUnlock',
2561 'SkAutoAlphaRestore',
2562 'SkAutoBitmapShaderInstall',
2563 'SkAutoBlitterChoose',
2564 'SkAutoBounderCommit',
2565 'SkAutoCallProc',
2566 'SkAutoCanvasRestore',
2567 'SkAutoCommentBlock',
2568 'SkAutoDescriptor',
2569 'SkAutoDisableDirectionCheck',
2570 'SkAutoDisableOvalCheck',
2571 'SkAutoFree',
2572 'SkAutoGlyphCache',
2573 'SkAutoHDC',
2574 'SkAutoLockColors',
2575 'SkAutoLockPixels',
2576 'SkAutoMalloc',
2577 'SkAutoMaskFreeImage',
2578 'SkAutoMutexAcquire',
2579 'SkAutoPathBoundsUpdate',
2580 'SkAutoPDFRelease',
2581 'SkAutoRasterClipValidate',
2582 'SkAutoRef',
2583 'SkAutoTime',
2584 'SkAutoTrace',
2585 'SkAutoUnref',
2586 ]
2587 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2588 # bad: base::AutoLock(lock.get());
2589 # not bad: base::AutoLock lock(lock.get());
2590 bad_pattern = input_api.re.compile(anonymous)
2591 # good: new base::AutoLock(lock.get())
2592 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2593 errors = []
2594
2595 for f in input_api.AffectedFiles():
2596 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2597 continue
2598 for linenum, line in f.ChangedContents():
2599 if bad_pattern.search(line) and not good_pattern.search(line):
2600 errors.append('%s:%d' % (f.LocalPath(), linenum))
2601
2602 if errors:
2603 return [output_api.PresubmitError(
2604 'These lines create anonymous variables that need to be named:',
2605 items=errors)]
2606 return []
2607
2608
Saagar Sanghavifceeaae2020-08-12 16:40:362609def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532610 # Returns whether |template_str| is of the form <T, U...> for some types T
2611 # and U. Assumes that |template_str| is already in the form <...>.
2612 def HasMoreThanOneArg(template_str):
2613 # Level of <...> nesting.
2614 nesting = 0
2615 for c in template_str:
2616 if c == '<':
2617 nesting += 1
2618 elif c == '>':
2619 nesting -= 1
2620 elif c == ',' and nesting == 1:
2621 return True
2622 return False
2623
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492624 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102625 sources = lambda affected_file: input_api.FilterSourceFile(
2626 affected_file,
James Cook24a504192020-07-23 00:08:442627 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2628 input_api.DEFAULT_FILES_TO_SKIP),
2629 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552630
2631 # Pattern to capture a single "<...>" block of template arguments. It can
2632 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2633 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2634 # latter would likely require counting that < and > match, which is not
2635 # expressible in regular languages. Should the need arise, one can introduce
2636 # limited counting (matching up to a total number of nesting depth), which
2637 # should cover all practical cases for already a low nesting limit.
2638 template_arg_pattern = (
2639 r'<[^>]*' # Opening block of <.
2640 r'>([^<]*>)?') # Closing block of >.
2641 # Prefix expressing that whatever follows is not already inside a <...>
2642 # block.
2643 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102644 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552645 not_inside_template_arg_pattern
2646 + r'\bstd::unique_ptr'
2647 + template_arg_pattern
2648 + r'\(\)')
2649
2650 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2651 template_arg_no_array_pattern = (
2652 r'<[^>]*[^]]' # Opening block of <.
2653 r'>([^(<]*[^]]>)?') # Closing block of >.
2654 # Prefix saying that what follows is the start of an expression.
2655 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2656 # Suffix saying that what follows are call parentheses with a non-empty list
2657 # of arguments.
2658 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532659 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552660 return_construct_pattern = input_api.re.compile(
2661 start_of_expr_pattern
2662 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532663 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552664 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532665 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552666 + nonempty_arg_list_pattern)
2667
Vaclav Brozek851d9602018-04-04 16:13:052668 problems_constructor = []
2669 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102670 for f in input_api.AffectedSourceFiles(sources):
2671 for line_number, line in f.ChangedContents():
2672 # Disallow:
2673 # return std::unique_ptr<T>(foo);
2674 # bar = std::unique_ptr<T>(foo);
2675 # But allow:
2676 # return std::unique_ptr<T[]>(foo);
2677 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532678 # And also allow cases when the second template argument is present. Those
2679 # cases cannot be handled by std::make_unique:
2680 # return std::unique_ptr<T, U>(foo);
2681 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052682 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532683 return_construct_result = return_construct_pattern.search(line)
2684 if return_construct_result and not HasMoreThanOneArg(
2685 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052686 problems_constructor.append(
2687 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102688 # Disallow:
2689 # std::unique_ptr<T>()
2690 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052691 problems_nullptr.append(
2692 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2693
2694 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162695 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052696 errors.append(output_api.PresubmitError(
2697 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162698 problems_nullptr))
2699 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052700 errors.append(output_api.PresubmitError(
2701 'The following files use explicit std::unique_ptr constructor.'
2702 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162703 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102704 return errors
2705
2706
Saagar Sanghavifceeaae2020-08-12 16:40:362707def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082708 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522709 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082710 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522711 # If actions.xml is already included in the changelist, the PRESUBMIT
2712 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082713 return []
2714
[email protected]999261d2014-03-03 20:08:082715 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2716 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522717 current_actions = None
[email protected]999261d2014-03-03 20:08:082718 for f in input_api.AffectedFiles(file_filter=file_filter):
2719 for line_num, line in f.ChangedContents():
2720 match = input_api.re.search(action_re, line)
2721 if match:
[email protected]2f92dec2014-03-07 19:21:522722 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2723 # loaded only once.
2724 if not current_actions:
2725 with open('tools/metrics/actions/actions.xml') as actions_f:
2726 current_actions = actions_f.read()
2727 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082728 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522729 action = 'name="{0}"'.format(action_name)
2730 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082731 return [output_api.PresubmitPromptWarning(
2732 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522733 'tools/metrics/actions/actions.xml. Please run '
2734 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082735 % (f.LocalPath(), line_num, action_name))]
2736 return []
2737
2738
Daniel Cheng13ca61a882017-08-25 15:11:252739def _ImportJSONCommentEater(input_api):
2740 import sys
2741 sys.path = sys.path + [input_api.os_path.join(
2742 input_api.PresubmitLocalPath(),
2743 'tools', 'json_comment_eater')]
2744 import json_comment_eater
2745 return json_comment_eater
2746
2747
[email protected]99171a92014-06-03 08:44:472748def _GetJSONParseError(input_api, filename, eat_comments=True):
2749 try:
2750 contents = input_api.ReadFile(filename)
2751 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252752 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132753 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472754
2755 input_api.json.loads(contents)
2756 except ValueError as e:
2757 return e
2758 return None
2759
2760
2761def _GetIDLParseError(input_api, filename):
2762 try:
2763 contents = input_api.ReadFile(filename)
2764 idl_schema = input_api.os_path.join(
2765 input_api.PresubmitLocalPath(),
2766 'tools', 'json_schema_compiler', 'idl_schema.py')
2767 process = input_api.subprocess.Popen(
2768 [input_api.python_executable, idl_schema],
2769 stdin=input_api.subprocess.PIPE,
2770 stdout=input_api.subprocess.PIPE,
2771 stderr=input_api.subprocess.PIPE,
2772 universal_newlines=True)
2773 (_, error) = process.communicate(input=contents)
2774 return error or None
2775 except ValueError as e:
2776 return e
2777
2778
Saagar Sanghavifceeaae2020-08-12 16:40:362779def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472780 """Check that IDL and JSON files do not contain syntax errors."""
2781 actions = {
2782 '.idl': _GetIDLParseError,
2783 '.json': _GetJSONParseError,
2784 }
[email protected]99171a92014-06-03 08:44:472785 # Most JSON files are preprocessed and support comments, but these do not.
2786 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042787 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472788 ]
2789 # Only run IDL checker on files in these directories.
2790 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042791 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2792 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472793 ]
2794
2795 def get_action(affected_file):
2796 filename = affected_file.LocalPath()
2797 return actions.get(input_api.os_path.splitext(filename)[1])
2798
[email protected]99171a92014-06-03 08:44:472799 def FilterFile(affected_file):
2800 action = get_action(affected_file)
2801 if not action:
2802 return False
2803 path = affected_file.LocalPath()
2804
Erik Staab2dd72b12020-04-16 15:03:402805 if _MatchesFile(input_api,
2806 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2807 path):
[email protected]99171a92014-06-03 08:44:472808 return False
2809
2810 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162811 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472812 return False
2813 return True
2814
2815 results = []
2816 for affected_file in input_api.AffectedFiles(
2817 file_filter=FilterFile, include_deletes=False):
2818 action = get_action(affected_file)
2819 kwargs = {}
2820 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162821 _MatchesFile(input_api, json_no_comments_patterns,
2822 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472823 kwargs['eat_comments'] = False
2824 parse_error = action(input_api,
2825 affected_file.AbsoluteLocalPath(),
2826 **kwargs)
2827 if parse_error:
2828 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2829 (affected_file.LocalPath(), parse_error)))
2830 return results
2831
2832
Saagar Sanghavifceeaae2020-08-12 16:40:362833def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492834 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472835 import sys
[email protected]760deea2013-12-10 19:33:492836 original_sys_path = sys.path
2837 try:
2838 sys.path = sys.path + [input_api.os_path.join(
2839 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2840 import checkstyle
2841 finally:
2842 # Restore sys.path to what it was before.
2843 sys.path = original_sys_path
2844
2845 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092846 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442847 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492848
2849
Saagar Sanghavifceeaae2020-08-12 16:40:362850def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002851 """Checks to make sure devil is initialized correctly in python scripts."""
2852 script_common_initialize_pattern = input_api.re.compile(
2853 r'script_common\.InitializeEnvironment\(')
2854 devil_env_config_initialize = input_api.re.compile(
2855 r'devil_env\.config\.Initialize\(')
2856
2857 errors = []
2858
2859 sources = lambda affected_file: input_api.FilterSourceFile(
2860 affected_file,
James Cook24a504192020-07-23 00:08:442861 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2862 (r'^build[\\/]android[\\/]devil_chromium\.py',
2863 r'^third_party[\\/].*',)),
2864 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002865
2866 for f in input_api.AffectedSourceFiles(sources):
2867 for line_num, line in f.ChangedContents():
2868 if (script_common_initialize_pattern.search(line) or
2869 devil_env_config_initialize.search(line)):
2870 errors.append("%s:%d" % (f.LocalPath(), line_num))
2871
2872 results = []
2873
2874 if errors:
2875 results.append(output_api.PresubmitError(
2876 'Devil initialization should always be done using '
2877 'devil_chromium.Initialize() in the chromium project, to use better '
2878 'defaults for dependencies (ex. up-to-date version of adb).',
2879 errors))
2880
2881 return results
2882
2883
Sean Kau46e29bc2017-08-28 16:31:162884def _MatchesFile(input_api, patterns, path):
2885 for pattern in patterns:
2886 if input_api.re.search(pattern, path):
2887 return True
2888 return False
2889
2890
Daniel Cheng7052cdf2017-11-21 19:23:292891def _GetOwnersFilesToCheckForIpcOwners(input_api):
2892 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172893
Daniel Cheng7052cdf2017-11-21 19:23:292894 Returns:
2895 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2896 contain to cover IPC-related files with noparent reviewer rules.
2897 """
2898 # Whether or not a file affects IPC is (mostly) determined by a simple list
2899 # of filename patterns.
dchenge07de812016-06-20 19:27:172900 file_patterns = [
palmerb19a0932017-01-24 04:00:312901 # Legacy IPC:
dchenge07de812016-06-20 19:27:172902 '*_messages.cc',
2903 '*_messages*.h',
2904 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312905 # Mojo IPC:
dchenge07de812016-06-20 19:27:172906 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472907 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172908 '*_struct_traits*.*',
2909 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312910 '*.typemap',
2911 # Android native IPC:
2912 '*.aidl',
2913 # Blink uses a different file naming convention:
2914 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472915 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172916 '*StructTraits*.*',
2917 '*TypeConverter*.*',
2918 ]
2919
scottmg7a6ed5ba2016-11-04 18:22:042920 # These third_party directories do not contain IPCs, but contain files
2921 # matching the above patterns, which trigger false positives.
2922 exclude_paths = [
2923 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162924 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232925 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292926 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542927 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162928 # These files are just used to communicate between class loaders running
2929 # in the same process.
2930 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572931 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2932
scottmg7a6ed5ba2016-11-04 18:22:042933 ]
2934
dchenge07de812016-06-20 19:27:172935 # Dictionary mapping an OWNERS file path to Patterns.
2936 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2937 # rules ) to a PatternEntry.
2938 # PatternEntry is a dictionary with two keys:
2939 # - 'files': the files that are matched by this pattern
2940 # - 'rules': the per-file rules needed for this pattern
2941 # For example, if we expect OWNERS file to contain rules for *.mojom and
2942 # *_struct_traits*.*, Patterns might look like this:
2943 # {
2944 # '*.mojom': {
2945 # 'files': ...,
2946 # 'rules': [
2947 # 'per-file *.mojom=set noparent',
2948 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2949 # ],
2950 # },
2951 # '*_struct_traits*.*': {
2952 # 'files': ...,
2953 # 'rules': [
2954 # 'per-file *_struct_traits*.*=set noparent',
2955 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2956 # ],
2957 # },
2958 # }
2959 to_check = {}
2960
Daniel Cheng13ca61a882017-08-25 15:11:252961 def AddPatternToCheck(input_file, pattern):
2962 owners_file = input_api.os_path.join(
2963 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2964 if owners_file not in to_check:
2965 to_check[owners_file] = {}
2966 if pattern not in to_check[owners_file]:
2967 to_check[owners_file][pattern] = {
2968 'files': [],
2969 'rules': [
2970 'per-file %s=set noparent' % pattern,
2971 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2972 ]
2973 }
Vaclav Brozekd5de76a2018-03-17 07:57:502974 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252975
dchenge07de812016-06-20 19:27:172976 # Iterate through the affected files to see what we actually need to check
2977 # for. We should only nag patch authors about per-file rules if a file in that
2978 # directory would match that pattern. If a directory only contains *.mojom
2979 # files and no *_messages*.h files, we should only nag about rules for
2980 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252981 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262982 # Manifest files don't have a strong naming convention. Instead, try to find
2983 # affected .cc and .h files which look like they contain a manifest
2984 # definition.
2985 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2986 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2987 if (manifest_pattern.search(f.LocalPath()) and not
2988 test_manifest_pattern.search(f.LocalPath())):
2989 # We expect all actual service manifest files to contain at least one
2990 # qualified reference to service_manager::Manifest.
2991 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252992 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172993 for pattern in file_patterns:
2994 if input_api.fnmatch.fnmatch(
2995 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042996 skip = False
2997 for exclude in exclude_paths:
2998 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2999 skip = True
3000 break
3001 if skip:
3002 continue
Daniel Cheng13ca61a882017-08-25 15:11:253003 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173004 break
3005
Daniel Cheng7052cdf2017-11-21 19:23:293006 return to_check
3007
3008
Wez17c66962020-04-29 15:26:033009def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3010 """Adds OWNERS files to check for correct Fuchsia security owners."""
3011
3012 file_patterns = [
3013 # Component specifications.
3014 '*.cml', # Component Framework v2.
3015 '*.cmx', # Component Framework v1.
3016
3017 # Fuchsia IDL protocol specifications.
3018 '*.fidl',
3019 ]
3020
3021 def AddPatternToCheck(input_file, pattern):
3022 owners_file = input_api.os_path.join(
3023 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3024 if owners_file not in to_check:
3025 to_check[owners_file] = {}
3026 if pattern not in to_check[owners_file]:
3027 to_check[owners_file][pattern] = {
3028 'files': [],
3029 'rules': [
3030 'per-file %s=set noparent' % pattern,
3031 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3032 ]
3033 }
3034 to_check[owners_file][pattern]['files'].append(input_file)
3035
3036 # Iterate through the affected files to see what we actually need to check
3037 # for. We should only nag patch authors about per-file rules if a file in that
3038 # directory would match that pattern.
3039 for f in input_api.AffectedFiles(include_deletes=False):
3040 for pattern in file_patterns:
3041 if input_api.fnmatch.fnmatch(
3042 input_api.os_path.basename(f.LocalPath()), pattern):
3043 AddPatternToCheck(f, pattern)
3044 break
3045
3046 return to_check
3047
3048
Saagar Sanghavifceeaae2020-08-12 16:40:363049def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293050 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3051 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033052 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293053
3054 if to_check:
3055 # If there are any OWNERS files to check, there are IPC-related changes in
3056 # this CL. Auto-CC the review list.
3057 output_api.AppendCC('[email protected]')
3058
3059 # Go through the OWNERS files to check, filtering out rules that are already
3060 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173061 for owners_file, patterns in to_check.iteritems():
3062 try:
3063 with file(owners_file) as f:
3064 lines = set(f.read().splitlines())
3065 for entry in patterns.itervalues():
3066 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3067 ]
3068 except IOError:
3069 # No OWNERS file, so all the rules are definitely missing.
3070 continue
3071
3072 # All the remaining lines weren't found in OWNERS files, so emit an error.
3073 errors = []
3074 for owners_file, patterns in to_check.iteritems():
3075 missing_lines = []
3076 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503077 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173078 missing_lines.extend(entry['rules'])
3079 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3080 if missing_lines:
3081 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053082 'Because of the presence of files:\n%s\n\n'
3083 '%s needs the following %d lines added:\n\n%s' %
3084 ('\n'.join(files), owners_file, len(missing_lines),
3085 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173086
3087 results = []
3088 if errors:
vabrf5ce3bf92016-07-11 14:52:413089 if input_api.is_committing:
3090 output = output_api.PresubmitError
3091 else:
3092 output = output_api.PresubmitPromptWarning
3093 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593094 'Found OWNERS files that need to be updated for IPC security ' +
3095 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173096 long_text='\n\n'.join(errors)))
3097
3098 return results
3099
3100
Robert Sesek2c905332020-05-06 23:17:133101def _GetFilesUsingSecurityCriticalFunctions(input_api):
3102 """Checks affected files for changes to security-critical calls. This
3103 function checks the full change diff, to catch both additions/changes
3104 and removals.
3105
3106 Returns a dict keyed by file name, and the value is a set of detected
3107 functions.
3108 """
3109 # Map of function pretty name (displayed in an error) to the pattern to
3110 # match it with.
3111 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373112 'content::GetServiceSandboxType<>()':
3113 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133114 }
3115 _PATTERNS_TO_CHECK = {
3116 k: input_api.re.compile(v)
3117 for k, v in _PATTERNS_TO_CHECK.items()
3118 }
3119
3120 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3121 files_to_functions = {}
3122 for f in input_api.AffectedFiles():
3123 diff = f.GenerateScmDiff()
3124 for line in diff.split('\n'):
3125 # Not using just RightHandSideLines() because removing a
3126 # call to a security-critical function can be just as important
3127 # as adding or changing the arguments.
3128 if line.startswith('-') or (line.startswith('+') and
3129 not line.startswith('++')):
3130 for name, pattern in _PATTERNS_TO_CHECK.items():
3131 if pattern.search(line):
3132 path = f.LocalPath()
3133 if not path in files_to_functions:
3134 files_to_functions[path] = set()
3135 files_to_functions[path].add(name)
3136 return files_to_functions
3137
3138
Saagar Sanghavifceeaae2020-08-12 16:40:363139def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133140 """Checks that changes involving security-critical functions are reviewed
3141 by the security team.
3142 """
3143 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3144 if len(files_to_functions):
3145 owners_db = input_api.owners_db
3146 owner_email, reviewers = (
3147 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3148 input_api,
3149 owners_db.email_regexp,
3150 approval_needed=input_api.is_committing))
3151
3152 # Load the OWNERS file for security changes.
3153 owners_file = 'ipc/SECURITY_OWNERS'
3154 security_owners = owners_db.owners_rooted_at_file(owners_file)
3155
3156 has_security_owner = any([owner in reviewers for owner in security_owners])
3157 if not has_security_owner:
3158 msg = 'The following files change calls to security-sensive functions\n' \
3159 'that need to be reviewed by {}.\n'.format(owners_file)
3160 for path, names in files_to_functions.items():
3161 msg += ' {}\n'.format(path)
3162 for name in names:
3163 msg += ' {}\n'.format(name)
3164 msg += '\n'
3165
3166 if input_api.is_committing:
3167 output = output_api.PresubmitError
3168 else:
3169 output = output_api.PresubmitNotifyResult
3170 return [output(msg)]
3171
3172 return []
3173
3174
Saagar Sanghavifceeaae2020-08-12 16:40:363175def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263176 """Checks that set noparent is only used together with an OWNERS file in
3177 //build/OWNERS.setnoparent (see also
3178 //docs/code_reviews.md#owners-files-details)
3179 """
3180 errors = []
3181
3182 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3183 allowed_owners_files = set()
3184 with open(allowed_owners_files_file, 'r') as f:
3185 for line in f:
3186 line = line.strip()
3187 if not line or line.startswith('#'):
3188 continue
3189 allowed_owners_files.add(line)
3190
3191 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3192
3193 for f in input_api.AffectedFiles(include_deletes=False):
3194 if not f.LocalPath().endswith('OWNERS'):
3195 continue
3196
3197 found_owners_files = set()
3198 found_set_noparent_lines = dict()
3199
3200 # Parse the OWNERS file.
3201 for lineno, line in enumerate(f.NewContents(), 1):
3202 line = line.strip()
3203 if line.startswith('set noparent'):
3204 found_set_noparent_lines[''] = lineno
3205 if line.startswith('file://'):
3206 if line in allowed_owners_files:
3207 found_owners_files.add('')
3208 if line.startswith('per-file'):
3209 match = per_file_pattern.match(line)
3210 if match:
3211 glob = match.group(1).strip()
3212 directive = match.group(2).strip()
3213 if directive == 'set noparent':
3214 found_set_noparent_lines[glob] = lineno
3215 if directive.startswith('file://'):
3216 if directive in allowed_owners_files:
3217 found_owners_files.add(glob)
3218
3219 # Check that every set noparent line has a corresponding file:// line
3220 # listed in build/OWNERS.setnoparent.
3221 for set_noparent_line in found_set_noparent_lines:
3222 if set_noparent_line in found_owners_files:
3223 continue
3224 errors.append(' %s:%d' % (f.LocalPath(),
3225 found_set_noparent_lines[set_noparent_line]))
3226
3227 results = []
3228 if errors:
3229 if input_api.is_committing:
3230 output = output_api.PresubmitError
3231 else:
3232 output = output_api.PresubmitPromptWarning
3233 results.append(output(
3234 'Found the following "set noparent" restrictions in OWNERS files that '
3235 'do not include owners from build/OWNERS.setnoparent:',
3236 long_text='\n\n'.join(errors)))
3237 return results
3238
3239
Saagar Sanghavifceeaae2020-08-12 16:40:363240def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313241 """Checks that added or removed lines in non third party affected
3242 header files do not lead to new useless class or struct forward
3243 declaration.
jbriance9e12f162016-11-25 07:57:503244 """
3245 results = []
3246 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3247 input_api.re.MULTILINE)
3248 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3249 input_api.re.MULTILINE)
3250 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313251 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193252 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493253 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313254 continue
3255
jbriance9e12f162016-11-25 07:57:503256 if not f.LocalPath().endswith('.h'):
3257 continue
3258
3259 contents = input_api.ReadFile(f)
3260 fwd_decls = input_api.re.findall(class_pattern, contents)
3261 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3262
3263 useless_fwd_decls = []
3264 for decl in fwd_decls:
3265 count = sum(1 for _ in input_api.re.finditer(
3266 r'\b%s\b' % input_api.re.escape(decl), contents))
3267 if count == 1:
3268 useless_fwd_decls.append(decl)
3269
3270 if not useless_fwd_decls:
3271 continue
3272
3273 for line in f.GenerateScmDiff().splitlines():
3274 if (line.startswith('-') and not line.startswith('--') or
3275 line.startswith('+') and not line.startswith('++')):
3276 for decl in useless_fwd_decls:
3277 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3278 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243279 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503280 (f.LocalPath(), decl)))
3281 useless_fwd_decls.remove(decl)
3282
3283 return results
3284
Jinsong Fan91ebbbd2019-04-16 14:57:173285def _CheckAndroidDebuggableBuild(input_api, output_api):
3286 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3287 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3288 this is a debuggable build of Android.
3289 """
3290 build_type_check_pattern = input_api.re.compile(
3291 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3292
3293 errors = []
3294
3295 sources = lambda affected_file: input_api.FilterSourceFile(
3296 affected_file,
James Cook24a504192020-07-23 00:08:443297 files_to_skip=(_EXCLUDED_PATHS +
3298 _TEST_CODE_EXCLUDED_PATHS +
3299 input_api.DEFAULT_FILES_TO_SKIP +
3300 (r"^android_webview[\\/]support_library[\\/]"
3301 "boundary_interfaces[\\/]",
3302 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3303 r'^third_party[\\/].*',
3304 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3305 r"webview[\\/]chromium[\\/]License.*",)),
3306 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173307
3308 for f in input_api.AffectedSourceFiles(sources):
3309 for line_num, line in f.ChangedContents():
3310 if build_type_check_pattern.search(line):
3311 errors.append("%s:%d" % (f.LocalPath(), line_num))
3312
3313 results = []
3314
3315 if errors:
3316 results.append(output_api.PresubmitPromptWarning(
3317 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3318 ' Please use BuildInfo.isDebugAndroid() instead.',
3319 errors))
3320
3321 return results
jbriance9e12f162016-11-25 07:57:503322
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493323# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293324def _CheckAndroidToastUsage(input_api, output_api):
3325 """Checks that code uses org.chromium.ui.widget.Toast instead of
3326 android.widget.Toast (Chromium Toast doesn't force hardware
3327 acceleration on low-end devices, saving memory).
3328 """
3329 toast_import_pattern = input_api.re.compile(
3330 r'^import android\.widget\.Toast;$')
3331
3332 errors = []
3333
3334 sources = lambda affected_file: input_api.FilterSourceFile(
3335 affected_file,
James Cook24a504192020-07-23 00:08:443336 files_to_skip=(_EXCLUDED_PATHS +
3337 _TEST_CODE_EXCLUDED_PATHS +
3338 input_api.DEFAULT_FILES_TO_SKIP +
3339 (r'^chromecast[\\/].*',
3340 r'^remoting[\\/].*')),
3341 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293342
3343 for f in input_api.AffectedSourceFiles(sources):
3344 for line_num, line in f.ChangedContents():
3345 if toast_import_pattern.search(line):
3346 errors.append("%s:%d" % (f.LocalPath(), line_num))
3347
3348 results = []
3349
3350 if errors:
3351 results.append(output_api.PresubmitError(
3352 'android.widget.Toast usage is detected. Android toasts use hardware'
3353 ' acceleration, and can be\ncostly on low-end devices. Please use'
3354 ' org.chromium.ui.widget.Toast instead.\n'
3355 'Contact [email protected] if you have any questions.',
3356 errors))
3357
3358 return results
3359
3360
dgnaa68d5e2015-06-10 10:08:223361def _CheckAndroidCrLogUsage(input_api, output_api):
3362 """Checks that new logs using org.chromium.base.Log:
3363 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513364 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223365 """
pkotwicza1dd0b002016-05-16 14:41:043366
torne89540622017-03-24 19:41:303367 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043368 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303369 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043370 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303371 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043372 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3373 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093374 # The customtabs_benchmark is a small app that does not depend on Chromium
3375 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043376 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043377 ]
3378
dgnaa68d5e2015-06-10 10:08:223379 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123380 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3381 class_in_base_pattern = input_api.re.compile(
3382 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3383 has_some_log_import_pattern = input_api.re.compile(
3384 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223385 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553386 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223387 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463388 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553389 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223390
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463391 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443392 sources = lambda x: input_api.FilterSourceFile(x,
3393 files_to_check=[r'.*\.java$'],
3394 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123395
dgnaa68d5e2015-06-10 10:08:223396 tag_decl_errors = []
3397 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123398 tag_errors = []
dgn38736db2015-09-18 19:20:513399 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123400 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223401
3402 for f in input_api.AffectedSourceFiles(sources):
3403 file_content = input_api.ReadFile(f)
3404 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223405 # Per line checks
dgn87d9fb62015-06-12 09:15:123406 if (cr_log_import_pattern.search(file_content) or
3407 (class_in_base_pattern.search(file_content) and
3408 not has_some_log_import_pattern.search(file_content))):
3409 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223410 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553411 if rough_log_decl_pattern.search(line):
3412 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223413
3414 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123415 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223416 if match:
3417 has_modified_logs = True
3418
3419 # Make sure it uses "TAG"
3420 if not match.group('tag') == 'TAG':
3421 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123422 else:
3423 # Report non cr Log function calls in changed lines
3424 for line_num, line in f.ChangedContents():
3425 if log_call_pattern.search(line):
3426 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223427
3428 # Per file checks
3429 if has_modified_logs:
3430 # Make sure the tag is using the "cr" prefix and is not too long
3431 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513432 tag_name = match.group('name') if match else None
3433 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223434 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513435 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223436 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513437 elif '.' in tag_name:
3438 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223439
3440 results = []
3441 if tag_decl_errors:
3442 results.append(output_api.PresubmitPromptWarning(
3443 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513444 '"private static final String TAG = "<package tag>".\n'
3445 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223446 tag_decl_errors))
3447
3448 if tag_length_errors:
3449 results.append(output_api.PresubmitError(
3450 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513451 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223452 tag_length_errors))
3453
3454 if tag_errors:
3455 results.append(output_api.PresubmitPromptWarning(
3456 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3457 tag_errors))
3458
dgn87d9fb62015-06-12 09:15:123459 if util_log_errors:
dgn4401aa52015-04-29 16:26:173460 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123461 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3462 util_log_errors))
3463
dgn38736db2015-09-18 19:20:513464 if tag_with_dot_errors:
3465 results.append(output_api.PresubmitPromptWarning(
3466 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3467 tag_with_dot_errors))
3468
dgn4401aa52015-04-29 16:26:173469 return results
3470
3471
Yoland Yanb92fa522017-08-28 17:37:063472def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3473 """Checks that junit.framework.* is no longer used."""
3474 deprecated_junit_framework_pattern = input_api.re.compile(
3475 r'^import junit\.framework\..*;',
3476 input_api.re.MULTILINE)
3477 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443478 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063479 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133480 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063481 for line_num, line in f.ChangedContents():
3482 if deprecated_junit_framework_pattern.search(line):
3483 errors.append("%s:%d" % (f.LocalPath(), line_num))
3484
3485 results = []
3486 if errors:
3487 results.append(output_api.PresubmitError(
3488 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3489 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3490 ' if you have any question.', errors))
3491 return results
3492
3493
3494def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3495 """Checks that if new Java test classes have inheritance.
3496 Either the new test class is JUnit3 test or it is a JUnit4 test class
3497 with a base class, either case is undesirable.
3498 """
3499 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3500
3501 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443502 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063503 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133504 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063505 if not f.OldContents():
3506 class_declaration_start_flag = False
3507 for line_num, line in f.ChangedContents():
3508 if class_declaration_pattern.search(line):
3509 class_declaration_start_flag = True
3510 if class_declaration_start_flag and ' extends ' in line:
3511 errors.append('%s:%d' % (f.LocalPath(), line_num))
3512 if '{' in line:
3513 class_declaration_start_flag = False
3514
3515 results = []
3516 if errors:
3517 results.append(output_api.PresubmitPromptWarning(
3518 'The newly created files include Test classes that inherits from base'
3519 ' class. Please do not use inheritance in JUnit4 tests or add new'
3520 ' JUnit3 tests. Contact [email protected] if you have any'
3521 ' questions.', errors))
3522 return results
3523
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203524
yolandyan45001472016-12-21 21:12:423525def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3526 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3527 deprecated_annotation_import_pattern = input_api.re.compile(
3528 r'^import android\.test\.suitebuilder\.annotation\..*;',
3529 input_api.re.MULTILINE)
3530 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443531 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423532 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133533 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423534 for line_num, line in f.ChangedContents():
3535 if deprecated_annotation_import_pattern.search(line):
3536 errors.append("%s:%d" % (f.LocalPath(), line_num))
3537
3538 results = []
3539 if errors:
3540 results.append(output_api.PresubmitError(
3541 'Annotations in android.test.suitebuilder.annotation have been'
3542 ' deprecated since API level 24. Please use android.support.test.filters'
3543 ' from //third_party/android_support_test_runner:runner_java instead.'
3544 ' Contact [email protected] if you have any questions.', errors))
3545 return results
3546
3547
agrieve7b6479d82015-10-07 14:24:223548def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3549 """Checks if MDPI assets are placed in a correct directory."""
3550 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3551 ('/res/drawable/' in f.LocalPath() or
3552 '/res/drawable-ldrtl/' in f.LocalPath()))
3553 errors = []
3554 for f in input_api.AffectedFiles(include_deletes=False,
3555 file_filter=file_filter):
3556 errors.append(' %s' % f.LocalPath())
3557
3558 results = []
3559 if errors:
3560 results.append(output_api.PresubmitError(
3561 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3562 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3563 '/res/drawable-ldrtl/.\n'
3564 'Contact [email protected] if you have questions.', errors))
3565 return results
3566
3567
Nate Fischer535972b2017-09-16 01:06:183568def _CheckAndroidWebkitImports(input_api, output_api):
3569 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353570 android.webview.ValueCallback except in the WebView glue layer
3571 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183572 """
3573 valuecallback_import_pattern = input_api.re.compile(
3574 r'^import android\.webkit\.ValueCallback;$')
3575
3576 errors = []
3577
3578 sources = lambda affected_file: input_api.FilterSourceFile(
3579 affected_file,
James Cook24a504192020-07-23 00:08:443580 files_to_skip=(_EXCLUDED_PATHS +
3581 _TEST_CODE_EXCLUDED_PATHS +
3582 input_api.DEFAULT_FILES_TO_SKIP +
3583 (r'^android_webview[\\/]glue[\\/].*',
3584 r'^weblayer[\\/].*',)),
3585 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183586
3587 for f in input_api.AffectedSourceFiles(sources):
3588 for line_num, line in f.ChangedContents():
3589 if valuecallback_import_pattern.search(line):
3590 errors.append("%s:%d" % (f.LocalPath(), line_num))
3591
3592 results = []
3593
3594 if errors:
3595 results.append(output_api.PresubmitError(
3596 'android.webkit.ValueCallback usage is detected outside of the glue'
3597 ' layer. To stay compatible with the support library, android.webkit.*'
3598 ' classes should only be used inside the glue layer and'
3599 ' org.chromium.base.Callback should be used instead.',
3600 errors))
3601
3602 return results
3603
3604
Becky Zhou7c69b50992018-12-10 19:37:573605def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3606 """Checks Android XML styles """
3607 import sys
3608 original_sys_path = sys.path
3609 try:
3610 sys.path = sys.path + [input_api.os_path.join(
3611 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3612 import checkxmlstyle
3613 finally:
3614 # Restore sys.path to what it was before.
3615 sys.path = original_sys_path
3616
3617 if is_check_on_upload:
3618 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3619 else:
3620 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3621
3622
agrievef32bcc72016-04-04 14:57:403623class PydepsChecker(object):
3624 def __init__(self, input_api, pydeps_files):
3625 self._file_cache = {}
3626 self._input_api = input_api
3627 self._pydeps_files = pydeps_files
3628
3629 def _LoadFile(self, path):
3630 """Returns the list of paths within a .pydeps file relative to //."""
3631 if path not in self._file_cache:
3632 with open(path) as f:
3633 self._file_cache[path] = f.read()
3634 return self._file_cache[path]
3635
3636 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3637 """Returns an interable of paths within the .pydep, relativized to //."""
3638 os_path = self._input_api.os_path
3639 pydeps_dir = os_path.dirname(pydeps_path)
3640 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3641 if not l.startswith('*'))
3642 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3643
3644 def _CreateFilesToPydepsMap(self):
3645 """Returns a map of local_path -> list_of_pydeps."""
3646 ret = {}
3647 for pydep_local_path in self._pydeps_files:
3648 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3649 ret.setdefault(path, []).append(pydep_local_path)
3650 return ret
3651
3652 def ComputeAffectedPydeps(self):
3653 """Returns an iterable of .pydeps files that might need regenerating."""
3654 affected_pydeps = set()
3655 file_to_pydeps_map = None
3656 for f in self._input_api.AffectedFiles(include_deletes=True):
3657 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463658 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3659 # subrepositories. We can't figure out which files change, so re-check
3660 # all files.
3661 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383662 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3663 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403664 return self._pydeps_files
3665 elif local_path.endswith('.pydeps'):
3666 if local_path in self._pydeps_files:
3667 affected_pydeps.add(local_path)
3668 elif local_path.endswith('.py'):
3669 if file_to_pydeps_map is None:
3670 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3671 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3672 return affected_pydeps
3673
3674 def DetermineIfStale(self, pydeps_path):
3675 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413676 import difflib
John Budorick47ca3fe2018-02-10 00:53:103677 import os
3678
agrievef32bcc72016-04-04 14:57:403679 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033680 if old_pydeps_data:
3681 cmd = old_pydeps_data[1][1:].strip()
3682 old_contents = old_pydeps_data[2:]
3683 else:
3684 # A default cmd that should work in most cases (as long as pydeps filename
3685 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3686 # file is empty/new.
3687 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3688 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3689 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103690 env = dict(os.environ)
3691 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403692 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103693 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413694 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033695 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413696 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403697
3698
Tibor Goldschwendt360793f72019-06-25 18:23:493699def _ParseGclientArgs():
3700 args = {}
3701 with open('build/config/gclient_args.gni', 'r') as f:
3702 for line in f:
3703 line = line.strip()
3704 if not line or line.startswith('#'):
3705 continue
3706 attribute, value = line.split('=')
3707 args[attribute.strip()] = value.strip()
3708 return args
3709
3710
Saagar Sanghavifceeaae2020-08-12 16:40:363711def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403712 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403713 # This check is for Python dependency lists (.pydeps files), and involves
3714 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3715 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283716 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003717 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493718 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403719 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403720 results = []
3721 # First, check for new / deleted .pydeps.
3722 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033723 # Check whether we are running the presubmit check for a file in src.
3724 # f.LocalPath is relative to repo (src, or internal repo).
3725 # os_path.exists is relative to src repo.
3726 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3727 # to src and we can conclude that the pydeps is in src.
3728 if input_api.os_path.exists(f.LocalPath()):
3729 if f.LocalPath().endswith('.pydeps'):
3730 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3731 results.append(output_api.PresubmitError(
3732 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3733 'remove %s' % f.LocalPath()))
3734 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3735 results.append(output_api.PresubmitError(
3736 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3737 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403738
3739 if results:
3740 return results
3741
Mohamed Heikal7cd4d8312020-06-16 16:49:403742 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3743 affected_pydeps = set(checker.ComputeAffectedPydeps())
3744 affected_android_pydeps = affected_pydeps.intersection(
3745 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3746 if affected_android_pydeps and not is_android:
3747 results.append(output_api.PresubmitPromptOrNotify(
3748 'You have changed python files that may affect pydeps for android\n'
3749 'specific scripts. However, the relevant presumbit check cannot be\n'
3750 'run because you are not using an Android checkout. To validate that\n'
3751 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3752 'use the android-internal-presubmit optional trybot.\n'
3753 'Possibly stale pydeps files:\n{}'.format(
3754 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403755
Mohamed Heikal7cd4d8312020-06-16 16:49:403756 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3757 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403758 try:
phajdan.jr0d9878552016-11-04 10:49:413759 result = checker.DetermineIfStale(pydep_path)
3760 if result:
3761 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403762 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413763 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3764 'To regenerate, run:\n\n %s' %
3765 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403766 except input_api.subprocess.CalledProcessError as error:
3767 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3768 long_text=error.output)]
3769
3770 return results
3771
3772
Saagar Sanghavifceeaae2020-08-12 16:40:363773def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433774 """Checks to make sure no header files have |Singleton<|."""
3775 def FileFilter(affected_file):
3776 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443777 files_to_skip = (_EXCLUDED_PATHS +
3778 input_api.DEFAULT_FILES_TO_SKIP +
3779 (r"^base[\\/]memory[\\/]singleton\.h$",
3780 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3781 r"quic_singleton_impl\.h$"))
3782 return input_api.FilterSourceFile(affected_file,
3783 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433784
sergeyu34d21222015-09-16 00:11:443785 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433786 files = []
3787 for f in input_api.AffectedSourceFiles(FileFilter):
3788 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3789 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3790 contents = input_api.ReadFile(f)
3791 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243792 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433793 pattern.search(line)):
3794 files.append(f)
3795 break
3796
3797 if files:
yolandyandaabc6d2016-04-18 18:29:393798 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443799 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433800 'Please move them to an appropriate source file so that the ' +
3801 'template gets instantiated in a single compilation unit.',
3802 files) ]
3803 return []
3804
3805
[email protected]fd20b902014-05-09 02:14:533806_DEPRECATED_CSS = [
3807 # Values
3808 ( "-webkit-box", "flex" ),
3809 ( "-webkit-inline-box", "inline-flex" ),
3810 ( "-webkit-flex", "flex" ),
3811 ( "-webkit-inline-flex", "inline-flex" ),
3812 ( "-webkit-min-content", "min-content" ),
3813 ( "-webkit-max-content", "max-content" ),
3814
3815 # Properties
3816 ( "-webkit-background-clip", "background-clip" ),
3817 ( "-webkit-background-origin", "background-origin" ),
3818 ( "-webkit-background-size", "background-size" ),
3819 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443820 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533821
3822 # Functions
3823 ( "-webkit-gradient", "gradient" ),
3824 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3825 ( "-webkit-linear-gradient", "linear-gradient" ),
3826 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3827 ( "-webkit-radial-gradient", "radial-gradient" ),
3828 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3829]
3830
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203831
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493832# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363833def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533834 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253835 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343836 documentation and iOS CSS for dom distiller
3837 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253838 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533839 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493840 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443841 files_to_skip = (_EXCLUDED_PATHS +
3842 _TEST_CODE_EXCLUDED_PATHS +
3843 input_api.DEFAULT_FILES_TO_SKIP +
3844 (r"^chrome/common/extensions/docs",
3845 r"^chrome/docs",
3846 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3847 r"^components/neterror/resources/neterror.css",
3848 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253849 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443850 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533851 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3852 for line_num, line in fpath.ChangedContents():
3853 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023854 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533855 results.append(output_api.PresubmitError(
3856 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3857 (fpath.LocalPath(), line_num, deprecated_value, value)))
3858 return results
3859
mohan.reddyf21db962014-10-16 12:26:473860
Saagar Sanghavifceeaae2020-08-12 16:40:363861def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363862 bad_files = {}
3863 for f in input_api.AffectedFiles(include_deletes=False):
3864 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493865 not f.LocalPath().startswith('third_party/blink') and
3866 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363867 continue
3868
Daniel Bratell65b033262019-04-23 08:17:063869 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363870 continue
3871
Vaclav Brozekd5de76a2018-03-17 07:57:503872 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363873 if "#include" in line and "../" in line]
3874 if not relative_includes:
3875 continue
3876 bad_files[f.LocalPath()] = relative_includes
3877
3878 if not bad_files:
3879 return []
3880
3881 error_descriptions = []
3882 for file_path, bad_lines in bad_files.iteritems():
3883 error_description = file_path
3884 for line in bad_lines:
3885 error_description += '\n ' + line
3886 error_descriptions.append(error_description)
3887
3888 results = []
3889 results.append(output_api.PresubmitError(
3890 'You added one or more relative #include paths (including "../").\n'
3891 'These shouldn\'t be used because they can be used to include headers\n'
3892 'from code that\'s not correctly specified as a dependency in the\n'
3893 'relevant BUILD.gn file(s).',
3894 error_descriptions))
3895
3896 return results
3897
Takeshi Yoshinoe387aa32017-08-02 13:16:133898
Saagar Sanghavifceeaae2020-08-12 16:40:363899def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063900 """Check that nobody tries to include a cc file. It's a relatively
3901 common error which results in duplicate symbols in object
3902 files. This may not always break the build until someone later gets
3903 very confusing linking errors."""
3904 results = []
3905 for f in input_api.AffectedFiles(include_deletes=False):
3906 # We let third_party code do whatever it wants
3907 if (f.LocalPath().startswith('third_party') and
3908 not f.LocalPath().startswith('third_party/blink') and
3909 not f.LocalPath().startswith('third_party\\blink')):
3910 continue
3911
3912 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3913 continue
3914
3915 for _, line in f.ChangedContents():
3916 if line.startswith('#include "'):
3917 included_file = line.split('"')[1]
3918 if _IsCPlusPlusFile(input_api, included_file):
3919 # The most common naming for external files with C++ code,
3920 # apart from standard headers, is to call them foo.inc, but
3921 # Chromium sometimes uses foo-inc.cc so allow that as well.
3922 if not included_file.endswith(('.h', '-inc.cc')):
3923 results.append(output_api.PresubmitError(
3924 'Only header files or .inc files should be included in other\n'
3925 'C++ files. Compiling the contents of a cc file more than once\n'
3926 'will cause duplicate information in the build which may later\n'
3927 'result in strange link_errors.\n' +
3928 f.LocalPath() + ':\n ' +
3929 line))
3930
3931 return results
3932
3933
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203934def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3935 if not isinstance(key, ast.Str):
3936 return 'Key at line %d must be a string literal' % key.lineno
3937 if not isinstance(value, ast.Dict):
3938 return 'Value at line %d must be a dict' % value.lineno
3939 if len(value.keys) != 1:
3940 return 'Dict at line %d must have single entry' % value.lineno
3941 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3942 return (
3943 'Entry at line %d must have a string literal \'filepath\' as key' %
3944 value.lineno)
3945 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133946
Takeshi Yoshinoe387aa32017-08-02 13:16:133947
Sergey Ulanov4af16052018-11-08 02:41:463948def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203949 if not isinstance(key, ast.Str):
3950 return 'Key at line %d must be a string literal' % key.lineno
3951 if not isinstance(value, ast.List):
3952 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463953 for element in value.elts:
3954 if not isinstance(element, ast.Str):
3955 return 'Watchlist elements on line %d is not a string' % key.lineno
3956 if not email_regex.match(element.s):
3957 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3958 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203959 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133960
Takeshi Yoshinoe387aa32017-08-02 13:16:133961
Sergey Ulanov4af16052018-11-08 02:41:463962def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203963 mismatch_template = (
3964 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3965 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133966
Sergey Ulanov4af16052018-11-08 02:41:463967 email_regex = input_api.re.compile(
3968 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3969
3970 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203971 i = 0
3972 last_key = ''
3973 while True:
3974 if i >= len(wd_dict.keys):
3975 if i >= len(w_dict.keys):
3976 return None
3977 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3978 elif i >= len(w_dict.keys):
3979 return (
3980 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133981
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203982 wd_key = wd_dict.keys[i]
3983 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133984
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203985 result = _CheckWatchlistDefinitionsEntrySyntax(
3986 wd_key, wd_dict.values[i], ast)
3987 if result is not None:
3988 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133989
Sergey Ulanov4af16052018-11-08 02:41:463990 result = _CheckWatchlistsEntrySyntax(
3991 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203992 if result is not None:
3993 return 'Bad entry in WATCHLISTS dict: %s' % result
3994
3995 if wd_key.s != w_key.s:
3996 return mismatch_template % (
3997 '%s at line %d' % (wd_key.s, wd_key.lineno),
3998 '%s at line %d' % (w_key.s, w_key.lineno))
3999
4000 if wd_key.s < last_key:
4001 return (
4002 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4003 (wd_key.lineno, w_key.lineno))
4004 last_key = wd_key.s
4005
4006 i = i + 1
4007
4008
Sergey Ulanov4af16052018-11-08 02:41:464009def _CheckWATCHLISTSSyntax(expression, input_api):
4010 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204011 if not isinstance(expression, ast.Expression):
4012 return 'WATCHLISTS file must contain a valid expression'
4013 dictionary = expression.body
4014 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4015 return 'WATCHLISTS file must have single dict with exactly two entries'
4016
4017 first_key = dictionary.keys[0]
4018 first_value = dictionary.values[0]
4019 second_key = dictionary.keys[1]
4020 second_value = dictionary.values[1]
4021
4022 if (not isinstance(first_key, ast.Str) or
4023 first_key.s != 'WATCHLIST_DEFINITIONS' or
4024 not isinstance(first_value, ast.Dict)):
4025 return (
4026 'The first entry of the dict in WATCHLISTS file must be '
4027 'WATCHLIST_DEFINITIONS dict')
4028
4029 if (not isinstance(second_key, ast.Str) or
4030 second_key.s != 'WATCHLISTS' or
4031 not isinstance(second_value, ast.Dict)):
4032 return (
4033 'The second entry of the dict in WATCHLISTS file must be '
4034 'WATCHLISTS dict')
4035
Sergey Ulanov4af16052018-11-08 02:41:464036 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134037
4038
Saagar Sanghavifceeaae2020-08-12 16:40:364039def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:134040 for f in input_api.AffectedFiles(include_deletes=False):
4041 if f.LocalPath() == 'WATCHLISTS':
4042 contents = input_api.ReadFile(f, 'r')
4043
4044 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204045 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134046 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204047 # Get an AST tree for it and scan the tree for detailed style checking.
4048 expression = input_api.ast.parse(
4049 contents, filename='WATCHLISTS', mode='eval')
4050 except ValueError as e:
4051 return [output_api.PresubmitError(
4052 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4053 except SyntaxError as e:
4054 return [output_api.PresubmitError(
4055 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4056 except TypeError as e:
4057 return [output_api.PresubmitError(
4058 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134059
Sergey Ulanov4af16052018-11-08 02:41:464060 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204061 if result is not None:
4062 return [output_api.PresubmitError(result)]
4063 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134064
4065 return []
4066
4067
Saagar Sanghavifceeaae2020-08-12 16:40:364068def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194069 """Checks that newly added header files have corresponding GN changes.
4070 Note that this is only a heuristic. To be precise, run script:
4071 build/check_gn_headers.py.
4072 """
4073
4074 def headers(f):
4075 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444076 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194077
4078 new_headers = []
4079 for f in input_api.AffectedSourceFiles(headers):
4080 if f.Action() != 'A':
4081 continue
4082 new_headers.append(f.LocalPath())
4083
4084 def gn_files(f):
James Cook24a504192020-07-23 00:08:444085 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194086
4087 all_gn_changed_contents = ''
4088 for f in input_api.AffectedSourceFiles(gn_files):
4089 for _, line in f.ChangedContents():
4090 all_gn_changed_contents += line
4091
4092 problems = []
4093 for header in new_headers:
4094 basename = input_api.os_path.basename(header)
4095 if basename not in all_gn_changed_contents:
4096 problems.append(header)
4097
4098 if problems:
4099 return [output_api.PresubmitPromptWarning(
4100 'Missing GN changes for new header files', items=sorted(problems),
4101 long_text='Please double check whether newly added header files need '
4102 'corresponding changes in gn or gni files.\nThis checking is only a '
4103 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4104 'Read https://crbug.com/661774 for more info.')]
4105 return []
4106
4107
Saagar Sanghavifceeaae2020-08-12 16:40:364108def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024109 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4110
4111 This assumes we won't intentionally reference one product from the other
4112 product.
4113 """
4114 all_problems = []
4115 test_cases = [{
4116 "filename_postfix": "google_chrome_strings.grd",
4117 "correct_name": "Chrome",
4118 "incorrect_name": "Chromium",
4119 }, {
4120 "filename_postfix": "chromium_strings.grd",
4121 "correct_name": "Chromium",
4122 "incorrect_name": "Chrome",
4123 }]
4124
4125 for test_case in test_cases:
4126 problems = []
4127 filename_filter = lambda x: x.LocalPath().endswith(
4128 test_case["filename_postfix"])
4129
4130 # Check each new line. Can yield false positives in multiline comments, but
4131 # easier than trying to parse the XML because messages can have nested
4132 # children, and associating message elements with affected lines is hard.
4133 for f in input_api.AffectedSourceFiles(filename_filter):
4134 for line_num, line in f.ChangedContents():
4135 if "<message" in line or "<!--" in line or "-->" in line:
4136 continue
4137 if test_case["incorrect_name"] in line:
4138 problems.append(
4139 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4140
4141 if problems:
4142 message = (
4143 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4144 % (test_case["correct_name"], test_case["correct_name"],
4145 test_case["incorrect_name"]))
4146 all_problems.append(
4147 output_api.PresubmitPromptWarning(message, items=problems))
4148
4149 return all_problems
4150
4151
Saagar Sanghavifceeaae2020-08-12 16:40:364152def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514153 # TODO(crbug.com/941824): We need to make sure the entries in
4154 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4155 # so that users of //buildtools in other projects get the same tooling
4156 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4157 # support to gclient, we can eliminate the duplication and delete
4158 # this presubmit check.
4159
4160 # Update this regexp if new revisions are added to the files.
4161 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264162 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514163
4164 # If a user is changing one revision, they need to change the same
4165 # line in both files. This means that any given change should contain
4166 # exactly the same list of changed lines that match the regexps. The
4167 # replace(' ', '') call allows us to ignore whitespace changes to the
4168 # lines. The 'long_text' parameter to the error will contain the
4169 # list of changed lines in both files, which should make it easy enough
4170 # to spot the error without going overboard in this implementation.
4171 revs_changes = {
4172 'DEPS': {},
4173 'buildtools/DEPS': {},
4174 }
4175 long_text = ''
4176
4177 for f in input_api.AffectedFiles(
4178 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4179 for line_num, line in f.ChangedContents():
4180 if rev_regexp.search(line):
4181 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4182 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4183
4184 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4185 return [output_api.PresubmitError(
4186 'Change buildtools revisions in sync in both //DEPS and '
4187 '//buildtools/DEPS.', long_text=long_text + '\n')]
4188 else:
4189 return []
4190
4191
Saagar Sanghavifceeaae2020-08-12 16:40:364192def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364193 """Avoid large files, especially binary files, in the repository since
4194 git doesn't scale well for those. They will be in everyone's repo
4195 clones forever, forever making Chromium slower to clone and work
4196 with."""
4197
4198 # Uploading files to cloud storage is not trivial so we don't want
4199 # to set the limit too low, but the upper limit for "normal" large
4200 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4201 # anything over 20 MB is exceptional.
4202 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4203
4204 too_large_files = []
4205 for f in input_api.AffectedFiles():
4206 # Check both added and modified files (but not deleted files).
4207 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384208 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364209 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4210 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4211
4212 if too_large_files:
4213 message = (
4214 'Do not commit large files to git since git scales badly for those.\n' +
4215 'Instead put the large files in cloud storage and use DEPS to\n' +
4216 'fetch them.\n' + '\n'.join(too_large_files)
4217 )
4218 return [output_api.PresubmitError(
4219 'Too large files found in commit', long_text=message + '\n')]
4220 else:
4221 return []
4222
Max Morozb47503b2019-08-08 21:03:274223
Saagar Sanghavifceeaae2020-08-12 16:40:364224def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274225 """Checks specific for fuzz target sources."""
4226 EXPORTED_SYMBOLS = [
4227 'LLVMFuzzerInitialize',
4228 'LLVMFuzzerCustomMutator',
4229 'LLVMFuzzerCustomCrossOver',
4230 'LLVMFuzzerMutate',
4231 ]
4232
4233 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4234
4235 def FilterFile(affected_file):
4236 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444237 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4238 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274239
4240 return input_api.FilterSourceFile(
4241 affected_file,
James Cook24a504192020-07-23 00:08:444242 files_to_check=[files_to_check],
4243 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274244
4245 files_with_missing_header = []
4246 for f in input_api.AffectedSourceFiles(FilterFile):
4247 contents = input_api.ReadFile(f, 'r')
4248 if REQUIRED_HEADER in contents:
4249 continue
4250
4251 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4252 files_with_missing_header.append(f.LocalPath())
4253
4254 if not files_with_missing_header:
4255 return []
4256
4257 long_text = (
4258 'If you define any of the libFuzzer optional functions (%s), it is '
4259 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4260 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4261 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4262 'to access command line arguments passed to the fuzzer. Instead, prefer '
4263 'static initialization and shared resources as documented in '
4264 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4265 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4266 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4267 )
4268
4269 return [output_api.PresubmitPromptWarning(
4270 message="Missing '%s' in:" % REQUIRED_HEADER,
4271 items=files_with_missing_header,
4272 long_text=long_text)]
4273
4274
Mohamed Heikald048240a2019-11-12 16:57:374275def _CheckNewImagesWarning(input_api, output_api):
4276 """
4277 Warns authors who add images into the repo to make sure their images are
4278 optimized before committing.
4279 """
4280 images_added = False
4281 image_paths = []
4282 errors = []
4283 filter_lambda = lambda x: input_api.FilterSourceFile(
4284 x,
James Cook24a504192020-07-23 00:08:444285 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4286 + input_api.DEFAULT_FILES_TO_SKIP),
4287 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374288 )
4289 for f in input_api.AffectedFiles(
4290 include_deletes=False, file_filter=filter_lambda):
4291 local_path = f.LocalPath().lower()
4292 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4293 images_added = True
4294 image_paths.append(f)
4295 if images_added:
4296 errors.append(output_api.PresubmitPromptWarning(
4297 'It looks like you are trying to commit some images. If these are '
4298 'non-test-only images, please make sure to read and apply the tips in '
4299 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4300 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4301 'FYI only and will not block your CL on the CQ.', image_paths))
4302 return errors
4303
4304
Saagar Sanghavifceeaae2020-08-12 16:40:364305def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574306 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224307 results = []
dgnaa68d5e2015-06-10 10:08:224308 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174309 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224310 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294311 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064312 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4313 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424314 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184315 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574316 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374317 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154318 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574319 return results
4320
Saagar Sanghavifceeaae2020-08-12 16:40:364321def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574322 """Groups commit checks that target android code."""
4323 results = []
4324 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224325 return results
4326
Chris Hall59f8d0c72020-05-01 07:31:194327# TODO(chrishall): could we additionally match on any path owned by
4328# ui/accessibility/OWNERS ?
4329_ACCESSIBILITY_PATHS = (
4330 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4331 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4332 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4333 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4334 r"^content[\\/]browser[\\/]accessibility[\\/]",
4335 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4336 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4337 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4338 r"^ui[\\/]accessibility[\\/]",
4339 r"^ui[\\/]views[\\/]accessibility[\\/]",
4340)
4341
Saagar Sanghavifceeaae2020-08-12 16:40:364342def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194343 """Checks that commits to accessibility code contain an AX-Relnotes field in
4344 their commit message."""
4345 def FileFilter(affected_file):
4346 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444347 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194348
4349 # Only consider changes affecting accessibility paths.
4350 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4351 return []
4352
Akihiro Ota08108e542020-05-20 15:30:534353 # AX-Relnotes can appear in either the description or the footer.
4354 # When searching the description, require 'AX-Relnotes:' to appear at the
4355 # beginning of a line.
4356 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4357 description_has_relnotes = any(ax_regex.match(line)
4358 for line in input_api.change.DescriptionText().lower().splitlines())
4359
4360 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4361 'AX-Relnotes', [])
4362 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194363 return []
4364
4365 # TODO(chrishall): link to Relnotes documentation in message.
4366 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4367 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4368 "user-facing changes"
4369 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4370 "user-facing effects"
4371 "\n if this is confusing or annoying then please contact members "
4372 "of ui/accessibility/OWNERS.")
4373
4374 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224375
Saagar Sanghavifceeaae2020-08-12 16:40:364376def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394377 """Checks common to both upload and commit."""
4378 results = []
4379 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384380 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544381 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084382
4383 author = input_api.change.author_email
4384 if author and author not in _KNOWN_ROBOTS:
4385 results.extend(
4386 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4387
[email protected]9f919cc2013-07-31 03:04:044388 results.extend(
4389 input_api.canned_checks.CheckChangeHasNoTabs(
4390 input_api,
4391 output_api,
4392 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434393 results.extend(input_api.RunTests(
4394 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244395
Edward Lesmesce51df52020-08-04 22:10:174396 dirmd_bin = input_api.os_path.join(
4397 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4398 results.extend(input_api.RunTests(
4399 input_api.canned_checks.CheckDirMetadataFormat(
4400 input_api, output_api, dirmd_bin)))
4401 results.extend(
4402 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4403 input_api, output_api))
4404
Vaclav Brozekcdc7defb2018-03-20 09:54:354405 for f in input_api.AffectedFiles():
4406 path, name = input_api.os_path.split(f.LocalPath())
4407 if name == 'PRESUBMIT.py':
4408 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004409 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4410 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074411 # The PRESUBMIT.py file (and the directory containing it) might
4412 # have been affected by being moved or removed, so only try to
4413 # run the tests if they still exist.
4414 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4415 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444416 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394417 return results
[email protected]1f7b4172010-01-28 01:17:344418
[email protected]b337cb5b2011-01-23 21:24:054419
Saagar Sanghavifceeaae2020-08-12 16:40:364420def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494421 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4422 if f.LocalPath().endswith(('.orig', '.rej'))]
4423 if problems:
4424 return [output_api.PresubmitError(
4425 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034426 else:
4427 return []
[email protected]b8079ae4a2012-12-05 19:56:494428
4429
Saagar Sanghavifceeaae2020-08-12 16:40:364430def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214431 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4432 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4433 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074434 include_re = input_api.re.compile(
4435 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4436 extension_re = input_api.re.compile(r'\.[a-z]+$')
4437 errors = []
4438 for f in input_api.AffectedFiles():
4439 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4440 continue
4441 found_line_number = None
4442 found_macro = None
4443 for line_num, line in f.ChangedContents():
4444 match = macro_re.search(line)
4445 if match:
4446 found_line_number = line_num
4447 found_macro = match.group(2)
4448 break
4449 if not found_line_number:
4450 continue
4451
4452 found_include = False
4453 for line in f.NewContents():
4454 if include_re.search(line):
4455 found_include = True
4456 break
4457 if found_include:
4458 continue
4459
4460 if not f.LocalPath().endswith('.h'):
4461 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4462 try:
4463 content = input_api.ReadFile(primary_header_path, 'r')
4464 if include_re.search(content):
4465 continue
4466 except IOError:
4467 pass
4468 errors.append('%s:%d %s macro is used without including build/'
4469 'build_config.h.'
4470 % (f.LocalPath(), found_line_number, found_macro))
4471 if errors:
4472 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4473 return []
4474
4475
[email protected]b00342e7f2013-03-26 16:21:544476def _DidYouMeanOSMacro(bad_macro):
4477 try:
4478 return {'A': 'OS_ANDROID',
4479 'B': 'OS_BSD',
4480 'C': 'OS_CHROMEOS',
4481 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444482 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544483 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444484 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544485 'N': 'OS_NACL',
4486 'O': 'OS_OPENBSD',
4487 'P': 'OS_POSIX',
4488 'S': 'OS_SOLARIS',
4489 'W': 'OS_WIN'}[bad_macro[3].upper()]
4490 except KeyError:
4491 return ''
4492
4493
4494def _CheckForInvalidOSMacrosInFile(input_api, f):
4495 """Check for sensible looking, totally invalid OS macros."""
4496 preprocessor_statement = input_api.re.compile(r'^\s*#')
4497 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4498 results = []
4499 for lnum, line in f.ChangedContents():
4500 if preprocessor_statement.search(line):
4501 for match in os_macro.finditer(line):
4502 if not match.group(1) in _VALID_OS_MACROS:
4503 good = _DidYouMeanOSMacro(match.group(1))
4504 did_you_mean = ' (did you mean %s?)' % good if good else ''
4505 results.append(' %s:%d %s%s' % (f.LocalPath(),
4506 lnum,
4507 match.group(1),
4508 did_you_mean))
4509 return results
4510
4511
Saagar Sanghavifceeaae2020-08-12 16:40:364512def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544513 """Check all affected files for invalid OS macros."""
4514 bad_macros = []
tzik3f295992018-12-04 20:32:234515 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474516 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544517 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4518
4519 if not bad_macros:
4520 return []
4521
4522 return [output_api.PresubmitError(
4523 'Possibly invalid OS macro[s] found. Please fix your code\n'
4524 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4525
lliabraa35bab3932014-10-01 12:16:444526
4527def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4528 """Check all affected files for invalid "if defined" macros."""
4529 ALWAYS_DEFINED_MACROS = (
4530 "TARGET_CPU_PPC",
4531 "TARGET_CPU_PPC64",
4532 "TARGET_CPU_68K",
4533 "TARGET_CPU_X86",
4534 "TARGET_CPU_ARM",
4535 "TARGET_CPU_MIPS",
4536 "TARGET_CPU_SPARC",
4537 "TARGET_CPU_ALPHA",
4538 "TARGET_IPHONE_SIMULATOR",
4539 "TARGET_OS_EMBEDDED",
4540 "TARGET_OS_IPHONE",
4541 "TARGET_OS_MAC",
4542 "TARGET_OS_UNIX",
4543 "TARGET_OS_WIN32",
4544 )
4545 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4546 results = []
4547 for lnum, line in f.ChangedContents():
4548 for match in ifdef_macro.finditer(line):
4549 if match.group(1) in ALWAYS_DEFINED_MACROS:
4550 always_defined = ' %s is always defined. ' % match.group(1)
4551 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4552 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4553 lnum,
4554 always_defined,
4555 did_you_mean))
4556 return results
4557
4558
Saagar Sanghavifceeaae2020-08-12 16:40:364559def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444560 """Check all affected files for invalid "if defined" macros."""
4561 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054562 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444563 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054564 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214565 continue
lliabraa35bab3932014-10-01 12:16:444566 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4567 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4568
4569 if not bad_macros:
4570 return []
4571
4572 return [output_api.PresubmitError(
4573 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4574 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4575 bad_macros)]
4576
4577
Saagar Sanghavifceeaae2020-08-12 16:40:364578def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044579 """Check for same IPC rules described in
4580 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4581 """
4582 base_pattern = r'IPC_ENUM_TRAITS\('
4583 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4584 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4585
4586 problems = []
4587 for f in input_api.AffectedSourceFiles(None):
4588 local_path = f.LocalPath()
4589 if not local_path.endswith('.h'):
4590 continue
4591 for line_number, line in f.ChangedContents():
4592 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4593 problems.append(
4594 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4595
4596 if problems:
4597 return [output_api.PresubmitPromptWarning(
4598 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4599 else:
4600 return []
4601
[email protected]b00342e7f2013-03-26 16:21:544602
Saagar Sanghavifceeaae2020-08-12 16:40:364603def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054604 """Check to make sure no files being submitted have long paths.
4605 This causes issues on Windows.
4606 """
4607 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194608 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054609 local_path = f.LocalPath()
4610 # Windows has a path limit of 260 characters. Limit path length to 200 so
4611 # that we have some extra for the prefix on dev machines and the bots.
4612 if len(local_path) > 200:
4613 problems.append(local_path)
4614
4615 if problems:
4616 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4617 else:
4618 return []
4619
4620
Saagar Sanghavifceeaae2020-08-12 16:40:364621def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144622 """Check that header files have proper guards against multiple inclusion.
4623 If a file should not have such guards (and it probably should) then it
4624 should include the string "no-include-guard-because-multiply-included".
4625 """
Daniel Bratell6a75baef62018-06-04 10:04:454626 def is_chromium_header_file(f):
4627 # We only check header files under the control of the Chromium
4628 # project. That is, those outside third_party apart from
4629 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324630 # We also exclude *_message_generator.h headers as they use
4631 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454632 file_with_path = input_api.os_path.normpath(f.LocalPath())
4633 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324634 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454635 (not file_with_path.startswith('third_party') or
4636 file_with_path.startswith(
4637 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144638
4639 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344640 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144641
4642 errors = []
4643
Daniel Bratell6a75baef62018-06-04 10:04:454644 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144645 guard_name = None
4646 guard_line_number = None
4647 seen_guard_end = False
4648
4649 file_with_path = input_api.os_path.normpath(f.LocalPath())
4650 base_file_name = input_api.os_path.splitext(
4651 input_api.os_path.basename(file_with_path))[0]
4652 upper_base_file_name = base_file_name.upper()
4653
4654 expected_guard = replace_special_with_underscore(
4655 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144656
4657 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574658 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4659 # are too many (1000+) files with slight deviations from the
4660 # coding style. The most important part is that the include guard
4661 # is there, and that it's unique, not the name so this check is
4662 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144663 #
4664 # As code becomes more uniform, this could be made stricter.
4665
4666 guard_name_pattern_list = [
4667 # Anything with the right suffix (maybe with an extra _).
4668 r'\w+_H__?',
4669
Daniel Bratell39b5b062018-05-16 18:09:574670 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144671 r'\w+_h',
4672
4673 # Anything including the uppercase name of the file.
4674 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4675 upper_base_file_name)) + r'\w*',
4676 ]
4677 guard_name_pattern = '|'.join(guard_name_pattern_list)
4678 guard_pattern = input_api.re.compile(
4679 r'#ifndef\s+(' + guard_name_pattern + ')')
4680
4681 for line_number, line in enumerate(f.NewContents()):
4682 if 'no-include-guard-because-multiply-included' in line:
4683 guard_name = 'DUMMY' # To not trigger check outside the loop.
4684 break
4685
4686 if guard_name is None:
4687 match = guard_pattern.match(line)
4688 if match:
4689 guard_name = match.group(1)
4690 guard_line_number = line_number
4691
Daniel Bratell39b5b062018-05-16 18:09:574692 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454693 # don't match the chromium style guide, but new files should
4694 # get it right.
4695 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574696 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144697 errors.append(output_api.PresubmitPromptWarning(
4698 'Header using the wrong include guard name %s' % guard_name,
4699 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574700 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144701 else:
4702 # The line after #ifndef should have a #define of the same name.
4703 if line_number == guard_line_number + 1:
4704 expected_line = '#define %s' % guard_name
4705 if line != expected_line:
4706 errors.append(output_api.PresubmitPromptWarning(
4707 'Missing "%s" for include guard' % expected_line,
4708 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4709 'Expected: %r\nGot: %r' % (expected_line, line)))
4710
4711 if not seen_guard_end and line == '#endif // %s' % guard_name:
4712 seen_guard_end = True
4713 elif seen_guard_end:
4714 if line.strip() != '':
4715 errors.append(output_api.PresubmitPromptWarning(
4716 'Include guard %s not covering the whole file' % (
4717 guard_name), [f.LocalPath()]))
4718 break # Nothing else to check and enough to warn once.
4719
4720 if guard_name is None:
4721 errors.append(output_api.PresubmitPromptWarning(
4722 'Missing include guard %s' % expected_guard,
4723 [f.LocalPath()],
4724 'Missing include guard in %s\n'
4725 'Recommended name: %s\n'
4726 'This check can be disabled by having the string\n'
4727 'no-include-guard-because-multiply-included in the header.' %
4728 (f.LocalPath(), expected_guard)))
4729
4730 return errors
4731
4732
Saagar Sanghavifceeaae2020-08-12 16:40:364733def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234734 """Check source code and known ascii text files for Windows style line
4735 endings.
4736 """
earthdok1b5e0ee2015-03-10 15:19:104737 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234738
4739 file_inclusion_pattern = (
4740 known_text_files,
4741 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4742 )
4743
mostynbb639aca52015-01-07 20:31:234744 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534745 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444746 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534747 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504748 include_file = False
4749 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234750 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504751 include_file = True
4752 if include_file:
4753 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234754
4755 if problems:
4756 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4757 'these files to contain Windows style line endings?\n' +
4758 '\n'.join(problems))]
4759
4760 return []
4761
4762
Saagar Sanghavifceeaae2020-08-12 16:40:364763def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134764 """Checks that all source files use SYSLOG properly."""
4765 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364766 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564767 for line_number, line in f.ChangedContents():
4768 if 'SYSLOG' in line:
4769 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4770
pastarmovj89f7ee12016-09-20 14:58:134771 if syslog_files:
4772 return [output_api.PresubmitPromptWarning(
4773 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4774 ' calls.\nFiles to check:\n', items=syslog_files)]
4775 return []
4776
4777
[email protected]1f7b4172010-01-28 01:17:344778def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364779 if input_api.version < [2, 0, 0]:
4780 return [output_api.PresubmitError("Your depot_tools is out of date. "
4781 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4782 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344783 results = []
scottmg39b29952014-12-08 18:31:284784 results.extend(
jam93a6ee792017-02-08 23:59:224785 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544786 return results
[email protected]ca8d1982009-02-19 16:33:124787
4788
[email protected]1bfb8322014-04-23 01:02:414789def GetTryServerMasterForBot(bot):
4790 """Returns the Try Server master for the given bot.
4791
[email protected]0bb112362014-07-26 04:38:324792 It tries to guess the master from the bot name, but may still fail
4793 and return None. There is no longer a default master.
4794 """
4795 # Potentially ambiguous bot names are listed explicitly.
4796 master_map = {
tandriie5587792016-07-14 00:34:504797 'chromium_presubmit': 'master.tryserver.chromium.linux',
4798 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414799 }
[email protected]0bb112362014-07-26 04:38:324800 master = master_map.get(bot)
4801 if not master:
wnwen4fbaab82016-05-25 12:54:364802 if 'android' in bot:
tandriie5587792016-07-14 00:34:504803 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364804 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504805 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324806 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504807 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324808 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504809 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324810 return master
[email protected]1bfb8322014-04-23 01:02:414811
4812
[email protected]ca8d1982009-02-19 16:33:124813def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364814 if input_api.version < [2, 0, 0]:
4815 return [output_api.PresubmitError("Your depot_tools is out of date. "
4816 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4817 "but your version is %d.%d.%d" % tuple(input_api.version))]
4818
[email protected]fe5f57c52009-06-05 14:25:544819 results = []
[email protected]fe5f57c52009-06-05 14:25:544820 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274821 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344822 input_api,
4823 output_api,
[email protected]2fdd1f362013-01-16 03:56:034824 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274825
jam93a6ee792017-02-08 23:59:224826 results.extend(
4827 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544828 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4829 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384830 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4831 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414832 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4833 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544834 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144835
4836
Saagar Sanghavifceeaae2020-08-12 16:40:364837def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264838 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024839 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4840 # footer is set to true.
4841 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264842 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024843 footer.lower()
4844 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264845 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024846
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144847 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264848 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144849 import sys
4850 from io import StringIO
4851
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144852 new_or_added_paths = set(f.LocalPath()
4853 for f in input_api.AffectedFiles()
4854 if (f.Action() == 'A' or f.Action() == 'M'))
4855 removed_paths = set(f.LocalPath()
4856 for f in input_api.AffectedFiles(include_deletes=True)
4857 if f.Action() == 'D')
4858
Andrew Grieve0e8790c2020-09-03 17:27:324859 affected_grds = [
4860 f for f in input_api.AffectedFiles()
4861 if f.LocalPath().endswith(('.grd', '.grdp'))
4862 ]
4863 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164864 if not affected_grds:
4865 return []
4866
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144867 affected_png_paths = [f.AbsoluteLocalPath()
4868 for f in input_api.AffectedFiles()
4869 if (f.LocalPath().endswith('.png'))]
4870
4871 # Check for screenshots. Developers can upload screenshots using
4872 # tools/translation/upload_screenshots.py which finds and uploads
4873 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4874 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4875 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4876 #
4877 # The logic here is as follows:
4878 #
4879 # - If the CL has a .png file under the screenshots directory for a grd
4880 # file, warn the developer. Actual images should never be checked into the
4881 # Chrome repo.
4882 #
4883 # - If the CL contains modified or new messages in grd files and doesn't
4884 # contain the corresponding .sha1 files, warn the developer to add images
4885 # and upload them via tools/translation/upload_screenshots.py.
4886 #
4887 # - If the CL contains modified or new messages in grd files and the
4888 # corresponding .sha1 files, everything looks good.
4889 #
4890 # - If the CL contains removed messages in grd files but the corresponding
4891 # .sha1 files aren't removed, warn the developer to remove them.
4892 unnecessary_screenshots = []
4893 missing_sha1 = []
4894 unnecessary_sha1_files = []
4895
Rainhard Findlingfc31844c52020-05-15 09:58:264896 # This checks verifies that the ICU syntax of messages this CL touched is
4897 # valid, and reports any found syntax errors.
4898 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4899 # without developers being aware of them. Later on, such ICU syntax errors
4900 # break message extraction for translation, hence would block Chromium
4901 # translations until they are fixed.
4902 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144903
4904 def _CheckScreenshotAdded(screenshots_dir, message_id):
4905 sha1_path = input_api.os_path.join(
4906 screenshots_dir, message_id + '.png.sha1')
4907 if sha1_path not in new_or_added_paths:
4908 missing_sha1.append(sha1_path)
4909
4910
4911 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4912 sha1_path = input_api.os_path.join(
4913 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034914 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144915 unnecessary_sha1_files.append(sha1_path)
4916
Rainhard Findlingfc31844c52020-05-15 09:58:264917
4918 def _ValidateIcuSyntax(text, level, signatures):
4919 """Validates ICU syntax of a text string.
4920
4921 Check if text looks similar to ICU and checks for ICU syntax correctness
4922 in this case. Reports various issues with ICU syntax and values of
4923 variants. Supports checking of nested messages. Accumulate information of
4924 each ICU messages found in the text for further checking.
4925
4926 Args:
4927 text: a string to check.
4928 level: a number of current nesting level.
4929 signatures: an accumulator, a list of tuple of (level, variable,
4930 kind, variants).
4931
4932 Returns:
4933 None if a string is not ICU or no issue detected.
4934 A tuple of (message, start index, end index) if an issue detected.
4935 """
4936 valid_types = {
4937 'plural': (frozenset(
4938 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4939 frozenset(['=1', 'other'])),
4940 'selectordinal': (frozenset(
4941 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4942 frozenset(['one', 'other'])),
4943 'select': (frozenset(), frozenset(['other'])),
4944 }
4945
4946 # Check if the message looks like an attempt to use ICU
4947 # plural. If yes - check if its syntax strictly matches ICU format.
4948 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4949 if not like:
4950 signatures.append((level, None, None, None))
4951 return
4952
4953 # Check for valid prefix and suffix
4954 m = re.match(
4955 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4956 r'(plural|selectordinal|select),\s*'
4957 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4958 if not m:
4959 return (('This message looks like an ICU plural, '
4960 'but does not follow ICU syntax.'), like.start(), like.end())
4961 starting, variable, kind, variant_pairs = m.groups()
4962 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4963 if depth:
4964 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4965 len(text))
4966 first = text[0]
4967 ending = text[last_pos:]
4968 if not starting:
4969 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4970 last_pos)
4971 if not ending or '}' not in ending:
4972 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4973 last_pos)
4974 elif first != '{':
4975 return (
4976 ('Invalid ICU format. Extra characters at the start of a complex '
4977 'message (go/icu-message-migration): "%s"') %
4978 starting, 0, len(starting))
4979 elif ending != '}':
4980 return (('Invalid ICU format. Extra characters at the end of a complex '
4981 'message (go/icu-message-migration): "%s"')
4982 % ending, last_pos - 1, len(text) - 1)
4983 if kind not in valid_types:
4984 return (('Unknown ICU message type %s. '
4985 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4986 known, required = valid_types[kind]
4987 defined_variants = set()
4988 for variant, variant_range, value, value_range in variants:
4989 start, end = variant_range
4990 if variant in defined_variants:
4991 return ('Variant "%s" is defined more than once' % variant,
4992 start, end)
4993 elif known and variant not in known:
4994 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4995 start, end)
4996 defined_variants.add(variant)
4997 # Check for nested structure
4998 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4999 if res:
5000 return (res[0], res[1] + value_range[0] + 1,
5001 res[2] + value_range[0] + 1)
5002 missing = required - defined_variants
5003 if missing:
5004 return ('Required variants missing: %s' % ', '.join(missing), 0,
5005 len(text))
5006 signatures.append((level, variable, kind, defined_variants))
5007
5008
5009 def _ParseIcuVariants(text, offset=0):
5010 """Parse variants part of ICU complex message.
5011
5012 Builds a tuple of variant names and values, as well as
5013 their offsets in the input string.
5014
5015 Args:
5016 text: a string to parse
5017 offset: additional offset to add to positions in the text to get correct
5018 position in the complete ICU string.
5019
5020 Returns:
5021 List of tuples, each tuple consist of four fields: variant name,
5022 variant name span (tuple of two integers), variant value, value
5023 span (tuple of two integers).
5024 """
5025 depth, start, end = 0, -1, -1
5026 variants = []
5027 key = None
5028 for idx, char in enumerate(text):
5029 if char == '{':
5030 if not depth:
5031 start = idx
5032 chunk = text[end + 1:start]
5033 key = chunk.strip()
5034 pos = offset + end + 1 + chunk.find(key)
5035 span = (pos, pos + len(key))
5036 depth += 1
5037 elif char == '}':
5038 if not depth:
5039 return variants, depth, offset + idx
5040 depth -= 1
5041 if not depth:
5042 end = idx
5043 variants.append((key, span, text[start:end + 1], (offset + start,
5044 offset + end + 1)))
5045 return variants, depth, offset + end + 1
5046
meacer8c0d3832019-12-26 21:46:165047 try:
5048 old_sys_path = sys.path
5049 sys.path = sys.path + [input_api.os_path.join(
5050 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5051 from helper import grd_helper
5052 finally:
5053 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145054
5055 for f in affected_grds:
5056 file_path = f.LocalPath()
5057 old_id_to_msg_map = {}
5058 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385059 # Note that this code doesn't check if the file has been deleted. This is
5060 # OK because it only uses the old and new file contents and doesn't load
5061 # the file via its path.
5062 # It's also possible that a file's content refers to a renamed or deleted
5063 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5064 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5065 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145066 if file_path.endswith('.grdp'):
5067 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585068 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395069 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145070 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585071 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395072 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145073 else:
meacerff8a9b62019-12-10 19:43:585074 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145075 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585076 old_id_to_msg_map = grd_helper.GetGrdMessages(
5077 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145078 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585079 new_id_to_msg_map = grd_helper.GetGrdMessages(
5080 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145081
Rainhard Findlingd8d04372020-08-13 13:30:095082 grd_name, ext = input_api.os_path.splitext(
5083 input_api.os_path.basename(file_path))
5084 screenshots_dir = input_api.os_path.join(
5085 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5086
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145087 # Compute added, removed and modified message IDs.
5088 old_ids = set(old_id_to_msg_map)
5089 new_ids = set(new_id_to_msg_map)
5090 added_ids = new_ids - old_ids
5091 removed_ids = old_ids - new_ids
5092 modified_ids = set([])
5093 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355094 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095095 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5096 # The message content itself changed. Require an updated screenshot.
5097 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355098 elif old_id_to_msg_map[key].attrs['meaning'] != \
5099 new_id_to_msg_map[key].attrs['meaning']:
5100 # The message meaning changed. Ensure there is a screenshot for it.
5101 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5102 if sha1_path not in new_or_added_paths and not \
5103 input_api.os_path.exists(sha1_path):
5104 # There is neither a previous screenshot nor is a new one added now.
5105 # Require a screenshot.
5106 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145107
Rainhard Findlingfc31844c52020-05-15 09:58:265108 if run_screenshot_check:
5109 # Check the screenshot directory for .png files. Warn if there is any.
5110 for png_path in affected_png_paths:
5111 if png_path.startswith(screenshots_dir):
5112 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145113
Rainhard Findlingfc31844c52020-05-15 09:58:265114 for added_id in added_ids:
5115 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145116
Rainhard Findlingfc31844c52020-05-15 09:58:265117 for modified_id in modified_ids:
5118 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145119
Rainhard Findlingfc31844c52020-05-15 09:58:265120 for removed_id in removed_ids:
5121 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5122
5123 # Check new and changed strings for ICU syntax errors.
5124 for key in added_ids.union(modified_ids):
5125 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5126 err = _ValidateIcuSyntax(msg, 0, [])
5127 if err is not None:
5128 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145129
5130 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265131 if run_screenshot_check:
5132 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005133 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265134 'Do not include actual screenshots in the changelist. Run '
5135 'tools/translate/upload_screenshots.py to upload them instead:',
5136 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145137
Rainhard Findlingfc31844c52020-05-15 09:58:265138 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005139 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265140 'You are adding or modifying UI strings.\n'
5141 'To ensure the best translations, take screenshots of the relevant UI '
5142 '(https://g.co/chrome/translation) and add these files to your '
5143 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145144
Rainhard Findlingfc31844c52020-05-15 09:58:265145 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005146 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265147 'You removed strings associated with these files. Remove:',
5148 sorted(unnecessary_sha1_files)))
5149 else:
5150 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5151 'screenshots check.'))
5152
5153 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075154 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265155 'ICU syntax errors were found in the following strings (problems or '
5156 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145157
5158 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125159
5160
Saagar Sanghavifceeaae2020-08-12 16:40:365161def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125162 repo_root=None,
5163 translation_expectations_path=None,
5164 grd_files=None):
5165 import sys
5166 affected_grds = [f for f in input_api.AffectedFiles()
5167 if (f.LocalPath().endswith('.grd') or
5168 f.LocalPath().endswith('.grdp'))]
5169 if not affected_grds:
5170 return []
5171
5172 try:
5173 old_sys_path = sys.path
5174 sys.path = sys.path + [
5175 input_api.os_path.join(
5176 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5177 from helper import git_helper
5178 from helper import translation_helper
5179 finally:
5180 sys.path = old_sys_path
5181
5182 # Check that translation expectations can be parsed and we can get a list of
5183 # translatable grd files. |repo_root| and |translation_expectations_path| are
5184 # only passed by tests.
5185 if not repo_root:
5186 repo_root = input_api.PresubmitLocalPath()
5187 if not translation_expectations_path:
5188 translation_expectations_path = input_api.os_path.join(
5189 repo_root, 'tools', 'gritsettings',
5190 'translation_expectations.pyl')
5191 if not grd_files:
5192 grd_files = git_helper.list_grds_in_repository(repo_root)
5193
5194 try:
5195 translation_helper.get_translatable_grds(repo_root, grd_files,
5196 translation_expectations_path)
5197 except Exception as e:
5198 return [output_api.PresubmitNotifyResult(
5199 'Failed to get a list of translatable grd files. This happens when:\n'
5200 ' - One of the modified grd or grdp files cannot be parsed or\n'
5201 ' - %s is not updated.\n'
5202 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5203 return []
Ken Rockotc31f4832020-05-29 18:58:515204
5205
Saagar Sanghavifceeaae2020-08-12 16:40:365206def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515207 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095208 changed_mojoms = input_api.AffectedFiles(
5209 include_deletes=True,
5210 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515211 delta = []
5212 for mojom in changed_mojoms:
5213 old_contents = ''.join(mojom.OldContents()) or None
5214 new_contents = ''.join(mojom.NewContents()) or None
5215 delta.append({
5216 'filename': mojom.LocalPath(),
5217 'old': '\n'.join(mojom.OldContents()) or None,
5218 'new': '\n'.join(mojom.NewContents()) or None,
5219 })
5220
5221 process = input_api.subprocess.Popen(
5222 [input_api.python_executable,
5223 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5224 'public', 'tools', 'mojom',
5225 'check_stable_mojom_compatibility.py'),
5226 '--src-root', input_api.PresubmitLocalPath()],
5227 stdin=input_api.subprocess.PIPE,
5228 stdout=input_api.subprocess.PIPE,
5229 stderr=input_api.subprocess.PIPE,
5230 universal_newlines=True)
5231 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5232 if process.returncode:
5233 return [output_api.PresubmitError(
5234 'One or more [Stable] mojom definitions appears to have been changed '
5235 'in a way that is not backward-compatible.',
5236 long_text=error)]
5237 return []