blob: 538029ec0321a2683e97210df9dcf5d657377e3d [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[\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4471)
[email protected]ca8d1982009-02-19 16:33:1272
Daniel Bratell609102be2019-03-27 20:53:2173_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1574
[email protected]eea609a2011-11-18 13:10:1275_TEST_ONLY_WARNING = (
76 'You might be calling functions intended only for testing from\n'
77 'production code. It is OK to ignore this warning if you know what\n'
78 'you are doing, as the heuristics used to detect the situation are\n'
Mohamed Heikal5cf63162019-10-25 19:59:0779 'not perfect. The commit queue will not block on this warning,\n'
80 'however the android-binary-size trybot will block if the method\n'
81 'exists in the release apk.')
[email protected]eea609a2011-11-18 13:10:1282
83
[email protected]cf9b78f2012-11-14 11:40:2884_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4085 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2186 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
87 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2888
Michael Thiessen44457642020-02-06 00:24:1589# Format: Sequence of tuples containing:
90# * Full import path.
91# * Sequence of strings to show when the pattern matches.
92# * Sequence of path or filename exceptions to this rule
93_BANNED_JAVA_IMPORTS = (
94 (
Colin Blundell170d78c82020-03-12 13:56:0495 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:1596 (
97 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
98 ),
99 (
100 'net/android/javatests/src/org/chromium/net/'
101 'AndroidProxySelectorTest.java',
102 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04103 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15104 ),
105 ),
Michael Thiessened631912020-08-07 19:01:31106 (
107 'android.support.test.rule.UiThreadTestRule;',
108 (
109 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43110 '@org.chromium.base.test.UiThreadTest on test methods that should run '
111 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31112 ),
113 (),
114 ),
115 (
116 'android.support.test.annotation.UiThreadTest;',
117 (
118 'Do not use android.support.test.annotation.UiThreadTest, use '
119 'org.chromium.base.test.UiThreadTest instead. See '
120 'https://crbug.com/1111893.',
121 ),
122 ()
123 )
Michael Thiessen44457642020-02-06 00:24:15124)
wnwenbdc444e2016-05-25 13:44:15125
Daniel Bratell609102be2019-03-27 20:53:21126# Format: Sequence of tuples containing:
127# * String pattern or, if starting with a slash, a regular expression.
128# * Sequence of strings to show when the pattern matches.
129# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41130_BANNED_JAVA_FUNCTIONS = (
131 (
132 'StrictMode.allowThreadDiskReads()',
133 (
134 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
135 'directly.',
136 ),
137 False,
138 ),
139 (
140 'StrictMode.allowThreadDiskWrites()',
141 (
142 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
143 'directly.',
144 ),
145 False,
146 ),
Michael Thiessen0f2547e2020-07-27 21:55:36147 (
148 '.waitForIdleSync()',
149 (
150 'Do not use waitForIdleSync as it masks underlying issues. There is '
151 'almost always something else you should wait on instead.',
152 ),
153 False,
154 ),
Eric Stevensona9a980972017-09-23 00:04:41155)
156
Daniel Bratell609102be2019-03-27 20:53:21157# Format: Sequence of tuples containing:
158# * String pattern or, if starting with a slash, a regular expression.
159# * Sequence of strings to show when the pattern matches.
160# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59161_BANNED_OBJC_FUNCTIONS = (
162 (
163 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20164 (
165 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59166 'prohibited. Please use CrTrackingArea instead.',
167 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
168 ),
169 False,
170 ),
171 (
[email protected]eaae1972014-04-16 04:17:26172 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20173 (
174 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59175 'instead.',
176 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
177 ),
178 False,
179 ),
180 (
181 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20182 (
183 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59184 'Please use |convertPoint:(point) fromView:nil| instead.',
185 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
186 ),
187 True,
188 ),
189 (
190 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20191 (
192 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59193 'Please use |convertPoint:(point) toView:nil| instead.',
194 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
195 ),
196 True,
197 ),
198 (
199 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20200 (
201 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59202 'Please use |convertRect:(point) fromView:nil| instead.',
203 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
204 ),
205 True,
206 ),
207 (
208 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20209 (
210 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59211 'Please use |convertRect:(point) toView:nil| instead.',
212 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
213 ),
214 True,
215 ),
216 (
217 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20218 (
219 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59220 'Please use |convertSize:(point) fromView:nil| instead.',
221 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
222 ),
223 True,
224 ),
225 (
226 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20227 (
228 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59229 'Please use |convertSize:(point) toView:nil| instead.',
230 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
231 ),
232 True,
233 ),
jif65398702016-10-27 10:19:48234 (
235 r"/\s+UTF8String\s*]",
236 (
237 'The use of -[NSString UTF8String] is dangerous as it can return null',
238 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
239 'Please use |SysNSStringToUTF8| instead.',
240 ),
241 True,
242 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34243 (
244 r'__unsafe_unretained',
245 (
246 'The use of __unsafe_unretained is almost certainly wrong, unless',
247 'when interacting with NSFastEnumeration or NSInvocation.',
248 'Please use __weak in files build with ARC, nothing otherwise.',
249 ),
250 False,
251 ),
Avi Drissman7382afa02019-04-29 23:27:13252 (
253 'freeWhenDone:NO',
254 (
255 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
256 'Foundation types is prohibited.',
257 ),
258 True,
259 ),
[email protected]127f18ec2012-06-16 05:05:59260)
261
Daniel Bratell609102be2019-03-27 20:53:21262# Format: Sequence of tuples containing:
263# * String pattern or, if starting with a slash, a regular expression.
264# * Sequence of strings to show when the pattern matches.
265# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54266_BANNED_IOS_OBJC_FUNCTIONS = (
267 (
268 r'/\bTEST[(]',
269 (
270 'TEST() macro should not be used in Objective-C++ code as it does not ',
271 'drain the autorelease pool at the end of the test. Use TEST_F() ',
272 'macro instead with a fixture inheriting from PlatformTest (or a ',
273 'typedef).'
274 ),
275 True,
276 ),
277 (
278 r'/\btesting::Test\b',
279 (
280 'testing::Test should not be used in Objective-C++ code as it does ',
281 'not drain the autorelease pool at the end of the test. Use ',
282 'PlatformTest instead.'
283 ),
284 True,
285 ),
286)
287
Peter K. Lee6c03ccff2019-07-15 14:40:05288# Format: Sequence of tuples containing:
289# * String pattern or, if starting with a slash, a regular expression.
290# * Sequence of strings to show when the pattern matches.
291# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
292_BANNED_IOS_EGTEST_FUNCTIONS = (
293 (
294 r'/\bEXPECT_OCMOCK_VERIFY\b',
295 (
296 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
297 'it is meant for GTests. Use [mock verify] instead.'
298 ),
299 True,
300 ),
301)
302
danakj7a2b7082019-05-21 21:13:51303# Directories that contain deprecated Bind() or Callback types.
304# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36305# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51306# echo "-- $i"
danakj710b4c02019-11-28 16:08:45307# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51308# done
309#
310# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
311# when they have been converted to modern callback types (OnceCallback,
312# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
313# checks for them and prevent regressions.
314_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51315 '^base/callback.h', # Intentional.
Alexander Cooper6b447b22020-07-22 00:47:18316 '^chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc',
317 '^chrome/browser/apps/guest_view/',
318 '^chrome/browser/apps/platform_apps/shortcut_manager.cc',
319 '^chrome/browser/browsing_data/',
320 '^chrome/browser/captive_portal/captive_portal_browsertest.cc',
321 '^chrome/browser/chromeos/',
322 '^chrome/browser/component_updater/',
323 '^chrome/browser/custom_handlers/protocol_handler_registry.cc',
Peter Wen6367b882020-08-05 16:55:50324 '^chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc', # pylint: disable=line-too-long
Alexander Cooper6b447b22020-07-22 00:47:18325 '^chrome/browser/devtools/',
326 '^chrome/browser/download/',
327 '^chrome/browser/extensions/',
328 '^chrome/browser/external_protocol/external_protocol_handler.cc',
329 '^chrome/browser/history/',
330 '^chrome/browser/installable/installable_manager_browsertest.cc',
331 '^chrome/browser/lifetime/',
332 '^chrome/browser/media_galleries/',
333 '^chrome/browser/media/',
334 '^chrome/browser/metrics/',
335 '^chrome/browser/nacl_host/test/gdb_debug_stub_browsertest.cc',
Peter Wen6367b882020-08-05 16:55:50336 '^chrome/browser/nearby_sharing/client/nearby_share_api_call_flow_impl_unittest.cc', # pylint: disable=line-too-long
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/password_manager/',
343 '^chrome/browser/payments/payment_manifest_parser_browsertest.cc',
344 '^chrome/browser/pdf/pdf_extension_test.cc',
345 '^chrome/browser/plugins/',
346 '^chrome/browser/policy/',
347 '^chrome/browser/portal/portal_browsertest.cc',
348 '^chrome/browser/prefs/profile_pref_store_manager_unittest.cc',
349 '^chrome/browser/prerender/',
350 '^chrome/browser/previews/',
351 '^chrome/browser/printing/printing_message_filter.cc',
352 '^chrome/browser/profiles/',
353 '^chrome/browser/profiling_host/profiling_process_host.cc',
354 '^chrome/browser/push_messaging/',
355 '^chrome/browser/recovery/recovery_install_global_error.cc',
356 '^chrome/browser/renderer_context_menu/',
357 '^chrome/browser/renderer_host/pepper/',
358 '^chrome/browser/resource_coordinator/',
359 '^chrome/browser/resources/chromeos/accessibility/',
360 '^chrome/browser/rlz/chrome_rlz_tracker_delegate.cc',
361 '^chrome/browser/safe_browsing/',
362 '^chrome/browser/search_engines/',
363 '^chrome/browser/service_process/',
364 '^chrome/browser/signin/',
365 '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
366 '^chrome/browser/ssl/',
367 '^chrome/browser/subresource_filter/',
368 '^chrome/browser/supervised_user/',
369 '^chrome/browser/sync_file_system/',
370 '^chrome/browser/sync/',
371 '^chrome/browser/themes/theme_service.cc',
372 '^chrome/browser/thumbnail/cc/',
373 '^chrome/browser/tracing/chrome_tracing_delegate_browsertest.cc',
374 '^chrome/browser/translate/',
375 '^chrome/browser/ui/',
Alexander Cooper6b447b22020-07-22 00:47:18376 '^chrome/browser/web_applications/',
377 '^chrome/browser/win/',
danakj7a2b7082019-05-21 21:13:51378 '^chrome/services/',
379 '^chrome/test/',
380 '^chrome/tools/',
danakj7a2b7082019-05-21 21:13:51381 '^chromecast/media/',
danakj7a2b7082019-05-21 21:13:51382 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51383 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51384 '^components/arc/',
danakj7a2b7082019-05-21 21:13:51385 '^components/autofill/',
386 '^components/autofill_assistant/',
danakj7a2b7082019-05-21 21:13:51387 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51388 '^components/component_updater/',
389 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51390 '^components/drive/',
danakj7a2b7082019-05-21 21:13:51391 '^components/nacl/',
392 '^components/navigation_interception/',
danakj7a2b7082019-05-21 21:13:51393 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51394 '^components/password_manager/',
danakj7a2b7082019-05-21 21:13:51395 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51396 '^components/search_engines/',
danakj7a2b7082019-05-21 21:13:51397 '^components/security_interstitials/',
danakj7a2b7082019-05-21 21:13:51398 '^components/signin/',
danakj7a2b7082019-05-21 21:13:51399 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51400 '^components/ukm/',
danakj7a2b7082019-05-21 21:13:51401 '^components/webcrypto/',
Alan Cutter04a00642020-03-02 01:45:20402 '^extensions/browser/',
403 '^extensions/renderer/',
Alexander Cooper922f2112020-07-22 16:27:43404 '^google_apis/drive/',
danakj7a2b7082019-05-21 21:13:51405 '^ios/chrome/',
406 '^ios/components/',
407 '^ios/net/',
408 '^ios/web/',
409 '^ios/web_view/',
410 '^ipc/',
danakjc8576092019-11-26 19:01:36411 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51412 '^media/cast/',
413 '^media/cdm/',
danakj7a2b7082019-05-21 21:13:51414 '^media/filters/',
danakj7a2b7082019-05-21 21:13:51415 '^media/gpu/',
416 '^media/mojo/',
Steve Kobes334b6ed2020-07-09 07:26:31417 '^net/http/',
418 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51419 '^ppapi/proxy/',
danakj7a2b7082019-05-21 21:13:51420 '^services/',
danakj7a2b7082019-05-21 21:13:51421 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51422 '^tools/clang/base_bind_rewriters/', # Intentional.
423 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51424))
[email protected]127f18ec2012-06-16 05:05:59425
Daniel Bratell609102be2019-03-27 20:53:21426# Format: Sequence of tuples containing:
427# * String pattern or, if starting with a slash, a regular expression.
428# * Sequence of strings to show when the pattern matches.
429# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
430# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59431_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20432 (
Dave Tapuska98199b612019-07-10 13:30:44433 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53434 (
435 'New code should not use NULL. Use nullptr instead.',
436 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20437 False,
thomasandersone7caaa9b2017-03-29 19:22:53438 (),
439 ),
Peter Kasting94a56c42019-10-25 21:54:04440 (
441 r'/\busing namespace ',
442 (
443 'Using directives ("using namespace x") are banned by the Google Style',
444 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
445 'Explicitly qualify symbols or use using declarations ("using x::foo").',
446 ),
447 True,
448 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
449 ),
Antonio Gomes07300d02019-03-13 20:59:57450 # Make sure that gtest's FRIEND_TEST() macro is not used; the
451 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
452 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53453 (
[email protected]23e6cbc2012-06-16 18:51:20454 'FRIEND_TEST(',
455 (
[email protected]e3c945502012-06-26 20:01:49456 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20457 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
458 ),
459 False,
[email protected]7345da02012-11-27 14:31:49460 (),
[email protected]23e6cbc2012-06-16 18:51:20461 ),
462 (
Dave Tapuska98199b612019-07-10 13:30:44463 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53464 (
465 'Chrome clients wishing to select events on X windows should use',
466 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
467 'you are selecting events from the GPU process, or if you are using',
468 'an XDisplay other than gfx::GetXDisplay().',
469 ),
470 True,
471 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40472 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04473 r"^ui[\\/]gl[\\/].*\.cc$",
474 r"^media[\\/]gpu[\\/].*\.cc$",
475 r"^gpu[\\/].*\.cc$",
Maksim Sisova4d1cfbe2020-06-16 07:58:37476 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]xwmstartupcheck\.cc$",
477 ),
thomasanderson4b569052016-09-14 20:15:53478 ),
479 (
Tom Anderson74d064b2020-07-08 03:47:32480 r'/\WX?(((Width|Height)(MM)?OfScreen)|(Display(Width|Height)))\(',
481 (
482 'Use the corresponding fields in x11::Screen instead.',
483 ),
484 True,
485 (),
486 ),
487 (
Dave Tapuska98199b612019-07-10 13:30:44488 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20489 (
thomasanderson11aa41d2017-06-08 22:22:38490 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20491 ),
492 True,
493 (
Egor Paskoce145c42018-09-28 19:31:04494 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
495 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
496 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20497 ),
498 ),
499 (
tomhudsone2c14d552016-05-26 17:07:46500 'setMatrixClip',
501 (
502 'Overriding setMatrixClip() is prohibited; ',
503 'the base function is deprecated. ',
504 ),
505 True,
506 (),
507 ),
508 (
[email protected]52657f62013-05-20 05:30:31509 'SkRefPtr',
510 (
511 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22512 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31513 ),
514 True,
515 (),
516 ),
517 (
518 'SkAutoRef',
519 (
520 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22521 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31522 ),
523 True,
524 (),
525 ),
526 (
527 'SkAutoTUnref',
528 (
529 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22530 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31531 ),
532 True,
533 (),
534 ),
535 (
536 'SkAutoUnref',
537 (
538 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
539 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22540 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31541 ),
542 True,
543 (),
544 ),
[email protected]d89eec82013-12-03 14:10:59545 (
546 r'/HANDLE_EINTR\(.*close',
547 (
548 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
549 'descriptor will be closed, and it is incorrect to retry the close.',
550 'Either call close directly and ignore its return value, or wrap close',
551 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
552 ),
553 True,
554 (),
555 ),
556 (
557 r'/IGNORE_EINTR\((?!.*close)',
558 (
559 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
560 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
561 ),
562 True,
563 (
564 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04565 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
566 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59567 ),
568 ),
[email protected]ec5b3f02014-04-04 18:43:43569 (
570 r'/v8::Extension\(',
571 (
572 'Do not introduce new v8::Extensions into the code base, use',
573 'gin::Wrappable instead. See http://crbug.com/334679',
574 ),
575 True,
[email protected]f55c90ee62014-04-12 00:50:03576 (
Egor Paskoce145c42018-09-28 19:31:04577 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03578 ),
[email protected]ec5b3f02014-04-04 18:43:43579 ),
skyostilf9469f72015-04-20 10:38:52580 (
jame2d1a952016-04-02 00:27:10581 '#pragma comment(lib,',
582 (
583 'Specify libraries to link with in build files and not in the source.',
584 ),
585 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41586 (
tzik3f295992018-12-04 20:32:23587 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04588 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41589 ),
jame2d1a952016-04-02 00:27:10590 ),
fdorayc4ac18d2017-05-01 21:39:59591 (
Gabriel Charette7cc6c432018-04-25 20:52:02592 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59593 (
594 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
595 ),
596 False,
597 (),
598 ),
599 (
Gabriel Charette7cc6c432018-04-25 20:52:02600 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59601 (
602 'Consider using THREAD_CHECKER macros instead of the class directly.',
603 ),
604 False,
605 (),
606 ),
dbeamb6f4fde2017-06-15 04:03:06607 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06608 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
609 (
610 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
611 'deprecated (http://crbug.com/634507). Please avoid converting away',
612 'from the Time types in Chromium code, especially if any math is',
613 'being done on time values. For interfacing with platform/library',
614 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
615 'type converter methods instead. For faking TimeXXX values (for unit',
616 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
617 'other use cases, please contact base/time/OWNERS.',
618 ),
619 False,
620 (),
621 ),
622 (
dbeamb6f4fde2017-06-15 04:03:06623 'CallJavascriptFunctionUnsafe',
624 (
625 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
626 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
627 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
628 ),
629 False,
630 (
Egor Paskoce145c42018-09-28 19:31:04631 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
632 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
633 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06634 ),
635 ),
dskiba1474c2bfd62017-07-20 02:19:24636 (
637 'leveldb::DB::Open',
638 (
639 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
640 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
641 "Chrome's tracing, making their memory usage visible.",
642 ),
643 True,
644 (
645 r'^third_party/leveldatabase/.*\.(cc|h)$',
646 ),
Gabriel Charette0592c3a2017-07-26 12:02:04647 ),
648 (
Chris Mumfordc38afb62017-10-09 17:55:08649 'leveldb::NewMemEnv',
650 (
651 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58652 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
653 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08654 ),
655 True,
656 (
657 r'^third_party/leveldatabase/.*\.(cc|h)$',
658 ),
659 ),
660 (
Gabriel Charetted9839bc2017-07-29 14:17:47661 'RunLoop::QuitCurrent',
662 (
Robert Liao64b7ab22017-08-04 23:03:43663 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
664 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47665 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41666 False,
Gabriel Charetted9839bc2017-07-29 14:17:47667 (),
Gabriel Charettea44975052017-08-21 23:14:04668 ),
669 (
670 'base::ScopedMockTimeMessageLoopTaskRunner',
671 (
Gabriel Charette87cc1af2018-04-25 20:52:51672 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11673 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51674 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
675 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
676 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04677 ),
Gabriel Charette87cc1af2018-04-25 20:52:51678 False,
Gabriel Charettea44975052017-08-21 23:14:04679 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57680 ),
681 (
Dave Tapuska98199b612019-07-10 13:30:44682 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57683 (
684 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02685 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57686 ),
687 True,
688 (),
Francois Doray43670e32017-09-27 12:40:38689 ),
690 (
Peter Kasting991618a62019-06-17 22:00:09691 r'/\bstd::stoi\b',
692 (
693 'std::stoi uses exceptions to communicate results. ',
694 'Use base::StringToInt() instead.',
695 ),
696 True,
697 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
698 ),
699 (
700 r'/\bstd::stol\b',
701 (
702 'std::stol uses exceptions to communicate results. ',
703 'Use base::StringToInt() instead.',
704 ),
705 True,
706 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
707 ),
708 (
709 r'/\bstd::stoul\b',
710 (
711 'std::stoul uses exceptions to communicate results. ',
712 'Use base::StringToUint() instead.',
713 ),
714 True,
715 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
716 ),
717 (
718 r'/\bstd::stoll\b',
719 (
720 'std::stoll uses exceptions to communicate results. ',
721 'Use base::StringToInt64() instead.',
722 ),
723 True,
724 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
725 ),
726 (
727 r'/\bstd::stoull\b',
728 (
729 'std::stoull uses exceptions to communicate results. ',
730 'Use base::StringToUint64() instead.',
731 ),
732 True,
733 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
734 ),
735 (
736 r'/\bstd::stof\b',
737 (
738 'std::stof uses exceptions to communicate results. ',
739 'For locale-independent values, e.g. reading numbers from disk',
740 'profiles, use base::StringToDouble().',
741 'For user-visible values, parse using ICU.',
742 ),
743 True,
744 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
745 ),
746 (
747 r'/\bstd::stod\b',
748 (
749 'std::stod uses exceptions to communicate results. ',
750 'For locale-independent values, e.g. reading numbers from disk',
751 'profiles, use base::StringToDouble().',
752 'For user-visible values, parse using ICU.',
753 ),
754 True,
755 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
756 ),
757 (
758 r'/\bstd::stold\b',
759 (
760 'std::stold uses exceptions to communicate results. ',
761 'For locale-independent values, e.g. reading numbers from disk',
762 'profiles, use base::StringToDouble().',
763 'For user-visible values, parse using ICU.',
764 ),
765 True,
766 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
767 ),
768 (
Daniel Bratell69334cc2019-03-26 11:07:45769 r'/\bstd::to_string\b',
770 (
771 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09772 'For locale-independent strings, e.g. writing numbers to disk',
773 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45774 'For user-visible strings, use base::FormatNumber() and',
775 'the related functions in base/i18n/number_formatting.h.',
776 ),
Peter Kasting991618a62019-06-17 22:00:09777 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21778 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45779 ),
780 (
781 r'/\bstd::shared_ptr\b',
782 (
783 'std::shared_ptr should not be used. Use scoped_refptr instead.',
784 ),
785 True,
Alex Chau9eb03cdd52020-07-13 21:04:57786 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
787 'array_buffer_contents\.(cc|h)',
788 # Needed for interop with third-party library
789 'chrome/services/sharing/nearby/',
790 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21791 ),
792 (
Peter Kasting991618a62019-06-17 22:00:09793 r'/\bstd::weak_ptr\b',
794 (
795 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
796 ),
797 True,
798 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
799 ),
800 (
Daniel Bratell609102be2019-03-27 20:53:21801 r'/\blong long\b',
802 (
803 'long long is banned. Use stdint.h if you need a 64 bit number.',
804 ),
805 False, # Only a warning since it is already used.
806 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
807 ),
808 (
809 r'/\bstd::bind\b',
810 (
811 'std::bind is banned because of lifetime risks.',
812 'Use base::BindOnce or base::BindRepeating instead.',
813 ),
814 True,
815 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
816 ),
817 (
818 r'/\b#include <chrono>\b',
819 (
820 '<chrono> overlaps with Time APIs in base. Keep using',
821 'base classes.',
822 ),
823 True,
824 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
825 ),
826 (
827 r'/\b#include <exception>\b',
828 (
829 'Exceptions are banned and disabled in Chromium.',
830 ),
831 True,
832 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
833 ),
834 (
835 r'/\bstd::function\b',
836 (
837 'std::function is banned. Instead use base::Callback which directly',
838 'supports Chromium\'s weak pointers, ref counting and more.',
839 ),
Peter Kasting991618a62019-06-17 22:00:09840 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21841 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
842 ),
843 (
844 r'/\b#include <random>\b',
845 (
846 'Do not use any random number engines from <random>. Instead',
847 'use base::RandomBitGenerator.',
848 ),
849 True,
850 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
851 ),
852 (
853 r'/\bstd::ratio\b',
854 (
855 'std::ratio is banned by the Google Style Guide.',
856 ),
857 True,
858 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45859 ),
860 (
Francois Doray43670e32017-09-27 12:40:38861 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
862 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
863 (
864 'Use the new API in base/threading/thread_restrictions.h.',
865 ),
Gabriel Charette04b138f2018-08-06 00:03:22866 False,
Francois Doray43670e32017-09-27 12:40:38867 (),
868 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38869 (
danakj7a2b7082019-05-21 21:13:51870 r'/\bbase::Bind\(',
871 (
872 'Please use base::Bind{Once,Repeating} instead',
873 'of base::Bind. (crbug.com/714018)',
874 ),
875 False,
Erik Staaba737d7602019-11-25 18:41:07876 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51877 ),
878 (
879 r'/\bbase::Callback[<:]',
880 (
881 'Please use base::{Once,Repeating}Callback instead',
882 'of base::Callback. (crbug.com/714018)',
883 ),
884 False,
Erik Staaba737d7602019-11-25 18:41:07885 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51886 ),
887 (
888 r'/\bbase::Closure\b',
889 (
890 'Please use base::{Once,Repeating}Closure instead',
891 'of base::Closure. (crbug.com/714018)',
892 ),
893 False,
Erik Staaba737d7602019-11-25 18:41:07894 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51895 ),
896 (
Michael Giuffrida7f93d6922019-04-19 14:39:58897 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19898 (
899 'RunMessageLoop is deprecated, use RunLoop instead.',
900 ),
901 False,
902 (),
903 ),
904 (
Dave Tapuska98199b612019-07-10 13:30:44905 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19906 (
907 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
908 ),
909 False,
910 (),
911 ),
912 (
Dave Tapuska98199b612019-07-10 13:30:44913 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19914 (
915 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
916 "if you're convinced you need this.",
917 ),
918 False,
919 (),
920 ),
921 (
Dave Tapuska98199b612019-07-10 13:30:44922 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19923 (
924 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04925 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19926 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
927 'async events instead of flushing threads.',
928 ),
929 False,
930 (),
931 ),
932 (
933 r'MessageLoopRunner',
934 (
935 'MessageLoopRunner is deprecated, use RunLoop instead.',
936 ),
937 False,
938 (),
939 ),
940 (
Dave Tapuska98199b612019-07-10 13:30:44941 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19942 (
943 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
944 "gab@ if you found a use case where this is the only solution.",
945 ),
946 False,
947 (),
948 ),
949 (
Victor Costane48a2e82019-03-15 22:02:34950 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16951 (
Victor Costane48a2e82019-03-15 22:02:34952 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16953 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
954 ),
955 True,
956 (
957 r'^sql/initialization\.(cc|h)$',
958 r'^third_party/sqlite/.*\.(c|cc|h)$',
959 ),
960 ),
Matt Menke7f520a82018-03-28 21:38:37961 (
Dave Tapuska98199b612019-07-10 13:30:44962 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47963 (
964 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
965 'base::RandomShuffle instead.'
966 ),
967 True,
968 (),
969 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24970 (
971 'ios/web/public/test/http_server',
972 (
973 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
974 ),
975 False,
976 (),
977 ),
Robert Liao764c9492019-01-24 18:46:28978 (
979 'GetAddressOf',
980 (
981 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53982 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
983 'operator& is generally recommended. So always use operator& instead. '
984 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28985 ),
986 True,
987 (),
988 ),
Antonio Gomes07300d02019-03-13 20:59:57989 (
990 'DEFINE_TYPE_CASTS',
991 (
992 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
993 '//third_party/blink/renderer/platform/casting.h.'
994 ),
995 True,
996 (
997 r'^third_party/blink/renderer/.*\.(cc|h)$',
998 ),
999 ),
Carlos Knippschildab192b8c2019-04-08 20:02:381000 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:451001 r'/\bIsHTML.+Element\(\b',
1002 (
1003 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
1004 ' helpers IsA<HTMLXXXXElement> from ',
1005 '//third_party/blink/renderer/platform/casting.h.'
1006 ),
1007 False,
1008 (
1009 r'^third_party/blink/renderer/.*\.(cc|h)$',
1010 ),
1011 ),
1012 (
1013 r'/\bToHTML.+Element(|OrNull)\(\b',
1014 (
1015 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
1016 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
1017 'and DynamicTo<HTMLXXXXElement> from ',
1018 '//third_party/blink/renderer/platform/casting.h.'
1019 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
1020 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
1021 ),
1022 False,
1023 (
1024 r'^third_party/blink/renderer/.*\.(cc|h)$',
1025 ),
1026 ),
1027 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371028 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381029 (
1030 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1031 ),
1032 True,
1033 (),
1034 ),
Ben Lewisa9514602019-04-29 17:53:051035 (
1036 'SHFileOperation',
1037 (
1038 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1039 'complex functions to achieve the same goals. Use IFileOperation for ',
1040 'any esoteric actions instead.'
1041 ),
1042 True,
1043 (),
1044 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181045 (
Cliff Smolinsky81951642019-04-30 21:39:511046 'StringFromGUID2',
1047 (
1048 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241049 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511050 ),
1051 True,
1052 (
1053 r'/base/win/win_util_unittest.cc'
1054 ),
1055 ),
1056 (
1057 'StringFromCLSID',
1058 (
1059 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241060 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511061 ),
1062 True,
1063 (
1064 r'/base/win/win_util_unittest.cc'
1065 ),
1066 ),
1067 (
Avi Drissman7382afa02019-04-29 23:27:131068 'kCFAllocatorNull',
1069 (
1070 'The use of kCFAllocatorNull with the NoCopy creation of ',
1071 'CoreFoundation types is prohibited.',
1072 ),
1073 True,
1074 (),
1075 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291076 (
1077 'mojo::ConvertTo',
1078 (
1079 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1080 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1081 'StringTraits if you would like to convert between custom types and',
1082 'the wire format of mojom types.'
1083 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221084 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291085 (
Wezf89dec092019-09-11 19:38:331086 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1087 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291088 r'^third_party/blink/.*\.(cc|h)$',
1089 r'^content/renderer/.*\.(cc|h)$',
1090 ),
1091 ),
Robert Liao1d78df52019-11-11 20:02:011092 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161093 'GetInterfaceProvider',
1094 (
1095 'InterfaceProvider is deprecated.',
1096 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1097 'or Platform::GetBrowserInterfaceBroker.'
1098 ),
1099 False,
1100 (),
1101 ),
1102 (
Robert Liao1d78df52019-11-11 20:02:011103 'CComPtr',
1104 (
1105 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1106 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1107 'details.'
1108 ),
1109 False,
1110 (),
1111 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201112 (
1113 r'/\b(IFACE|STD)METHOD_?\(',
1114 (
1115 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1116 'Instead, always use IFACEMETHODIMP in the declaration.'
1117 ),
1118 False,
1119 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1120 ),
Allen Bauer53b43fb12020-03-12 17:21:471121 (
1122 'set_owned_by_client',
1123 (
1124 'set_owned_by_client is deprecated.',
1125 'views::View already owns the child views by default. This introduces ',
1126 'a competing ownership model which makes the code difficult to reason ',
1127 'about. See http://crbug.com/1044687 for more details.'
1128 ),
1129 False,
1130 (),
1131 ),
Eric Secklerbe6f48d2020-05-06 18:09:121132 (
1133 r'/\bTRACE_EVENT_ASYNC_',
1134 (
1135 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1136 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1137 ),
1138 False,
1139 (
1140 r'^base/trace_event/.*',
1141 r'^base/tracing/.*',
1142 ),
1143 ),
[email protected]127f18ec2012-06-16 05:05:591144)
1145
Mario Sanchez Prada2472cab2019-09-18 10:58:311146# Format: Sequence of tuples containing:
1147# * String pattern or, if starting with a slash, a regular expression.
1148# * Sequence of strings to show when the pattern matches.
1149_DEPRECATED_MOJO_TYPES = (
1150 (
1151 r'/\bmojo::AssociatedBinding\b',
1152 (
1153 'mojo::AssociatedBinding<Interface> is deprecated.',
1154 'Use mojo::AssociatedReceiver<Interface> instead.',
1155 ),
1156 ),
1157 (
1158 r'/\bmojo::AssociatedBindingSet\b',
1159 (
1160 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1161 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1162 ),
1163 ),
1164 (
1165 r'/\bmojo::AssociatedInterfacePtr\b',
1166 (
1167 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1168 'Use mojo::AssociatedRemote<Interface> instead.',
1169 ),
1170 ),
1171 (
1172 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1173 (
1174 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1175 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1176 ),
1177 ),
1178 (
1179 r'/\bmojo::AssociatedInterfaceRequest\b',
1180 (
1181 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1182 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1183 ),
1184 ),
1185 (
1186 r'/\bmojo::Binding\b',
1187 (
1188 'mojo::Binding<Interface> is deprecated.',
1189 'Use mojo::Receiver<Interface> instead.',
1190 ),
1191 ),
1192 (
1193 r'/\bmojo::BindingSet\b',
1194 (
1195 'mojo::BindingSet<Interface> is deprecated.',
1196 'Use mojo::ReceiverSet<Interface> instead.',
1197 ),
1198 ),
1199 (
1200 r'/\bmojo::InterfacePtr\b',
1201 (
1202 'mojo::InterfacePtr<Interface> is deprecated.',
1203 'Use mojo::Remote<Interface> instead.',
1204 ),
1205 ),
1206 (
1207 r'/\bmojo::InterfacePtrInfo\b',
1208 (
1209 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1210 'Use mojo::PendingRemote<Interface> instead.',
1211 ),
1212 ),
1213 (
1214 r'/\bmojo::InterfaceRequest\b',
1215 (
1216 'mojo::InterfaceRequest<Interface> is deprecated.',
1217 'Use mojo::PendingReceiver<Interface> instead.',
1218 ),
1219 ),
1220 (
1221 r'/\bmojo::MakeRequest\b',
1222 (
1223 'mojo::MakeRequest is deprecated.',
1224 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1225 ),
1226 ),
1227 (
1228 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1229 (
1230 'mojo::MakeRequest is deprecated.',
1231 'Use mojo::AssociatedRemote::'
1232 'BindNewEndpointAndPassDedicatedReceiverForTesting() instead.',
1233 ),
1234 ),
1235 (
1236 r'/\bmojo::MakeStrongBinding\b',
1237 (
1238 'mojo::MakeStrongBinding is deprecated.',
1239 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1240 'mojo::MakeSelfOwnedReceiver() instead.',
1241 ),
1242 ),
1243 (
1244 r'/\bmojo::MakeStrongAssociatedBinding\b',
1245 (
1246 'mojo::MakeStrongAssociatedBinding is deprecated.',
1247 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1248 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1249 ),
1250 ),
1251 (
Gyuyoung Kim4952ba62020-07-07 07:33:441252 r'/\bmojo::StrongAssociatedBinding\b',
1253 (
1254 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1255 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1256 ),
1257 ),
1258 (
1259 r'/\bmojo::StrongBinding\b',
1260 (
1261 'mojo::StrongBinding<Interface> is deprecated.',
1262 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1263 ),
1264 ),
1265 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311266 r'/\bmojo::StrongAssociatedBindingSet\b',
1267 (
1268 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1269 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1270 ),
1271 ),
1272 (
1273 r'/\bmojo::StrongBindingSet\b',
1274 (
1275 'mojo::StrongBindingSet<Interface> is deprecated.',
1276 'Use mojo::UniqueReceiverSet<Interface> instead.',
1277 ),
1278 ),
1279)
wnwenbdc444e2016-05-25 13:44:151280
mlamouria82272622014-09-16 18:45:041281_IPC_ENUM_TRAITS_DEPRECATED = (
1282 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501283 'See http://www.chromium.org/Home/chromium-security/education/'
1284 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041285
Stephen Martinis97a394142018-06-07 23:06:051286_LONG_PATH_ERROR = (
1287 'Some files included in this CL have file names that are too long (> 200'
1288 ' characters). If committed, these files will cause issues on Windows. See'
1289 ' https://crbug.com/612667 for more details.'
1290)
1291
Shenghua Zhangbfaa38b82017-11-16 21:58:021292_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041293 r".*[\\/]BuildHooksAndroidImpl\.java",
1294 r".*[\\/]LicenseContentProvider\.java",
1295 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281296 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021297]
[email protected]127f18ec2012-06-16 05:05:591298
Mohamed Heikald048240a2019-11-12 16:57:371299# List of image extensions that are used as resources in chromium.
1300_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1301
Sean Kau46e29bc2017-08-28 16:31:161302# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401303_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041304 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401305 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041306 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1307 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041308 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431309 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161310]
1311
1312
[email protected]b00342e7f2013-03-26 16:21:541313_VALID_OS_MACROS = (
1314 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081315 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541316 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441317 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121318 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541319 'OS_BSD',
1320 'OS_CAT', # For testing.
1321 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041322 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541323 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371324 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541325 'OS_IOS',
1326 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441327 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541328 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211329 'OS_NACL_NONSFI',
1330 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121331 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541332 'OS_OPENBSD',
1333 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371334 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541335 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541336 'OS_WIN',
1337)
1338
1339
Andrew Grieveb773bad2020-06-05 18:00:381340# These are not checked on the public chromium-presubmit trybot.
1341# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041342# checkouts.
agrievef32bcc72016-04-04 14:57:401343_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381344 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381345]
1346
1347
1348_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041349 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361350 'base/android/jni_generator/jni_generator.pydeps',
1351 'base/android/jni_generator/jni_registration_generator.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041352 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/gyp/aar.pydeps',
1354 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271355 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361356 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381357 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361358 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111359 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361360 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361361 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361362 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111363 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041364 'build/android/gyp/create_app_bundle_apks.pydeps',
1365 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361366 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121367 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221368 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001369 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361370 'build/android/gyp/desugar.pydeps',
1371 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421372 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041373 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361374 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361375 'build/android/gyp/filter_zip.pydeps',
1376 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361377 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361378 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581379 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361380 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261381 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011382 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041383 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361384 'build/android/gyp/lint.pydeps',
1385 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361386 'build/android/gyp/merge_manifest.pydeps',
1387 'build/android/gyp/prepare_resources.pydeps',
1388 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461389 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241390 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361391 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461392 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561393 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361394 'build/android/incremental_install/generate_android_manifest.pydeps',
1395 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041396 'build/android/resource_sizes.pydeps',
1397 'build/android/test_runner.pydeps',
1398 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361399 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361400 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271401 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1402 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001403 'components/cronet/tools/generate_javadoc.pydeps',
1404 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381405 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001406 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381407 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041408 'testing/scripts/run_android_wpt.pydeps',
1409 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421410 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1411 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131412 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191413 ('third_party/blink/renderer/bindings/scripts/'
1414 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061415 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221416 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401417]
1418
wnwenbdc444e2016-05-25 13:44:151419
agrievef32bcc72016-04-04 14:57:401420_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1421
1422
Eric Boren6fd2b932018-01-25 15:05:081423# Bypass the AUTHORS check for these accounts.
1424_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591425 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451426 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591427 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521428 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
1429 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041430 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271431 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041432 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301433 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081434
1435
Daniel Bratell65b033262019-04-23 08:17:061436def _IsCPlusPlusFile(input_api, file_path):
1437 """Returns True if this file contains C++-like code (and not Python,
1438 Go, Java, MarkDown, ...)"""
1439
1440 ext = input_api.os_path.splitext(file_path)[1]
1441 # This list is compatible with CppChecker.IsCppFile but we should
1442 # consider adding ".c" to it. If we do that we can use this function
1443 # at more places in the code.
1444 return ext in (
1445 '.h',
1446 '.cc',
1447 '.cpp',
1448 '.m',
1449 '.mm',
1450 )
1451
1452def _IsCPlusPlusHeaderFile(input_api, file_path):
1453 return input_api.os_path.splitext(file_path)[1] == ".h"
1454
1455
1456def _IsJavaFile(input_api, file_path):
1457 return input_api.os_path.splitext(file_path)[1] == ".java"
1458
1459
1460def _IsProtoFile(input_api, file_path):
1461 return input_api.os_path.splitext(file_path)[1] == ".proto"
1462
Saagar Sanghavifceeaae2020-08-12 16:40:361463def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191464 """Attempts to prevent use of functions intended only for testing in
1465 non-testing code. For now this is just a best-effort implementation
1466 that ignores header files and may have some false positives. A
1467 better implementation would probably need a proper C++ parser.
1468 """
1469 # We only scan .cc files and the like, as the declaration of
1470 # for-testing functions in header files are hard to distinguish from
1471 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491472 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191473
jochenc0d4808c2015-07-27 09:25:421474 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191475 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091476 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191477 exclusion_pattern = input_api.re.compile(
1478 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1479 base_function_pattern, base_function_pattern))
1480
1481 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441482 files_to_skip = (_EXCLUDED_PATHS +
1483 _TEST_CODE_EXCLUDED_PATHS +
1484 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191485 return input_api.FilterSourceFile(
1486 affected_file,
James Cook24a504192020-07-23 00:08:441487 files_to_check=file_inclusion_pattern,
1488 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191489
1490 problems = []
1491 for f in input_api.AffectedSourceFiles(FilterFile):
1492 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241493 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031494 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461495 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031496 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191497 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031498 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191499
1500 if problems:
[email protected]f7051d52013-04-02 18:31:421501 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031502 else:
1503 return []
[email protected]55459852011-08-10 15:17:191504
1505
Saagar Sanghavifceeaae2020-08-12 16:40:361506def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231507 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591508 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231509 """
1510 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1511 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1512 name_pattern = r'ForTest(s|ing)?'
1513 # Describes an occurrence of "ForTest*" inside a // comment.
1514 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501515 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1516 annotation_re = input_api.re.compile(r'@VisibleForTesting\(otherwise')
Vaclav Brozek7dbc28c2018-03-27 08:35:231517 # Catch calls.
1518 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1519 # Ignore definitions. (Comments are ignored separately.)
1520 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1521
1522 problems = []
1523 sources = lambda x: input_api.FilterSourceFile(
1524 x,
James Cook24a504192020-07-23 00:08:441525 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1526 + input_api.DEFAULT_FILES_TO_SKIP),
1527 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231528 )
1529 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1530 local_path = f.LocalPath()
1531 is_inside_javadoc = False
1532 for line_number, line in f.ChangedContents():
1533 if is_inside_javadoc and javadoc_end_re.search(line):
1534 is_inside_javadoc = False
1535 if not is_inside_javadoc and javadoc_start_re.search(line):
1536 is_inside_javadoc = True
1537 if is_inside_javadoc:
1538 continue
1539 if (inclusion_re.search(line) and
1540 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501541 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231542 not exclusion_re.search(line)):
1543 problems.append(
1544 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1545
1546 if problems:
1547 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1548 else:
1549 return []
1550
1551
Saagar Sanghavifceeaae2020-08-12 16:40:361552def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541553 """Checks to make sure no .h files include <iostream>."""
1554 files = []
1555 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1556 input_api.re.MULTILINE)
1557 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1558 if not f.LocalPath().endswith('.h'):
1559 continue
1560 contents = input_api.ReadFile(f)
1561 if pattern.search(contents):
1562 files.append(f)
1563
1564 if len(files):
yolandyandaabc6d2016-04-18 18:29:391565 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061566 'Do not #include <iostream> in header files, since it inserts static '
1567 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541568 '#include <ostream>. See http://crbug.com/94794',
1569 files) ]
1570 return []
1571
Danil Chapovalov3518f362018-08-11 16:13:431572def _CheckNoStrCatRedefines(input_api, output_api):
1573 """Checks no windows headers with StrCat redefined are included directly."""
1574 files = []
1575 pattern_deny = input_api.re.compile(
1576 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1577 input_api.re.MULTILINE)
1578 pattern_allow = input_api.re.compile(
1579 r'^#include\s"base/win/windows_defines.inc"',
1580 input_api.re.MULTILINE)
1581 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1582 contents = input_api.ReadFile(f)
1583 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1584 files.append(f.LocalPath())
1585
1586 if len(files):
1587 return [output_api.PresubmitError(
1588 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1589 'directly since they pollute code with StrCat macro. Instead, '
1590 'include matching header from base/win. See http://crbug.com/856536',
1591 files) ]
1592 return []
1593
[email protected]10689ca2011-09-02 02:31:541594
Saagar Sanghavifceeaae2020-08-12 16:40:361595def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521596 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181597 problems = []
1598 for f in input_api.AffectedFiles():
1599 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1600 continue
1601
1602 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041603 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181604 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1605
1606 if not problems:
1607 return []
1608 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1609 '\n'.join(problems))]
1610
Saagar Sanghavifceeaae2020-08-12 16:40:361611def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341612 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1613
1614 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1615 instead of DISABLED_. To filter false positives, reports are only generated
1616 if a corresponding MAYBE_ line exists.
1617 """
1618 problems = []
1619
1620 # The following two patterns are looked for in tandem - is a test labeled
1621 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1622 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1623 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1624
1625 # This is for the case that a test is disabled on all platforms.
1626 full_disable_pattern = input_api.re.compile(
1627 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1628 input_api.re.MULTILINE)
1629
Katie Df13948e2018-09-25 07:33:441630 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341631 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1632 continue
1633
1634 # Search for MABYE_, DISABLE_ pairs.
1635 disable_lines = {} # Maps of test name to line number.
1636 maybe_lines = {}
1637 for line_num, line in f.ChangedContents():
1638 disable_match = disable_pattern.search(line)
1639 if disable_match:
1640 disable_lines[disable_match.group(1)] = line_num
1641 maybe_match = maybe_pattern.search(line)
1642 if maybe_match:
1643 maybe_lines[maybe_match.group(1)] = line_num
1644
1645 # Search for DISABLE_ occurrences within a TEST() macro.
1646 disable_tests = set(disable_lines.keys())
1647 maybe_tests = set(maybe_lines.keys())
1648 for test in disable_tests.intersection(maybe_tests):
1649 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1650
1651 contents = input_api.ReadFile(f)
1652 full_disable_match = full_disable_pattern.search(contents)
1653 if full_disable_match:
1654 problems.append(' %s' % f.LocalPath())
1655
1656 if not problems:
1657 return []
1658 return [
1659 output_api.PresubmitPromptWarning(
1660 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1661 '\n'.join(problems))
1662 ]
1663
[email protected]72df4e782012-06-21 16:28:181664
Saagar Sanghavifceeaae2020-08-12 16:40:361665def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571666 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521667 errors = []
Hans Wennborg944479f2020-06-25 21:39:251668 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521669 input_api.re.MULTILINE)
1670 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1671 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1672 continue
1673 for lnum, line in f.ChangedContents():
1674 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171675 errors.append(output_api.PresubmitError(
1676 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571677 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171678 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521679 return errors
1680
1681
Makoto Shimazu3ad422cd2019-05-08 02:35:141682def _FindHistogramNameInChunk(histogram_name, chunk):
1683 """Tries to find a histogram name or prefix in a line.
1684
1685 Returns the existence of the histogram name, or None if it needs more chunk
1686 to determine."""
mcasasb7440c282015-02-04 14:52:191687 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1688 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141689 if '<affected-histogram' in chunk:
1690 # If the tag is not completed, needs more chunk to get the name.
1691 if not '>' in chunk:
1692 return None
1693 if not 'name="' in chunk:
1694 return False
1695 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1696 # expect the only attribute is the name.
1697 histogram_prefix = chunk.split('"')[1]
1698 return histogram_prefix in histogram_name
1699 # Typically the whole histogram name should in the line.
1700 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191701
1702
Saagar Sanghavifceeaae2020-08-12 16:40:361703def CheckUmaHistogramChangesOnUpload(input_api, output_api):
mcasasb7440c282015-02-04 14:52:191704 """Check that UMA histogram names in touched lines can still be found in other
1705 lines of the patch or in histograms.xml. Note that this check would not catch
1706 the reverse: changes in histograms.xml not matched in the code itself."""
1707 touched_histograms = []
1708 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471709 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1710 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1711 name_pattern = r'"(.*?)"'
1712 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1713 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1714 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1715 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1716 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171717 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191718 for f in input_api.AffectedFiles():
1719 # If histograms.xml itself is modified, keep the modified lines for later.
1720 if f.LocalPath().endswith(('histograms.xml')):
1721 histograms_xml_modifications = f.ChangedContents()
1722 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471723 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1724 single_line_re = single_line_c_re
1725 split_line_prefix_re = split_line_c_prefix_re
1726 elif f.LocalPath().endswith(('java')):
1727 single_line_re = single_line_java_re
1728 split_line_prefix_re = split_line_java_prefix_re
1729 else:
mcasasb7440c282015-02-04 14:52:191730 continue
1731 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171732 if last_line_matched_prefix:
1733 suffix_found = split_line_suffix_re.search(line)
1734 if suffix_found :
1735 touched_histograms.append([suffix_found.group(1), f, line_num])
1736 last_line_matched_prefix = False
1737 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061738 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191739 if found:
1740 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171741 continue
1742 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191743
1744 # Search for the touched histogram names in the local modifications to
1745 # histograms.xml, and, if not found, on the base histograms.xml file.
1746 unmatched_histograms = []
1747 for histogram_info in touched_histograms:
1748 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141749 chunk = ''
mcasasb7440c282015-02-04 14:52:191750 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141751 chunk += line
1752 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1753 if histogram_name_found is None:
1754 continue
1755 chunk = ''
mcasasb7440c282015-02-04 14:52:191756 if histogram_name_found:
1757 break
1758 if not histogram_name_found:
1759 unmatched_histograms.append(histogram_info)
1760
eromanb90c82e7e32015-04-01 15:13:491761 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191762 problems = []
1763 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491764 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191765 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451766 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191767 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141768 chunk = ''
mcasasb7440c282015-02-04 14:52:191769 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141770 chunk += line
1771 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1772 chunk)
1773 if histogram_name_found is None:
1774 continue
1775 chunk = ''
mcasasb7440c282015-02-04 14:52:191776 if histogram_name_found:
1777 break
1778 if not histogram_name_found:
1779 problems.append(' [%s:%d] %s' %
1780 (f.LocalPath(), line_num, histogram_name))
1781
1782 if not problems:
1783 return []
1784 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1785 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491786 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191787
wnwenbdc444e2016-05-25 13:44:151788
Saagar Sanghavifceeaae2020-08-12 16:40:361789def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391790 """Check that FlakyTest annotation is our own instead of the android one"""
1791 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1792 files = []
1793 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1794 if f.LocalPath().endswith('Test.java'):
1795 if pattern.search(input_api.ReadFile(f)):
1796 files.append(f)
1797 if len(files):
1798 return [output_api.PresubmitError(
1799 'Use org.chromium.base.test.util.FlakyTest instead of '
1800 'android.test.FlakyTest',
1801 files)]
1802 return []
mcasasb7440c282015-02-04 14:52:191803
wnwenbdc444e2016-05-25 13:44:151804
Saagar Sanghavifceeaae2020-08-12 16:40:361805def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221806 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271807 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221808 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201809 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571810 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341811 '/win/' in f.LocalPath() or
1812 'chrome_elf' in f.LocalPath() or
1813 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201814 continue
[email protected]8ea5d4b2011-09-13 21:49:221815
[email protected]a11dbe9b2012-08-07 01:32:581816 allowWString = False
[email protected]b5c24292011-11-28 14:38:201817 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581818 if 'presubmit: allow wstring' in line:
1819 allowWString = True
1820 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271821 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581822 allowWString = False
1823 else:
1824 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221825
[email protected]55463aa62011-10-12 00:48:271826 if not problems:
1827 return []
1828 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581829 ' If you are calling a cross-platform API that accepts a wstring, '
1830 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271831 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221832
1833
Saagar Sanghavifceeaae2020-08-12 16:40:361834def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441835 """Make sure .DEPS.git is never modified manually."""
1836 if any(f.LocalPath().endswith('.DEPS.git') for f in
1837 input_api.AffectedFiles()):
1838 return [output_api.PresubmitError(
1839 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1840 'automated system based on what\'s in DEPS and your changes will be\n'
1841 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501842 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1843 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441844 'for more information')]
1845 return []
1846
1847
Saagar Sanghavifceeaae2020-08-12 16:40:361848def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471849 """Checks that DEPS file deps are from allowed_hosts."""
1850 # Run only if DEPS file has been modified to annoy fewer bystanders.
1851 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1852 return []
1853 # Outsource work to gclient verify
1854 try:
John Budorickf20c0042019-04-25 23:23:401855 gclient_path = input_api.os_path.join(
1856 input_api.PresubmitLocalPath(),
1857 'third_party', 'depot_tools', 'gclient.py')
1858 input_api.subprocess.check_output(
1859 [input_api.python_executable, gclient_path, 'verify'],
1860 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471861 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201862 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471863 return [output_api.PresubmitError(
1864 'DEPS file must have only git dependencies.',
1865 long_text=error.output)]
1866
1867
Mario Sanchez Prada2472cab2019-09-18 10:58:311868def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1869 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591870 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311871
1872 Returns an string composed of the name of the file, the line number where the
1873 match has been found and the additional text passed as |message| in case the
1874 target type name matches the text inside the line passed as parameter.
1875 """
Peng Huang9c5949a02020-06-11 19:20:541876 result = []
1877
1878 if line.endswith(" nocheck"):
1879 return result
1880
Mario Sanchez Prada2472cab2019-09-18 10:58:311881 matched = False
1882 if type_name[0:1] == '/':
1883 regex = type_name[1:]
1884 if input_api.re.search(regex, line):
1885 matched = True
1886 elif type_name in line:
1887 matched = True
1888
Mario Sanchez Prada2472cab2019-09-18 10:58:311889 if matched:
1890 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1891 for message_line in message:
1892 result.append(' %s' % message_line)
1893
1894 return result
1895
1896
Saagar Sanghavifceeaae2020-08-12 16:40:361897def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591898 """Make sure that banned functions are not used."""
1899 warnings = []
1900 errors = []
1901
James Cook24a504192020-07-23 00:08:441902 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151903 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441904 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151905 if input_api.re.match(item, local_path):
1906 return True
1907 return False
1908
Peter K. Lee6c03ccff2019-07-15 14:40:051909 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541910 local_path = affected_file.LocalPath()
1911 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1912 return False
1913 basename = input_api.os_path.basename(local_path)
1914 if 'ios' in basename.split('_'):
1915 return True
1916 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1917 if sep and 'ios' in local_path.split(sep):
1918 return True
1919 return False
1920
wnwenbdc444e2016-05-25 13:44:151921 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311922 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1923 func_name, message)
1924 if problems:
wnwenbdc444e2016-05-25 13:44:151925 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311926 errors.extend(problems)
1927 else:
1928 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151929
Eric Stevensona9a980972017-09-23 00:04:411930 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1931 for f in input_api.AffectedFiles(file_filter=file_filter):
1932 for line_num, line in f.ChangedContents():
1933 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1934 CheckForMatch(f, line_num, line, func_name, message, error)
1935
[email protected]127f18ec2012-06-16 05:05:591936 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1937 for f in input_api.AffectedFiles(file_filter=file_filter):
1938 for line_num, line in f.ChangedContents():
1939 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151940 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591941
Peter K. Lee6c03ccff2019-07-15 14:40:051942 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541943 for line_num, line in f.ChangedContents():
1944 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1945 CheckForMatch(f, line_num, line, func_name, message, error)
1946
Peter K. Lee6c03ccff2019-07-15 14:40:051947 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1948 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1949 for line_num, line in f.ChangedContents():
1950 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1951 CheckForMatch(f, line_num, line, func_name, message, error)
1952
[email protected]127f18ec2012-06-16 05:05:591953 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1954 for f in input_api.AffectedFiles(file_filter=file_filter):
1955 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491956 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441957 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491958 continue
wnwenbdc444e2016-05-25 13:44:151959 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591960
1961 result = []
1962 if (warnings):
1963 result.append(output_api.PresubmitPromptWarning(
1964 'Banned functions were used.\n' + '\n'.join(warnings)))
1965 if (errors):
1966 result.append(output_api.PresubmitError(
1967 'Banned functions were used.\n' + '\n'.join(errors)))
1968 return result
1969
1970
Michael Thiessen44457642020-02-06 00:24:151971def _CheckAndroidNoBannedImports(input_api, output_api):
1972 """Make sure that banned java imports are not used."""
1973 errors = []
1974
1975 def IsException(path, exceptions):
1976 for exception in exceptions:
1977 if (path.startswith(exception)):
1978 return True
1979 return False
1980
1981 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1982 for f in input_api.AffectedFiles(file_filter=file_filter):
1983 for line_num, line in f.ChangedContents():
1984 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1985 if IsException(f.LocalPath(), exceptions):
1986 continue;
1987 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1988 'import ' + import_name, message)
1989 if problems:
1990 errors.extend(problems)
1991 result = []
1992 if (errors):
1993 result.append(output_api.PresubmitError(
1994 'Banned imports were used.\n' + '\n'.join(errors)))
1995 return result
1996
1997
Saagar Sanghavifceeaae2020-08-12 16:40:361998def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311999 """Make sure that old Mojo types are not used."""
2000 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:572001 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:312002
Mario Sanchez Pradaaab91382019-12-19 08:57:092003 # For any path that is not an "ok" or an "error" path, a warning will be
2004 # raised if deprecated mojo types are found.
2005 ok_paths = ['components/arc']
2006 error_paths = ['third_party/blink', 'content']
2007
Mario Sanchez Prada2472cab2019-09-18 10:58:312008 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2009 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:572010 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:092011 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:312012 continue
2013
2014 for line_num, line in f.ChangedContents():
2015 for func_name, message in _DEPRECATED_MOJO_TYPES:
2016 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
2017 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:572018
Mario Sanchez Prada2472cab2019-09-18 10:58:312019 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:092020 # Raise errors inside |error_paths| and warnings everywhere else.
2021 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:572022 errors.extend(problems)
2023 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:312024 warnings.extend(problems)
2025
2026 result = []
2027 if (warnings):
2028 result.append(output_api.PresubmitPromptWarning(
2029 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:572030 if (errors):
2031 result.append(output_api.PresubmitError(
2032 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:312033 return result
2034
2035
Saagar Sanghavifceeaae2020-08-12 16:40:362036def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:062037 """Make sure that banned functions are not used."""
2038 files = []
2039 pattern = input_api.re.compile(r'^#pragma\s+once',
2040 input_api.re.MULTILINE)
2041 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2042 if not f.LocalPath().endswith('.h'):
2043 continue
2044 contents = input_api.ReadFile(f)
2045 if pattern.search(contents):
2046 files.append(f)
2047
2048 if files:
2049 return [output_api.PresubmitError(
2050 'Do not use #pragma once in header files.\n'
2051 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2052 files)]
2053 return []
2054
[email protected]127f18ec2012-06-16 05:05:592055
Saagar Sanghavifceeaae2020-08-12 16:40:362056def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:122057 """Checks to make sure we don't introduce use of foo ? true : false."""
2058 problems = []
2059 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2060 for f in input_api.AffectedFiles():
2061 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2062 continue
2063
2064 for line_num, line in f.ChangedContents():
2065 if pattern.match(line):
2066 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2067
2068 if not problems:
2069 return []
2070 return [output_api.PresubmitPromptWarning(
2071 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2072 '\n'.join(problems))]
2073
2074
Saagar Sanghavifceeaae2020-08-12 16:40:362075def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282076 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182077 change. Breaking - rules is an error, breaking ! rules is a
2078 warning.
2079 """
mohan.reddyf21db962014-10-16 12:26:472080 import sys
[email protected]55f9f382012-07-31 11:02:182081 # We need to wait until we have an input_api object and use this
2082 # roundabout construct to import checkdeps because this file is
2083 # eval-ed and thus doesn't have __file__.
2084 original_sys_path = sys.path
2085 try:
2086 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472087 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182088 import checkdeps
[email protected]55f9f382012-07-31 11:02:182089 from rules import Rule
2090 finally:
2091 # Restore sys.path to what it was before.
2092 sys.path = original_sys_path
2093
2094 added_includes = []
rhalavati08acd232017-04-03 07:23:282095 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242096 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182097 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062098 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502099 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082100 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062101 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502102 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082103 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062104 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502105 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082106 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182107
[email protected]26385172013-05-09 23:11:352108 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182109
2110 error_descriptions = []
2111 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282112 error_subjects = set()
2113 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362114
[email protected]55f9f382012-07-31 11:02:182115 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2116 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082117 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182118 description_with_path = '%s\n %s' % (path, rule_description)
2119 if rule_type == Rule.DISALLOW:
2120 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282121 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182122 else:
2123 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282124 warning_subjects.add("#includes")
2125
2126 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2127 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082128 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282129 description_with_path = '%s\n %s' % (path, rule_description)
2130 if rule_type == Rule.DISALLOW:
2131 error_descriptions.append(description_with_path)
2132 error_subjects.add("imports")
2133 else:
2134 warning_descriptions.append(description_with_path)
2135 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182136
Jinsuk Kim5a092672017-10-24 22:42:242137 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022138 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082139 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242140 description_with_path = '%s\n %s' % (path, rule_description)
2141 if rule_type == Rule.DISALLOW:
2142 error_descriptions.append(description_with_path)
2143 error_subjects.add("imports")
2144 else:
2145 warning_descriptions.append(description_with_path)
2146 warning_subjects.add("imports")
2147
[email protected]55f9f382012-07-31 11:02:182148 results = []
2149 if error_descriptions:
2150 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282151 'You added one or more %s that violate checkdeps rules.'
2152 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182153 error_descriptions))
2154 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422155 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282156 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182157 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282158 '%s? See relevant DEPS file(s) for details and contacts.' %
2159 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182160 warning_descriptions))
2161 return results
2162
2163
Saagar Sanghavifceeaae2020-08-12 16:40:362164def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222165 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152166 if input_api.platform == 'win32':
2167 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292168 checkperms_tool = input_api.os_path.join(
2169 input_api.PresubmitLocalPath(),
2170 'tools', 'checkperms', 'checkperms.py')
2171 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472172 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392173 with input_api.CreateTemporaryFile() as file_list:
2174 for f in input_api.AffectedFiles():
2175 # checkperms.py file/directory arguments must be relative to the
2176 # repository.
2177 file_list.write(f.LocalPath() + '\n')
2178 file_list.close()
2179 args += ['--file-list', file_list.name]
2180 try:
2181 input_api.subprocess.check_output(args)
2182 return []
2183 except input_api.subprocess.CalledProcessError as error:
2184 return [output_api.PresubmitError(
2185 'checkperms.py failed:',
2186 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222187
2188
Saagar Sanghavifceeaae2020-08-12 16:40:362189def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492190 """Makes sure we don't include ui/aura/window_property.h
2191 in header files.
2192 """
2193 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2194 errors = []
2195 for f in input_api.AffectedFiles():
2196 if not f.LocalPath().endswith('.h'):
2197 continue
2198 for line_num, line in f.ChangedContents():
2199 if pattern.match(line):
2200 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2201
2202 results = []
2203 if errors:
2204 results.append(output_api.PresubmitError(
2205 'Header files should not include ui/aura/window_property.h', errors))
2206 return results
2207
2208
[email protected]70ca77752012-11-20 03:45:032209def _CheckForVersionControlConflictsInFile(input_api, f):
2210 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2211 errors = []
2212 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162213 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232214 # First-level headers in markdown look a lot like version control
2215 # conflict markers. http://daringfireball.net/projects/markdown/basics
2216 continue
[email protected]70ca77752012-11-20 03:45:032217 if pattern.match(line):
2218 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2219 return errors
2220
2221
Saagar Sanghavifceeaae2020-08-12 16:40:362222def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032223 """Usually this is not intentional and will cause a compile failure."""
2224 errors = []
2225 for f in input_api.AffectedFiles():
2226 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2227
2228 results = []
2229 if errors:
2230 results.append(output_api.PresubmitError(
2231 'Version control conflict markers found, please resolve.', errors))
2232 return results
2233
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202234
Saagar Sanghavifceeaae2020-08-12 16:40:362235def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162236 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2237 errors = []
2238 for f in input_api.AffectedFiles():
2239 for line_num, line in f.ChangedContents():
2240 if pattern.search(line):
2241 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2242
2243 results = []
2244 if errors:
2245 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502246 'Found Google support URL addressed by answer number. Please replace '
2247 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162248 return results
2249
[email protected]70ca77752012-11-20 03:45:032250
Saagar Sanghavifceeaae2020-08-12 16:40:362251def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442252 def FilterFile(affected_file):
2253 """Filter function for use with input_api.AffectedSourceFiles,
2254 below. This filters out everything except non-test files from
2255 top-level directories that generally speaking should not hard-code
2256 service URLs (e.g. src/android_webview/, src/content/ and others).
2257 """
2258 return input_api.FilterSourceFile(
2259 affected_file,
James Cook24a504192020-07-23 00:08:442260 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2261 files_to_skip=(_EXCLUDED_PATHS +
2262 _TEST_CODE_EXCLUDED_PATHS +
2263 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442264
reillyi38965732015-11-16 18:27:332265 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2266 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462267 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2268 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442269 problems = [] # items are (filename, line_number, line)
2270 for f in input_api.AffectedSourceFiles(FilterFile):
2271 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462272 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442273 problems.append((f.LocalPath(), line_num, line))
2274
2275 if problems:
[email protected]f7051d52013-04-02 18:31:422276 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442277 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582278 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442279 [' %s:%d: %s' % (
2280 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032281 else:
2282 return []
[email protected]06e6d0ff2012-12-11 01:36:442283
2284
Saagar Sanghavifceeaae2020-08-12 16:40:362285def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292286 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2287 def FileFilter(affected_file):
2288 """Includes directories known to be Chrome OS only."""
2289 return input_api.FilterSourceFile(
2290 affected_file,
James Cook24a504192020-07-23 00:08:442291 files_to_check=('^ash/',
2292 '^chromeos/', # Top-level src/chromeos.
2293 '/chromeos/', # Any path component.
2294 '^components/arc',
2295 '^components/exo'),
2296 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292297
2298 prefs = []
2299 priority_prefs = []
2300 for f in input_api.AffectedFiles(file_filter=FileFilter):
2301 for line_num, line in f.ChangedContents():
2302 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2303 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2304 prefs.append(' %s' % line)
2305 if input_api.re.search(
2306 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2307 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2308 priority_prefs.append(' %s' % line)
2309
2310 results = []
2311 if (prefs):
2312 results.append(output_api.PresubmitPromptWarning(
2313 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2314 'by browser sync settings. If these prefs should be controlled by OS '
2315 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2316 if (priority_prefs):
2317 results.append(output_api.PresubmitPromptWarning(
2318 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2319 'controlled by browser sync settings. If these prefs should be '
2320 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2321 'instead.\n' + '\n'.join(prefs)))
2322 return results
2323
2324
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492325# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362326def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272327 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312328 The native_client_sdk directory is excluded because it has auto-generated PNG
2329 files for documentation.
[email protected]d2530012013-01-25 16:39:272330 """
[email protected]d2530012013-01-25 16:39:272331 errors = []
James Cook24a504192020-07-23 00:08:442332 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2333 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312334 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442335 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312336 for f in input_api.AffectedFiles(include_deletes=False,
2337 file_filter=file_filter):
2338 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272339
2340 results = []
2341 if errors:
2342 results.append(output_api.PresubmitError(
2343 'The name of PNG files should not have abbreviations. \n'
2344 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2345 'Contact [email protected] if you have questions.', errors))
2346 return results
2347
2348
Daniel Cheng4dcdb6b2017-04-13 08:30:172349def _ExtractAddRulesFromParsedDeps(parsed_deps):
2350 """Extract the rules that add dependencies from a parsed DEPS file.
2351
2352 Args:
2353 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2354 add_rules = set()
2355 add_rules.update([
2356 rule[1:] for rule in parsed_deps.get('include_rules', [])
2357 if rule.startswith('+') or rule.startswith('!')
2358 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502359 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172360 {}).iteritems():
2361 add_rules.update([
2362 rule[1:] for rule in rules
2363 if rule.startswith('+') or rule.startswith('!')
2364 ])
2365 return add_rules
2366
2367
2368def _ParseDeps(contents):
2369 """Simple helper for parsing DEPS files."""
2370 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172371 class _VarImpl:
2372
2373 def __init__(self, local_scope):
2374 self._local_scope = local_scope
2375
2376 def Lookup(self, var_name):
2377 """Implements the Var syntax."""
2378 try:
2379 return self._local_scope['vars'][var_name]
2380 except KeyError:
2381 raise Exception('Var is not defined: %s' % var_name)
2382
2383 local_scope = {}
2384 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172385 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592386 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172387 }
2388 exec contents in global_scope, local_scope
2389 return local_scope
2390
2391
2392def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592393 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412394 a set of DEPS entries that we should look up.
2395
2396 For a directory (rather than a specific filename) we fake a path to
2397 a specific filename by adding /DEPS. This is chosen as a file that
2398 will seldom or never be subject to per-file include_rules.
2399 """
[email protected]2b438d62013-11-14 17:54:142400 # We ignore deps entries on auto-generated directories.
2401 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082402
Daniel Cheng4dcdb6b2017-04-13 08:30:172403 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2404 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2405
2406 added_deps = new_deps.difference(old_deps)
2407
[email protected]2b438d62013-11-14 17:54:142408 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172409 for added_dep in added_deps:
2410 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2411 continue
2412 # Assume that a rule that ends in .h is a rule for a specific file.
2413 if added_dep.endswith('.h'):
2414 results.add(added_dep)
2415 else:
2416 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082417 return results
2418
2419
Saagar Sanghavifceeaae2020-08-12 16:40:362420def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552421 """When a dependency prefixed with + is added to a DEPS file, we
2422 want to make sure that the change is reviewed by an OWNER of the
2423 target file or directory, to avoid layering violations from being
2424 introduced. This check verifies that this happens.
2425 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172426 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242427
2428 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492429 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242430 for f in input_api.AffectedFiles(include_deletes=False,
2431 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552432 filename = input_api.os_path.basename(f.LocalPath())
2433 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172434 virtual_depended_on_files.update(_CalculateAddedDeps(
2435 input_api.os_path,
2436 '\n'.join(f.OldContents()),
2437 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552438
[email protected]e871964c2013-05-13 14:14:552439 if not virtual_depended_on_files:
2440 return []
2441
2442 if input_api.is_committing:
2443 if input_api.tbr:
2444 return [output_api.PresubmitNotifyResult(
2445 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272446 if input_api.dry_run:
2447 return [output_api.PresubmitNotifyResult(
2448 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552449 if not input_api.change.issue:
2450 return [output_api.PresubmitError(
2451 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402452 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552453 output = output_api.PresubmitError
2454 else:
2455 output = output_api.PresubmitNotifyResult
2456
2457 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502458 owner_email, reviewers = (
2459 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2460 input_api,
2461 owners_db.email_regexp,
2462 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552463
2464 owner_email = owner_email or input_api.change.author_email
2465
[email protected]de4f7d22013-05-23 14:27:462466 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512467 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462468 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552469 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2470 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412471
2472 # We strip the /DEPS part that was added by
2473 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2474 # directory.
2475 def StripDeps(path):
2476 start_deps = path.rfind('/DEPS')
2477 if start_deps != -1:
2478 return path[:start_deps]
2479 else:
2480 return path
2481 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552482 for path in missing_files]
2483
2484 if unapproved_dependencies:
2485 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152486 output('You need LGTM from owners of depends-on paths in DEPS that were '
2487 'modified in this CL:\n %s' %
2488 '\n '.join(sorted(unapproved_dependencies)))]
2489 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2490 output_list.append(output(
2491 'Suggested missing target path OWNERS:\n %s' %
2492 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552493 return output_list
2494
2495 return []
2496
2497
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492498# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362499def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492500 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442501 files_to_skip = (_EXCLUDED_PATHS +
2502 _TEST_CODE_EXCLUDED_PATHS +
2503 input_api.DEFAULT_FILES_TO_SKIP +
2504 (r"^base[\\/]logging\.h$",
2505 r"^base[\\/]logging\.cc$",
2506 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2507 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2508 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2509 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2510 r"startup_browser_creator\.cc$",
2511 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2512 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2513 r"diagnostics_writer\.cc$",
2514 r"^chrome[\\/]chrome_cleaner[\\/].*",
2515 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2516 r"dll_hash_main\.cc$",
2517 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2518 r"^chromecast[\\/]",
2519 r"^cloud_print[\\/]",
2520 r"^components[\\/]browser_watcher[\\/]"
2521 r"dump_stability_report_main_win.cc$",
2522 r"^components[\\/]media_control[\\/]renderer[\\/]"
2523 r"media_playback_options\.cc$",
2524 r"^components[\\/]zucchini[\\/].*",
2525 # TODO(peter): Remove exception. https://crbug.com/534537
2526 r"^content[\\/]browser[\\/]notifications[\\/]"
2527 r"notification_event_dispatcher_impl\.cc$",
2528 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2529 r"gl_helper_benchmark\.cc$",
2530 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2531 r"^courgette[\\/]courgette_tool\.cc$",
2532 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2533 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2534 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2535 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2536 r"^ipc[\\/]ipc_logging\.cc$",
2537 r"^native_client_sdk[\\/]",
2538 r"^remoting[\\/]base[\\/]logging\.h$",
2539 r"^remoting[\\/]host[\\/].*",
2540 r"^sandbox[\\/]linux[\\/].*",
2541 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2542 r"dump_file_system.cc$",
2543 r"^tools[\\/]",
2544 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2545 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2546 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2547 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2548 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402549 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442550 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402551
thomasanderson625d3932017-03-29 07:16:582552 log_info = set([])
2553 printf = set([])
[email protected]85218562013-11-22 07:41:402554
2555 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582556 for _, line in f.ChangedContents():
2557 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2558 log_info.add(f.LocalPath())
2559 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2560 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372561
thomasanderson625d3932017-03-29 07:16:582562 if input_api.re.search(r"\bprintf\(", line):
2563 printf.add(f.LocalPath())
2564 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2565 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402566
2567 if log_info:
2568 return [output_api.PresubmitError(
2569 'These files spam the console log with LOG(INFO):',
2570 items=log_info)]
2571 if printf:
2572 return [output_api.PresubmitError(
2573 'These files spam the console log with printf/fprintf:',
2574 items=printf)]
2575 return []
2576
2577
Saagar Sanghavifceeaae2020-08-12 16:40:362578def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162579 """These types are all expected to hold locks while in scope and
2580 so should never be anonymous (which causes them to be immediately
2581 destroyed)."""
2582 they_who_must_be_named = [
2583 'base::AutoLock',
2584 'base::AutoReset',
2585 'base::AutoUnlock',
2586 'SkAutoAlphaRestore',
2587 'SkAutoBitmapShaderInstall',
2588 'SkAutoBlitterChoose',
2589 'SkAutoBounderCommit',
2590 'SkAutoCallProc',
2591 'SkAutoCanvasRestore',
2592 'SkAutoCommentBlock',
2593 'SkAutoDescriptor',
2594 'SkAutoDisableDirectionCheck',
2595 'SkAutoDisableOvalCheck',
2596 'SkAutoFree',
2597 'SkAutoGlyphCache',
2598 'SkAutoHDC',
2599 'SkAutoLockColors',
2600 'SkAutoLockPixels',
2601 'SkAutoMalloc',
2602 'SkAutoMaskFreeImage',
2603 'SkAutoMutexAcquire',
2604 'SkAutoPathBoundsUpdate',
2605 'SkAutoPDFRelease',
2606 'SkAutoRasterClipValidate',
2607 'SkAutoRef',
2608 'SkAutoTime',
2609 'SkAutoTrace',
2610 'SkAutoUnref',
2611 ]
2612 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2613 # bad: base::AutoLock(lock.get());
2614 # not bad: base::AutoLock lock(lock.get());
2615 bad_pattern = input_api.re.compile(anonymous)
2616 # good: new base::AutoLock(lock.get())
2617 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2618 errors = []
2619
2620 for f in input_api.AffectedFiles():
2621 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2622 continue
2623 for linenum, line in f.ChangedContents():
2624 if bad_pattern.search(line) and not good_pattern.search(line):
2625 errors.append('%s:%d' % (f.LocalPath(), linenum))
2626
2627 if errors:
2628 return [output_api.PresubmitError(
2629 'These lines create anonymous variables that need to be named:',
2630 items=errors)]
2631 return []
2632
2633
Saagar Sanghavifceeaae2020-08-12 16:40:362634def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532635 # Returns whether |template_str| is of the form <T, U...> for some types T
2636 # and U. Assumes that |template_str| is already in the form <...>.
2637 def HasMoreThanOneArg(template_str):
2638 # Level of <...> nesting.
2639 nesting = 0
2640 for c in template_str:
2641 if c == '<':
2642 nesting += 1
2643 elif c == '>':
2644 nesting -= 1
2645 elif c == ',' and nesting == 1:
2646 return True
2647 return False
2648
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492649 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102650 sources = lambda affected_file: input_api.FilterSourceFile(
2651 affected_file,
James Cook24a504192020-07-23 00:08:442652 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2653 input_api.DEFAULT_FILES_TO_SKIP),
2654 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552655
2656 # Pattern to capture a single "<...>" block of template arguments. It can
2657 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2658 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2659 # latter would likely require counting that < and > match, which is not
2660 # expressible in regular languages. Should the need arise, one can introduce
2661 # limited counting (matching up to a total number of nesting depth), which
2662 # should cover all practical cases for already a low nesting limit.
2663 template_arg_pattern = (
2664 r'<[^>]*' # Opening block of <.
2665 r'>([^<]*>)?') # Closing block of >.
2666 # Prefix expressing that whatever follows is not already inside a <...>
2667 # block.
2668 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102669 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552670 not_inside_template_arg_pattern
2671 + r'\bstd::unique_ptr'
2672 + template_arg_pattern
2673 + r'\(\)')
2674
2675 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2676 template_arg_no_array_pattern = (
2677 r'<[^>]*[^]]' # Opening block of <.
2678 r'>([^(<]*[^]]>)?') # Closing block of >.
2679 # Prefix saying that what follows is the start of an expression.
2680 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2681 # Suffix saying that what follows are call parentheses with a non-empty list
2682 # of arguments.
2683 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532684 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552685 return_construct_pattern = input_api.re.compile(
2686 start_of_expr_pattern
2687 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532688 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552689 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532690 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552691 + nonempty_arg_list_pattern)
2692
Vaclav Brozek851d9602018-04-04 16:13:052693 problems_constructor = []
2694 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102695 for f in input_api.AffectedSourceFiles(sources):
2696 for line_number, line in f.ChangedContents():
2697 # Disallow:
2698 # return std::unique_ptr<T>(foo);
2699 # bar = std::unique_ptr<T>(foo);
2700 # But allow:
2701 # return std::unique_ptr<T[]>(foo);
2702 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532703 # And also allow cases when the second template argument is present. Those
2704 # cases cannot be handled by std::make_unique:
2705 # return std::unique_ptr<T, U>(foo);
2706 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052707 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532708 return_construct_result = return_construct_pattern.search(line)
2709 if return_construct_result and not HasMoreThanOneArg(
2710 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052711 problems_constructor.append(
2712 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102713 # Disallow:
2714 # std::unique_ptr<T>()
2715 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052716 problems_nullptr.append(
2717 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2718
2719 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162720 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052721 errors.append(output_api.PresubmitError(
2722 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162723 problems_nullptr))
2724 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052725 errors.append(output_api.PresubmitError(
2726 'The following files use explicit std::unique_ptr constructor.'
2727 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162728 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102729 return errors
2730
2731
Saagar Sanghavifceeaae2020-08-12 16:40:362732def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082733 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522734 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082735 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522736 # If actions.xml is already included in the changelist, the PRESUBMIT
2737 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082738 return []
2739
[email protected]999261d2014-03-03 20:08:082740 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2741 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522742 current_actions = None
[email protected]999261d2014-03-03 20:08:082743 for f in input_api.AffectedFiles(file_filter=file_filter):
2744 for line_num, line in f.ChangedContents():
2745 match = input_api.re.search(action_re, line)
2746 if match:
[email protected]2f92dec2014-03-07 19:21:522747 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2748 # loaded only once.
2749 if not current_actions:
2750 with open('tools/metrics/actions/actions.xml') as actions_f:
2751 current_actions = actions_f.read()
2752 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082753 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522754 action = 'name="{0}"'.format(action_name)
2755 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082756 return [output_api.PresubmitPromptWarning(
2757 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522758 'tools/metrics/actions/actions.xml. Please run '
2759 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082760 % (f.LocalPath(), line_num, action_name))]
2761 return []
2762
2763
Daniel Cheng13ca61a882017-08-25 15:11:252764def _ImportJSONCommentEater(input_api):
2765 import sys
2766 sys.path = sys.path + [input_api.os_path.join(
2767 input_api.PresubmitLocalPath(),
2768 'tools', 'json_comment_eater')]
2769 import json_comment_eater
2770 return json_comment_eater
2771
2772
[email protected]99171a92014-06-03 08:44:472773def _GetJSONParseError(input_api, filename, eat_comments=True):
2774 try:
2775 contents = input_api.ReadFile(filename)
2776 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252777 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132778 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472779
2780 input_api.json.loads(contents)
2781 except ValueError as e:
2782 return e
2783 return None
2784
2785
2786def _GetIDLParseError(input_api, filename):
2787 try:
2788 contents = input_api.ReadFile(filename)
2789 idl_schema = input_api.os_path.join(
2790 input_api.PresubmitLocalPath(),
2791 'tools', 'json_schema_compiler', 'idl_schema.py')
2792 process = input_api.subprocess.Popen(
2793 [input_api.python_executable, idl_schema],
2794 stdin=input_api.subprocess.PIPE,
2795 stdout=input_api.subprocess.PIPE,
2796 stderr=input_api.subprocess.PIPE,
2797 universal_newlines=True)
2798 (_, error) = process.communicate(input=contents)
2799 return error or None
2800 except ValueError as e:
2801 return e
2802
2803
Saagar Sanghavifceeaae2020-08-12 16:40:362804def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472805 """Check that IDL and JSON files do not contain syntax errors."""
2806 actions = {
2807 '.idl': _GetIDLParseError,
2808 '.json': _GetJSONParseError,
2809 }
[email protected]99171a92014-06-03 08:44:472810 # Most JSON files are preprocessed and support comments, but these do not.
2811 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042812 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472813 ]
2814 # Only run IDL checker on files in these directories.
2815 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042816 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2817 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472818 ]
2819
2820 def get_action(affected_file):
2821 filename = affected_file.LocalPath()
2822 return actions.get(input_api.os_path.splitext(filename)[1])
2823
[email protected]99171a92014-06-03 08:44:472824 def FilterFile(affected_file):
2825 action = get_action(affected_file)
2826 if not action:
2827 return False
2828 path = affected_file.LocalPath()
2829
Erik Staab2dd72b12020-04-16 15:03:402830 if _MatchesFile(input_api,
2831 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2832 path):
[email protected]99171a92014-06-03 08:44:472833 return False
2834
2835 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162836 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472837 return False
2838 return True
2839
2840 results = []
2841 for affected_file in input_api.AffectedFiles(
2842 file_filter=FilterFile, include_deletes=False):
2843 action = get_action(affected_file)
2844 kwargs = {}
2845 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162846 _MatchesFile(input_api, json_no_comments_patterns,
2847 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472848 kwargs['eat_comments'] = False
2849 parse_error = action(input_api,
2850 affected_file.AbsoluteLocalPath(),
2851 **kwargs)
2852 if parse_error:
2853 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2854 (affected_file.LocalPath(), parse_error)))
2855 return results
2856
2857
Saagar Sanghavifceeaae2020-08-12 16:40:362858def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492859 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472860 import sys
[email protected]760deea2013-12-10 19:33:492861 original_sys_path = sys.path
2862 try:
2863 sys.path = sys.path + [input_api.os_path.join(
2864 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2865 import checkstyle
2866 finally:
2867 # Restore sys.path to what it was before.
2868 sys.path = original_sys_path
2869
2870 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092871 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442872 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492873
2874
Saagar Sanghavifceeaae2020-08-12 16:40:362875def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002876 """Checks to make sure devil is initialized correctly in python scripts."""
2877 script_common_initialize_pattern = input_api.re.compile(
2878 r'script_common\.InitializeEnvironment\(')
2879 devil_env_config_initialize = input_api.re.compile(
2880 r'devil_env\.config\.Initialize\(')
2881
2882 errors = []
2883
2884 sources = lambda affected_file: input_api.FilterSourceFile(
2885 affected_file,
James Cook24a504192020-07-23 00:08:442886 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2887 (r'^build[\\/]android[\\/]devil_chromium\.py',
2888 r'^third_party[\\/].*',)),
2889 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002890
2891 for f in input_api.AffectedSourceFiles(sources):
2892 for line_num, line in f.ChangedContents():
2893 if (script_common_initialize_pattern.search(line) or
2894 devil_env_config_initialize.search(line)):
2895 errors.append("%s:%d" % (f.LocalPath(), line_num))
2896
2897 results = []
2898
2899 if errors:
2900 results.append(output_api.PresubmitError(
2901 'Devil initialization should always be done using '
2902 'devil_chromium.Initialize() in the chromium project, to use better '
2903 'defaults for dependencies (ex. up-to-date version of adb).',
2904 errors))
2905
2906 return results
2907
2908
Sean Kau46e29bc2017-08-28 16:31:162909def _MatchesFile(input_api, patterns, path):
2910 for pattern in patterns:
2911 if input_api.re.search(pattern, path):
2912 return True
2913 return False
2914
2915
Daniel Cheng7052cdf2017-11-21 19:23:292916def _GetOwnersFilesToCheckForIpcOwners(input_api):
2917 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172918
Daniel Cheng7052cdf2017-11-21 19:23:292919 Returns:
2920 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2921 contain to cover IPC-related files with noparent reviewer rules.
2922 """
2923 # Whether or not a file affects IPC is (mostly) determined by a simple list
2924 # of filename patterns.
dchenge07de812016-06-20 19:27:172925 file_patterns = [
palmerb19a0932017-01-24 04:00:312926 # Legacy IPC:
dchenge07de812016-06-20 19:27:172927 '*_messages.cc',
2928 '*_messages*.h',
2929 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312930 # Mojo IPC:
dchenge07de812016-06-20 19:27:172931 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472932 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172933 '*_struct_traits*.*',
2934 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312935 '*.typemap',
2936 # Android native IPC:
2937 '*.aidl',
2938 # Blink uses a different file naming convention:
2939 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472940 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172941 '*StructTraits*.*',
2942 '*TypeConverter*.*',
2943 ]
2944
scottmg7a6ed5ba2016-11-04 18:22:042945 # These third_party directories do not contain IPCs, but contain files
2946 # matching the above patterns, which trigger false positives.
2947 exclude_paths = [
2948 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162949 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232950 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292951 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542952 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162953 # These files are just used to communicate between class loaders running
2954 # in the same process.
2955 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572956 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2957
scottmg7a6ed5ba2016-11-04 18:22:042958 ]
2959
dchenge07de812016-06-20 19:27:172960 # Dictionary mapping an OWNERS file path to Patterns.
2961 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2962 # rules ) to a PatternEntry.
2963 # PatternEntry is a dictionary with two keys:
2964 # - 'files': the files that are matched by this pattern
2965 # - 'rules': the per-file rules needed for this pattern
2966 # For example, if we expect OWNERS file to contain rules for *.mojom and
2967 # *_struct_traits*.*, Patterns might look like this:
2968 # {
2969 # '*.mojom': {
2970 # 'files': ...,
2971 # 'rules': [
2972 # 'per-file *.mojom=set noparent',
2973 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2974 # ],
2975 # },
2976 # '*_struct_traits*.*': {
2977 # 'files': ...,
2978 # 'rules': [
2979 # 'per-file *_struct_traits*.*=set noparent',
2980 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2981 # ],
2982 # },
2983 # }
2984 to_check = {}
2985
Daniel Cheng13ca61a882017-08-25 15:11:252986 def AddPatternToCheck(input_file, pattern):
2987 owners_file = input_api.os_path.join(
2988 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2989 if owners_file not in to_check:
2990 to_check[owners_file] = {}
2991 if pattern not in to_check[owners_file]:
2992 to_check[owners_file][pattern] = {
2993 'files': [],
2994 'rules': [
2995 'per-file %s=set noparent' % pattern,
2996 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2997 ]
2998 }
Vaclav Brozekd5de76a2018-03-17 07:57:502999 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:253000
dchenge07de812016-06-20 19:27:173001 # Iterate through the affected files to see what we actually need to check
3002 # for. We should only nag patch authors about per-file rules if a file in that
3003 # directory would match that pattern. If a directory only contains *.mojom
3004 # files and no *_messages*.h files, we should only nag about rules for
3005 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:253006 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:263007 # Manifest files don't have a strong naming convention. Instead, try to find
3008 # affected .cc and .h files which look like they contain a manifest
3009 # definition.
3010 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3011 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3012 if (manifest_pattern.search(f.LocalPath()) and not
3013 test_manifest_pattern.search(f.LocalPath())):
3014 # We expect all actual service manifest files to contain at least one
3015 # qualified reference to service_manager::Manifest.
3016 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:253017 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:173018 for pattern in file_patterns:
3019 if input_api.fnmatch.fnmatch(
3020 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:043021 skip = False
3022 for exclude in exclude_paths:
3023 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
3024 skip = True
3025 break
3026 if skip:
3027 continue
Daniel Cheng13ca61a882017-08-25 15:11:253028 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173029 break
3030
Daniel Cheng7052cdf2017-11-21 19:23:293031 return to_check
3032
3033
Wez17c66962020-04-29 15:26:033034def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3035 """Adds OWNERS files to check for correct Fuchsia security owners."""
3036
3037 file_patterns = [
3038 # Component specifications.
3039 '*.cml', # Component Framework v2.
3040 '*.cmx', # Component Framework v1.
3041
3042 # Fuchsia IDL protocol specifications.
3043 '*.fidl',
3044 ]
3045
3046 def AddPatternToCheck(input_file, pattern):
3047 owners_file = input_api.os_path.join(
3048 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3049 if owners_file not in to_check:
3050 to_check[owners_file] = {}
3051 if pattern not in to_check[owners_file]:
3052 to_check[owners_file][pattern] = {
3053 'files': [],
3054 'rules': [
3055 'per-file %s=set noparent' % pattern,
3056 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3057 ]
3058 }
3059 to_check[owners_file][pattern]['files'].append(input_file)
3060
3061 # Iterate through the affected files to see what we actually need to check
3062 # for. We should only nag patch authors about per-file rules if a file in that
3063 # directory would match that pattern.
3064 for f in input_api.AffectedFiles(include_deletes=False):
3065 for pattern in file_patterns:
3066 if input_api.fnmatch.fnmatch(
3067 input_api.os_path.basename(f.LocalPath()), pattern):
3068 AddPatternToCheck(f, pattern)
3069 break
3070
3071 return to_check
3072
3073
Saagar Sanghavifceeaae2020-08-12 16:40:363074def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293075 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3076 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033077 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293078
3079 if to_check:
3080 # If there are any OWNERS files to check, there are IPC-related changes in
3081 # this CL. Auto-CC the review list.
3082 output_api.AppendCC('[email protected]')
3083
3084 # Go through the OWNERS files to check, filtering out rules that are already
3085 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173086 for owners_file, patterns in to_check.iteritems():
3087 try:
3088 with file(owners_file) as f:
3089 lines = set(f.read().splitlines())
3090 for entry in patterns.itervalues():
3091 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3092 ]
3093 except IOError:
3094 # No OWNERS file, so all the rules are definitely missing.
3095 continue
3096
3097 # All the remaining lines weren't found in OWNERS files, so emit an error.
3098 errors = []
3099 for owners_file, patterns in to_check.iteritems():
3100 missing_lines = []
3101 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503102 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173103 missing_lines.extend(entry['rules'])
3104 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3105 if missing_lines:
3106 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053107 'Because of the presence of files:\n%s\n\n'
3108 '%s needs the following %d lines added:\n\n%s' %
3109 ('\n'.join(files), owners_file, len(missing_lines),
3110 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173111
3112 results = []
3113 if errors:
vabrf5ce3bf92016-07-11 14:52:413114 if input_api.is_committing:
3115 output = output_api.PresubmitError
3116 else:
3117 output = output_api.PresubmitPromptWarning
3118 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593119 'Found OWNERS files that need to be updated for IPC security ' +
3120 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173121 long_text='\n\n'.join(errors)))
3122
3123 return results
3124
3125
Robert Sesek2c905332020-05-06 23:17:133126def _GetFilesUsingSecurityCriticalFunctions(input_api):
3127 """Checks affected files for changes to security-critical calls. This
3128 function checks the full change diff, to catch both additions/changes
3129 and removals.
3130
3131 Returns a dict keyed by file name, and the value is a set of detected
3132 functions.
3133 """
3134 # Map of function pretty name (displayed in an error) to the pattern to
3135 # match it with.
3136 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373137 'content::GetServiceSandboxType<>()':
3138 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133139 }
3140 _PATTERNS_TO_CHECK = {
3141 k: input_api.re.compile(v)
3142 for k, v in _PATTERNS_TO_CHECK.items()
3143 }
3144
3145 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3146 files_to_functions = {}
3147 for f in input_api.AffectedFiles():
3148 diff = f.GenerateScmDiff()
3149 for line in diff.split('\n'):
3150 # Not using just RightHandSideLines() because removing a
3151 # call to a security-critical function can be just as important
3152 # as adding or changing the arguments.
3153 if line.startswith('-') or (line.startswith('+') and
3154 not line.startswith('++')):
3155 for name, pattern in _PATTERNS_TO_CHECK.items():
3156 if pattern.search(line):
3157 path = f.LocalPath()
3158 if not path in files_to_functions:
3159 files_to_functions[path] = set()
3160 files_to_functions[path].add(name)
3161 return files_to_functions
3162
3163
Saagar Sanghavifceeaae2020-08-12 16:40:363164def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133165 """Checks that changes involving security-critical functions are reviewed
3166 by the security team.
3167 """
3168 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3169 if len(files_to_functions):
3170 owners_db = input_api.owners_db
3171 owner_email, reviewers = (
3172 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3173 input_api,
3174 owners_db.email_regexp,
3175 approval_needed=input_api.is_committing))
3176
3177 # Load the OWNERS file for security changes.
3178 owners_file = 'ipc/SECURITY_OWNERS'
3179 security_owners = owners_db.owners_rooted_at_file(owners_file)
3180
3181 has_security_owner = any([owner in reviewers for owner in security_owners])
3182 if not has_security_owner:
3183 msg = 'The following files change calls to security-sensive functions\n' \
3184 'that need to be reviewed by {}.\n'.format(owners_file)
3185 for path, names in files_to_functions.items():
3186 msg += ' {}\n'.format(path)
3187 for name in names:
3188 msg += ' {}\n'.format(name)
3189 msg += '\n'
3190
3191 if input_api.is_committing:
3192 output = output_api.PresubmitError
3193 else:
3194 output = output_api.PresubmitNotifyResult
3195 return [output(msg)]
3196
3197 return []
3198
3199
Saagar Sanghavifceeaae2020-08-12 16:40:363200def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263201 """Checks that set noparent is only used together with an OWNERS file in
3202 //build/OWNERS.setnoparent (see also
3203 //docs/code_reviews.md#owners-files-details)
3204 """
3205 errors = []
3206
3207 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3208 allowed_owners_files = set()
3209 with open(allowed_owners_files_file, 'r') as f:
3210 for line in f:
3211 line = line.strip()
3212 if not line or line.startswith('#'):
3213 continue
3214 allowed_owners_files.add(line)
3215
3216 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3217
3218 for f in input_api.AffectedFiles(include_deletes=False):
3219 if not f.LocalPath().endswith('OWNERS'):
3220 continue
3221
3222 found_owners_files = set()
3223 found_set_noparent_lines = dict()
3224
3225 # Parse the OWNERS file.
3226 for lineno, line in enumerate(f.NewContents(), 1):
3227 line = line.strip()
3228 if line.startswith('set noparent'):
3229 found_set_noparent_lines[''] = lineno
3230 if line.startswith('file://'):
3231 if line in allowed_owners_files:
3232 found_owners_files.add('')
3233 if line.startswith('per-file'):
3234 match = per_file_pattern.match(line)
3235 if match:
3236 glob = match.group(1).strip()
3237 directive = match.group(2).strip()
3238 if directive == 'set noparent':
3239 found_set_noparent_lines[glob] = lineno
3240 if directive.startswith('file://'):
3241 if directive in allowed_owners_files:
3242 found_owners_files.add(glob)
3243
3244 # Check that every set noparent line has a corresponding file:// line
3245 # listed in build/OWNERS.setnoparent.
3246 for set_noparent_line in found_set_noparent_lines:
3247 if set_noparent_line in found_owners_files:
3248 continue
3249 errors.append(' %s:%d' % (f.LocalPath(),
3250 found_set_noparent_lines[set_noparent_line]))
3251
3252 results = []
3253 if errors:
3254 if input_api.is_committing:
3255 output = output_api.PresubmitError
3256 else:
3257 output = output_api.PresubmitPromptWarning
3258 results.append(output(
3259 'Found the following "set noparent" restrictions in OWNERS files that '
3260 'do not include owners from build/OWNERS.setnoparent:',
3261 long_text='\n\n'.join(errors)))
3262 return results
3263
3264
Saagar Sanghavifceeaae2020-08-12 16:40:363265def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313266 """Checks that added or removed lines in non third party affected
3267 header files do not lead to new useless class or struct forward
3268 declaration.
jbriance9e12f162016-11-25 07:57:503269 """
3270 results = []
3271 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3272 input_api.re.MULTILINE)
3273 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3274 input_api.re.MULTILINE)
3275 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313276 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193277 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493278 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313279 continue
3280
jbriance9e12f162016-11-25 07:57:503281 if not f.LocalPath().endswith('.h'):
3282 continue
3283
3284 contents = input_api.ReadFile(f)
3285 fwd_decls = input_api.re.findall(class_pattern, contents)
3286 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3287
3288 useless_fwd_decls = []
3289 for decl in fwd_decls:
3290 count = sum(1 for _ in input_api.re.finditer(
3291 r'\b%s\b' % input_api.re.escape(decl), contents))
3292 if count == 1:
3293 useless_fwd_decls.append(decl)
3294
3295 if not useless_fwd_decls:
3296 continue
3297
3298 for line in f.GenerateScmDiff().splitlines():
3299 if (line.startswith('-') and not line.startswith('--') or
3300 line.startswith('+') and not line.startswith('++')):
3301 for decl in useless_fwd_decls:
3302 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3303 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243304 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503305 (f.LocalPath(), decl)))
3306 useless_fwd_decls.remove(decl)
3307
3308 return results
3309
Jinsong Fan91ebbbd2019-04-16 14:57:173310def _CheckAndroidDebuggableBuild(input_api, output_api):
3311 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3312 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3313 this is a debuggable build of Android.
3314 """
3315 build_type_check_pattern = input_api.re.compile(
3316 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3317
3318 errors = []
3319
3320 sources = lambda affected_file: input_api.FilterSourceFile(
3321 affected_file,
James Cook24a504192020-07-23 00:08:443322 files_to_skip=(_EXCLUDED_PATHS +
3323 _TEST_CODE_EXCLUDED_PATHS +
3324 input_api.DEFAULT_FILES_TO_SKIP +
3325 (r"^android_webview[\\/]support_library[\\/]"
3326 "boundary_interfaces[\\/]",
3327 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3328 r'^third_party[\\/].*',
3329 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3330 r"webview[\\/]chromium[\\/]License.*",)),
3331 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173332
3333 for f in input_api.AffectedSourceFiles(sources):
3334 for line_num, line in f.ChangedContents():
3335 if build_type_check_pattern.search(line):
3336 errors.append("%s:%d" % (f.LocalPath(), line_num))
3337
3338 results = []
3339
3340 if errors:
3341 results.append(output_api.PresubmitPromptWarning(
3342 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3343 ' Please use BuildInfo.isDebugAndroid() instead.',
3344 errors))
3345
3346 return results
jbriance9e12f162016-11-25 07:57:503347
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493348# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293349def _CheckAndroidToastUsage(input_api, output_api):
3350 """Checks that code uses org.chromium.ui.widget.Toast instead of
3351 android.widget.Toast (Chromium Toast doesn't force hardware
3352 acceleration on low-end devices, saving memory).
3353 """
3354 toast_import_pattern = input_api.re.compile(
3355 r'^import android\.widget\.Toast;$')
3356
3357 errors = []
3358
3359 sources = lambda affected_file: input_api.FilterSourceFile(
3360 affected_file,
James Cook24a504192020-07-23 00:08:443361 files_to_skip=(_EXCLUDED_PATHS +
3362 _TEST_CODE_EXCLUDED_PATHS +
3363 input_api.DEFAULT_FILES_TO_SKIP +
3364 (r'^chromecast[\\/].*',
3365 r'^remoting[\\/].*')),
3366 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293367
3368 for f in input_api.AffectedSourceFiles(sources):
3369 for line_num, line in f.ChangedContents():
3370 if toast_import_pattern.search(line):
3371 errors.append("%s:%d" % (f.LocalPath(), line_num))
3372
3373 results = []
3374
3375 if errors:
3376 results.append(output_api.PresubmitError(
3377 'android.widget.Toast usage is detected. Android toasts use hardware'
3378 ' acceleration, and can be\ncostly on low-end devices. Please use'
3379 ' org.chromium.ui.widget.Toast instead.\n'
3380 'Contact [email protected] if you have any questions.',
3381 errors))
3382
3383 return results
3384
3385
dgnaa68d5e2015-06-10 10:08:223386def _CheckAndroidCrLogUsage(input_api, output_api):
3387 """Checks that new logs using org.chromium.base.Log:
3388 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513389 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223390 """
pkotwicza1dd0b002016-05-16 14:41:043391
torne89540622017-03-24 19:41:303392 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043393 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303394 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043395 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303396 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043397 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3398 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093399 # The customtabs_benchmark is a small app that does not depend on Chromium
3400 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043401 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043402 ]
3403
dgnaa68d5e2015-06-10 10:08:223404 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123405 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3406 class_in_base_pattern = input_api.re.compile(
3407 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3408 has_some_log_import_pattern = input_api.re.compile(
3409 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223410 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553411 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223412 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463413 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553414 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223415
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463416 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443417 sources = lambda x: input_api.FilterSourceFile(x,
3418 files_to_check=[r'.*\.java$'],
3419 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123420
dgnaa68d5e2015-06-10 10:08:223421 tag_decl_errors = []
3422 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123423 tag_errors = []
dgn38736db2015-09-18 19:20:513424 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123425 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223426
3427 for f in input_api.AffectedSourceFiles(sources):
3428 file_content = input_api.ReadFile(f)
3429 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223430 # Per line checks
dgn87d9fb62015-06-12 09:15:123431 if (cr_log_import_pattern.search(file_content) or
3432 (class_in_base_pattern.search(file_content) and
3433 not has_some_log_import_pattern.search(file_content))):
3434 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223435 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553436 if rough_log_decl_pattern.search(line):
3437 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223438
3439 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123440 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223441 if match:
3442 has_modified_logs = True
3443
3444 # Make sure it uses "TAG"
3445 if not match.group('tag') == 'TAG':
3446 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123447 else:
3448 # Report non cr Log function calls in changed lines
3449 for line_num, line in f.ChangedContents():
3450 if log_call_pattern.search(line):
3451 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223452
3453 # Per file checks
3454 if has_modified_logs:
3455 # Make sure the tag is using the "cr" prefix and is not too long
3456 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513457 tag_name = match.group('name') if match else None
3458 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223459 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513460 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223461 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513462 elif '.' in tag_name:
3463 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223464
3465 results = []
3466 if tag_decl_errors:
3467 results.append(output_api.PresubmitPromptWarning(
3468 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513469 '"private static final String TAG = "<package tag>".\n'
3470 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223471 tag_decl_errors))
3472
3473 if tag_length_errors:
3474 results.append(output_api.PresubmitError(
3475 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513476 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223477 tag_length_errors))
3478
3479 if tag_errors:
3480 results.append(output_api.PresubmitPromptWarning(
3481 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3482 tag_errors))
3483
dgn87d9fb62015-06-12 09:15:123484 if util_log_errors:
dgn4401aa52015-04-29 16:26:173485 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123486 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3487 util_log_errors))
3488
dgn38736db2015-09-18 19:20:513489 if tag_with_dot_errors:
3490 results.append(output_api.PresubmitPromptWarning(
3491 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3492 tag_with_dot_errors))
3493
dgn4401aa52015-04-29 16:26:173494 return results
3495
3496
Yoland Yanb92fa522017-08-28 17:37:063497def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3498 """Checks that junit.framework.* is no longer used."""
3499 deprecated_junit_framework_pattern = input_api.re.compile(
3500 r'^import junit\.framework\..*;',
3501 input_api.re.MULTILINE)
3502 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443503 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063504 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133505 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063506 for line_num, line in f.ChangedContents():
3507 if deprecated_junit_framework_pattern.search(line):
3508 errors.append("%s:%d" % (f.LocalPath(), line_num))
3509
3510 results = []
3511 if errors:
3512 results.append(output_api.PresubmitError(
3513 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3514 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3515 ' if you have any question.', errors))
3516 return results
3517
3518
3519def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3520 """Checks that if new Java test classes have inheritance.
3521 Either the new test class is JUnit3 test or it is a JUnit4 test class
3522 with a base class, either case is undesirable.
3523 """
3524 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3525
3526 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443527 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063528 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133529 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063530 if not f.OldContents():
3531 class_declaration_start_flag = False
3532 for line_num, line in f.ChangedContents():
3533 if class_declaration_pattern.search(line):
3534 class_declaration_start_flag = True
3535 if class_declaration_start_flag and ' extends ' in line:
3536 errors.append('%s:%d' % (f.LocalPath(), line_num))
3537 if '{' in line:
3538 class_declaration_start_flag = False
3539
3540 results = []
3541 if errors:
3542 results.append(output_api.PresubmitPromptWarning(
3543 'The newly created files include Test classes that inherits from base'
3544 ' class. Please do not use inheritance in JUnit4 tests or add new'
3545 ' JUnit3 tests. Contact [email protected] if you have any'
3546 ' questions.', errors))
3547 return results
3548
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203549
yolandyan45001472016-12-21 21:12:423550def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3551 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3552 deprecated_annotation_import_pattern = input_api.re.compile(
3553 r'^import android\.test\.suitebuilder\.annotation\..*;',
3554 input_api.re.MULTILINE)
3555 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443556 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423557 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133558 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423559 for line_num, line in f.ChangedContents():
3560 if deprecated_annotation_import_pattern.search(line):
3561 errors.append("%s:%d" % (f.LocalPath(), line_num))
3562
3563 results = []
3564 if errors:
3565 results.append(output_api.PresubmitError(
3566 'Annotations in android.test.suitebuilder.annotation have been'
3567 ' deprecated since API level 24. Please use android.support.test.filters'
3568 ' from //third_party/android_support_test_runner:runner_java instead.'
3569 ' Contact [email protected] if you have any questions.', errors))
3570 return results
3571
3572
agrieve7b6479d82015-10-07 14:24:223573def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3574 """Checks if MDPI assets are placed in a correct directory."""
3575 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3576 ('/res/drawable/' in f.LocalPath() or
3577 '/res/drawable-ldrtl/' in f.LocalPath()))
3578 errors = []
3579 for f in input_api.AffectedFiles(include_deletes=False,
3580 file_filter=file_filter):
3581 errors.append(' %s' % f.LocalPath())
3582
3583 results = []
3584 if errors:
3585 results.append(output_api.PresubmitError(
3586 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3587 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3588 '/res/drawable-ldrtl/.\n'
3589 'Contact [email protected] if you have questions.', errors))
3590 return results
3591
3592
Nate Fischer535972b2017-09-16 01:06:183593def _CheckAndroidWebkitImports(input_api, output_api):
3594 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353595 android.webview.ValueCallback except in the WebView glue layer
3596 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183597 """
3598 valuecallback_import_pattern = input_api.re.compile(
3599 r'^import android\.webkit\.ValueCallback;$')
3600
3601 errors = []
3602
3603 sources = lambda affected_file: input_api.FilterSourceFile(
3604 affected_file,
James Cook24a504192020-07-23 00:08:443605 files_to_skip=(_EXCLUDED_PATHS +
3606 _TEST_CODE_EXCLUDED_PATHS +
3607 input_api.DEFAULT_FILES_TO_SKIP +
3608 (r'^android_webview[\\/]glue[\\/].*',
3609 r'^weblayer[\\/].*',)),
3610 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183611
3612 for f in input_api.AffectedSourceFiles(sources):
3613 for line_num, line in f.ChangedContents():
3614 if valuecallback_import_pattern.search(line):
3615 errors.append("%s:%d" % (f.LocalPath(), line_num))
3616
3617 results = []
3618
3619 if errors:
3620 results.append(output_api.PresubmitError(
3621 'android.webkit.ValueCallback usage is detected outside of the glue'
3622 ' layer. To stay compatible with the support library, android.webkit.*'
3623 ' classes should only be used inside the glue layer and'
3624 ' org.chromium.base.Callback should be used instead.',
3625 errors))
3626
3627 return results
3628
3629
Becky Zhou7c69b50992018-12-10 19:37:573630def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3631 """Checks Android XML styles """
3632 import sys
3633 original_sys_path = sys.path
3634 try:
3635 sys.path = sys.path + [input_api.os_path.join(
3636 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3637 import checkxmlstyle
3638 finally:
3639 # Restore sys.path to what it was before.
3640 sys.path = original_sys_path
3641
3642 if is_check_on_upload:
3643 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3644 else:
3645 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3646
3647
agrievef32bcc72016-04-04 14:57:403648class PydepsChecker(object):
3649 def __init__(self, input_api, pydeps_files):
3650 self._file_cache = {}
3651 self._input_api = input_api
3652 self._pydeps_files = pydeps_files
3653
3654 def _LoadFile(self, path):
3655 """Returns the list of paths within a .pydeps file relative to //."""
3656 if path not in self._file_cache:
3657 with open(path) as f:
3658 self._file_cache[path] = f.read()
3659 return self._file_cache[path]
3660
3661 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3662 """Returns an interable of paths within the .pydep, relativized to //."""
3663 os_path = self._input_api.os_path
3664 pydeps_dir = os_path.dirname(pydeps_path)
3665 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3666 if not l.startswith('*'))
3667 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3668
3669 def _CreateFilesToPydepsMap(self):
3670 """Returns a map of local_path -> list_of_pydeps."""
3671 ret = {}
3672 for pydep_local_path in self._pydeps_files:
3673 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3674 ret.setdefault(path, []).append(pydep_local_path)
3675 return ret
3676
3677 def ComputeAffectedPydeps(self):
3678 """Returns an iterable of .pydeps files that might need regenerating."""
3679 affected_pydeps = set()
3680 file_to_pydeps_map = None
3681 for f in self._input_api.AffectedFiles(include_deletes=True):
3682 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463683 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3684 # subrepositories. We can't figure out which files change, so re-check
3685 # all files.
3686 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383687 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3688 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403689 return self._pydeps_files
3690 elif local_path.endswith('.pydeps'):
3691 if local_path in self._pydeps_files:
3692 affected_pydeps.add(local_path)
3693 elif local_path.endswith('.py'):
3694 if file_to_pydeps_map is None:
3695 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3696 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3697 return affected_pydeps
3698
3699 def DetermineIfStale(self, pydeps_path):
3700 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413701 import difflib
John Budorick47ca3fe2018-02-10 00:53:103702 import os
3703
agrievef32bcc72016-04-04 14:57:403704 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033705 if old_pydeps_data:
3706 cmd = old_pydeps_data[1][1:].strip()
3707 old_contents = old_pydeps_data[2:]
3708 else:
3709 # A default cmd that should work in most cases (as long as pydeps filename
3710 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3711 # file is empty/new.
3712 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3713 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3714 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103715 env = dict(os.environ)
3716 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403717 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103718 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413719 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033720 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413721 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403722
3723
Tibor Goldschwendt360793f72019-06-25 18:23:493724def _ParseGclientArgs():
3725 args = {}
3726 with open('build/config/gclient_args.gni', 'r') as f:
3727 for line in f:
3728 line = line.strip()
3729 if not line or line.startswith('#'):
3730 continue
3731 attribute, value = line.split('=')
3732 args[attribute.strip()] = value.strip()
3733 return args
3734
3735
Saagar Sanghavifceeaae2020-08-12 16:40:363736def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403737 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403738 # This check is for Python dependency lists (.pydeps files), and involves
3739 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3740 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283741 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003742 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493743 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403744 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403745 results = []
3746 # First, check for new / deleted .pydeps.
3747 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033748 # Check whether we are running the presubmit check for a file in src.
3749 # f.LocalPath is relative to repo (src, or internal repo).
3750 # os_path.exists is relative to src repo.
3751 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3752 # to src and we can conclude that the pydeps is in src.
3753 if input_api.os_path.exists(f.LocalPath()):
3754 if f.LocalPath().endswith('.pydeps'):
3755 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3756 results.append(output_api.PresubmitError(
3757 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3758 'remove %s' % f.LocalPath()))
3759 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3760 results.append(output_api.PresubmitError(
3761 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3762 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403763
3764 if results:
3765 return results
3766
Mohamed Heikal7cd4d8312020-06-16 16:49:403767 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3768 affected_pydeps = set(checker.ComputeAffectedPydeps())
3769 affected_android_pydeps = affected_pydeps.intersection(
3770 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3771 if affected_android_pydeps and not is_android:
3772 results.append(output_api.PresubmitPromptOrNotify(
3773 'You have changed python files that may affect pydeps for android\n'
3774 'specific scripts. However, the relevant presumbit check cannot be\n'
3775 'run because you are not using an Android checkout. To validate that\n'
3776 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3777 'use the android-internal-presubmit optional trybot.\n'
3778 'Possibly stale pydeps files:\n{}'.format(
3779 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403780
Mohamed Heikal7cd4d8312020-06-16 16:49:403781 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3782 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403783 try:
phajdan.jr0d9878552016-11-04 10:49:413784 result = checker.DetermineIfStale(pydep_path)
3785 if result:
3786 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403787 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413788 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3789 'To regenerate, run:\n\n %s' %
3790 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403791 except input_api.subprocess.CalledProcessError as error:
3792 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3793 long_text=error.output)]
3794
3795 return results
3796
3797
Saagar Sanghavifceeaae2020-08-12 16:40:363798def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433799 """Checks to make sure no header files have |Singleton<|."""
3800 def FileFilter(affected_file):
3801 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443802 files_to_skip = (_EXCLUDED_PATHS +
3803 input_api.DEFAULT_FILES_TO_SKIP +
3804 (r"^base[\\/]memory[\\/]singleton\.h$",
3805 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3806 r"quic_singleton_impl\.h$"))
3807 return input_api.FilterSourceFile(affected_file,
3808 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433809
sergeyu34d21222015-09-16 00:11:443810 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433811 files = []
3812 for f in input_api.AffectedSourceFiles(FileFilter):
3813 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3814 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3815 contents = input_api.ReadFile(f)
3816 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243817 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433818 pattern.search(line)):
3819 files.append(f)
3820 break
3821
3822 if files:
yolandyandaabc6d2016-04-18 18:29:393823 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443824 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433825 'Please move them to an appropriate source file so that the ' +
3826 'template gets instantiated in a single compilation unit.',
3827 files) ]
3828 return []
3829
3830
[email protected]fd20b902014-05-09 02:14:533831_DEPRECATED_CSS = [
3832 # Values
3833 ( "-webkit-box", "flex" ),
3834 ( "-webkit-inline-box", "inline-flex" ),
3835 ( "-webkit-flex", "flex" ),
3836 ( "-webkit-inline-flex", "inline-flex" ),
3837 ( "-webkit-min-content", "min-content" ),
3838 ( "-webkit-max-content", "max-content" ),
3839
3840 # Properties
3841 ( "-webkit-background-clip", "background-clip" ),
3842 ( "-webkit-background-origin", "background-origin" ),
3843 ( "-webkit-background-size", "background-size" ),
3844 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443845 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533846
3847 # Functions
3848 ( "-webkit-gradient", "gradient" ),
3849 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3850 ( "-webkit-linear-gradient", "linear-gradient" ),
3851 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3852 ( "-webkit-radial-gradient", "radial-gradient" ),
3853 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3854]
3855
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203856
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493857# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363858def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533859 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253860 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343861 documentation and iOS CSS for dom distiller
3862 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253863 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533864 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493865 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443866 files_to_skip = (_EXCLUDED_PATHS +
3867 _TEST_CODE_EXCLUDED_PATHS +
3868 input_api.DEFAULT_FILES_TO_SKIP +
3869 (r"^chrome/common/extensions/docs",
3870 r"^chrome/docs",
3871 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3872 r"^components/neterror/resources/neterror.css",
3873 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253874 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443875 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533876 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3877 for line_num, line in fpath.ChangedContents():
3878 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023879 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533880 results.append(output_api.PresubmitError(
3881 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3882 (fpath.LocalPath(), line_num, deprecated_value, value)))
3883 return results
3884
mohan.reddyf21db962014-10-16 12:26:473885
Saagar Sanghavifceeaae2020-08-12 16:40:363886def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363887 bad_files = {}
3888 for f in input_api.AffectedFiles(include_deletes=False):
3889 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493890 not f.LocalPath().startswith('third_party/blink') and
3891 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363892 continue
3893
Daniel Bratell65b033262019-04-23 08:17:063894 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363895 continue
3896
Vaclav Brozekd5de76a2018-03-17 07:57:503897 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363898 if "#include" in line and "../" in line]
3899 if not relative_includes:
3900 continue
3901 bad_files[f.LocalPath()] = relative_includes
3902
3903 if not bad_files:
3904 return []
3905
3906 error_descriptions = []
3907 for file_path, bad_lines in bad_files.iteritems():
3908 error_description = file_path
3909 for line in bad_lines:
3910 error_description += '\n ' + line
3911 error_descriptions.append(error_description)
3912
3913 results = []
3914 results.append(output_api.PresubmitError(
3915 'You added one or more relative #include paths (including "../").\n'
3916 'These shouldn\'t be used because they can be used to include headers\n'
3917 'from code that\'s not correctly specified as a dependency in the\n'
3918 'relevant BUILD.gn file(s).',
3919 error_descriptions))
3920
3921 return results
3922
Takeshi Yoshinoe387aa32017-08-02 13:16:133923
Saagar Sanghavifceeaae2020-08-12 16:40:363924def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063925 """Check that nobody tries to include a cc file. It's a relatively
3926 common error which results in duplicate symbols in object
3927 files. This may not always break the build until someone later gets
3928 very confusing linking errors."""
3929 results = []
3930 for f in input_api.AffectedFiles(include_deletes=False):
3931 # We let third_party code do whatever it wants
3932 if (f.LocalPath().startswith('third_party') and
3933 not f.LocalPath().startswith('third_party/blink') and
3934 not f.LocalPath().startswith('third_party\\blink')):
3935 continue
3936
3937 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3938 continue
3939
3940 for _, line in f.ChangedContents():
3941 if line.startswith('#include "'):
3942 included_file = line.split('"')[1]
3943 if _IsCPlusPlusFile(input_api, included_file):
3944 # The most common naming for external files with C++ code,
3945 # apart from standard headers, is to call them foo.inc, but
3946 # Chromium sometimes uses foo-inc.cc so allow that as well.
3947 if not included_file.endswith(('.h', '-inc.cc')):
3948 results.append(output_api.PresubmitError(
3949 'Only header files or .inc files should be included in other\n'
3950 'C++ files. Compiling the contents of a cc file more than once\n'
3951 'will cause duplicate information in the build which may later\n'
3952 'result in strange link_errors.\n' +
3953 f.LocalPath() + ':\n ' +
3954 line))
3955
3956 return results
3957
3958
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203959def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3960 if not isinstance(key, ast.Str):
3961 return 'Key at line %d must be a string literal' % key.lineno
3962 if not isinstance(value, ast.Dict):
3963 return 'Value at line %d must be a dict' % value.lineno
3964 if len(value.keys) != 1:
3965 return 'Dict at line %d must have single entry' % value.lineno
3966 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3967 return (
3968 'Entry at line %d must have a string literal \'filepath\' as key' %
3969 value.lineno)
3970 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133971
Takeshi Yoshinoe387aa32017-08-02 13:16:133972
Sergey Ulanov4af16052018-11-08 02:41:463973def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203974 if not isinstance(key, ast.Str):
3975 return 'Key at line %d must be a string literal' % key.lineno
3976 if not isinstance(value, ast.List):
3977 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463978 for element in value.elts:
3979 if not isinstance(element, ast.Str):
3980 return 'Watchlist elements on line %d is not a string' % key.lineno
3981 if not email_regex.match(element.s):
3982 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3983 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203984 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133985
Takeshi Yoshinoe387aa32017-08-02 13:16:133986
Sergey Ulanov4af16052018-11-08 02:41:463987def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203988 mismatch_template = (
3989 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3990 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133991
Sergey Ulanov4af16052018-11-08 02:41:463992 email_regex = input_api.re.compile(
3993 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3994
3995 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203996 i = 0
3997 last_key = ''
3998 while True:
3999 if i >= len(wd_dict.keys):
4000 if i >= len(w_dict.keys):
4001 return None
4002 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
4003 elif i >= len(w_dict.keys):
4004 return (
4005 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134006
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204007 wd_key = wd_dict.keys[i]
4008 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134009
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204010 result = _CheckWatchlistDefinitionsEntrySyntax(
4011 wd_key, wd_dict.values[i], ast)
4012 if result is not None:
4013 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134014
Sergey Ulanov4af16052018-11-08 02:41:464015 result = _CheckWatchlistsEntrySyntax(
4016 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204017 if result is not None:
4018 return 'Bad entry in WATCHLISTS dict: %s' % result
4019
4020 if wd_key.s != w_key.s:
4021 return mismatch_template % (
4022 '%s at line %d' % (wd_key.s, wd_key.lineno),
4023 '%s at line %d' % (w_key.s, w_key.lineno))
4024
4025 if wd_key.s < last_key:
4026 return (
4027 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4028 (wd_key.lineno, w_key.lineno))
4029 last_key = wd_key.s
4030
4031 i = i + 1
4032
4033
Sergey Ulanov4af16052018-11-08 02:41:464034def _CheckWATCHLISTSSyntax(expression, input_api):
4035 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204036 if not isinstance(expression, ast.Expression):
4037 return 'WATCHLISTS file must contain a valid expression'
4038 dictionary = expression.body
4039 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4040 return 'WATCHLISTS file must have single dict with exactly two entries'
4041
4042 first_key = dictionary.keys[0]
4043 first_value = dictionary.values[0]
4044 second_key = dictionary.keys[1]
4045 second_value = dictionary.values[1]
4046
4047 if (not isinstance(first_key, ast.Str) or
4048 first_key.s != 'WATCHLIST_DEFINITIONS' or
4049 not isinstance(first_value, ast.Dict)):
4050 return (
4051 'The first entry of the dict in WATCHLISTS file must be '
4052 'WATCHLIST_DEFINITIONS dict')
4053
4054 if (not isinstance(second_key, ast.Str) or
4055 second_key.s != 'WATCHLISTS' or
4056 not isinstance(second_value, ast.Dict)):
4057 return (
4058 'The second entry of the dict in WATCHLISTS file must be '
4059 'WATCHLISTS dict')
4060
Sergey Ulanov4af16052018-11-08 02:41:464061 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134062
4063
Saagar Sanghavifceeaae2020-08-12 16:40:364064def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:134065 for f in input_api.AffectedFiles(include_deletes=False):
4066 if f.LocalPath() == 'WATCHLISTS':
4067 contents = input_api.ReadFile(f, 'r')
4068
4069 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204070 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134071 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204072 # Get an AST tree for it and scan the tree for detailed style checking.
4073 expression = input_api.ast.parse(
4074 contents, filename='WATCHLISTS', mode='eval')
4075 except ValueError as e:
4076 return [output_api.PresubmitError(
4077 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4078 except SyntaxError as e:
4079 return [output_api.PresubmitError(
4080 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4081 except TypeError as e:
4082 return [output_api.PresubmitError(
4083 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134084
Sergey Ulanov4af16052018-11-08 02:41:464085 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204086 if result is not None:
4087 return [output_api.PresubmitError(result)]
4088 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134089
4090 return []
4091
4092
Saagar Sanghavifceeaae2020-08-12 16:40:364093def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194094 """Checks that newly added header files have corresponding GN changes.
4095 Note that this is only a heuristic. To be precise, run script:
4096 build/check_gn_headers.py.
4097 """
4098
4099 def headers(f):
4100 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444101 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194102
4103 new_headers = []
4104 for f in input_api.AffectedSourceFiles(headers):
4105 if f.Action() != 'A':
4106 continue
4107 new_headers.append(f.LocalPath())
4108
4109 def gn_files(f):
James Cook24a504192020-07-23 00:08:444110 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194111
4112 all_gn_changed_contents = ''
4113 for f in input_api.AffectedSourceFiles(gn_files):
4114 for _, line in f.ChangedContents():
4115 all_gn_changed_contents += line
4116
4117 problems = []
4118 for header in new_headers:
4119 basename = input_api.os_path.basename(header)
4120 if basename not in all_gn_changed_contents:
4121 problems.append(header)
4122
4123 if problems:
4124 return [output_api.PresubmitPromptWarning(
4125 'Missing GN changes for new header files', items=sorted(problems),
4126 long_text='Please double check whether newly added header files need '
4127 'corresponding changes in gn or gni files.\nThis checking is only a '
4128 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4129 'Read https://crbug.com/661774 for more info.')]
4130 return []
4131
4132
Saagar Sanghavifceeaae2020-08-12 16:40:364133def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024134 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4135
4136 This assumes we won't intentionally reference one product from the other
4137 product.
4138 """
4139 all_problems = []
4140 test_cases = [{
4141 "filename_postfix": "google_chrome_strings.grd",
4142 "correct_name": "Chrome",
4143 "incorrect_name": "Chromium",
4144 }, {
4145 "filename_postfix": "chromium_strings.grd",
4146 "correct_name": "Chromium",
4147 "incorrect_name": "Chrome",
4148 }]
4149
4150 for test_case in test_cases:
4151 problems = []
4152 filename_filter = lambda x: x.LocalPath().endswith(
4153 test_case["filename_postfix"])
4154
4155 # Check each new line. Can yield false positives in multiline comments, but
4156 # easier than trying to parse the XML because messages can have nested
4157 # children, and associating message elements with affected lines is hard.
4158 for f in input_api.AffectedSourceFiles(filename_filter):
4159 for line_num, line in f.ChangedContents():
4160 if "<message" in line or "<!--" in line or "-->" in line:
4161 continue
4162 if test_case["incorrect_name"] in line:
4163 problems.append(
4164 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4165
4166 if problems:
4167 message = (
4168 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4169 % (test_case["correct_name"], test_case["correct_name"],
4170 test_case["incorrect_name"]))
4171 all_problems.append(
4172 output_api.PresubmitPromptWarning(message, items=problems))
4173
4174 return all_problems
4175
4176
Saagar Sanghavifceeaae2020-08-12 16:40:364177def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514178 # TODO(crbug.com/941824): We need to make sure the entries in
4179 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4180 # so that users of //buildtools in other projects get the same tooling
4181 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4182 # support to gclient, we can eliminate the duplication and delete
4183 # this presubmit check.
4184
4185 # Update this regexp if new revisions are added to the files.
4186 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264187 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514188
4189 # If a user is changing one revision, they need to change the same
4190 # line in both files. This means that any given change should contain
4191 # exactly the same list of changed lines that match the regexps. The
4192 # replace(' ', '') call allows us to ignore whitespace changes to the
4193 # lines. The 'long_text' parameter to the error will contain the
4194 # list of changed lines in both files, which should make it easy enough
4195 # to spot the error without going overboard in this implementation.
4196 revs_changes = {
4197 'DEPS': {},
4198 'buildtools/DEPS': {},
4199 }
4200 long_text = ''
4201
4202 for f in input_api.AffectedFiles(
4203 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4204 for line_num, line in f.ChangedContents():
4205 if rev_regexp.search(line):
4206 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4207 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4208
4209 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4210 return [output_api.PresubmitError(
4211 'Change buildtools revisions in sync in both //DEPS and '
4212 '//buildtools/DEPS.', long_text=long_text + '\n')]
4213 else:
4214 return []
4215
4216
Saagar Sanghavifceeaae2020-08-12 16:40:364217def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364218 """Avoid large files, especially binary files, in the repository since
4219 git doesn't scale well for those. They will be in everyone's repo
4220 clones forever, forever making Chromium slower to clone and work
4221 with."""
4222
4223 # Uploading files to cloud storage is not trivial so we don't want
4224 # to set the limit too low, but the upper limit for "normal" large
4225 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4226 # anything over 20 MB is exceptional.
4227 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4228
4229 too_large_files = []
4230 for f in input_api.AffectedFiles():
4231 # Check both added and modified files (but not deleted files).
4232 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384233 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364234 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4235 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4236
4237 if too_large_files:
4238 message = (
4239 'Do not commit large files to git since git scales badly for those.\n' +
4240 'Instead put the large files in cloud storage and use DEPS to\n' +
4241 'fetch them.\n' + '\n'.join(too_large_files)
4242 )
4243 return [output_api.PresubmitError(
4244 'Too large files found in commit', long_text=message + '\n')]
4245 else:
4246 return []
4247
Max Morozb47503b2019-08-08 21:03:274248
Saagar Sanghavifceeaae2020-08-12 16:40:364249def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274250 """Checks specific for fuzz target sources."""
4251 EXPORTED_SYMBOLS = [
4252 'LLVMFuzzerInitialize',
4253 'LLVMFuzzerCustomMutator',
4254 'LLVMFuzzerCustomCrossOver',
4255 'LLVMFuzzerMutate',
4256 ]
4257
4258 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4259
4260 def FilterFile(affected_file):
4261 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444262 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4263 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274264
4265 return input_api.FilterSourceFile(
4266 affected_file,
James Cook24a504192020-07-23 00:08:444267 files_to_check=[files_to_check],
4268 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274269
4270 files_with_missing_header = []
4271 for f in input_api.AffectedSourceFiles(FilterFile):
4272 contents = input_api.ReadFile(f, 'r')
4273 if REQUIRED_HEADER in contents:
4274 continue
4275
4276 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4277 files_with_missing_header.append(f.LocalPath())
4278
4279 if not files_with_missing_header:
4280 return []
4281
4282 long_text = (
4283 'If you define any of the libFuzzer optional functions (%s), it is '
4284 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4285 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4286 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4287 'to access command line arguments passed to the fuzzer. Instead, prefer '
4288 'static initialization and shared resources as documented in '
4289 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4290 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4291 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4292 )
4293
4294 return [output_api.PresubmitPromptWarning(
4295 message="Missing '%s' in:" % REQUIRED_HEADER,
4296 items=files_with_missing_header,
4297 long_text=long_text)]
4298
4299
Mohamed Heikald048240a2019-11-12 16:57:374300def _CheckNewImagesWarning(input_api, output_api):
4301 """
4302 Warns authors who add images into the repo to make sure their images are
4303 optimized before committing.
4304 """
4305 images_added = False
4306 image_paths = []
4307 errors = []
4308 filter_lambda = lambda x: input_api.FilterSourceFile(
4309 x,
James Cook24a504192020-07-23 00:08:444310 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4311 + input_api.DEFAULT_FILES_TO_SKIP),
4312 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374313 )
4314 for f in input_api.AffectedFiles(
4315 include_deletes=False, file_filter=filter_lambda):
4316 local_path = f.LocalPath().lower()
4317 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4318 images_added = True
4319 image_paths.append(f)
4320 if images_added:
4321 errors.append(output_api.PresubmitPromptWarning(
4322 'It looks like you are trying to commit some images. If these are '
4323 'non-test-only images, please make sure to read and apply the tips in '
4324 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4325 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4326 'FYI only and will not block your CL on the CQ.', image_paths))
4327 return errors
4328
4329
Saagar Sanghavifceeaae2020-08-12 16:40:364330def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574331 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224332 results = []
dgnaa68d5e2015-06-10 10:08:224333 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174334 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224335 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294336 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064337 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4338 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424339 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184340 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574341 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374342 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154343 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574344 return results
4345
Saagar Sanghavifceeaae2020-08-12 16:40:364346def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574347 """Groups commit checks that target android code."""
4348 results = []
4349 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224350 return results
4351
Chris Hall59f8d0c72020-05-01 07:31:194352# TODO(chrishall): could we additionally match on any path owned by
4353# ui/accessibility/OWNERS ?
4354_ACCESSIBILITY_PATHS = (
4355 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4356 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4357 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4358 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4359 r"^content[\\/]browser[\\/]accessibility[\\/]",
4360 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4361 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4362 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4363 r"^ui[\\/]accessibility[\\/]",
4364 r"^ui[\\/]views[\\/]accessibility[\\/]",
4365)
4366
Saagar Sanghavifceeaae2020-08-12 16:40:364367def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194368 """Checks that commits to accessibility code contain an AX-Relnotes field in
4369 their commit message."""
4370 def FileFilter(affected_file):
4371 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444372 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194373
4374 # Only consider changes affecting accessibility paths.
4375 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4376 return []
4377
Akihiro Ota08108e542020-05-20 15:30:534378 # AX-Relnotes can appear in either the description or the footer.
4379 # When searching the description, require 'AX-Relnotes:' to appear at the
4380 # beginning of a line.
4381 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4382 description_has_relnotes = any(ax_regex.match(line)
4383 for line in input_api.change.DescriptionText().lower().splitlines())
4384
4385 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4386 'AX-Relnotes', [])
4387 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194388 return []
4389
4390 # TODO(chrishall): link to Relnotes documentation in message.
4391 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4392 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4393 "user-facing changes"
4394 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4395 "user-facing effects"
4396 "\n if this is confusing or annoying then please contact members "
4397 "of ui/accessibility/OWNERS.")
4398
4399 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224400
Saagar Sanghavifceeaae2020-08-12 16:40:364401def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394402 """Checks common to both upload and commit."""
4403 results = []
4404 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384405 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544406 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084407
4408 author = input_api.change.author_email
4409 if author and author not in _KNOWN_ROBOTS:
4410 results.extend(
4411 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4412
[email protected]9f919cc2013-07-31 03:04:044413 results.extend(
4414 input_api.canned_checks.CheckChangeHasNoTabs(
4415 input_api,
4416 output_api,
4417 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434418 results.extend(input_api.RunTests(
4419 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244420
Edward Lesmesce51df52020-08-04 22:10:174421 dirmd_bin = input_api.os_path.join(
4422 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4423 results.extend(input_api.RunTests(
4424 input_api.canned_checks.CheckDirMetadataFormat(
4425 input_api, output_api, dirmd_bin)))
4426 results.extend(
4427 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4428 input_api, output_api))
4429
Vaclav Brozekcdc7defb2018-03-20 09:54:354430 for f in input_api.AffectedFiles():
4431 path, name = input_api.os_path.split(f.LocalPath())
4432 if name == 'PRESUBMIT.py':
4433 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004434 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4435 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074436 # The PRESUBMIT.py file (and the directory containing it) might
4437 # have been affected by being moved or removed, so only try to
4438 # run the tests if they still exist.
4439 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4440 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444441 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394442 return results
[email protected]1f7b4172010-01-28 01:17:344443
[email protected]b337cb5b2011-01-23 21:24:054444
Saagar Sanghavifceeaae2020-08-12 16:40:364445def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494446 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4447 if f.LocalPath().endswith(('.orig', '.rej'))]
4448 if problems:
4449 return [output_api.PresubmitError(
4450 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034451 else:
4452 return []
[email protected]b8079ae4a2012-12-05 19:56:494453
4454
Saagar Sanghavifceeaae2020-08-12 16:40:364455def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214456 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4457 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4458 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074459 include_re = input_api.re.compile(
4460 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4461 extension_re = input_api.re.compile(r'\.[a-z]+$')
4462 errors = []
4463 for f in input_api.AffectedFiles():
4464 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4465 continue
4466 found_line_number = None
4467 found_macro = None
4468 for line_num, line in f.ChangedContents():
4469 match = macro_re.search(line)
4470 if match:
4471 found_line_number = line_num
4472 found_macro = match.group(2)
4473 break
4474 if not found_line_number:
4475 continue
4476
4477 found_include = False
4478 for line in f.NewContents():
4479 if include_re.search(line):
4480 found_include = True
4481 break
4482 if found_include:
4483 continue
4484
4485 if not f.LocalPath().endswith('.h'):
4486 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4487 try:
4488 content = input_api.ReadFile(primary_header_path, 'r')
4489 if include_re.search(content):
4490 continue
4491 except IOError:
4492 pass
4493 errors.append('%s:%d %s macro is used without including build/'
4494 'build_config.h.'
4495 % (f.LocalPath(), found_line_number, found_macro))
4496 if errors:
4497 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4498 return []
4499
4500
[email protected]b00342e7f2013-03-26 16:21:544501def _DidYouMeanOSMacro(bad_macro):
4502 try:
4503 return {'A': 'OS_ANDROID',
4504 'B': 'OS_BSD',
4505 'C': 'OS_CHROMEOS',
4506 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444507 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544508 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444509 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544510 'N': 'OS_NACL',
4511 'O': 'OS_OPENBSD',
4512 'P': 'OS_POSIX',
4513 'S': 'OS_SOLARIS',
4514 'W': 'OS_WIN'}[bad_macro[3].upper()]
4515 except KeyError:
4516 return ''
4517
4518
4519def _CheckForInvalidOSMacrosInFile(input_api, f):
4520 """Check for sensible looking, totally invalid OS macros."""
4521 preprocessor_statement = input_api.re.compile(r'^\s*#')
4522 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4523 results = []
4524 for lnum, line in f.ChangedContents():
4525 if preprocessor_statement.search(line):
4526 for match in os_macro.finditer(line):
4527 if not match.group(1) in _VALID_OS_MACROS:
4528 good = _DidYouMeanOSMacro(match.group(1))
4529 did_you_mean = ' (did you mean %s?)' % good if good else ''
4530 results.append(' %s:%d %s%s' % (f.LocalPath(),
4531 lnum,
4532 match.group(1),
4533 did_you_mean))
4534 return results
4535
4536
Saagar Sanghavifceeaae2020-08-12 16:40:364537def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544538 """Check all affected files for invalid OS macros."""
4539 bad_macros = []
tzik3f295992018-12-04 20:32:234540 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474541 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544542 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4543
4544 if not bad_macros:
4545 return []
4546
4547 return [output_api.PresubmitError(
4548 'Possibly invalid OS macro[s] found. Please fix your code\n'
4549 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4550
lliabraa35bab3932014-10-01 12:16:444551
4552def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4553 """Check all affected files for invalid "if defined" macros."""
4554 ALWAYS_DEFINED_MACROS = (
4555 "TARGET_CPU_PPC",
4556 "TARGET_CPU_PPC64",
4557 "TARGET_CPU_68K",
4558 "TARGET_CPU_X86",
4559 "TARGET_CPU_ARM",
4560 "TARGET_CPU_MIPS",
4561 "TARGET_CPU_SPARC",
4562 "TARGET_CPU_ALPHA",
4563 "TARGET_IPHONE_SIMULATOR",
4564 "TARGET_OS_EMBEDDED",
4565 "TARGET_OS_IPHONE",
4566 "TARGET_OS_MAC",
4567 "TARGET_OS_UNIX",
4568 "TARGET_OS_WIN32",
4569 )
4570 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4571 results = []
4572 for lnum, line in f.ChangedContents():
4573 for match in ifdef_macro.finditer(line):
4574 if match.group(1) in ALWAYS_DEFINED_MACROS:
4575 always_defined = ' %s is always defined. ' % match.group(1)
4576 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4577 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4578 lnum,
4579 always_defined,
4580 did_you_mean))
4581 return results
4582
4583
Saagar Sanghavifceeaae2020-08-12 16:40:364584def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444585 """Check all affected files for invalid "if defined" macros."""
4586 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054587 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444588 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054589 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214590 continue
lliabraa35bab3932014-10-01 12:16:444591 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4592 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4593
4594 if not bad_macros:
4595 return []
4596
4597 return [output_api.PresubmitError(
4598 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4599 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4600 bad_macros)]
4601
4602
Saagar Sanghavifceeaae2020-08-12 16:40:364603def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044604 """Check for same IPC rules described in
4605 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4606 """
4607 base_pattern = r'IPC_ENUM_TRAITS\('
4608 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4609 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4610
4611 problems = []
4612 for f in input_api.AffectedSourceFiles(None):
4613 local_path = f.LocalPath()
4614 if not local_path.endswith('.h'):
4615 continue
4616 for line_number, line in f.ChangedContents():
4617 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4618 problems.append(
4619 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4620
4621 if problems:
4622 return [output_api.PresubmitPromptWarning(
4623 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4624 else:
4625 return []
4626
[email protected]b00342e7f2013-03-26 16:21:544627
Saagar Sanghavifceeaae2020-08-12 16:40:364628def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054629 """Check to make sure no files being submitted have long paths.
4630 This causes issues on Windows.
4631 """
4632 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194633 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054634 local_path = f.LocalPath()
4635 # Windows has a path limit of 260 characters. Limit path length to 200 so
4636 # that we have some extra for the prefix on dev machines and the bots.
4637 if len(local_path) > 200:
4638 problems.append(local_path)
4639
4640 if problems:
4641 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4642 else:
4643 return []
4644
4645
Saagar Sanghavifceeaae2020-08-12 16:40:364646def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144647 """Check that header files have proper guards against multiple inclusion.
4648 If a file should not have such guards (and it probably should) then it
4649 should include the string "no-include-guard-because-multiply-included".
4650 """
Daniel Bratell6a75baef62018-06-04 10:04:454651 def is_chromium_header_file(f):
4652 # We only check header files under the control of the Chromium
4653 # project. That is, those outside third_party apart from
4654 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324655 # We also exclude *_message_generator.h headers as they use
4656 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454657 file_with_path = input_api.os_path.normpath(f.LocalPath())
4658 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324659 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454660 (not file_with_path.startswith('third_party') or
4661 file_with_path.startswith(
4662 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144663
4664 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344665 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144666
4667 errors = []
4668
Daniel Bratell6a75baef62018-06-04 10:04:454669 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144670 guard_name = None
4671 guard_line_number = None
4672 seen_guard_end = False
4673
4674 file_with_path = input_api.os_path.normpath(f.LocalPath())
4675 base_file_name = input_api.os_path.splitext(
4676 input_api.os_path.basename(file_with_path))[0]
4677 upper_base_file_name = base_file_name.upper()
4678
4679 expected_guard = replace_special_with_underscore(
4680 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144681
4682 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574683 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4684 # are too many (1000+) files with slight deviations from the
4685 # coding style. The most important part is that the include guard
4686 # is there, and that it's unique, not the name so this check is
4687 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144688 #
4689 # As code becomes more uniform, this could be made stricter.
4690
4691 guard_name_pattern_list = [
4692 # Anything with the right suffix (maybe with an extra _).
4693 r'\w+_H__?',
4694
Daniel Bratell39b5b062018-05-16 18:09:574695 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144696 r'\w+_h',
4697
4698 # Anything including the uppercase name of the file.
4699 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4700 upper_base_file_name)) + r'\w*',
4701 ]
4702 guard_name_pattern = '|'.join(guard_name_pattern_list)
4703 guard_pattern = input_api.re.compile(
4704 r'#ifndef\s+(' + guard_name_pattern + ')')
4705
4706 for line_number, line in enumerate(f.NewContents()):
4707 if 'no-include-guard-because-multiply-included' in line:
4708 guard_name = 'DUMMY' # To not trigger check outside the loop.
4709 break
4710
4711 if guard_name is None:
4712 match = guard_pattern.match(line)
4713 if match:
4714 guard_name = match.group(1)
4715 guard_line_number = line_number
4716
Daniel Bratell39b5b062018-05-16 18:09:574717 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454718 # don't match the chromium style guide, but new files should
4719 # get it right.
4720 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574721 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144722 errors.append(output_api.PresubmitPromptWarning(
4723 'Header using the wrong include guard name %s' % guard_name,
4724 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574725 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144726 else:
4727 # The line after #ifndef should have a #define of the same name.
4728 if line_number == guard_line_number + 1:
4729 expected_line = '#define %s' % guard_name
4730 if line != expected_line:
4731 errors.append(output_api.PresubmitPromptWarning(
4732 'Missing "%s" for include guard' % expected_line,
4733 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4734 'Expected: %r\nGot: %r' % (expected_line, line)))
4735
4736 if not seen_guard_end and line == '#endif // %s' % guard_name:
4737 seen_guard_end = True
4738 elif seen_guard_end:
4739 if line.strip() != '':
4740 errors.append(output_api.PresubmitPromptWarning(
4741 'Include guard %s not covering the whole file' % (
4742 guard_name), [f.LocalPath()]))
4743 break # Nothing else to check and enough to warn once.
4744
4745 if guard_name is None:
4746 errors.append(output_api.PresubmitPromptWarning(
4747 'Missing include guard %s' % expected_guard,
4748 [f.LocalPath()],
4749 'Missing include guard in %s\n'
4750 'Recommended name: %s\n'
4751 'This check can be disabled by having the string\n'
4752 'no-include-guard-because-multiply-included in the header.' %
4753 (f.LocalPath(), expected_guard)))
4754
4755 return errors
4756
4757
Saagar Sanghavifceeaae2020-08-12 16:40:364758def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234759 """Check source code and known ascii text files for Windows style line
4760 endings.
4761 """
earthdok1b5e0ee2015-03-10 15:19:104762 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234763
4764 file_inclusion_pattern = (
4765 known_text_files,
4766 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4767 )
4768
mostynbb639aca52015-01-07 20:31:234769 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534770 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444771 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534772 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504773 include_file = False
4774 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234775 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504776 include_file = True
4777 if include_file:
4778 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234779
4780 if problems:
4781 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4782 'these files to contain Windows style line endings?\n' +
4783 '\n'.join(problems))]
4784
4785 return []
4786
4787
Saagar Sanghavifceeaae2020-08-12 16:40:364788def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134789 """Checks that all source files use SYSLOG properly."""
4790 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364791 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564792 for line_number, line in f.ChangedContents():
4793 if 'SYSLOG' in line:
4794 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4795
pastarmovj89f7ee12016-09-20 14:58:134796 if syslog_files:
4797 return [output_api.PresubmitPromptWarning(
4798 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4799 ' calls.\nFiles to check:\n', items=syslog_files)]
4800 return []
4801
4802
[email protected]1f7b4172010-01-28 01:17:344803def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364804 if input_api.version < [2, 0, 0]:
4805 return [output_api.PresubmitError("Your depot_tools is out of date. "
4806 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4807 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344808 results = []
scottmg39b29952014-12-08 18:31:284809 results.extend(
jam93a6ee792017-02-08 23:59:224810 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544811 return results
[email protected]ca8d1982009-02-19 16:33:124812
4813
[email protected]1bfb8322014-04-23 01:02:414814def GetTryServerMasterForBot(bot):
4815 """Returns the Try Server master for the given bot.
4816
[email protected]0bb112362014-07-26 04:38:324817 It tries to guess the master from the bot name, but may still fail
4818 and return None. There is no longer a default master.
4819 """
4820 # Potentially ambiguous bot names are listed explicitly.
4821 master_map = {
tandriie5587792016-07-14 00:34:504822 'chromium_presubmit': 'master.tryserver.chromium.linux',
4823 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414824 }
[email protected]0bb112362014-07-26 04:38:324825 master = master_map.get(bot)
4826 if not master:
wnwen4fbaab82016-05-25 12:54:364827 if 'android' in bot:
tandriie5587792016-07-14 00:34:504828 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364829 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504830 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324831 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504832 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324833 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504834 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324835 return master
[email protected]1bfb8322014-04-23 01:02:414836
4837
[email protected]ca8d1982009-02-19 16:33:124838def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364839 if input_api.version < [2, 0, 0]:
4840 return [output_api.PresubmitError("Your depot_tools is out of date. "
4841 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4842 "but your version is %d.%d.%d" % tuple(input_api.version))]
4843
[email protected]fe5f57c52009-06-05 14:25:544844 results = []
[email protected]fe5f57c52009-06-05 14:25:544845 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274846 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344847 input_api,
4848 output_api,
[email protected]2fdd1f362013-01-16 03:56:034849 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274850
jam93a6ee792017-02-08 23:59:224851 results.extend(
4852 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544853 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4854 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384855 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4856 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414857 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4858 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544859 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144860
4861
Saagar Sanghavifceeaae2020-08-12 16:40:364862def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264863 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024864 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4865 # footer is set to true.
4866 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264867 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024868 footer.lower()
4869 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264870 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024871
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144872 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264873 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144874 import sys
4875 from io import StringIO
4876
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144877 new_or_added_paths = set(f.LocalPath()
4878 for f in input_api.AffectedFiles()
4879 if (f.Action() == 'A' or f.Action() == 'M'))
4880 removed_paths = set(f.LocalPath()
4881 for f in input_api.AffectedFiles(include_deletes=True)
4882 if f.Action() == 'D')
4883
4884 affected_grds = [f for f in input_api.AffectedFiles()
Rainhard Findlingfc31844c52020-05-15 09:58:264885 if (f.LocalPath().endswith(('.grd', '.grdp')))]
meacer8c0d3832019-12-26 21:46:164886 if not affected_grds:
4887 return []
4888
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144889 affected_png_paths = [f.AbsoluteLocalPath()
4890 for f in input_api.AffectedFiles()
4891 if (f.LocalPath().endswith('.png'))]
4892
4893 # Check for screenshots. Developers can upload screenshots using
4894 # tools/translation/upload_screenshots.py which finds and uploads
4895 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4896 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4897 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4898 #
4899 # The logic here is as follows:
4900 #
4901 # - If the CL has a .png file under the screenshots directory for a grd
4902 # file, warn the developer. Actual images should never be checked into the
4903 # Chrome repo.
4904 #
4905 # - If the CL contains modified or new messages in grd files and doesn't
4906 # contain the corresponding .sha1 files, warn the developer to add images
4907 # and upload them via tools/translation/upload_screenshots.py.
4908 #
4909 # - If the CL contains modified or new messages in grd files and the
4910 # corresponding .sha1 files, everything looks good.
4911 #
4912 # - If the CL contains removed messages in grd files but the corresponding
4913 # .sha1 files aren't removed, warn the developer to remove them.
4914 unnecessary_screenshots = []
4915 missing_sha1 = []
4916 unnecessary_sha1_files = []
4917
Rainhard Findlingfc31844c52020-05-15 09:58:264918 # This checks verifies that the ICU syntax of messages this CL touched is
4919 # valid, and reports any found syntax errors.
4920 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4921 # without developers being aware of them. Later on, such ICU syntax errors
4922 # break message extraction for translation, hence would block Chromium
4923 # translations until they are fixed.
4924 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144925
4926 def _CheckScreenshotAdded(screenshots_dir, message_id):
4927 sha1_path = input_api.os_path.join(
4928 screenshots_dir, message_id + '.png.sha1')
4929 if sha1_path not in new_or_added_paths:
4930 missing_sha1.append(sha1_path)
4931
4932
4933 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4934 sha1_path = input_api.os_path.join(
4935 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034936 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144937 unnecessary_sha1_files.append(sha1_path)
4938
Rainhard Findlingfc31844c52020-05-15 09:58:264939
4940 def _ValidateIcuSyntax(text, level, signatures):
4941 """Validates ICU syntax of a text string.
4942
4943 Check if text looks similar to ICU and checks for ICU syntax correctness
4944 in this case. Reports various issues with ICU syntax and values of
4945 variants. Supports checking of nested messages. Accumulate information of
4946 each ICU messages found in the text for further checking.
4947
4948 Args:
4949 text: a string to check.
4950 level: a number of current nesting level.
4951 signatures: an accumulator, a list of tuple of (level, variable,
4952 kind, variants).
4953
4954 Returns:
4955 None if a string is not ICU or no issue detected.
4956 A tuple of (message, start index, end index) if an issue detected.
4957 """
4958 valid_types = {
4959 'plural': (frozenset(
4960 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4961 frozenset(['=1', 'other'])),
4962 'selectordinal': (frozenset(
4963 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4964 frozenset(['one', 'other'])),
4965 'select': (frozenset(), frozenset(['other'])),
4966 }
4967
4968 # Check if the message looks like an attempt to use ICU
4969 # plural. If yes - check if its syntax strictly matches ICU format.
4970 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4971 if not like:
4972 signatures.append((level, None, None, None))
4973 return
4974
4975 # Check for valid prefix and suffix
4976 m = re.match(
4977 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4978 r'(plural|selectordinal|select),\s*'
4979 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4980 if not m:
4981 return (('This message looks like an ICU plural, '
4982 'but does not follow ICU syntax.'), like.start(), like.end())
4983 starting, variable, kind, variant_pairs = m.groups()
4984 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4985 if depth:
4986 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4987 len(text))
4988 first = text[0]
4989 ending = text[last_pos:]
4990 if not starting:
4991 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4992 last_pos)
4993 if not ending or '}' not in ending:
4994 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4995 last_pos)
4996 elif first != '{':
4997 return (
4998 ('Invalid ICU format. Extra characters at the start of a complex '
4999 'message (go/icu-message-migration): "%s"') %
5000 starting, 0, len(starting))
5001 elif ending != '}':
5002 return (('Invalid ICU format. Extra characters at the end of a complex '
5003 'message (go/icu-message-migration): "%s"')
5004 % ending, last_pos - 1, len(text) - 1)
5005 if kind not in valid_types:
5006 return (('Unknown ICU message type %s. '
5007 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5008 known, required = valid_types[kind]
5009 defined_variants = set()
5010 for variant, variant_range, value, value_range in variants:
5011 start, end = variant_range
5012 if variant in defined_variants:
5013 return ('Variant "%s" is defined more than once' % variant,
5014 start, end)
5015 elif known and variant not in known:
5016 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5017 start, end)
5018 defined_variants.add(variant)
5019 # Check for nested structure
5020 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5021 if res:
5022 return (res[0], res[1] + value_range[0] + 1,
5023 res[2] + value_range[0] + 1)
5024 missing = required - defined_variants
5025 if missing:
5026 return ('Required variants missing: %s' % ', '.join(missing), 0,
5027 len(text))
5028 signatures.append((level, variable, kind, defined_variants))
5029
5030
5031 def _ParseIcuVariants(text, offset=0):
5032 """Parse variants part of ICU complex message.
5033
5034 Builds a tuple of variant names and values, as well as
5035 their offsets in the input string.
5036
5037 Args:
5038 text: a string to parse
5039 offset: additional offset to add to positions in the text to get correct
5040 position in the complete ICU string.
5041
5042 Returns:
5043 List of tuples, each tuple consist of four fields: variant name,
5044 variant name span (tuple of two integers), variant value, value
5045 span (tuple of two integers).
5046 """
5047 depth, start, end = 0, -1, -1
5048 variants = []
5049 key = None
5050 for idx, char in enumerate(text):
5051 if char == '{':
5052 if not depth:
5053 start = idx
5054 chunk = text[end + 1:start]
5055 key = chunk.strip()
5056 pos = offset + end + 1 + chunk.find(key)
5057 span = (pos, pos + len(key))
5058 depth += 1
5059 elif char == '}':
5060 if not depth:
5061 return variants, depth, offset + idx
5062 depth -= 1
5063 if not depth:
5064 end = idx
5065 variants.append((key, span, text[start:end + 1], (offset + start,
5066 offset + end + 1)))
5067 return variants, depth, offset + end + 1
5068
meacer8c0d3832019-12-26 21:46:165069 try:
5070 old_sys_path = sys.path
5071 sys.path = sys.path + [input_api.os_path.join(
5072 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5073 from helper import grd_helper
5074 finally:
5075 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145076
5077 for f in affected_grds:
5078 file_path = f.LocalPath()
5079 old_id_to_msg_map = {}
5080 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385081 # Note that this code doesn't check if the file has been deleted. This is
5082 # OK because it only uses the old and new file contents and doesn't load
5083 # the file via its path.
5084 # It's also possible that a file's content refers to a renamed or deleted
5085 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5086 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5087 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145088 if file_path.endswith('.grdp'):
5089 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585090 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395091 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145092 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585093 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395094 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145095 else:
meacerff8a9b62019-12-10 19:43:585096 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145097 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585098 old_id_to_msg_map = grd_helper.GetGrdMessages(
5099 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145100 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585101 new_id_to_msg_map = grd_helper.GetGrdMessages(
5102 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145103
Rainhard Findlingd8d04372020-08-13 13:30:095104 grd_name, ext = input_api.os_path.splitext(
5105 input_api.os_path.basename(file_path))
5106 screenshots_dir = input_api.os_path.join(
5107 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5108
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145109 # Compute added, removed and modified message IDs.
5110 old_ids = set(old_id_to_msg_map)
5111 new_ids = set(new_id_to_msg_map)
5112 added_ids = new_ids - old_ids
5113 removed_ids = old_ids - new_ids
5114 modified_ids = set([])
5115 for key in old_ids.intersection(new_ids):
5116 if (old_id_to_msg_map[key].FormatXml()
5117 != new_id_to_msg_map[key].FormatXml()):
Rainhard Findlingd8d04372020-08-13 13:30:095118 sha1_path = input_api.os_path.join(
5119 screenshots_dir, key + '.png.sha1')
5120 if sha1_path not in new_or_added_paths and \
5121 not input_api.os_path.exists(sha1_path):
5122 # This message does not yet have a screenshot. Require one.
5123 modified_ids.add(key)
5124 elif (old_id_to_msg_map[key].ContentsAsXml('', True)
5125 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5126 # The message content itself changed. Require an updated screenshot.
5127 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145128
Rainhard Findlingfc31844c52020-05-15 09:58:265129 if run_screenshot_check:
5130 # Check the screenshot directory for .png files. Warn if there is any.
5131 for png_path in affected_png_paths:
5132 if png_path.startswith(screenshots_dir):
5133 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145134
Rainhard Findlingfc31844c52020-05-15 09:58:265135 for added_id in added_ids:
5136 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145137
Rainhard Findlingfc31844c52020-05-15 09:58:265138 for modified_id in modified_ids:
5139 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145140
Rainhard Findlingfc31844c52020-05-15 09:58:265141 for removed_id in removed_ids:
5142 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5143
5144 # Check new and changed strings for ICU syntax errors.
5145 for key in added_ids.union(modified_ids):
5146 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5147 err = _ValidateIcuSyntax(msg, 0, [])
5148 if err is not None:
5149 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145150
5151 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265152 if run_screenshot_check:
5153 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005154 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265155 'Do not include actual screenshots in the changelist. Run '
5156 'tools/translate/upload_screenshots.py to upload them instead:',
5157 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145158
Rainhard Findlingfc31844c52020-05-15 09:58:265159 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005160 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265161 'You are adding or modifying UI strings.\n'
5162 'To ensure the best translations, take screenshots of the relevant UI '
5163 '(https://g.co/chrome/translation) and add these files to your '
5164 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145165
Rainhard Findlingfc31844c52020-05-15 09:58:265166 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005167 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265168 'You removed strings associated with these files. Remove:',
5169 sorted(unnecessary_sha1_files)))
5170 else:
5171 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5172 'screenshots check.'))
5173
5174 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075175 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265176 'ICU syntax errors were found in the following strings (problems or '
5177 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145178
5179 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125180
5181
Saagar Sanghavifceeaae2020-08-12 16:40:365182def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125183 repo_root=None,
5184 translation_expectations_path=None,
5185 grd_files=None):
5186 import sys
5187 affected_grds = [f for f in input_api.AffectedFiles()
5188 if (f.LocalPath().endswith('.grd') or
5189 f.LocalPath().endswith('.grdp'))]
5190 if not affected_grds:
5191 return []
5192
5193 try:
5194 old_sys_path = sys.path
5195 sys.path = sys.path + [
5196 input_api.os_path.join(
5197 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5198 from helper import git_helper
5199 from helper import translation_helper
5200 finally:
5201 sys.path = old_sys_path
5202
5203 # Check that translation expectations can be parsed and we can get a list of
5204 # translatable grd files. |repo_root| and |translation_expectations_path| are
5205 # only passed by tests.
5206 if not repo_root:
5207 repo_root = input_api.PresubmitLocalPath()
5208 if not translation_expectations_path:
5209 translation_expectations_path = input_api.os_path.join(
5210 repo_root, 'tools', 'gritsettings',
5211 'translation_expectations.pyl')
5212 if not grd_files:
5213 grd_files = git_helper.list_grds_in_repository(repo_root)
5214
5215 try:
5216 translation_helper.get_translatable_grds(repo_root, grd_files,
5217 translation_expectations_path)
5218 except Exception as e:
5219 return [output_api.PresubmitNotifyResult(
5220 'Failed to get a list of translatable grd files. This happens when:\n'
5221 ' - One of the modified grd or grdp files cannot be parsed or\n'
5222 ' - %s is not updated.\n'
5223 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5224 return []
Ken Rockotc31f4832020-05-29 18:58:515225
5226
Saagar Sanghavifceeaae2020-08-12 16:40:365227def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515228 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095229 changed_mojoms = input_api.AffectedFiles(
5230 include_deletes=True,
5231 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515232 delta = []
5233 for mojom in changed_mojoms:
5234 old_contents = ''.join(mojom.OldContents()) or None
5235 new_contents = ''.join(mojom.NewContents()) or None
5236 delta.append({
5237 'filename': mojom.LocalPath(),
5238 'old': '\n'.join(mojom.OldContents()) or None,
5239 'new': '\n'.join(mojom.NewContents()) or None,
5240 })
5241
5242 process = input_api.subprocess.Popen(
5243 [input_api.python_executable,
5244 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5245 'public', 'tools', 'mojom',
5246 'check_stable_mojom_compatibility.py'),
5247 '--src-root', input_api.PresubmitLocalPath()],
5248 stdin=input_api.subprocess.PIPE,
5249 stdout=input_api.subprocess.PIPE,
5250 stderr=input_api.subprocess.PIPE,
5251 universal_newlines=True)
5252 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5253 if process.returncode:
5254 return [output_api.PresubmitError(
5255 'One or more [Stable] mojom definitions appears to have been changed '
5256 'in a way that is not backward-compatible.',
5257 long_text=error)]
5258 return []