blob: 0d47f44f68e4ecf4194919b44c9d132ed54b03ac [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Saagar Sanghavifceeaae2020-08-12 16:40:3610PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Ilya Shermane8a7d2d2020-07-25 04:33:4713 # Generated file.
14 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2615 r"client_variations.js"),
Egor Paskoce145c42018-09-28 19:31:0416 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
17 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
18 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
19 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
20 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4921 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4623 # sqlite is an imported third party dependency.
24 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0425 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5426 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5327 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1228 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0429 r".+[\\/]pnacl_shim\.c$",
30 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0431 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1432 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0433 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5434 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0435 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4036)
[email protected]ca8d1982009-02-19 16:33:1237
wnwenbdc444e2016-05-25 13:44:1538
[email protected]06e6d0ff2012-12-11 01:36:4439# Fragment of a regular expression that matches C++ and Objective-C++
40# implementation files.
41_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
42
wnwenbdc444e2016-05-25 13:44:1543
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1944# Fragment of a regular expression that matches C++ and Objective-C++
45# header files.
46_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
47
48
[email protected]06e6d0ff2012-12-11 01:36:4449# Regular expression that matches code only used for test binaries
50# (best effort).
51_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0452 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4453 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4454 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1255 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1856 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4457 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0458 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4359 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0460 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4361 # Web test harness.
62 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4763 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0464 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0865 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0466 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4167 # EarlGrey app side code for tests.
68 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1769 # Views Examples code
70 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4171 # Chromium Codelab
72 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4473)
[email protected]ca8d1982009-02-19 16:33:1274
Daniel Bratell609102be2019-03-27 20:53:2175_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1576
[email protected]eea609a2011-11-18 13:10:1277_TEST_ONLY_WARNING = (
78 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5579 'production code. If you are doing this from inside another method\n'
80 'named as *ForTesting(), then consider exposing things to have tests\n'
81 'make that same call directly.\n'
82 'If that is not possible, you may put a comment on the same line with\n'
83 ' // IN-TEST \n'
84 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
85 'method and can be ignored. Do not do this inside production code.\n'
86 'The android-binary-size trybot will block if the method exists in the\n'
87 'release apk.')
[email protected]eea609a2011-11-18 13:10:1288
89
[email protected]cf9b78f2012-11-14 11:40:2890_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4091 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2192 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
93 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2894
Michael Thiessen44457642020-02-06 00:24:1595# Format: Sequence of tuples containing:
96# * Full import path.
97# * Sequence of strings to show when the pattern matches.
98# * Sequence of path or filename exceptions to this rule
99_BANNED_JAVA_IMPORTS = (
100 (
Colin Blundell170d78c82020-03-12 13:56:04101 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15102 (
103 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
104 ),
105 (
106 'net/android/javatests/src/org/chromium/net/'
107 'AndroidProxySelectorTest.java',
108 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04109 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15110 ),
111 ),
Michael Thiessened631912020-08-07 19:01:31112 (
113 'android.support.test.rule.UiThreadTestRule;',
114 (
115 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43116 '@org.chromium.base.test.UiThreadTest on test methods that should run '
117 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31118 ),
119 (),
120 ),
121 (
122 'android.support.test.annotation.UiThreadTest;',
123 (
124 'Do not use android.support.test.annotation.UiThreadTest, use '
125 'org.chromium.base.test.UiThreadTest instead. See '
126 'https://crbug.com/1111893.',
127 ),
128 ()
Michael Thiessenfd6919b2020-12-08 20:44:01129 ),
130 (
131 'android.support.test.rule.ActivityTestRule;',
132 (
133 'Do not use ActivityTestRule, use '
134 'org.chromium.base.test.BaseActivityTestRule instead.',
135 ),
136 (
137 'components/cronet/',
138 )
Michael Thiessened631912020-08-07 19:01:31139 )
Michael Thiessen44457642020-02-06 00:24:15140)
wnwenbdc444e2016-05-25 13:44:15141
Daniel Bratell609102be2019-03-27 20:53:21142# Format: Sequence of tuples containing:
143# * String pattern or, if starting with a slash, a regular expression.
144# * Sequence of strings to show when the pattern matches.
145# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41146_BANNED_JAVA_FUNCTIONS = (
147 (
148 'StrictMode.allowThreadDiskReads()',
149 (
150 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
151 'directly.',
152 ),
153 False,
154 ),
155 (
156 'StrictMode.allowThreadDiskWrites()',
157 (
158 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
159 'directly.',
160 ),
161 False,
162 ),
Michael Thiessen0f2547e2020-07-27 21:55:36163 (
164 '.waitForIdleSync()',
165 (
166 'Do not use waitForIdleSync as it masks underlying issues. There is '
167 'almost always something else you should wait on instead.',
168 ),
169 False,
170 ),
Eric Stevensona9a980972017-09-23 00:04:41171)
172
Daniel Bratell609102be2019-03-27 20:53:21173# Format: Sequence of tuples containing:
174# * String pattern or, if starting with a slash, a regular expression.
175# * Sequence of strings to show when the pattern matches.
176# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59177_BANNED_OBJC_FUNCTIONS = (
178 (
179 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20180 (
181 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59182 'prohibited. Please use CrTrackingArea instead.',
183 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
184 ),
185 False,
186 ),
187 (
[email protected]eaae1972014-04-16 04:17:26188 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20189 (
190 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59191 'instead.',
192 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
193 ),
194 False,
195 ),
196 (
197 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20198 (
199 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59200 'Please use |convertPoint:(point) fromView:nil| instead.',
201 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
202 ),
203 True,
204 ),
205 (
206 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20207 (
208 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59209 'Please use |convertPoint:(point) toView:nil| instead.',
210 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
211 ),
212 True,
213 ),
214 (
215 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20216 (
217 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59218 'Please use |convertRect:(point) fromView:nil| instead.',
219 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
220 ),
221 True,
222 ),
223 (
224 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20225 (
226 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59227 'Please use |convertRect:(point) toView:nil| instead.',
228 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
229 ),
230 True,
231 ),
232 (
233 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20234 (
235 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59236 'Please use |convertSize:(point) fromView:nil| instead.',
237 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
238 ),
239 True,
240 ),
241 (
242 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20243 (
244 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59245 'Please use |convertSize:(point) toView:nil| instead.',
246 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
247 ),
248 True,
249 ),
jif65398702016-10-27 10:19:48250 (
251 r"/\s+UTF8String\s*]",
252 (
253 'The use of -[NSString UTF8String] is dangerous as it can return null',
254 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
255 'Please use |SysNSStringToUTF8| instead.',
256 ),
257 True,
258 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34259 (
260 r'__unsafe_unretained',
261 (
262 'The use of __unsafe_unretained is almost certainly wrong, unless',
263 'when interacting with NSFastEnumeration or NSInvocation.',
264 'Please use __weak in files build with ARC, nothing otherwise.',
265 ),
266 False,
267 ),
Avi Drissman7382afa02019-04-29 23:27:13268 (
269 'freeWhenDone:NO',
270 (
271 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
272 'Foundation types is prohibited.',
273 ),
274 True,
275 ),
[email protected]127f18ec2012-06-16 05:05:59276)
277
Daniel Bratell609102be2019-03-27 20:53:21278# Format: Sequence of tuples containing:
279# * String pattern or, if starting with a slash, a regular expression.
280# * Sequence of strings to show when the pattern matches.
281# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54282_BANNED_IOS_OBJC_FUNCTIONS = (
283 (
284 r'/\bTEST[(]',
285 (
286 'TEST() macro should not be used in Objective-C++ code as it does not ',
287 'drain the autorelease pool at the end of the test. Use TEST_F() ',
288 'macro instead with a fixture inheriting from PlatformTest (or a ',
289 'typedef).'
290 ),
291 True,
292 ),
293 (
294 r'/\btesting::Test\b',
295 (
296 'testing::Test should not be used in Objective-C++ code as it does ',
297 'not drain the autorelease pool at the end of the test. Use ',
298 'PlatformTest instead.'
299 ),
300 True,
301 ),
302)
303
Peter K. Lee6c03ccff2019-07-15 14:40:05304# Format: Sequence of tuples containing:
305# * String pattern or, if starting with a slash, a regular expression.
306# * Sequence of strings to show when the pattern matches.
307# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
308_BANNED_IOS_EGTEST_FUNCTIONS = (
309 (
310 r'/\bEXPECT_OCMOCK_VERIFY\b',
311 (
312 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
313 'it is meant for GTests. Use [mock verify] instead.'
314 ),
315 True,
316 ),
317)
318
danakj7a2b7082019-05-21 21:13:51319# Directories that contain deprecated Bind() or Callback types.
320# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36321# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51322# echo "-- $i"
Alexander Cooperd1244c582021-01-26 02:25:27323# (cd $i; git grep -nP \
324# 'base::(Bind\(|(Cancelable)?(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51325# done
326#
327# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
328# when they have been converted to modern callback types (OnceCallback,
329# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
330# checks for them and prevent regressions.
331_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51332 '^base/callback.h', # Intentional.
Alex Turnerb3ea38c2020-11-25 18:03:07333 '^base/cancelable_callback.h', # Intentional.
Alexander Cooperd1244c582021-01-26 02:25:27334 '^chrome/browser/apps/guest_view/web_view_browsertest.cc',
Alexander Cooperb3f1af662021-02-01 19:47:26335 "^chrome/browser/ash/accessibility/",
Alexander Cooper6b447b22020-07-22 00:47:18336 '^chrome/browser/captive_portal/captive_portal_browsertest.cc',
Peter Wen6367b882020-08-05 16:55:50337 '^chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc', # pylint: disable=line-too-long
Alexander Cooperd1244c582021-01-26 02:25:27338 '^chrome/browser/history/android/android_history_provider_service_unittest.cc', # pylint: disable=line-too-long
Alexander Cooper6b447b22020-07-22 00:47:18339 '^chrome/browser/media_galleries/',
Alexander Cooperb3f1af662021-02-01 19:47:26340 "^chrome/browser/metrics/",
Alexander Cooperd1244c582021-01-26 02:25:27341 '^chrome/browser/net/websocket_browsertest.cc',
Alexander Cooper6b447b22020-07-22 00:47:18342 '^chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc',
Peter Wen6367b882020-08-05 16:55:50343 '^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:18344 '^chrome/browser/payments/payment_manifest_parser_browsertest.cc',
Alexander Cooper6b447b22020-07-22 00:47:18345 '^chrome/browser/portal/portal_browsertest.cc',
Alexander Cooperb3f1af662021-02-01 19:47:26346 "^chrome/browser/prefetch/no_state_prefetch/",
347 '^chrome/browser/previews/',
Alexander Cooper6b447b22020-07-22 00:47:18348 '^chrome/browser/profiling_host/profiling_process_host.cc',
Alexander Cooper6b447b22020-07-22 00:47:18349 '^chrome/browser/recovery/recovery_install_global_error.cc',
Alexander Cooper6b447b22020-07-22 00:47:18350 '^chrome/browser/resources/chromeos/accessibility/',
351 '^chrome/browser/rlz/chrome_rlz_tracker_delegate.cc',
Alexander Cooper6b447b22020-07-22 00:47:18352 '^chrome/browser/search_engines/',
Alexander Cooper6b447b22020-07-22 00:47:18353 '^chrome/browser/signin/',
354 '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
Alexander Cooper6b447b22020-07-22 00:47:18355 '^chrome/browser/sync_file_system/',
Alexander Cooperb3f1af662021-02-01 19:47:26356 "^components/browsing_data/content/",
357 "^components/enterprise/browser/controller/chrome_browser_cloud_management_controller\\.cc", # pylint: disable=line-too-long
358 "^components/feature_engagement/internal/",
359 "^docs/callback\\.md", # Intentional
360 "^docs/webui_explainer\\.md",
361 "^docs/process/lsc/large_scale_changes\\.md", # Intentional
362 "^docs/security/mojo\\.md",
363 "^docs/threading_and_tasks\\.md",
364 "^docs/ui/learn/bestpractices/layout\\.md",
Alan Cutter04a00642020-03-02 01:45:20365 '^extensions/browser/',
366 '^extensions/renderer/',
Alexander Cooperd1244c582021-01-26 02:25:27367 '^media/blink/webmediaplayer_impl.cc',
368 '^media/blink/webmediaplayer_impl.h',
danakj7a2b7082019-05-21 21:13:51369 '^ppapi/proxy/',
Alexander Cooperb3f1af662021-02-01 19:47:26370 '^third_party/blink/PRESUBMIT_test.py', # Intentional.
371 '^third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py' # Intentional pylint: disable=line-too-long
danakj7a2b7082019-05-21 21:13:51372 '^tools/clang/base_bind_rewriters/', # Intentional.
373 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51374))
[email protected]127f18ec2012-06-16 05:05:59375
Alexander Cooper46a92712021-01-30 00:00:20376# Directories that contain deprecated CallbackList types.
377# Find sub-directories from a given directory by running:
378# for i in `find . -maxdepth 1 -type d|sort`; do
379# echo "-- $i"
380# (cd $i; git grep -nP 'base::CallbackList<'|wc -l)
381# done
382#
383# TODO(crbug.com/1113007): Remove (or narrow the scope of) paths from this list
384# when they have been converted to modern callback list types (OnceCallback,
385# RepeatingCallback) in order to enable presubmit checks for them and prevent
386# regressions.
387_NOT_CONVERTED_TO_MODERN_CALLBACK_LIST = '|'.join((
388 r'^chrome/browser/android/oom_intervention/near_oom_monitor\.h',
389 r'^chrome/browser/ash/account_manager/child_account_type_changed_user_data\.h', # pylint: disable=line-too-long
390 r'^chrome/browser/browser_switcher/',
391 r'^chrome/browser/chromeos/',
392 r'^chrome/browser/media/router/providers/cast/',
393 r'^chrome/brwoser/sessions/session_restore\.cc',
394 r'^chrome/browser/supervised_user/',
395 r'^chrome/browser/ui/',
396 r'^chromecast/external_mojo/external_service_support/',
397 r'^components/captive_portal/content/captive_portal_service\.h',
398 r'^components/keyed_service/core/keyed_service_shutdown_notifier\.h',
399 r'^components/media_router/browser/',
400 r'^components/ntp_tils/custom_links_manager_impl\.h',
401 r'^components/password_manager/core/browser/hash_password_manager\.h',
402 r'^components/suggestions/suggestions_service\.h',
403 r'^components/sync_device_info/',
404 r'^components/sync_sessions/session_sync_service_impl\.h',
405 r'^components/zoom/zoom_event_manager\.h',
406 r'^content/browser/host_zoom_map_impl\.h',
407 r'^content/browser/network_service_instance_impl\.h',
408 r'^content/browser/rendeer_host/render_process_host_impl\.cc',
409 r'^extensions/test/extension_test_notification_observer\.h',
410 r'^ios/chrome/browser/tabs/tab_parenting_global_observer\.h',
411 r'^ios/net/cookies/cookie_store_ios\.h',
412 r'^net/cookies/cookie_monster_change_dispatcher\.h',
413 r'^remoting/signaling/messaging_client\.h',
414 r'^services/device/battery/battery_status_service\.h',
415 r'^services/device/geolocation/',
416 r'^weblayer/browser/i18n_util\.cc',
417 r'^weblayer/public/cookie_manager\.h',
418))
419
Daniel Bratell609102be2019-03-27 20:53:21420# Format: Sequence of tuples containing:
421# * String pattern or, if starting with a slash, a regular expression.
422# * Sequence of strings to show when the pattern matches.
423# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
424# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59425_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20426 (
Peter Kasting94a56c42019-10-25 21:54:04427 r'/\busing namespace ',
428 (
429 'Using directives ("using namespace x") are banned by the Google Style',
430 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
431 'Explicitly qualify symbols or use using declarations ("using x::foo").',
432 ),
433 True,
434 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
435 ),
Antonio Gomes07300d02019-03-13 20:59:57436 # Make sure that gtest's FRIEND_TEST() macro is not used; the
437 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
438 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53439 (
[email protected]23e6cbc2012-06-16 18:51:20440 'FRIEND_TEST(',
441 (
[email protected]e3c945502012-06-26 20:01:49442 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20443 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
444 ),
445 False,
[email protected]7345da02012-11-27 14:31:49446 (),
[email protected]23e6cbc2012-06-16 18:51:20447 ),
448 (
tomhudsone2c14d552016-05-26 17:07:46449 'setMatrixClip',
450 (
451 'Overriding setMatrixClip() is prohibited; ',
452 'the base function is deprecated. ',
453 ),
454 True,
455 (),
456 ),
457 (
[email protected]52657f62013-05-20 05:30:31458 'SkRefPtr',
459 (
460 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22461 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31462 ),
463 True,
464 (),
465 ),
466 (
467 'SkAutoRef',
468 (
469 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22470 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31471 ),
472 True,
473 (),
474 ),
475 (
476 'SkAutoTUnref',
477 (
478 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22479 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31480 ),
481 True,
482 (),
483 ),
484 (
485 'SkAutoUnref',
486 (
487 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
488 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22489 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31490 ),
491 True,
492 (),
493 ),
[email protected]d89eec82013-12-03 14:10:59494 (
495 r'/HANDLE_EINTR\(.*close',
496 (
497 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
498 'descriptor will be closed, and it is incorrect to retry the close.',
499 'Either call close directly and ignore its return value, or wrap close',
500 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
501 ),
502 True,
503 (),
504 ),
505 (
506 r'/IGNORE_EINTR\((?!.*close)',
507 (
508 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
509 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
510 ),
511 True,
512 (
513 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04514 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
515 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59516 ),
517 ),
[email protected]ec5b3f02014-04-04 18:43:43518 (
519 r'/v8::Extension\(',
520 (
521 'Do not introduce new v8::Extensions into the code base, use',
522 'gin::Wrappable instead. See http://crbug.com/334679',
523 ),
524 True,
[email protected]f55c90ee62014-04-12 00:50:03525 (
Egor Paskoce145c42018-09-28 19:31:04526 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03527 ),
[email protected]ec5b3f02014-04-04 18:43:43528 ),
skyostilf9469f72015-04-20 10:38:52529 (
jame2d1a952016-04-02 00:27:10530 '#pragma comment(lib,',
531 (
532 'Specify libraries to link with in build files and not in the source.',
533 ),
534 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41535 (
tzik3f295992018-12-04 20:32:23536 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04537 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41538 ),
jame2d1a952016-04-02 00:27:10539 ),
fdorayc4ac18d2017-05-01 21:39:59540 (
Gabriel Charette7cc6c432018-04-25 20:52:02541 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59542 (
543 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
544 ),
545 False,
546 (),
547 ),
548 (
Gabriel Charette7cc6c432018-04-25 20:52:02549 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59550 (
551 'Consider using THREAD_CHECKER macros instead of the class directly.',
552 ),
553 False,
554 (),
555 ),
dbeamb6f4fde2017-06-15 04:03:06556 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06557 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
558 (
559 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
560 'deprecated (http://crbug.com/634507). Please avoid converting away',
561 'from the Time types in Chromium code, especially if any math is',
562 'being done on time values. For interfacing with platform/library',
563 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
564 'type converter methods instead. For faking TimeXXX values (for unit',
565 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
566 'other use cases, please contact base/time/OWNERS.',
567 ),
568 False,
569 (),
570 ),
571 (
dbeamb6f4fde2017-06-15 04:03:06572 'CallJavascriptFunctionUnsafe',
573 (
574 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
575 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
576 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
577 ),
578 False,
579 (
Egor Paskoce145c42018-09-28 19:31:04580 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
581 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
582 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06583 ),
584 ),
dskiba1474c2bfd62017-07-20 02:19:24585 (
586 'leveldb::DB::Open',
587 (
588 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
589 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
590 "Chrome's tracing, making their memory usage visible.",
591 ),
592 True,
593 (
594 r'^third_party/leveldatabase/.*\.(cc|h)$',
595 ),
Gabriel Charette0592c3a2017-07-26 12:02:04596 ),
597 (
Chris Mumfordc38afb62017-10-09 17:55:08598 'leveldb::NewMemEnv',
599 (
600 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58601 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
602 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08603 ),
604 True,
605 (
606 r'^third_party/leveldatabase/.*\.(cc|h)$',
607 ),
608 ),
609 (
Gabriel Charetted9839bc2017-07-29 14:17:47610 'RunLoop::QuitCurrent',
611 (
Robert Liao64b7ab22017-08-04 23:03:43612 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
613 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47614 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41615 False,
Gabriel Charetted9839bc2017-07-29 14:17:47616 (),
Gabriel Charettea44975052017-08-21 23:14:04617 ),
618 (
619 'base::ScopedMockTimeMessageLoopTaskRunner',
620 (
Gabriel Charette87cc1af2018-04-25 20:52:51621 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11622 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51623 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
624 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
625 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04626 ),
Gabriel Charette87cc1af2018-04-25 20:52:51627 False,
Gabriel Charettea44975052017-08-21 23:14:04628 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57629 ),
630 (
Dave Tapuska98199b612019-07-10 13:30:44631 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57632 (
633 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02634 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57635 ),
636 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16637 # Abseil's benchmarks never linked into chrome.
638 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38639 ),
640 (
Peter Kasting991618a62019-06-17 22:00:09641 r'/\bstd::stoi\b',
642 (
643 'std::stoi uses exceptions to communicate results. ',
644 'Use base::StringToInt() instead.',
645 ),
646 True,
647 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
648 ),
649 (
650 r'/\bstd::stol\b',
651 (
652 'std::stol uses exceptions to communicate results. ',
653 'Use base::StringToInt() instead.',
654 ),
655 True,
656 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
657 ),
658 (
659 r'/\bstd::stoul\b',
660 (
661 'std::stoul uses exceptions to communicate results. ',
662 'Use base::StringToUint() instead.',
663 ),
664 True,
665 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
666 ),
667 (
668 r'/\bstd::stoll\b',
669 (
670 'std::stoll uses exceptions to communicate results. ',
671 'Use base::StringToInt64() instead.',
672 ),
673 True,
674 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
675 ),
676 (
677 r'/\bstd::stoull\b',
678 (
679 'std::stoull uses exceptions to communicate results. ',
680 'Use base::StringToUint64() instead.',
681 ),
682 True,
683 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
684 ),
685 (
686 r'/\bstd::stof\b',
687 (
688 'std::stof uses exceptions to communicate results. ',
689 'For locale-independent values, e.g. reading numbers from disk',
690 'profiles, use base::StringToDouble().',
691 'For user-visible values, parse using ICU.',
692 ),
693 True,
694 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
695 ),
696 (
697 r'/\bstd::stod\b',
698 (
699 'std::stod uses exceptions to communicate results. ',
700 'For locale-independent values, e.g. reading numbers from disk',
701 'profiles, use base::StringToDouble().',
702 'For user-visible values, parse using ICU.',
703 ),
704 True,
705 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
706 ),
707 (
708 r'/\bstd::stold\b',
709 (
710 'std::stold uses exceptions to communicate results. ',
711 'For locale-independent values, e.g. reading numbers from disk',
712 'profiles, use base::StringToDouble().',
713 'For user-visible values, parse using ICU.',
714 ),
715 True,
716 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
717 ),
718 (
Daniel Bratell69334cc2019-03-26 11:07:45719 r'/\bstd::to_string\b',
720 (
721 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09722 'For locale-independent strings, e.g. writing numbers to disk',
723 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45724 'For user-visible strings, use base::FormatNumber() and',
725 'the related functions in base/i18n/number_formatting.h.',
726 ),
Peter Kasting991618a62019-06-17 22:00:09727 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21728 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45729 ),
730 (
731 r'/\bstd::shared_ptr\b',
732 (
733 'std::shared_ptr should not be used. Use scoped_refptr instead.',
734 ),
735 True,
Alex Chau9eb03cdd52020-07-13 21:04:57736 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
737 'array_buffer_contents\.(cc|h)',
738 # Needed for interop with third-party library
739 'chrome/services/sharing/nearby/',
740 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21741 ),
742 (
Peter Kasting991618a62019-06-17 22:00:09743 r'/\bstd::weak_ptr\b',
744 (
745 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
746 ),
747 True,
748 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
749 ),
750 (
Daniel Bratell609102be2019-03-27 20:53:21751 r'/\blong long\b',
752 (
753 'long long is banned. Use stdint.h if you need a 64 bit number.',
754 ),
755 False, # Only a warning since it is already used.
756 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
757 ),
758 (
759 r'/\bstd::bind\b',
760 (
761 'std::bind is banned because of lifetime risks.',
762 'Use base::BindOnce or base::BindRepeating instead.',
763 ),
764 True,
765 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
766 ),
767 (
768 r'/\b#include <chrono>\b',
769 (
770 '<chrono> overlaps with Time APIs in base. Keep using',
771 'base classes.',
772 ),
773 True,
774 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
775 ),
776 (
777 r'/\b#include <exception>\b',
778 (
779 'Exceptions are banned and disabled in Chromium.',
780 ),
781 True,
782 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
783 ),
784 (
785 r'/\bstd::function\b',
786 (
787 'std::function is banned. Instead use base::Callback which directly',
788 'supports Chromium\'s weak pointers, ref counting and more.',
789 ),
Peter Kasting991618a62019-06-17 22:00:09790 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21791 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
792 ),
793 (
794 r'/\b#include <random>\b',
795 (
796 'Do not use any random number engines from <random>. Instead',
797 'use base::RandomBitGenerator.',
798 ),
799 True,
800 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
801 ),
802 (
Tom Andersona95e12042020-09-09 23:08:00803 r'/\b#include <X11/',
804 (
805 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
806 ),
807 True,
808 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
809 ),
810 (
Daniel Bratell609102be2019-03-27 20:53:21811 r'/\bstd::ratio\b',
812 (
813 'std::ratio is banned by the Google Style Guide.',
814 ),
815 True,
816 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45817 ),
818 (
Francois Doray43670e32017-09-27 12:40:38819 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
820 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
821 (
822 'Use the new API in base/threading/thread_restrictions.h.',
823 ),
Gabriel Charette04b138f2018-08-06 00:03:22824 False,
Francois Doray43670e32017-09-27 12:40:38825 (),
826 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38827 (
danakj7a2b7082019-05-21 21:13:51828 r'/\bbase::Bind\(',
829 (
830 'Please use base::Bind{Once,Repeating} instead',
831 'of base::Bind. (crbug.com/714018)',
832 ),
833 False,
Erik Staaba737d7602019-11-25 18:41:07834 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51835 ),
836 (
837 r'/\bbase::Callback[<:]',
838 (
839 'Please use base::{Once,Repeating}Callback instead',
840 'of base::Callback. (crbug.com/714018)',
841 ),
842 False,
Erik Staaba737d7602019-11-25 18:41:07843 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51844 ),
845 (
846 r'/\bbase::Closure\b',
847 (
848 'Please use base::{Once,Repeating}Closure instead',
849 'of base::Closure. (crbug.com/714018)',
850 ),
851 False,
Erik Staaba737d7602019-11-25 18:41:07852 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51853 ),
854 (
Alex Turnerb3ea38c2020-11-25 18:03:07855 r'/\bbase::CancelableCallback[<:]',
856 (
857 'Please use base::Cancelable{Once,Repeating}Callback instead',
858 'of base::CancelableCallback. (crbug.com/714018)',
859 ),
860 False,
861 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
862 ),
863 (
864 r'/\bbase::CancelableClosure\b',
865 (
866 'Please use base::Cancelable{Once,Repeating}Closure instead',
867 'of base::CancelableClosure. (crbug.com/714018)',
868 ),
869 False,
870 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
871 ),
872 (
Alexander Cooper46a92712021-01-30 00:00:20873 r'/\bbase::CallbackList<',
874 (
875 'Please use base::{Once,Repeating}CallbackList instead',
876 'of base::CallbackList. (crbug.com/1113007)'
877 ),
878 False,
879 (_NOT_CONVERTED_TO_MODERN_CALLBACK_LIST,),
880 ),
881 (
Michael Giuffrida7f93d6922019-04-19 14:39:58882 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19883 (
884 'RunMessageLoop is deprecated, use RunLoop instead.',
885 ),
886 False,
887 (),
888 ),
889 (
Dave Tapuska98199b612019-07-10 13:30:44890 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19891 (
892 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
893 ),
894 False,
895 (),
896 ),
897 (
Dave Tapuska98199b612019-07-10 13:30:44898 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19899 (
900 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
901 "if you're convinced you need this.",
902 ),
903 False,
904 (),
905 ),
906 (
Dave Tapuska98199b612019-07-10 13:30:44907 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19908 (
909 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04910 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19911 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
912 'async events instead of flushing threads.',
913 ),
914 False,
915 (),
916 ),
917 (
918 r'MessageLoopRunner',
919 (
920 'MessageLoopRunner is deprecated, use RunLoop instead.',
921 ),
922 False,
923 (),
924 ),
925 (
Dave Tapuska98199b612019-07-10 13:30:44926 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19927 (
928 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
929 "gab@ if you found a use case where this is the only solution.",
930 ),
931 False,
932 (),
933 ),
934 (
Victor Costane48a2e82019-03-15 22:02:34935 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16936 (
Victor Costane48a2e82019-03-15 22:02:34937 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16938 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
939 ),
940 True,
941 (
942 r'^sql/initialization\.(cc|h)$',
943 r'^third_party/sqlite/.*\.(c|cc|h)$',
944 ),
945 ),
Matt Menke7f520a82018-03-28 21:38:37946 (
Dave Tapuska98199b612019-07-10 13:30:44947 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47948 (
949 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
950 'base::RandomShuffle instead.'
951 ),
952 True,
953 (),
954 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24955 (
956 'ios/web/public/test/http_server',
957 (
958 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
959 ),
960 False,
961 (),
962 ),
Robert Liao764c9492019-01-24 18:46:28963 (
964 'GetAddressOf',
965 (
966 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53967 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11968 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53969 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28970 ),
971 True,
972 (),
973 ),
Antonio Gomes07300d02019-03-13 20:59:57974 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37975 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38976 (
977 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
978 ),
979 True,
980 (),
981 ),
Ben Lewisa9514602019-04-29 17:53:05982 (
983 'SHFileOperation',
984 (
985 'SHFileOperation was deprecated in Windows Vista, and there are less ',
986 'complex functions to achieve the same goals. Use IFileOperation for ',
987 'any esoteric actions instead.'
988 ),
989 True,
990 (),
991 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18992 (
Cliff Smolinsky81951642019-04-30 21:39:51993 'StringFromGUID2',
994 (
995 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24996 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51997 ),
998 True,
999 (
1000 r'/base/win/win_util_unittest.cc'
1001 ),
1002 ),
1003 (
1004 'StringFromCLSID',
1005 (
1006 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241007 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511008 ),
1009 True,
1010 (
1011 r'/base/win/win_util_unittest.cc'
1012 ),
1013 ),
1014 (
Avi Drissman7382afa02019-04-29 23:27:131015 'kCFAllocatorNull',
1016 (
1017 'The use of kCFAllocatorNull with the NoCopy creation of ',
1018 'CoreFoundation types is prohibited.',
1019 ),
1020 True,
1021 (),
1022 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291023 (
1024 'mojo::ConvertTo',
1025 (
1026 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1027 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1028 'StringTraits if you would like to convert between custom types and',
1029 'the wire format of mojom types.'
1030 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221031 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291032 (
Wezf89dec092019-09-11 19:38:331033 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1034 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291035 r'^third_party/blink/.*\.(cc|h)$',
1036 r'^content/renderer/.*\.(cc|h)$',
1037 ),
1038 ),
Robert Liao1d78df52019-11-11 20:02:011039 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161040 'GetInterfaceProvider',
1041 (
1042 'InterfaceProvider is deprecated.',
1043 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1044 'or Platform::GetBrowserInterfaceBroker.'
1045 ),
1046 False,
1047 (),
1048 ),
1049 (
Robert Liao1d78df52019-11-11 20:02:011050 'CComPtr',
1051 (
1052 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1053 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1054 'details.'
1055 ),
1056 False,
1057 (),
1058 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201059 (
1060 r'/\b(IFACE|STD)METHOD_?\(',
1061 (
1062 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1063 'Instead, always use IFACEMETHODIMP in the declaration.'
1064 ),
1065 False,
1066 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1067 ),
Allen Bauer53b43fb12020-03-12 17:21:471068 (
1069 'set_owned_by_client',
1070 (
1071 'set_owned_by_client is deprecated.',
1072 'views::View already owns the child views by default. This introduces ',
1073 'a competing ownership model which makes the code difficult to reason ',
1074 'about. See http://crbug.com/1044687 for more details.'
1075 ),
1076 False,
1077 (),
1078 ),
Eric Secklerbe6f48d2020-05-06 18:09:121079 (
1080 r'/\bTRACE_EVENT_ASYNC_',
1081 (
1082 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1083 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1084 ),
1085 False,
1086 (
1087 r'^base/trace_event/.*',
1088 r'^base/tracing/.*',
1089 ),
1090 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:261091 (
1092 r'/\bScopedObserver',
1093 (
1094 'ScopedObserver is deprecated.',
1095 'Please use base::ScopedObservation for observing a single source,',
1096 'or base::ScopedMultiSourceObservation for observing multple sources',
1097 ),
1098 False,
1099 (),
1100 ),
[email protected]127f18ec2012-06-16 05:05:591101)
1102
Mario Sanchez Prada2472cab2019-09-18 10:58:311103# Format: Sequence of tuples containing:
1104# * String pattern or, if starting with a slash, a regular expression.
1105# * Sequence of strings to show when the pattern matches.
1106_DEPRECATED_MOJO_TYPES = (
1107 (
1108 r'/\bmojo::AssociatedBinding\b',
1109 (
1110 'mojo::AssociatedBinding<Interface> is deprecated.',
1111 'Use mojo::AssociatedReceiver<Interface> instead.',
1112 ),
1113 ),
1114 (
1115 r'/\bmojo::AssociatedBindingSet\b',
1116 (
1117 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1118 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1119 ),
1120 ),
1121 (
1122 r'/\bmojo::AssociatedInterfacePtr\b',
1123 (
1124 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1125 'Use mojo::AssociatedRemote<Interface> instead.',
1126 ),
1127 ),
1128 (
1129 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1130 (
1131 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1132 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1133 ),
1134 ),
1135 (
1136 r'/\bmojo::AssociatedInterfaceRequest\b',
1137 (
1138 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1139 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1140 ),
1141 ),
1142 (
1143 r'/\bmojo::Binding\b',
1144 (
1145 'mojo::Binding<Interface> is deprecated.',
1146 'Use mojo::Receiver<Interface> instead.',
1147 ),
1148 ),
1149 (
1150 r'/\bmojo::BindingSet\b',
1151 (
1152 'mojo::BindingSet<Interface> is deprecated.',
1153 'Use mojo::ReceiverSet<Interface> instead.',
1154 ),
1155 ),
1156 (
1157 r'/\bmojo::InterfacePtr\b',
1158 (
1159 'mojo::InterfacePtr<Interface> is deprecated.',
1160 'Use mojo::Remote<Interface> instead.',
1161 ),
1162 ),
1163 (
1164 r'/\bmojo::InterfacePtrInfo\b',
1165 (
1166 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1167 'Use mojo::PendingRemote<Interface> instead.',
1168 ),
1169 ),
1170 (
1171 r'/\bmojo::InterfaceRequest\b',
1172 (
1173 'mojo::InterfaceRequest<Interface> is deprecated.',
1174 'Use mojo::PendingReceiver<Interface> instead.',
1175 ),
1176 ),
1177 (
1178 r'/\bmojo::MakeRequest\b',
1179 (
1180 'mojo::MakeRequest is deprecated.',
1181 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1182 ),
1183 ),
1184 (
1185 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1186 (
1187 'mojo::MakeRequest is deprecated.',
1188 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181189 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311190 ),
1191 ),
1192 (
1193 r'/\bmojo::MakeStrongBinding\b',
1194 (
1195 'mojo::MakeStrongBinding is deprecated.',
1196 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1197 'mojo::MakeSelfOwnedReceiver() instead.',
1198 ),
1199 ),
1200 (
1201 r'/\bmojo::MakeStrongAssociatedBinding\b',
1202 (
1203 'mojo::MakeStrongAssociatedBinding is deprecated.',
1204 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1205 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1206 ),
1207 ),
1208 (
Gyuyoung Kim4952ba62020-07-07 07:33:441209 r'/\bmojo::StrongAssociatedBinding\b',
1210 (
1211 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1212 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1213 ),
1214 ),
1215 (
1216 r'/\bmojo::StrongBinding\b',
1217 (
1218 'mojo::StrongBinding<Interface> is deprecated.',
1219 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1220 ),
1221 ),
1222 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311223 r'/\bmojo::StrongAssociatedBindingSet\b',
1224 (
1225 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1226 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1227 ),
1228 ),
1229 (
1230 r'/\bmojo::StrongBindingSet\b',
1231 (
1232 'mojo::StrongBindingSet<Interface> is deprecated.',
1233 'Use mojo::UniqueReceiverSet<Interface> instead.',
1234 ),
1235 ),
1236)
wnwenbdc444e2016-05-25 13:44:151237
mlamouria82272622014-09-16 18:45:041238_IPC_ENUM_TRAITS_DEPRECATED = (
1239 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501240 'See http://www.chromium.org/Home/chromium-security/education/'
1241 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041242
Stephen Martinis97a394142018-06-07 23:06:051243_LONG_PATH_ERROR = (
1244 'Some files included in this CL have file names that are too long (> 200'
1245 ' characters). If committed, these files will cause issues on Windows. See'
1246 ' https://crbug.com/612667 for more details.'
1247)
1248
Shenghua Zhangbfaa38b82017-11-16 21:58:021249_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041250 r".*[\\/]BuildHooksAndroidImpl\.java",
1251 r".*[\\/]LicenseContentProvider\.java",
1252 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281253 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021254]
[email protected]127f18ec2012-06-16 05:05:591255
Mohamed Heikald048240a2019-11-12 16:57:371256# List of image extensions that are used as resources in chromium.
1257_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1258
Sean Kau46e29bc2017-08-28 16:31:161259# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401260_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041261 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401262 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041263 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1264 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041265 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431266 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161267]
1268
1269
[email protected]b00342e7f2013-03-26 16:21:541270_VALID_OS_MACROS = (
1271 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081272 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541273 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441274 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121275 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541276 'OS_BSD',
1277 'OS_CAT', # For testing.
1278 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041279 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541280 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371281 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541282 'OS_IOS',
1283 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441284 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541285 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211286 'OS_NACL_NONSFI',
1287 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121288 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541289 'OS_OPENBSD',
1290 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371291 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541292 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541293 'OS_WIN',
1294)
1295
1296
Andrew Grieveb773bad2020-06-05 18:00:381297# These are not checked on the public chromium-presubmit trybot.
1298# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041299# checkouts.
agrievef32bcc72016-04-04 14:57:401300_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381301 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381302]
1303
1304
1305_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041306 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361307 'base/android/jni_generator/jni_generator.pydeps',
1308 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361309 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041310 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361311 'build/android/gyp/aar.pydeps',
1312 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271313 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361314 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381315 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361316 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021317 'build/android/gyp/bytecode_rewriter.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111318 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361319 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361320 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361321 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111322 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041323 'build/android/gyp/create_app_bundle_apks.pydeps',
1324 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361325 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121326 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091327 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221328 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001329 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361330 'build/android/gyp/desugar.pydeps',
1331 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421332 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041333 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361334 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361335 'build/android/gyp/filter_zip.pydeps',
1336 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361337 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361338 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581339 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361340 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141341 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261342 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011343 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041344 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361345 'build/android/gyp/lint.pydeps',
1346 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361347 'build/android/gyp/merge_manifest.pydeps',
1348 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221349 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361350 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461351 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241352 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461354 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561355 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361356 'build/android/incremental_install/generate_android_manifest.pydeps',
1357 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041358 'build/android/resource_sizes.pydeps',
1359 'build/android/test_runner.pydeps',
1360 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361361 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361362 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321363 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271364 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1365 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001366 'components/cronet/tools/generate_javadoc.pydeps',
1367 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381368 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001369 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381370 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041371 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181372 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041373 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421374 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1375 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131376 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061377 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221378 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401379]
1380
wnwenbdc444e2016-05-25 13:44:151381
agrievef32bcc72016-04-04 14:57:401382_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1383
1384
Eric Boren6fd2b932018-01-25 15:05:081385# Bypass the AUTHORS check for these accounts.
1386_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591387 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451388 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591389 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521390 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071391 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041392 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271393 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041394 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301395 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081396
1397
Daniel Bratell65b033262019-04-23 08:17:061398def _IsCPlusPlusFile(input_api, file_path):
1399 """Returns True if this file contains C++-like code (and not Python,
1400 Go, Java, MarkDown, ...)"""
1401
1402 ext = input_api.os_path.splitext(file_path)[1]
1403 # This list is compatible with CppChecker.IsCppFile but we should
1404 # consider adding ".c" to it. If we do that we can use this function
1405 # at more places in the code.
1406 return ext in (
1407 '.h',
1408 '.cc',
1409 '.cpp',
1410 '.m',
1411 '.mm',
1412 )
1413
1414def _IsCPlusPlusHeaderFile(input_api, file_path):
1415 return input_api.os_path.splitext(file_path)[1] == ".h"
1416
1417
1418def _IsJavaFile(input_api, file_path):
1419 return input_api.os_path.splitext(file_path)[1] == ".java"
1420
1421
1422def _IsProtoFile(input_api, file_path):
1423 return input_api.os_path.splitext(file_path)[1] == ".proto"
1424
Mohamed Heikal5e5b7922020-10-29 18:57:591425
1426def CheckNoUpstreamDepsOnClank(input_api, output_api):
1427 """Prevent additions of dependencies from the upstream repo on //clank."""
1428 # clank can depend on clank
1429 if input_api.change.RepositoryRoot().endswith('clank'):
1430 return []
1431 build_file_patterns = [
1432 r'(.+/)?BUILD\.gn',
1433 r'.+\.gni',
1434 ]
1435 excluded_files = [
1436 r'build[/\\]config[/\\]android[/\\]config\.gni'
1437 ]
1438 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1439
1440 error_message = 'Disallowed import on //clank in an upstream build file:'
1441
1442 def FilterFile(affected_file):
1443 return input_api.FilterSourceFile(
1444 affected_file,
1445 files_to_check=build_file_patterns,
1446 files_to_skip=excluded_files)
1447
1448 problems = []
1449 for f in input_api.AffectedSourceFiles(FilterFile):
1450 local_path = f.LocalPath()
1451 for line_number, line in f.ChangedContents():
1452 if (bad_pattern.search(line)):
1453 problems.append(
1454 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1455 if problems:
1456 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1457 else:
1458 return []
1459
1460
Saagar Sanghavifceeaae2020-08-12 16:40:361461def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191462 """Attempts to prevent use of functions intended only for testing in
1463 non-testing code. For now this is just a best-effort implementation
1464 that ignores header files and may have some false positives. A
1465 better implementation would probably need a proper C++ parser.
1466 """
1467 # We only scan .cc files and the like, as the declaration of
1468 # for-testing functions in header files are hard to distinguish from
1469 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491470 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191471
jochenc0d4808c2015-07-27 09:25:421472 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191473 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091474 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131475 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191476 exclusion_pattern = input_api.re.compile(
1477 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1478 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131479 # Avoid a false positive in this case, where the method name, the ::, and
1480 # the closing { are all on different lines due to line wrapping.
1481 # HelperClassForTesting::
1482 # HelperClassForTesting(
1483 # args)
1484 # : member(0) {}
1485 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191486
1487 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441488 files_to_skip = (_EXCLUDED_PATHS +
1489 _TEST_CODE_EXCLUDED_PATHS +
1490 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191491 return input_api.FilterSourceFile(
1492 affected_file,
James Cook24a504192020-07-23 00:08:441493 files_to_check=file_inclusion_pattern,
1494 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191495
1496 problems = []
1497 for f in input_api.AffectedSourceFiles(FilterFile):
1498 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131499 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241500 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031501 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461502 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131503 not exclusion_pattern.search(line) and
1504 not allowlist_pattern.search(line) and
1505 not in_method_defn):
[email protected]55459852011-08-10 15:17:191506 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031507 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131508 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191509
1510 if problems:
[email protected]f7051d52013-04-02 18:31:421511 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031512 else:
1513 return []
[email protected]55459852011-08-10 15:17:191514
1515
Saagar Sanghavifceeaae2020-08-12 16:40:361516def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231517 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591518 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231519 """
1520 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1521 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1522 name_pattern = r'ForTest(s|ing)?'
1523 # Describes an occurrence of "ForTest*" inside a // comment.
1524 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501525 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551526 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231527 # Catch calls.
1528 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1529 # Ignore definitions. (Comments are ignored separately.)
1530 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1531
1532 problems = []
1533 sources = lambda x: input_api.FilterSourceFile(
1534 x,
James Cook24a504192020-07-23 00:08:441535 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1536 + input_api.DEFAULT_FILES_TO_SKIP),
1537 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231538 )
1539 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1540 local_path = f.LocalPath()
1541 is_inside_javadoc = False
1542 for line_number, line in f.ChangedContents():
1543 if is_inside_javadoc and javadoc_end_re.search(line):
1544 is_inside_javadoc = False
1545 if not is_inside_javadoc and javadoc_start_re.search(line):
1546 is_inside_javadoc = True
1547 if is_inside_javadoc:
1548 continue
1549 if (inclusion_re.search(line) and
1550 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501551 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231552 not exclusion_re.search(line)):
1553 problems.append(
1554 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1555
1556 if problems:
1557 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1558 else:
1559 return []
1560
1561
Saagar Sanghavifceeaae2020-08-12 16:40:361562def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541563 """Checks to make sure no .h files include <iostream>."""
1564 files = []
1565 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1566 input_api.re.MULTILINE)
1567 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1568 if not f.LocalPath().endswith('.h'):
1569 continue
1570 contents = input_api.ReadFile(f)
1571 if pattern.search(contents):
1572 files.append(f)
1573
1574 if len(files):
yolandyandaabc6d2016-04-18 18:29:391575 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061576 'Do not #include <iostream> in header files, since it inserts static '
1577 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541578 '#include <ostream>. See http://crbug.com/94794',
1579 files) ]
1580 return []
1581
Danil Chapovalov3518f362018-08-11 16:13:431582def _CheckNoStrCatRedefines(input_api, output_api):
1583 """Checks no windows headers with StrCat redefined are included directly."""
1584 files = []
1585 pattern_deny = input_api.re.compile(
1586 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1587 input_api.re.MULTILINE)
1588 pattern_allow = input_api.re.compile(
1589 r'^#include\s"base/win/windows_defines.inc"',
1590 input_api.re.MULTILINE)
1591 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1592 contents = input_api.ReadFile(f)
1593 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1594 files.append(f.LocalPath())
1595
1596 if len(files):
1597 return [output_api.PresubmitError(
1598 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1599 'directly since they pollute code with StrCat macro. Instead, '
1600 'include matching header from base/win. See http://crbug.com/856536',
1601 files) ]
1602 return []
1603
[email protected]10689ca2011-09-02 02:31:541604
Saagar Sanghavifceeaae2020-08-12 16:40:361605def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521606 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181607 problems = []
1608 for f in input_api.AffectedFiles():
1609 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1610 continue
1611
1612 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041613 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181614 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1615
1616 if not problems:
1617 return []
1618 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1619 '\n'.join(problems))]
1620
Saagar Sanghavifceeaae2020-08-12 16:40:361621def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341622 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1623
1624 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1625 instead of DISABLED_. To filter false positives, reports are only generated
1626 if a corresponding MAYBE_ line exists.
1627 """
1628 problems = []
1629
1630 # The following two patterns are looked for in tandem - is a test labeled
1631 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1632 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1633 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1634
1635 # This is for the case that a test is disabled on all platforms.
1636 full_disable_pattern = input_api.re.compile(
1637 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1638 input_api.re.MULTILINE)
1639
Katie Df13948e2018-09-25 07:33:441640 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341641 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1642 continue
1643
1644 # Search for MABYE_, DISABLE_ pairs.
1645 disable_lines = {} # Maps of test name to line number.
1646 maybe_lines = {}
1647 for line_num, line in f.ChangedContents():
1648 disable_match = disable_pattern.search(line)
1649 if disable_match:
1650 disable_lines[disable_match.group(1)] = line_num
1651 maybe_match = maybe_pattern.search(line)
1652 if maybe_match:
1653 maybe_lines[maybe_match.group(1)] = line_num
1654
1655 # Search for DISABLE_ occurrences within a TEST() macro.
1656 disable_tests = set(disable_lines.keys())
1657 maybe_tests = set(maybe_lines.keys())
1658 for test in disable_tests.intersection(maybe_tests):
1659 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1660
1661 contents = input_api.ReadFile(f)
1662 full_disable_match = full_disable_pattern.search(contents)
1663 if full_disable_match:
1664 problems.append(' %s' % f.LocalPath())
1665
1666 if not problems:
1667 return []
1668 return [
1669 output_api.PresubmitPromptWarning(
1670 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1671 '\n'.join(problems))
1672 ]
1673
[email protected]72df4e782012-06-21 16:28:181674
Saagar Sanghavifceeaae2020-08-12 16:40:361675def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571676 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521677 errors = []
Hans Wennborg944479f2020-06-25 21:39:251678 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521679 input_api.re.MULTILINE)
1680 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1681 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1682 continue
1683 for lnum, line in f.ChangedContents():
1684 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171685 errors.append(output_api.PresubmitError(
1686 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571687 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171688 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521689 return errors
1690
1691
Weilun Shia487fad2020-10-28 00:10:341692# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1693# more reliable way. See
1694# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191695
wnwenbdc444e2016-05-25 13:44:151696
Saagar Sanghavifceeaae2020-08-12 16:40:361697def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391698 """Check that FlakyTest annotation is our own instead of the android one"""
1699 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1700 files = []
1701 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1702 if f.LocalPath().endswith('Test.java'):
1703 if pattern.search(input_api.ReadFile(f)):
1704 files.append(f)
1705 if len(files):
1706 return [output_api.PresubmitError(
1707 'Use org.chromium.base.test.util.FlakyTest instead of '
1708 'android.test.FlakyTest',
1709 files)]
1710 return []
mcasasb7440c282015-02-04 14:52:191711
wnwenbdc444e2016-05-25 13:44:151712
Saagar Sanghavifceeaae2020-08-12 16:40:361713def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221714 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271715 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221716 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201717 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571718 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341719 '/win/' in f.LocalPath() or
1720 'chrome_elf' in f.LocalPath() or
1721 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201722 continue
[email protected]8ea5d4b2011-09-13 21:49:221723
[email protected]a11dbe9b2012-08-07 01:32:581724 allowWString = False
[email protected]b5c24292011-11-28 14:38:201725 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581726 if 'presubmit: allow wstring' in line:
1727 allowWString = True
1728 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271729 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581730 allowWString = False
1731 else:
1732 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221733
[email protected]55463aa62011-10-12 00:48:271734 if not problems:
1735 return []
1736 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581737 ' If you are calling a cross-platform API that accepts a wstring, '
1738 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271739 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221740
1741
Saagar Sanghavifceeaae2020-08-12 16:40:361742def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441743 """Make sure .DEPS.git is never modified manually."""
1744 if any(f.LocalPath().endswith('.DEPS.git') for f in
1745 input_api.AffectedFiles()):
1746 return [output_api.PresubmitError(
1747 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1748 'automated system based on what\'s in DEPS and your changes will be\n'
1749 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501750 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1751 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441752 'for more information')]
1753 return []
1754
1755
Saagar Sanghavifceeaae2020-08-12 16:40:361756def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471757 """Checks that DEPS file deps are from allowed_hosts."""
1758 # Run only if DEPS file has been modified to annoy fewer bystanders.
1759 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1760 return []
1761 # Outsource work to gclient verify
1762 try:
John Budorickf20c0042019-04-25 23:23:401763 gclient_path = input_api.os_path.join(
1764 input_api.PresubmitLocalPath(),
1765 'third_party', 'depot_tools', 'gclient.py')
1766 input_api.subprocess.check_output(
1767 [input_api.python_executable, gclient_path, 'verify'],
1768 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471769 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201770 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471771 return [output_api.PresubmitError(
1772 'DEPS file must have only git dependencies.',
1773 long_text=error.output)]
1774
1775
Mario Sanchez Prada2472cab2019-09-18 10:58:311776def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1777 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591778 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311779
1780 Returns an string composed of the name of the file, the line number where the
1781 match has been found and the additional text passed as |message| in case the
1782 target type name matches the text inside the line passed as parameter.
1783 """
Peng Huang9c5949a02020-06-11 19:20:541784 result = []
1785
danakjd18e8892020-12-17 17:42:011786 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1787 return result
1788 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541789 return result
1790
Mario Sanchez Prada2472cab2019-09-18 10:58:311791 matched = False
1792 if type_name[0:1] == '/':
1793 regex = type_name[1:]
1794 if input_api.re.search(regex, line):
1795 matched = True
1796 elif type_name in line:
1797 matched = True
1798
Mario Sanchez Prada2472cab2019-09-18 10:58:311799 if matched:
1800 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1801 for message_line in message:
1802 result.append(' %s' % message_line)
1803
1804 return result
1805
1806
Saagar Sanghavifceeaae2020-08-12 16:40:361807def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591808 """Make sure that banned functions are not used."""
1809 warnings = []
1810 errors = []
1811
James Cook24a504192020-07-23 00:08:441812 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151813 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441814 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151815 if input_api.re.match(item, local_path):
1816 return True
1817 return False
1818
Peter K. Lee6c03ccff2019-07-15 14:40:051819 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541820 local_path = affected_file.LocalPath()
1821 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1822 return False
1823 basename = input_api.os_path.basename(local_path)
1824 if 'ios' in basename.split('_'):
1825 return True
1826 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1827 if sep and 'ios' in local_path.split(sep):
1828 return True
1829 return False
1830
wnwenbdc444e2016-05-25 13:44:151831 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311832 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1833 func_name, message)
1834 if problems:
wnwenbdc444e2016-05-25 13:44:151835 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311836 errors.extend(problems)
1837 else:
1838 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151839
Eric Stevensona9a980972017-09-23 00:04:411840 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1841 for f in input_api.AffectedFiles(file_filter=file_filter):
1842 for line_num, line in f.ChangedContents():
1843 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1844 CheckForMatch(f, line_num, line, func_name, message, error)
1845
[email protected]127f18ec2012-06-16 05:05:591846 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1847 for f in input_api.AffectedFiles(file_filter=file_filter):
1848 for line_num, line in f.ChangedContents():
1849 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151850 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591851
Peter K. Lee6c03ccff2019-07-15 14:40:051852 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541853 for line_num, line in f.ChangedContents():
1854 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1855 CheckForMatch(f, line_num, line, func_name, message, error)
1856
Peter K. Lee6c03ccff2019-07-15 14:40:051857 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1858 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1859 for line_num, line in f.ChangedContents():
1860 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1861 CheckForMatch(f, line_num, line, func_name, message, error)
1862
[email protected]127f18ec2012-06-16 05:05:591863 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1864 for f in input_api.AffectedFiles(file_filter=file_filter):
1865 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491866 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441867 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491868 continue
wnwenbdc444e2016-05-25 13:44:151869 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591870
1871 result = []
1872 if (warnings):
1873 result.append(output_api.PresubmitPromptWarning(
1874 'Banned functions were used.\n' + '\n'.join(warnings)))
1875 if (errors):
1876 result.append(output_api.PresubmitError(
1877 'Banned functions were used.\n' + '\n'.join(errors)))
1878 return result
1879
1880
Michael Thiessen44457642020-02-06 00:24:151881def _CheckAndroidNoBannedImports(input_api, output_api):
1882 """Make sure that banned java imports are not used."""
1883 errors = []
1884
1885 def IsException(path, exceptions):
1886 for exception in exceptions:
1887 if (path.startswith(exception)):
1888 return True
1889 return False
1890
1891 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1892 for f in input_api.AffectedFiles(file_filter=file_filter):
1893 for line_num, line in f.ChangedContents():
1894 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1895 if IsException(f.LocalPath(), exceptions):
1896 continue;
1897 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1898 'import ' + import_name, message)
1899 if problems:
1900 errors.extend(problems)
1901 result = []
1902 if (errors):
1903 result.append(output_api.PresubmitError(
1904 'Banned imports were used.\n' + '\n'.join(errors)))
1905 return result
1906
1907
Saagar Sanghavifceeaae2020-08-12 16:40:361908def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311909 """Make sure that old Mojo types are not used."""
1910 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571911 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311912
Mario Sanchez Pradaaab91382019-12-19 08:57:091913 # For any path that is not an "ok" or an "error" path, a warning will be
1914 # raised if deprecated mojo types are found.
1915 ok_paths = ['components/arc']
1916 error_paths = ['third_party/blink', 'content']
1917
Mario Sanchez Prada2472cab2019-09-18 10:58:311918 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1919 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571920 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091921 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311922 continue
1923
1924 for line_num, line in f.ChangedContents():
1925 for func_name, message in _DEPRECATED_MOJO_TYPES:
1926 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1927 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571928
Mario Sanchez Prada2472cab2019-09-18 10:58:311929 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091930 # Raise errors inside |error_paths| and warnings everywhere else.
1931 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571932 errors.extend(problems)
1933 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311934 warnings.extend(problems)
1935
1936 result = []
1937 if (warnings):
1938 result.append(output_api.PresubmitPromptWarning(
1939 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571940 if (errors):
1941 result.append(output_api.PresubmitError(
1942 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311943 return result
1944
1945
Saagar Sanghavifceeaae2020-08-12 16:40:361946def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061947 """Make sure that banned functions are not used."""
1948 files = []
1949 pattern = input_api.re.compile(r'^#pragma\s+once',
1950 input_api.re.MULTILINE)
1951 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1952 if not f.LocalPath().endswith('.h'):
1953 continue
1954 contents = input_api.ReadFile(f)
1955 if pattern.search(contents):
1956 files.append(f)
1957
1958 if files:
1959 return [output_api.PresubmitError(
1960 'Do not use #pragma once in header files.\n'
1961 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1962 files)]
1963 return []
1964
[email protected]127f18ec2012-06-16 05:05:591965
Saagar Sanghavifceeaae2020-08-12 16:40:361966def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121967 """Checks to make sure we don't introduce use of foo ? true : false."""
1968 problems = []
1969 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1970 for f in input_api.AffectedFiles():
1971 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1972 continue
1973
1974 for line_num, line in f.ChangedContents():
1975 if pattern.match(line):
1976 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1977
1978 if not problems:
1979 return []
1980 return [output_api.PresubmitPromptWarning(
1981 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1982 '\n'.join(problems))]
1983
1984
Saagar Sanghavifceeaae2020-08-12 16:40:361985def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281986 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181987 change. Breaking - rules is an error, breaking ! rules is a
1988 warning.
1989 """
mohan.reddyf21db962014-10-16 12:26:471990 import sys
[email protected]55f9f382012-07-31 11:02:181991 # We need to wait until we have an input_api object and use this
1992 # roundabout construct to import checkdeps because this file is
1993 # eval-ed and thus doesn't have __file__.
1994 original_sys_path = sys.path
1995 try:
1996 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471997 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181998 import checkdeps
[email protected]55f9f382012-07-31 11:02:181999 from rules import Rule
2000 finally:
2001 # Restore sys.path to what it was before.
2002 sys.path = original_sys_path
2003
2004 added_includes = []
rhalavati08acd232017-04-03 07:23:282005 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242006 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182007 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062008 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502009 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082010 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062011 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502012 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082013 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062014 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502015 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082016 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182017
[email protected]26385172013-05-09 23:11:352018 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182019
2020 error_descriptions = []
2021 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282022 error_subjects = set()
2023 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362024
[email protected]55f9f382012-07-31 11:02:182025 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2026 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082027 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182028 description_with_path = '%s\n %s' % (path, rule_description)
2029 if rule_type == Rule.DISALLOW:
2030 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282031 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182032 else:
2033 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282034 warning_subjects.add("#includes")
2035
2036 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2037 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082038 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282039 description_with_path = '%s\n %s' % (path, rule_description)
2040 if rule_type == Rule.DISALLOW:
2041 error_descriptions.append(description_with_path)
2042 error_subjects.add("imports")
2043 else:
2044 warning_descriptions.append(description_with_path)
2045 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182046
Jinsuk Kim5a092672017-10-24 22:42:242047 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022048 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082049 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242050 description_with_path = '%s\n %s' % (path, rule_description)
2051 if rule_type == Rule.DISALLOW:
2052 error_descriptions.append(description_with_path)
2053 error_subjects.add("imports")
2054 else:
2055 warning_descriptions.append(description_with_path)
2056 warning_subjects.add("imports")
2057
[email protected]55f9f382012-07-31 11:02:182058 results = []
2059 if error_descriptions:
2060 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282061 'You added one or more %s that violate checkdeps rules.'
2062 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182063 error_descriptions))
2064 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422065 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282066 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182067 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282068 '%s? See relevant DEPS file(s) for details and contacts.' %
2069 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182070 warning_descriptions))
2071 return results
2072
2073
Saagar Sanghavifceeaae2020-08-12 16:40:362074def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222075 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152076 if input_api.platform == 'win32':
2077 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292078 checkperms_tool = input_api.os_path.join(
2079 input_api.PresubmitLocalPath(),
2080 'tools', 'checkperms', 'checkperms.py')
2081 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472082 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392083 with input_api.CreateTemporaryFile() as file_list:
2084 for f in input_api.AffectedFiles():
2085 # checkperms.py file/directory arguments must be relative to the
2086 # repository.
2087 file_list.write(f.LocalPath() + '\n')
2088 file_list.close()
2089 args += ['--file-list', file_list.name]
2090 try:
2091 input_api.subprocess.check_output(args)
2092 return []
2093 except input_api.subprocess.CalledProcessError as error:
2094 return [output_api.PresubmitError(
2095 'checkperms.py failed:',
2096 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222097
2098
Saagar Sanghavifceeaae2020-08-12 16:40:362099def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492100 """Makes sure we don't include ui/aura/window_property.h
2101 in header files.
2102 """
2103 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2104 errors = []
2105 for f in input_api.AffectedFiles():
2106 if not f.LocalPath().endswith('.h'):
2107 continue
2108 for line_num, line in f.ChangedContents():
2109 if pattern.match(line):
2110 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2111
2112 results = []
2113 if errors:
2114 results.append(output_api.PresubmitError(
2115 'Header files should not include ui/aura/window_property.h', errors))
2116 return results
2117
2118
[email protected]70ca77752012-11-20 03:45:032119def _CheckForVersionControlConflictsInFile(input_api, f):
2120 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2121 errors = []
2122 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162123 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232124 # First-level headers in markdown look a lot like version control
2125 # conflict markers. http://daringfireball.net/projects/markdown/basics
2126 continue
[email protected]70ca77752012-11-20 03:45:032127 if pattern.match(line):
2128 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2129 return errors
2130
2131
Saagar Sanghavifceeaae2020-08-12 16:40:362132def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032133 """Usually this is not intentional and will cause a compile failure."""
2134 errors = []
2135 for f in input_api.AffectedFiles():
2136 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2137
2138 results = []
2139 if errors:
2140 results.append(output_api.PresubmitError(
2141 'Version control conflict markers found, please resolve.', errors))
2142 return results
2143
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202144
Saagar Sanghavifceeaae2020-08-12 16:40:362145def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162146 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2147 errors = []
2148 for f in input_api.AffectedFiles():
2149 for line_num, line in f.ChangedContents():
2150 if pattern.search(line):
2151 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2152
2153 results = []
2154 if errors:
2155 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502156 'Found Google support URL addressed by answer number. Please replace '
2157 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162158 return results
2159
[email protected]70ca77752012-11-20 03:45:032160
Saagar Sanghavifceeaae2020-08-12 16:40:362161def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442162 def FilterFile(affected_file):
2163 """Filter function for use with input_api.AffectedSourceFiles,
2164 below. This filters out everything except non-test files from
2165 top-level directories that generally speaking should not hard-code
2166 service URLs (e.g. src/android_webview/, src/content/ and others).
2167 """
2168 return input_api.FilterSourceFile(
2169 affected_file,
James Cook24a504192020-07-23 00:08:442170 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2171 files_to_skip=(_EXCLUDED_PATHS +
2172 _TEST_CODE_EXCLUDED_PATHS +
2173 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442174
reillyi38965732015-11-16 18:27:332175 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2176 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462177 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2178 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442179 problems = [] # items are (filename, line_number, line)
2180 for f in input_api.AffectedSourceFiles(FilterFile):
2181 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462182 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442183 problems.append((f.LocalPath(), line_num, line))
2184
2185 if problems:
[email protected]f7051d52013-04-02 18:31:422186 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442187 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582188 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442189 [' %s:%d: %s' % (
2190 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032191 else:
2192 return []
[email protected]06e6d0ff2012-12-11 01:36:442193
2194
Saagar Sanghavifceeaae2020-08-12 16:40:362195def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292196 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2197 def FileFilter(affected_file):
2198 """Includes directories known to be Chrome OS only."""
2199 return input_api.FilterSourceFile(
2200 affected_file,
James Cook24a504192020-07-23 00:08:442201 files_to_check=('^ash/',
2202 '^chromeos/', # Top-level src/chromeos.
2203 '/chromeos/', # Any path component.
2204 '^components/arc',
2205 '^components/exo'),
2206 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292207
2208 prefs = []
2209 priority_prefs = []
2210 for f in input_api.AffectedFiles(file_filter=FileFilter):
2211 for line_num, line in f.ChangedContents():
2212 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2213 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2214 prefs.append(' %s' % line)
2215 if input_api.re.search(
2216 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2217 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2218 priority_prefs.append(' %s' % line)
2219
2220 results = []
2221 if (prefs):
2222 results.append(output_api.PresubmitPromptWarning(
2223 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2224 'by browser sync settings. If these prefs should be controlled by OS '
2225 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2226 if (priority_prefs):
2227 results.append(output_api.PresubmitPromptWarning(
2228 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2229 'controlled by browser sync settings. If these prefs should be '
2230 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2231 'instead.\n' + '\n'.join(prefs)))
2232 return results
2233
2234
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492235# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362236def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272237 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312238 The native_client_sdk directory is excluded because it has auto-generated PNG
2239 files for documentation.
[email protected]d2530012013-01-25 16:39:272240 """
[email protected]d2530012013-01-25 16:39:272241 errors = []
James Cook24a504192020-07-23 00:08:442242 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2243 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312244 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442245 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312246 for f in input_api.AffectedFiles(include_deletes=False,
2247 file_filter=file_filter):
2248 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272249
2250 results = []
2251 if errors:
2252 results.append(output_api.PresubmitError(
2253 'The name of PNG files should not have abbreviations. \n'
2254 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2255 'Contact [email protected] if you have questions.', errors))
2256 return results
2257
2258
Daniel Cheng4dcdb6b2017-04-13 08:30:172259def _ExtractAddRulesFromParsedDeps(parsed_deps):
2260 """Extract the rules that add dependencies from a parsed DEPS file.
2261
2262 Args:
2263 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2264 add_rules = set()
2265 add_rules.update([
2266 rule[1:] for rule in parsed_deps.get('include_rules', [])
2267 if rule.startswith('+') or rule.startswith('!')
2268 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502269 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172270 {}).iteritems():
2271 add_rules.update([
2272 rule[1:] for rule in rules
2273 if rule.startswith('+') or rule.startswith('!')
2274 ])
2275 return add_rules
2276
2277
2278def _ParseDeps(contents):
2279 """Simple helper for parsing DEPS files."""
2280 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172281 class _VarImpl:
2282
2283 def __init__(self, local_scope):
2284 self._local_scope = local_scope
2285
2286 def Lookup(self, var_name):
2287 """Implements the Var syntax."""
2288 try:
2289 return self._local_scope['vars'][var_name]
2290 except KeyError:
2291 raise Exception('Var is not defined: %s' % var_name)
2292
2293 local_scope = {}
2294 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172295 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592296 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172297 }
2298 exec contents in global_scope, local_scope
2299 return local_scope
2300
2301
2302def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592303 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412304 a set of DEPS entries that we should look up.
2305
2306 For a directory (rather than a specific filename) we fake a path to
2307 a specific filename by adding /DEPS. This is chosen as a file that
2308 will seldom or never be subject to per-file include_rules.
2309 """
[email protected]2b438d62013-11-14 17:54:142310 # We ignore deps entries on auto-generated directories.
2311 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082312
Daniel Cheng4dcdb6b2017-04-13 08:30:172313 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2314 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2315
2316 added_deps = new_deps.difference(old_deps)
2317
[email protected]2b438d62013-11-14 17:54:142318 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172319 for added_dep in added_deps:
2320 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2321 continue
2322 # Assume that a rule that ends in .h is a rule for a specific file.
2323 if added_dep.endswith('.h'):
2324 results.add(added_dep)
2325 else:
2326 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082327 return results
2328
2329
Saagar Sanghavifceeaae2020-08-12 16:40:362330def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552331 """When a dependency prefixed with + is added to a DEPS file, we
2332 want to make sure that the change is reviewed by an OWNER of the
2333 target file or directory, to avoid layering violations from being
2334 introduced. This check verifies that this happens.
2335 """
Edward Lesmes6fba51082021-01-20 04:20:232336 if input_api.change.issue:
2337 # Skip OWNERS check when Bot-Commit label is approved. This label is
2338 # intended for commits made by trusted bots that don't require review nor
2339 # owners approval.
2340 if input_api.gerrit.IsBotCommitApproved(input_api.change.issue):
2341 return []
2342 # Skip OWNERS check when Owners-Override label is approved. This is intended
2343 # for global owners, trusted bots, and on-call sheriffs. Review is still
2344 # required for these changes.
2345 if input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue):
2346 return []
2347
Daniel Cheng4dcdb6b2017-04-13 08:30:172348 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242349
2350 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492351 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242352 for f in input_api.AffectedFiles(include_deletes=False,
2353 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552354 filename = input_api.os_path.basename(f.LocalPath())
2355 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172356 virtual_depended_on_files.update(_CalculateAddedDeps(
2357 input_api.os_path,
2358 '\n'.join(f.OldContents()),
2359 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552360
[email protected]e871964c2013-05-13 14:14:552361 if not virtual_depended_on_files:
2362 return []
2363
2364 if input_api.is_committing:
2365 if input_api.tbr:
2366 return [output_api.PresubmitNotifyResult(
2367 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272368 if input_api.dry_run:
2369 return [output_api.PresubmitNotifyResult(
2370 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552371 if not input_api.change.issue:
2372 return [output_api.PresubmitError(
2373 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402374 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552375 output = output_api.PresubmitError
2376 else:
2377 output = output_api.PresubmitNotifyResult
2378
2379 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502380 owner_email, reviewers = (
2381 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2382 input_api,
2383 owners_db.email_regexp,
2384 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552385
2386 owner_email = owner_email or input_api.change.author_email
2387
[email protected]de4f7d22013-05-23 14:27:462388 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512389 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462390 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552391 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2392 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412393
2394 # We strip the /DEPS part that was added by
2395 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2396 # directory.
2397 def StripDeps(path):
2398 start_deps = path.rfind('/DEPS')
2399 if start_deps != -1:
2400 return path[:start_deps]
2401 else:
2402 return path
2403 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552404 for path in missing_files]
2405
2406 if unapproved_dependencies:
2407 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152408 output('You need LGTM from owners of depends-on paths in DEPS that were '
2409 'modified in this CL:\n %s' %
2410 '\n '.join(sorted(unapproved_dependencies)))]
2411 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2412 output_list.append(output(
2413 'Suggested missing target path OWNERS:\n %s' %
2414 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552415 return output_list
2416
2417 return []
2418
2419
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492420# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362421def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492422 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442423 files_to_skip = (_EXCLUDED_PATHS +
2424 _TEST_CODE_EXCLUDED_PATHS +
2425 input_api.DEFAULT_FILES_TO_SKIP +
2426 (r"^base[\\/]logging\.h$",
2427 r"^base[\\/]logging\.cc$",
2428 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2429 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2430 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2431 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2432 r"startup_browser_creator\.cc$",
2433 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2434 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2435 r"diagnostics_writer\.cc$",
2436 r"^chrome[\\/]chrome_cleaner[\\/].*",
2437 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2438 r"dll_hash_main\.cc$",
2439 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2440 r"^chromecast[\\/]",
2441 r"^cloud_print[\\/]",
2442 r"^components[\\/]browser_watcher[\\/]"
2443 r"dump_stability_report_main_win.cc$",
2444 r"^components[\\/]media_control[\\/]renderer[\\/]"
2445 r"media_playback_options\.cc$",
2446 r"^components[\\/]zucchini[\\/].*",
2447 # TODO(peter): Remove exception. https://crbug.com/534537
2448 r"^content[\\/]browser[\\/]notifications[\\/]"
2449 r"notification_event_dispatcher_impl\.cc$",
2450 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2451 r"gl_helper_benchmark\.cc$",
2452 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2453 r"^courgette[\\/]courgette_tool\.cc$",
2454 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2455 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2456 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2457 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2458 r"^ipc[\\/]ipc_logging\.cc$",
2459 r"^native_client_sdk[\\/]",
2460 r"^remoting[\\/]base[\\/]logging\.h$",
2461 r"^remoting[\\/]host[\\/].*",
2462 r"^sandbox[\\/]linux[\\/].*",
2463 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2464 r"dump_file_system.cc$",
2465 r"^tools[\\/]",
2466 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2467 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2468 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2469 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2470 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402471 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442472 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402473
thomasanderson625d3932017-03-29 07:16:582474 log_info = set([])
2475 printf = set([])
[email protected]85218562013-11-22 07:41:402476
2477 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582478 for _, line in f.ChangedContents():
2479 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2480 log_info.add(f.LocalPath())
2481 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2482 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372483
thomasanderson625d3932017-03-29 07:16:582484 if input_api.re.search(r"\bprintf\(", line):
2485 printf.add(f.LocalPath())
2486 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2487 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402488
2489 if log_info:
2490 return [output_api.PresubmitError(
2491 'These files spam the console log with LOG(INFO):',
2492 items=log_info)]
2493 if printf:
2494 return [output_api.PresubmitError(
2495 'These files spam the console log with printf/fprintf:',
2496 items=printf)]
2497 return []
2498
2499
Saagar Sanghavifceeaae2020-08-12 16:40:362500def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162501 """These types are all expected to hold locks while in scope and
2502 so should never be anonymous (which causes them to be immediately
2503 destroyed)."""
2504 they_who_must_be_named = [
2505 'base::AutoLock',
2506 'base::AutoReset',
2507 'base::AutoUnlock',
2508 'SkAutoAlphaRestore',
2509 'SkAutoBitmapShaderInstall',
2510 'SkAutoBlitterChoose',
2511 'SkAutoBounderCommit',
2512 'SkAutoCallProc',
2513 'SkAutoCanvasRestore',
2514 'SkAutoCommentBlock',
2515 'SkAutoDescriptor',
2516 'SkAutoDisableDirectionCheck',
2517 'SkAutoDisableOvalCheck',
2518 'SkAutoFree',
2519 'SkAutoGlyphCache',
2520 'SkAutoHDC',
2521 'SkAutoLockColors',
2522 'SkAutoLockPixels',
2523 'SkAutoMalloc',
2524 'SkAutoMaskFreeImage',
2525 'SkAutoMutexAcquire',
2526 'SkAutoPathBoundsUpdate',
2527 'SkAutoPDFRelease',
2528 'SkAutoRasterClipValidate',
2529 'SkAutoRef',
2530 'SkAutoTime',
2531 'SkAutoTrace',
2532 'SkAutoUnref',
2533 ]
2534 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2535 # bad: base::AutoLock(lock.get());
2536 # not bad: base::AutoLock lock(lock.get());
2537 bad_pattern = input_api.re.compile(anonymous)
2538 # good: new base::AutoLock(lock.get())
2539 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2540 errors = []
2541
2542 for f in input_api.AffectedFiles():
2543 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2544 continue
2545 for linenum, line in f.ChangedContents():
2546 if bad_pattern.search(line) and not good_pattern.search(line):
2547 errors.append('%s:%d' % (f.LocalPath(), linenum))
2548
2549 if errors:
2550 return [output_api.PresubmitError(
2551 'These lines create anonymous variables that need to be named:',
2552 items=errors)]
2553 return []
2554
2555
Saagar Sanghavifceeaae2020-08-12 16:40:362556def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532557 # Returns whether |template_str| is of the form <T, U...> for some types T
2558 # and U. Assumes that |template_str| is already in the form <...>.
2559 def HasMoreThanOneArg(template_str):
2560 # Level of <...> nesting.
2561 nesting = 0
2562 for c in template_str:
2563 if c == '<':
2564 nesting += 1
2565 elif c == '>':
2566 nesting -= 1
2567 elif c == ',' and nesting == 1:
2568 return True
2569 return False
2570
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492571 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102572 sources = lambda affected_file: input_api.FilterSourceFile(
2573 affected_file,
James Cook24a504192020-07-23 00:08:442574 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2575 input_api.DEFAULT_FILES_TO_SKIP),
2576 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552577
2578 # Pattern to capture a single "<...>" block of template arguments. It can
2579 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2580 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2581 # latter would likely require counting that < and > match, which is not
2582 # expressible in regular languages. Should the need arise, one can introduce
2583 # limited counting (matching up to a total number of nesting depth), which
2584 # should cover all practical cases for already a low nesting limit.
2585 template_arg_pattern = (
2586 r'<[^>]*' # Opening block of <.
2587 r'>([^<]*>)?') # Closing block of >.
2588 # Prefix expressing that whatever follows is not already inside a <...>
2589 # block.
2590 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102591 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552592 not_inside_template_arg_pattern
2593 + r'\bstd::unique_ptr'
2594 + template_arg_pattern
2595 + r'\(\)')
2596
2597 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2598 template_arg_no_array_pattern = (
2599 r'<[^>]*[^]]' # Opening block of <.
2600 r'>([^(<]*[^]]>)?') # Closing block of >.
2601 # Prefix saying that what follows is the start of an expression.
2602 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2603 # Suffix saying that what follows are call parentheses with a non-empty list
2604 # of arguments.
2605 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532606 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552607 return_construct_pattern = input_api.re.compile(
2608 start_of_expr_pattern
2609 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532610 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552611 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532612 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552613 + nonempty_arg_list_pattern)
2614
Vaclav Brozek851d9602018-04-04 16:13:052615 problems_constructor = []
2616 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102617 for f in input_api.AffectedSourceFiles(sources):
2618 for line_number, line in f.ChangedContents():
2619 # Disallow:
2620 # return std::unique_ptr<T>(foo);
2621 # bar = std::unique_ptr<T>(foo);
2622 # But allow:
2623 # return std::unique_ptr<T[]>(foo);
2624 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532625 # And also allow cases when the second template argument is present. Those
2626 # cases cannot be handled by std::make_unique:
2627 # return std::unique_ptr<T, U>(foo);
2628 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052629 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532630 return_construct_result = return_construct_pattern.search(line)
2631 if return_construct_result and not HasMoreThanOneArg(
2632 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052633 problems_constructor.append(
2634 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102635 # Disallow:
2636 # std::unique_ptr<T>()
2637 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052638 problems_nullptr.append(
2639 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2640
2641 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162642 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052643 errors.append(output_api.PresubmitError(
2644 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162645 problems_nullptr))
2646 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052647 errors.append(output_api.PresubmitError(
2648 'The following files use explicit std::unique_ptr constructor.'
2649 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162650 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102651 return errors
2652
2653
Saagar Sanghavifceeaae2020-08-12 16:40:362654def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082655 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522656 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082657 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522658 # If actions.xml is already included in the changelist, the PRESUBMIT
2659 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082660 return []
2661
[email protected]999261d2014-03-03 20:08:082662 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2663 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522664 current_actions = None
[email protected]999261d2014-03-03 20:08:082665 for f in input_api.AffectedFiles(file_filter=file_filter):
2666 for line_num, line in f.ChangedContents():
2667 match = input_api.re.search(action_re, line)
2668 if match:
[email protected]2f92dec2014-03-07 19:21:522669 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2670 # loaded only once.
2671 if not current_actions:
2672 with open('tools/metrics/actions/actions.xml') as actions_f:
2673 current_actions = actions_f.read()
2674 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082675 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522676 action = 'name="{0}"'.format(action_name)
2677 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082678 return [output_api.PresubmitPromptWarning(
2679 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522680 'tools/metrics/actions/actions.xml. Please run '
2681 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082682 % (f.LocalPath(), line_num, action_name))]
2683 return []
2684
2685
Daniel Cheng13ca61a882017-08-25 15:11:252686def _ImportJSONCommentEater(input_api):
2687 import sys
2688 sys.path = sys.path + [input_api.os_path.join(
2689 input_api.PresubmitLocalPath(),
2690 'tools', 'json_comment_eater')]
2691 import json_comment_eater
2692 return json_comment_eater
2693
2694
[email protected]99171a92014-06-03 08:44:472695def _GetJSONParseError(input_api, filename, eat_comments=True):
2696 try:
2697 contents = input_api.ReadFile(filename)
2698 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252699 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132700 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472701
2702 input_api.json.loads(contents)
2703 except ValueError as e:
2704 return e
2705 return None
2706
2707
2708def _GetIDLParseError(input_api, filename):
2709 try:
2710 contents = input_api.ReadFile(filename)
2711 idl_schema = input_api.os_path.join(
2712 input_api.PresubmitLocalPath(),
2713 'tools', 'json_schema_compiler', 'idl_schema.py')
2714 process = input_api.subprocess.Popen(
2715 [input_api.python_executable, idl_schema],
2716 stdin=input_api.subprocess.PIPE,
2717 stdout=input_api.subprocess.PIPE,
2718 stderr=input_api.subprocess.PIPE,
2719 universal_newlines=True)
2720 (_, error) = process.communicate(input=contents)
2721 return error or None
2722 except ValueError as e:
2723 return e
2724
2725
Saagar Sanghavifceeaae2020-08-12 16:40:362726def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472727 """Check that IDL and JSON files do not contain syntax errors."""
2728 actions = {
2729 '.idl': _GetIDLParseError,
2730 '.json': _GetJSONParseError,
2731 }
[email protected]99171a92014-06-03 08:44:472732 # Most JSON files are preprocessed and support comments, but these do not.
2733 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042734 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472735 ]
2736 # Only run IDL checker on files in these directories.
2737 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042738 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2739 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472740 ]
2741
2742 def get_action(affected_file):
2743 filename = affected_file.LocalPath()
2744 return actions.get(input_api.os_path.splitext(filename)[1])
2745
[email protected]99171a92014-06-03 08:44:472746 def FilterFile(affected_file):
2747 action = get_action(affected_file)
2748 if not action:
2749 return False
2750 path = affected_file.LocalPath()
2751
Erik Staab2dd72b12020-04-16 15:03:402752 if _MatchesFile(input_api,
2753 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2754 path):
[email protected]99171a92014-06-03 08:44:472755 return False
2756
2757 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162758 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472759 return False
2760 return True
2761
2762 results = []
2763 for affected_file in input_api.AffectedFiles(
2764 file_filter=FilterFile, include_deletes=False):
2765 action = get_action(affected_file)
2766 kwargs = {}
2767 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162768 _MatchesFile(input_api, json_no_comments_patterns,
2769 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472770 kwargs['eat_comments'] = False
2771 parse_error = action(input_api,
2772 affected_file.AbsoluteLocalPath(),
2773 **kwargs)
2774 if parse_error:
2775 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2776 (affected_file.LocalPath(), parse_error)))
2777 return results
2778
2779
Saagar Sanghavifceeaae2020-08-12 16:40:362780def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492781 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472782 import sys
[email protected]760deea2013-12-10 19:33:492783 original_sys_path = sys.path
2784 try:
2785 sys.path = sys.path + [input_api.os_path.join(
2786 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2787 import checkstyle
2788 finally:
2789 # Restore sys.path to what it was before.
2790 sys.path = original_sys_path
2791
2792 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092793 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442794 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492795
2796
Saagar Sanghavifceeaae2020-08-12 16:40:362797def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002798 """Checks to make sure devil is initialized correctly in python scripts."""
2799 script_common_initialize_pattern = input_api.re.compile(
2800 r'script_common\.InitializeEnvironment\(')
2801 devil_env_config_initialize = input_api.re.compile(
2802 r'devil_env\.config\.Initialize\(')
2803
2804 errors = []
2805
2806 sources = lambda affected_file: input_api.FilterSourceFile(
2807 affected_file,
James Cook24a504192020-07-23 00:08:442808 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2809 (r'^build[\\/]android[\\/]devil_chromium\.py',
2810 r'^third_party[\\/].*',)),
2811 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002812
2813 for f in input_api.AffectedSourceFiles(sources):
2814 for line_num, line in f.ChangedContents():
2815 if (script_common_initialize_pattern.search(line) or
2816 devil_env_config_initialize.search(line)):
2817 errors.append("%s:%d" % (f.LocalPath(), line_num))
2818
2819 results = []
2820
2821 if errors:
2822 results.append(output_api.PresubmitError(
2823 'Devil initialization should always be done using '
2824 'devil_chromium.Initialize() in the chromium project, to use better '
2825 'defaults for dependencies (ex. up-to-date version of adb).',
2826 errors))
2827
2828 return results
2829
2830
Sean Kau46e29bc2017-08-28 16:31:162831def _MatchesFile(input_api, patterns, path):
2832 for pattern in patterns:
2833 if input_api.re.search(pattern, path):
2834 return True
2835 return False
2836
2837
Daniel Cheng7052cdf2017-11-21 19:23:292838def _GetOwnersFilesToCheckForIpcOwners(input_api):
2839 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172840
Daniel Cheng7052cdf2017-11-21 19:23:292841 Returns:
2842 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2843 contain to cover IPC-related files with noparent reviewer rules.
2844 """
2845 # Whether or not a file affects IPC is (mostly) determined by a simple list
2846 # of filename patterns.
dchenge07de812016-06-20 19:27:172847 file_patterns = [
palmerb19a0932017-01-24 04:00:312848 # Legacy IPC:
dchenge07de812016-06-20 19:27:172849 '*_messages.cc',
2850 '*_messages*.h',
2851 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312852 # Mojo IPC:
dchenge07de812016-06-20 19:27:172853 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472854 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172855 '*_struct_traits*.*',
2856 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312857 '*.typemap',
2858 # Android native IPC:
2859 '*.aidl',
2860 # Blink uses a different file naming convention:
2861 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472862 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172863 '*StructTraits*.*',
2864 '*TypeConverter*.*',
2865 ]
2866
scottmg7a6ed5ba2016-11-04 18:22:042867 # These third_party directories do not contain IPCs, but contain files
2868 # matching the above patterns, which trigger false positives.
2869 exclude_paths = [
2870 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162871 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232872 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292873 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542874 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162875 # These files are just used to communicate between class loaders running
2876 # in the same process.
2877 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572878 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2879
scottmg7a6ed5ba2016-11-04 18:22:042880 ]
2881
dchenge07de812016-06-20 19:27:172882 # Dictionary mapping an OWNERS file path to Patterns.
2883 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2884 # rules ) to a PatternEntry.
2885 # PatternEntry is a dictionary with two keys:
2886 # - 'files': the files that are matched by this pattern
2887 # - 'rules': the per-file rules needed for this pattern
2888 # For example, if we expect OWNERS file to contain rules for *.mojom and
2889 # *_struct_traits*.*, Patterns might look like this:
2890 # {
2891 # '*.mojom': {
2892 # 'files': ...,
2893 # 'rules': [
2894 # 'per-file *.mojom=set noparent',
2895 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2896 # ],
2897 # },
2898 # '*_struct_traits*.*': {
2899 # 'files': ...,
2900 # 'rules': [
2901 # 'per-file *_struct_traits*.*=set noparent',
2902 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2903 # ],
2904 # },
2905 # }
2906 to_check = {}
2907
Daniel Cheng13ca61a882017-08-25 15:11:252908 def AddPatternToCheck(input_file, pattern):
2909 owners_file = input_api.os_path.join(
2910 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2911 if owners_file not in to_check:
2912 to_check[owners_file] = {}
2913 if pattern not in to_check[owners_file]:
2914 to_check[owners_file][pattern] = {
2915 'files': [],
2916 'rules': [
2917 'per-file %s=set noparent' % pattern,
2918 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2919 ]
2920 }
Vaclav Brozekd5de76a2018-03-17 07:57:502921 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252922
dchenge07de812016-06-20 19:27:172923 # Iterate through the affected files to see what we actually need to check
2924 # for. We should only nag patch authors about per-file rules if a file in that
2925 # directory would match that pattern. If a directory only contains *.mojom
2926 # files and no *_messages*.h files, we should only nag about rules for
2927 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252928 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262929 # Manifest files don't have a strong naming convention. Instead, try to find
2930 # affected .cc and .h files which look like they contain a manifest
2931 # definition.
2932 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2933 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2934 if (manifest_pattern.search(f.LocalPath()) and not
2935 test_manifest_pattern.search(f.LocalPath())):
2936 # We expect all actual service manifest files to contain at least one
2937 # qualified reference to service_manager::Manifest.
2938 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252939 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172940 for pattern in file_patterns:
2941 if input_api.fnmatch.fnmatch(
2942 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042943 skip = False
2944 for exclude in exclude_paths:
2945 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2946 skip = True
2947 break
2948 if skip:
2949 continue
Daniel Cheng13ca61a882017-08-25 15:11:252950 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172951 break
2952
Daniel Cheng7052cdf2017-11-21 19:23:292953 return to_check
2954
2955
Wez17c66962020-04-29 15:26:032956def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2957 """Adds OWNERS files to check for correct Fuchsia security owners."""
2958
2959 file_patterns = [
2960 # Component specifications.
2961 '*.cml', # Component Framework v2.
2962 '*.cmx', # Component Framework v1.
2963
2964 # Fuchsia IDL protocol specifications.
2965 '*.fidl',
2966 ]
2967
Joshua Peraza1ca6d392020-12-08 00:14:092968 # Don't check for owners files for changes in these directories.
2969 exclude_paths = [
2970 'third_party/crashpad/*',
2971 ]
2972
Wez17c66962020-04-29 15:26:032973 def AddPatternToCheck(input_file, pattern):
2974 owners_file = input_api.os_path.join(
2975 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2976 if owners_file not in to_check:
2977 to_check[owners_file] = {}
2978 if pattern not in to_check[owners_file]:
2979 to_check[owners_file][pattern] = {
2980 'files': [],
2981 'rules': [
2982 'per-file %s=set noparent' % pattern,
2983 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2984 ]
2985 }
2986 to_check[owners_file][pattern]['files'].append(input_file)
2987
2988 # Iterate through the affected files to see what we actually need to check
2989 # for. We should only nag patch authors about per-file rules if a file in that
2990 # directory would match that pattern.
2991 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092992 skip = False
2993 for exclude in exclude_paths:
2994 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2995 skip = True
2996 if skip:
2997 continue
2998
Wez17c66962020-04-29 15:26:032999 for pattern in file_patterns:
3000 if input_api.fnmatch.fnmatch(
3001 input_api.os_path.basename(f.LocalPath()), pattern):
3002 AddPatternToCheck(f, pattern)
3003 break
3004
3005 return to_check
3006
3007
Saagar Sanghavifceeaae2020-08-12 16:40:363008def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293009 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3010 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033011 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293012
3013 if to_check:
3014 # If there are any OWNERS files to check, there are IPC-related changes in
3015 # this CL. Auto-CC the review list.
3016 output_api.AppendCC('[email protected]')
3017
3018 # Go through the OWNERS files to check, filtering out rules that are already
3019 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173020 for owners_file, patterns in to_check.iteritems():
3021 try:
3022 with file(owners_file) as f:
3023 lines = set(f.read().splitlines())
3024 for entry in patterns.itervalues():
3025 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3026 ]
3027 except IOError:
3028 # No OWNERS file, so all the rules are definitely missing.
3029 continue
3030
3031 # All the remaining lines weren't found in OWNERS files, so emit an error.
3032 errors = []
3033 for owners_file, patterns in to_check.iteritems():
3034 missing_lines = []
3035 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503036 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173037 missing_lines.extend(entry['rules'])
3038 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3039 if missing_lines:
3040 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053041 'Because of the presence of files:\n%s\n\n'
3042 '%s needs the following %d lines added:\n\n%s' %
3043 ('\n'.join(files), owners_file, len(missing_lines),
3044 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173045
3046 results = []
3047 if errors:
vabrf5ce3bf92016-07-11 14:52:413048 if input_api.is_committing:
3049 output = output_api.PresubmitError
3050 else:
3051 output = output_api.PresubmitPromptWarning
3052 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593053 'Found OWNERS files that need to be updated for IPC security ' +
3054 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173055 long_text='\n\n'.join(errors)))
3056
3057 return results
3058
3059
Robert Sesek2c905332020-05-06 23:17:133060def _GetFilesUsingSecurityCriticalFunctions(input_api):
3061 """Checks affected files for changes to security-critical calls. This
3062 function checks the full change diff, to catch both additions/changes
3063 and removals.
3064
3065 Returns a dict keyed by file name, and the value is a set of detected
3066 functions.
3067 """
3068 # Map of function pretty name (displayed in an error) to the pattern to
3069 # match it with.
3070 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373071 'content::GetServiceSandboxType<>()':
3072 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133073 }
3074 _PATTERNS_TO_CHECK = {
3075 k: input_api.re.compile(v)
3076 for k, v in _PATTERNS_TO_CHECK.items()
3077 }
3078
3079 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3080 files_to_functions = {}
3081 for f in input_api.AffectedFiles():
3082 diff = f.GenerateScmDiff()
3083 for line in diff.split('\n'):
3084 # Not using just RightHandSideLines() because removing a
3085 # call to a security-critical function can be just as important
3086 # as adding or changing the arguments.
3087 if line.startswith('-') or (line.startswith('+') and
3088 not line.startswith('++')):
3089 for name, pattern in _PATTERNS_TO_CHECK.items():
3090 if pattern.search(line):
3091 path = f.LocalPath()
3092 if not path in files_to_functions:
3093 files_to_functions[path] = set()
3094 files_to_functions[path].add(name)
3095 return files_to_functions
3096
3097
Saagar Sanghavifceeaae2020-08-12 16:40:363098def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133099 """Checks that changes involving security-critical functions are reviewed
3100 by the security team.
3101 """
3102 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3103 if len(files_to_functions):
3104 owners_db = input_api.owners_db
3105 owner_email, reviewers = (
3106 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3107 input_api,
3108 owners_db.email_regexp,
3109 approval_needed=input_api.is_committing))
3110
3111 # Load the OWNERS file for security changes.
3112 owners_file = 'ipc/SECURITY_OWNERS'
3113 security_owners = owners_db.owners_rooted_at_file(owners_file)
3114
3115 has_security_owner = any([owner in reviewers for owner in security_owners])
3116 if not has_security_owner:
3117 msg = 'The following files change calls to security-sensive functions\n' \
3118 'that need to be reviewed by {}.\n'.format(owners_file)
3119 for path, names in files_to_functions.items():
3120 msg += ' {}\n'.format(path)
3121 for name in names:
3122 msg += ' {}\n'.format(name)
3123 msg += '\n'
3124
3125 if input_api.is_committing:
3126 output = output_api.PresubmitError
3127 else:
3128 output = output_api.PresubmitNotifyResult
3129 return [output(msg)]
3130
3131 return []
3132
3133
Saagar Sanghavifceeaae2020-08-12 16:40:363134def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263135 """Checks that set noparent is only used together with an OWNERS file in
3136 //build/OWNERS.setnoparent (see also
3137 //docs/code_reviews.md#owners-files-details)
3138 """
3139 errors = []
3140
3141 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3142 allowed_owners_files = set()
3143 with open(allowed_owners_files_file, 'r') as f:
3144 for line in f:
3145 line = line.strip()
3146 if not line or line.startswith('#'):
3147 continue
3148 allowed_owners_files.add(line)
3149
3150 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3151
3152 for f in input_api.AffectedFiles(include_deletes=False):
3153 if not f.LocalPath().endswith('OWNERS'):
3154 continue
3155
3156 found_owners_files = set()
3157 found_set_noparent_lines = dict()
3158
3159 # Parse the OWNERS file.
3160 for lineno, line in enumerate(f.NewContents(), 1):
3161 line = line.strip()
3162 if line.startswith('set noparent'):
3163 found_set_noparent_lines[''] = lineno
3164 if line.startswith('file://'):
3165 if line in allowed_owners_files:
3166 found_owners_files.add('')
3167 if line.startswith('per-file'):
3168 match = per_file_pattern.match(line)
3169 if match:
3170 glob = match.group(1).strip()
3171 directive = match.group(2).strip()
3172 if directive == 'set noparent':
3173 found_set_noparent_lines[glob] = lineno
3174 if directive.startswith('file://'):
3175 if directive in allowed_owners_files:
3176 found_owners_files.add(glob)
3177
3178 # Check that every set noparent line has a corresponding file:// line
3179 # listed in build/OWNERS.setnoparent.
3180 for set_noparent_line in found_set_noparent_lines:
3181 if set_noparent_line in found_owners_files:
3182 continue
3183 errors.append(' %s:%d' % (f.LocalPath(),
3184 found_set_noparent_lines[set_noparent_line]))
3185
3186 results = []
3187 if errors:
3188 if input_api.is_committing:
3189 output = output_api.PresubmitError
3190 else:
3191 output = output_api.PresubmitPromptWarning
3192 results.append(output(
3193 'Found the following "set noparent" restrictions in OWNERS files that '
3194 'do not include owners from build/OWNERS.setnoparent:',
3195 long_text='\n\n'.join(errors)))
3196 return results
3197
3198
Saagar Sanghavifceeaae2020-08-12 16:40:363199def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313200 """Checks that added or removed lines in non third party affected
3201 header files do not lead to new useless class or struct forward
3202 declaration.
jbriance9e12f162016-11-25 07:57:503203 """
3204 results = []
3205 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3206 input_api.re.MULTILINE)
3207 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3208 input_api.re.MULTILINE)
3209 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313210 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193211 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493212 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313213 continue
3214
jbriance9e12f162016-11-25 07:57:503215 if not f.LocalPath().endswith('.h'):
3216 continue
3217
3218 contents = input_api.ReadFile(f)
3219 fwd_decls = input_api.re.findall(class_pattern, contents)
3220 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3221
3222 useless_fwd_decls = []
3223 for decl in fwd_decls:
3224 count = sum(1 for _ in input_api.re.finditer(
3225 r'\b%s\b' % input_api.re.escape(decl), contents))
3226 if count == 1:
3227 useless_fwd_decls.append(decl)
3228
3229 if not useless_fwd_decls:
3230 continue
3231
3232 for line in f.GenerateScmDiff().splitlines():
3233 if (line.startswith('-') and not line.startswith('--') or
3234 line.startswith('+') and not line.startswith('++')):
3235 for decl in useless_fwd_decls:
3236 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3237 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243238 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503239 (f.LocalPath(), decl)))
3240 useless_fwd_decls.remove(decl)
3241
3242 return results
3243
Jinsong Fan91ebbbd2019-04-16 14:57:173244def _CheckAndroidDebuggableBuild(input_api, output_api):
3245 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3246 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3247 this is a debuggable build of Android.
3248 """
3249 build_type_check_pattern = input_api.re.compile(
3250 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3251
3252 errors = []
3253
3254 sources = lambda affected_file: input_api.FilterSourceFile(
3255 affected_file,
James Cook24a504192020-07-23 00:08:443256 files_to_skip=(_EXCLUDED_PATHS +
3257 _TEST_CODE_EXCLUDED_PATHS +
3258 input_api.DEFAULT_FILES_TO_SKIP +
3259 (r"^android_webview[\\/]support_library[\\/]"
3260 "boundary_interfaces[\\/]",
3261 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3262 r'^third_party[\\/].*',
3263 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3264 r"webview[\\/]chromium[\\/]License.*",)),
3265 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173266
3267 for f in input_api.AffectedSourceFiles(sources):
3268 for line_num, line in f.ChangedContents():
3269 if build_type_check_pattern.search(line):
3270 errors.append("%s:%d" % (f.LocalPath(), line_num))
3271
3272 results = []
3273
3274 if errors:
3275 results.append(output_api.PresubmitPromptWarning(
3276 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3277 ' Please use BuildInfo.isDebugAndroid() instead.',
3278 errors))
3279
3280 return results
jbriance9e12f162016-11-25 07:57:503281
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493282# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293283def _CheckAndroidToastUsage(input_api, output_api):
3284 """Checks that code uses org.chromium.ui.widget.Toast instead of
3285 android.widget.Toast (Chromium Toast doesn't force hardware
3286 acceleration on low-end devices, saving memory).
3287 """
3288 toast_import_pattern = input_api.re.compile(
3289 r'^import android\.widget\.Toast;$')
3290
3291 errors = []
3292
3293 sources = lambda affected_file: input_api.FilterSourceFile(
3294 affected_file,
James Cook24a504192020-07-23 00:08:443295 files_to_skip=(_EXCLUDED_PATHS +
3296 _TEST_CODE_EXCLUDED_PATHS +
3297 input_api.DEFAULT_FILES_TO_SKIP +
3298 (r'^chromecast[\\/].*',
3299 r'^remoting[\\/].*')),
3300 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293301
3302 for f in input_api.AffectedSourceFiles(sources):
3303 for line_num, line in f.ChangedContents():
3304 if toast_import_pattern.search(line):
3305 errors.append("%s:%d" % (f.LocalPath(), line_num))
3306
3307 results = []
3308
3309 if errors:
3310 results.append(output_api.PresubmitError(
3311 'android.widget.Toast usage is detected. Android toasts use hardware'
3312 ' acceleration, and can be\ncostly on low-end devices. Please use'
3313 ' org.chromium.ui.widget.Toast instead.\n'
3314 'Contact [email protected] if you have any questions.',
3315 errors))
3316
3317 return results
3318
3319
dgnaa68d5e2015-06-10 10:08:223320def _CheckAndroidCrLogUsage(input_api, output_api):
3321 """Checks that new logs using org.chromium.base.Log:
3322 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513323 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223324 """
pkotwicza1dd0b002016-05-16 14:41:043325
torne89540622017-03-24 19:41:303326 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043327 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303328 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043329 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303330 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043331 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3332 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093333 # The customtabs_benchmark is a small app that does not depend on Chromium
3334 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043335 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043336 ]
3337
dgnaa68d5e2015-06-10 10:08:223338 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123339 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3340 class_in_base_pattern = input_api.re.compile(
3341 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3342 has_some_log_import_pattern = input_api.re.compile(
3343 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223344 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553345 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223346 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463347 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553348 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223349
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463350 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443351 sources = lambda x: input_api.FilterSourceFile(x,
3352 files_to_check=[r'.*\.java$'],
3353 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123354
dgnaa68d5e2015-06-10 10:08:223355 tag_decl_errors = []
3356 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123357 tag_errors = []
dgn38736db2015-09-18 19:20:513358 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123359 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223360
3361 for f in input_api.AffectedSourceFiles(sources):
3362 file_content = input_api.ReadFile(f)
3363 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223364 # Per line checks
dgn87d9fb62015-06-12 09:15:123365 if (cr_log_import_pattern.search(file_content) or
3366 (class_in_base_pattern.search(file_content) and
3367 not has_some_log_import_pattern.search(file_content))):
3368 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223369 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553370 if rough_log_decl_pattern.search(line):
3371 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223372
3373 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123374 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223375 if match:
3376 has_modified_logs = True
3377
3378 # Make sure it uses "TAG"
3379 if not match.group('tag') == 'TAG':
3380 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123381 else:
3382 # Report non cr Log function calls in changed lines
3383 for line_num, line in f.ChangedContents():
3384 if log_call_pattern.search(line):
3385 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223386
3387 # Per file checks
3388 if has_modified_logs:
3389 # Make sure the tag is using the "cr" prefix and is not too long
3390 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513391 tag_name = match.group('name') if match else None
3392 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223393 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513394 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223395 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513396 elif '.' in tag_name:
3397 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223398
3399 results = []
3400 if tag_decl_errors:
3401 results.append(output_api.PresubmitPromptWarning(
3402 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513403 '"private static final String TAG = "<package tag>".\n'
3404 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223405 tag_decl_errors))
3406
3407 if tag_length_errors:
3408 results.append(output_api.PresubmitError(
3409 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513410 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223411 tag_length_errors))
3412
3413 if tag_errors:
3414 results.append(output_api.PresubmitPromptWarning(
3415 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3416 tag_errors))
3417
dgn87d9fb62015-06-12 09:15:123418 if util_log_errors:
dgn4401aa52015-04-29 16:26:173419 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123420 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3421 util_log_errors))
3422
dgn38736db2015-09-18 19:20:513423 if tag_with_dot_errors:
3424 results.append(output_api.PresubmitPromptWarning(
3425 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3426 tag_with_dot_errors))
3427
dgn4401aa52015-04-29 16:26:173428 return results
3429
3430
Yoland Yanb92fa522017-08-28 17:37:063431def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3432 """Checks that junit.framework.* is no longer used."""
3433 deprecated_junit_framework_pattern = input_api.re.compile(
3434 r'^import junit\.framework\..*;',
3435 input_api.re.MULTILINE)
3436 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443437 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063438 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133439 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063440 for line_num, line in f.ChangedContents():
3441 if deprecated_junit_framework_pattern.search(line):
3442 errors.append("%s:%d" % (f.LocalPath(), line_num))
3443
3444 results = []
3445 if errors:
3446 results.append(output_api.PresubmitError(
3447 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3448 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3449 ' if you have any question.', errors))
3450 return results
3451
3452
3453def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3454 """Checks that if new Java test classes have inheritance.
3455 Either the new test class is JUnit3 test or it is a JUnit4 test class
3456 with a base class, either case is undesirable.
3457 """
3458 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3459
3460 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443461 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063462 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133463 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063464 if not f.OldContents():
3465 class_declaration_start_flag = False
3466 for line_num, line in f.ChangedContents():
3467 if class_declaration_pattern.search(line):
3468 class_declaration_start_flag = True
3469 if class_declaration_start_flag and ' extends ' in line:
3470 errors.append('%s:%d' % (f.LocalPath(), line_num))
3471 if '{' in line:
3472 class_declaration_start_flag = False
3473
3474 results = []
3475 if errors:
3476 results.append(output_api.PresubmitPromptWarning(
3477 'The newly created files include Test classes that inherits from base'
3478 ' class. Please do not use inheritance in JUnit4 tests or add new'
3479 ' JUnit3 tests. Contact [email protected] if you have any'
3480 ' questions.', errors))
3481 return results
3482
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203483
yolandyan45001472016-12-21 21:12:423484def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3485 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3486 deprecated_annotation_import_pattern = input_api.re.compile(
3487 r'^import android\.test\.suitebuilder\.annotation\..*;',
3488 input_api.re.MULTILINE)
3489 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443490 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423491 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133492 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423493 for line_num, line in f.ChangedContents():
3494 if deprecated_annotation_import_pattern.search(line):
3495 errors.append("%s:%d" % (f.LocalPath(), line_num))
3496
3497 results = []
3498 if errors:
3499 results.append(output_api.PresubmitError(
3500 'Annotations in android.test.suitebuilder.annotation have been'
3501 ' deprecated since API level 24. Please use android.support.test.filters'
3502 ' from //third_party/android_support_test_runner:runner_java instead.'
3503 ' Contact [email protected] if you have any questions.', errors))
3504 return results
3505
3506
agrieve7b6479d82015-10-07 14:24:223507def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3508 """Checks if MDPI assets are placed in a correct directory."""
3509 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3510 ('/res/drawable/' in f.LocalPath() or
3511 '/res/drawable-ldrtl/' in f.LocalPath()))
3512 errors = []
3513 for f in input_api.AffectedFiles(include_deletes=False,
3514 file_filter=file_filter):
3515 errors.append(' %s' % f.LocalPath())
3516
3517 results = []
3518 if errors:
3519 results.append(output_api.PresubmitError(
3520 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3521 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3522 '/res/drawable-ldrtl/.\n'
3523 'Contact [email protected] if you have questions.', errors))
3524 return results
3525
3526
Nate Fischer535972b2017-09-16 01:06:183527def _CheckAndroidWebkitImports(input_api, output_api):
3528 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353529 android.webview.ValueCallback except in the WebView glue layer
3530 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183531 """
3532 valuecallback_import_pattern = input_api.re.compile(
3533 r'^import android\.webkit\.ValueCallback;$')
3534
3535 errors = []
3536
3537 sources = lambda affected_file: input_api.FilterSourceFile(
3538 affected_file,
James Cook24a504192020-07-23 00:08:443539 files_to_skip=(_EXCLUDED_PATHS +
3540 _TEST_CODE_EXCLUDED_PATHS +
3541 input_api.DEFAULT_FILES_TO_SKIP +
3542 (r'^android_webview[\\/]glue[\\/].*',
3543 r'^weblayer[\\/].*',)),
3544 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183545
3546 for f in input_api.AffectedSourceFiles(sources):
3547 for line_num, line in f.ChangedContents():
3548 if valuecallback_import_pattern.search(line):
3549 errors.append("%s:%d" % (f.LocalPath(), line_num))
3550
3551 results = []
3552
3553 if errors:
3554 results.append(output_api.PresubmitError(
3555 'android.webkit.ValueCallback usage is detected outside of the glue'
3556 ' layer. To stay compatible with the support library, android.webkit.*'
3557 ' classes should only be used inside the glue layer and'
3558 ' org.chromium.base.Callback should be used instead.',
3559 errors))
3560
3561 return results
3562
3563
Becky Zhou7c69b50992018-12-10 19:37:573564def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3565 """Checks Android XML styles """
3566 import sys
3567 original_sys_path = sys.path
3568 try:
3569 sys.path = sys.path + [input_api.os_path.join(
3570 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3571 import checkxmlstyle
3572 finally:
3573 # Restore sys.path to what it was before.
3574 sys.path = original_sys_path
3575
3576 if is_check_on_upload:
3577 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3578 else:
3579 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3580
3581
agrievef32bcc72016-04-04 14:57:403582class PydepsChecker(object):
3583 def __init__(self, input_api, pydeps_files):
3584 self._file_cache = {}
3585 self._input_api = input_api
3586 self._pydeps_files = pydeps_files
3587
3588 def _LoadFile(self, path):
3589 """Returns the list of paths within a .pydeps file relative to //."""
3590 if path not in self._file_cache:
3591 with open(path) as f:
3592 self._file_cache[path] = f.read()
3593 return self._file_cache[path]
3594
3595 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3596 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393597 pydeps_data = self._LoadFile(pydeps_path)
3598 uses_gn_paths = '--gn-paths' in pydeps_data
3599 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3600 if uses_gn_paths:
3601 # Paths look like: //foo/bar/baz
3602 return (e[2:] for e in entries)
3603 else:
3604 # Paths look like: path/relative/to/file.pydeps
3605 os_path = self._input_api.os_path
3606 pydeps_dir = os_path.dirname(pydeps_path)
3607 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403608
3609 def _CreateFilesToPydepsMap(self):
3610 """Returns a map of local_path -> list_of_pydeps."""
3611 ret = {}
3612 for pydep_local_path in self._pydeps_files:
3613 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3614 ret.setdefault(path, []).append(pydep_local_path)
3615 return ret
3616
3617 def ComputeAffectedPydeps(self):
3618 """Returns an iterable of .pydeps files that might need regenerating."""
3619 affected_pydeps = set()
3620 file_to_pydeps_map = None
3621 for f in self._input_api.AffectedFiles(include_deletes=True):
3622 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463623 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3624 # subrepositories. We can't figure out which files change, so re-check
3625 # all files.
3626 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383627 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3628 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403629 return self._pydeps_files
3630 elif local_path.endswith('.pydeps'):
3631 if local_path in self._pydeps_files:
3632 affected_pydeps.add(local_path)
3633 elif local_path.endswith('.py'):
3634 if file_to_pydeps_map is None:
3635 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3636 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3637 return affected_pydeps
3638
3639 def DetermineIfStale(self, pydeps_path):
3640 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413641 import difflib
John Budorick47ca3fe2018-02-10 00:53:103642 import os
3643
agrievef32bcc72016-04-04 14:57:403644 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033645 if old_pydeps_data:
3646 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393647 if '--output' not in cmd:
3648 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033649 old_contents = old_pydeps_data[2:]
3650 else:
3651 # A default cmd that should work in most cases (as long as pydeps filename
3652 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3653 # file is empty/new.
3654 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3655 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3656 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103657 env = dict(os.environ)
3658 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403659 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103660 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413661 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033662 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413663 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403664
3665
Tibor Goldschwendt360793f72019-06-25 18:23:493666def _ParseGclientArgs():
3667 args = {}
3668 with open('build/config/gclient_args.gni', 'r') as f:
3669 for line in f:
3670 line = line.strip()
3671 if not line or line.startswith('#'):
3672 continue
3673 attribute, value = line.split('=')
3674 args[attribute.strip()] = value.strip()
3675 return args
3676
3677
Saagar Sanghavifceeaae2020-08-12 16:40:363678def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403679 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403680 # This check is for Python dependency lists (.pydeps files), and involves
3681 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3682 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283683 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003684 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493685 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403686 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403687 results = []
3688 # First, check for new / deleted .pydeps.
3689 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033690 # Check whether we are running the presubmit check for a file in src.
3691 # f.LocalPath is relative to repo (src, or internal repo).
3692 # os_path.exists is relative to src repo.
3693 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3694 # to src and we can conclude that the pydeps is in src.
3695 if input_api.os_path.exists(f.LocalPath()):
3696 if f.LocalPath().endswith('.pydeps'):
3697 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3698 results.append(output_api.PresubmitError(
3699 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3700 'remove %s' % f.LocalPath()))
3701 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3702 results.append(output_api.PresubmitError(
3703 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3704 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403705
3706 if results:
3707 return results
3708
Mohamed Heikal7cd4d8312020-06-16 16:49:403709 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3710 affected_pydeps = set(checker.ComputeAffectedPydeps())
3711 affected_android_pydeps = affected_pydeps.intersection(
3712 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3713 if affected_android_pydeps and not is_android:
3714 results.append(output_api.PresubmitPromptOrNotify(
3715 'You have changed python files that may affect pydeps for android\n'
3716 'specific scripts. However, the relevant presumbit check cannot be\n'
3717 'run because you are not using an Android checkout. To validate that\n'
3718 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3719 'use the android-internal-presubmit optional trybot.\n'
3720 'Possibly stale pydeps files:\n{}'.format(
3721 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403722
Mohamed Heikal7cd4d8312020-06-16 16:49:403723 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3724 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403725 try:
phajdan.jr0d9878552016-11-04 10:49:413726 result = checker.DetermineIfStale(pydep_path)
3727 if result:
3728 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403729 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413730 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3731 'To regenerate, run:\n\n %s' %
3732 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403733 except input_api.subprocess.CalledProcessError as error:
3734 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3735 long_text=error.output)]
3736
3737 return results
3738
3739
Saagar Sanghavifceeaae2020-08-12 16:40:363740def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433741 """Checks to make sure no header files have |Singleton<|."""
3742 def FileFilter(affected_file):
3743 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443744 files_to_skip = (_EXCLUDED_PATHS +
3745 input_api.DEFAULT_FILES_TO_SKIP +
3746 (r"^base[\\/]memory[\\/]singleton\.h$",
3747 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3748 r"quic_singleton_impl\.h$"))
3749 return input_api.FilterSourceFile(affected_file,
3750 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433751
sergeyu34d21222015-09-16 00:11:443752 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433753 files = []
3754 for f in input_api.AffectedSourceFiles(FileFilter):
3755 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3756 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3757 contents = input_api.ReadFile(f)
3758 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243759 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433760 pattern.search(line)):
3761 files.append(f)
3762 break
3763
3764 if files:
yolandyandaabc6d2016-04-18 18:29:393765 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443766 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433767 'Please move them to an appropriate source file so that the ' +
3768 'template gets instantiated in a single compilation unit.',
3769 files) ]
3770 return []
3771
3772
[email protected]fd20b902014-05-09 02:14:533773_DEPRECATED_CSS = [
3774 # Values
3775 ( "-webkit-box", "flex" ),
3776 ( "-webkit-inline-box", "inline-flex" ),
3777 ( "-webkit-flex", "flex" ),
3778 ( "-webkit-inline-flex", "inline-flex" ),
3779 ( "-webkit-min-content", "min-content" ),
3780 ( "-webkit-max-content", "max-content" ),
3781
3782 # Properties
3783 ( "-webkit-background-clip", "background-clip" ),
3784 ( "-webkit-background-origin", "background-origin" ),
3785 ( "-webkit-background-size", "background-size" ),
3786 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443787 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533788
3789 # Functions
3790 ( "-webkit-gradient", "gradient" ),
3791 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3792 ( "-webkit-linear-gradient", "linear-gradient" ),
3793 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3794 ( "-webkit-radial-gradient", "radial-gradient" ),
3795 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3796]
3797
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203798
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493799# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363800def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533801 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253802 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343803 documentation and iOS CSS for dom distiller
3804 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253805 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533806 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493807 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443808 files_to_skip = (_EXCLUDED_PATHS +
3809 _TEST_CODE_EXCLUDED_PATHS +
3810 input_api.DEFAULT_FILES_TO_SKIP +
3811 (r"^chrome/common/extensions/docs",
3812 r"^chrome/docs",
3813 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3814 r"^components/neterror/resources/neterror.css",
3815 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253816 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443817 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533818 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3819 for line_num, line in fpath.ChangedContents():
3820 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023821 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533822 results.append(output_api.PresubmitError(
3823 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3824 (fpath.LocalPath(), line_num, deprecated_value, value)))
3825 return results
3826
mohan.reddyf21db962014-10-16 12:26:473827
Saagar Sanghavifceeaae2020-08-12 16:40:363828def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363829 bad_files = {}
3830 for f in input_api.AffectedFiles(include_deletes=False):
3831 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493832 not f.LocalPath().startswith('third_party/blink') and
3833 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363834 continue
3835
Daniel Bratell65b033262019-04-23 08:17:063836 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363837 continue
3838
Vaclav Brozekd5de76a2018-03-17 07:57:503839 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363840 if "#include" in line and "../" in line]
3841 if not relative_includes:
3842 continue
3843 bad_files[f.LocalPath()] = relative_includes
3844
3845 if not bad_files:
3846 return []
3847
3848 error_descriptions = []
3849 for file_path, bad_lines in bad_files.iteritems():
3850 error_description = file_path
3851 for line in bad_lines:
3852 error_description += '\n ' + line
3853 error_descriptions.append(error_description)
3854
3855 results = []
3856 results.append(output_api.PresubmitError(
3857 'You added one or more relative #include paths (including "../").\n'
3858 'These shouldn\'t be used because they can be used to include headers\n'
3859 'from code that\'s not correctly specified as a dependency in the\n'
3860 'relevant BUILD.gn file(s).',
3861 error_descriptions))
3862
3863 return results
3864
Takeshi Yoshinoe387aa32017-08-02 13:16:133865
Saagar Sanghavifceeaae2020-08-12 16:40:363866def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063867 """Check that nobody tries to include a cc file. It's a relatively
3868 common error which results in duplicate symbols in object
3869 files. This may not always break the build until someone later gets
3870 very confusing linking errors."""
3871 results = []
3872 for f in input_api.AffectedFiles(include_deletes=False):
3873 # We let third_party code do whatever it wants
3874 if (f.LocalPath().startswith('third_party') and
3875 not f.LocalPath().startswith('third_party/blink') and
3876 not f.LocalPath().startswith('third_party\\blink')):
3877 continue
3878
3879 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3880 continue
3881
3882 for _, line in f.ChangedContents():
3883 if line.startswith('#include "'):
3884 included_file = line.split('"')[1]
3885 if _IsCPlusPlusFile(input_api, included_file):
3886 # The most common naming for external files with C++ code,
3887 # apart from standard headers, is to call them foo.inc, but
3888 # Chromium sometimes uses foo-inc.cc so allow that as well.
3889 if not included_file.endswith(('.h', '-inc.cc')):
3890 results.append(output_api.PresubmitError(
3891 'Only header files or .inc files should be included in other\n'
3892 'C++ files. Compiling the contents of a cc file more than once\n'
3893 'will cause duplicate information in the build which may later\n'
3894 'result in strange link_errors.\n' +
3895 f.LocalPath() + ':\n ' +
3896 line))
3897
3898 return results
3899
3900
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203901def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3902 if not isinstance(key, ast.Str):
3903 return 'Key at line %d must be a string literal' % key.lineno
3904 if not isinstance(value, ast.Dict):
3905 return 'Value at line %d must be a dict' % value.lineno
3906 if len(value.keys) != 1:
3907 return 'Dict at line %d must have single entry' % value.lineno
3908 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3909 return (
3910 'Entry at line %d must have a string literal \'filepath\' as key' %
3911 value.lineno)
3912 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133913
Takeshi Yoshinoe387aa32017-08-02 13:16:133914
Sergey Ulanov4af16052018-11-08 02:41:463915def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203916 if not isinstance(key, ast.Str):
3917 return 'Key at line %d must be a string literal' % key.lineno
3918 if not isinstance(value, ast.List):
3919 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463920 for element in value.elts:
3921 if not isinstance(element, ast.Str):
3922 return 'Watchlist elements on line %d is not a string' % key.lineno
3923 if not email_regex.match(element.s):
3924 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3925 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203926 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133927
Takeshi Yoshinoe387aa32017-08-02 13:16:133928
Sergey Ulanov4af16052018-11-08 02:41:463929def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203930 mismatch_template = (
3931 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3932 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133933
Sergey Ulanov4af16052018-11-08 02:41:463934 email_regex = input_api.re.compile(
3935 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3936
3937 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203938 i = 0
3939 last_key = ''
3940 while True:
3941 if i >= len(wd_dict.keys):
3942 if i >= len(w_dict.keys):
3943 return None
3944 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3945 elif i >= len(w_dict.keys):
3946 return (
3947 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133948
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203949 wd_key = wd_dict.keys[i]
3950 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133951
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203952 result = _CheckWatchlistDefinitionsEntrySyntax(
3953 wd_key, wd_dict.values[i], ast)
3954 if result is not None:
3955 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133956
Sergey Ulanov4af16052018-11-08 02:41:463957 result = _CheckWatchlistsEntrySyntax(
3958 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203959 if result is not None:
3960 return 'Bad entry in WATCHLISTS dict: %s' % result
3961
3962 if wd_key.s != w_key.s:
3963 return mismatch_template % (
3964 '%s at line %d' % (wd_key.s, wd_key.lineno),
3965 '%s at line %d' % (w_key.s, w_key.lineno))
3966
3967 if wd_key.s < last_key:
3968 return (
3969 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3970 (wd_key.lineno, w_key.lineno))
3971 last_key = wd_key.s
3972
3973 i = i + 1
3974
3975
Sergey Ulanov4af16052018-11-08 02:41:463976def _CheckWATCHLISTSSyntax(expression, input_api):
3977 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203978 if not isinstance(expression, ast.Expression):
3979 return 'WATCHLISTS file must contain a valid expression'
3980 dictionary = expression.body
3981 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3982 return 'WATCHLISTS file must have single dict with exactly two entries'
3983
3984 first_key = dictionary.keys[0]
3985 first_value = dictionary.values[0]
3986 second_key = dictionary.keys[1]
3987 second_value = dictionary.values[1]
3988
3989 if (not isinstance(first_key, ast.Str) or
3990 first_key.s != 'WATCHLIST_DEFINITIONS' or
3991 not isinstance(first_value, ast.Dict)):
3992 return (
3993 'The first entry of the dict in WATCHLISTS file must be '
3994 'WATCHLIST_DEFINITIONS dict')
3995
3996 if (not isinstance(second_key, ast.Str) or
3997 second_key.s != 'WATCHLISTS' or
3998 not isinstance(second_value, ast.Dict)):
3999 return (
4000 'The second entry of the dict in WATCHLISTS file must be '
4001 'WATCHLISTS dict')
4002
Sergey Ulanov4af16052018-11-08 02:41:464003 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134004
4005
Saagar Sanghavifceeaae2020-08-12 16:40:364006def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:134007 for f in input_api.AffectedFiles(include_deletes=False):
4008 if f.LocalPath() == 'WATCHLISTS':
4009 contents = input_api.ReadFile(f, 'r')
4010
4011 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204012 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134013 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204014 # Get an AST tree for it and scan the tree for detailed style checking.
4015 expression = input_api.ast.parse(
4016 contents, filename='WATCHLISTS', mode='eval')
4017 except ValueError as e:
4018 return [output_api.PresubmitError(
4019 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4020 except SyntaxError as e:
4021 return [output_api.PresubmitError(
4022 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4023 except TypeError as e:
4024 return [output_api.PresubmitError(
4025 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134026
Sergey Ulanov4af16052018-11-08 02:41:464027 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204028 if result is not None:
4029 return [output_api.PresubmitError(result)]
4030 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134031
4032 return []
4033
4034
Andrew Grieve1b290e4a22020-11-24 20:07:014035def CheckGnGlobForward(input_api, output_api):
4036 """Checks that forward_variables_from(invoker, "*") follows best practices.
4037
4038 As documented at //build/docs/writing_gn_templates.md
4039 """
4040 def gn_files(f):
4041 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
4042
4043 problems = []
4044 for f in input_api.AffectedSourceFiles(gn_files):
4045 for line_num, line in f.ChangedContents():
4046 if 'forward_variables_from(invoker, "*")' in line:
4047 problems.append(
4048 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
4049 f.LocalPath(), line_num))
4050
4051 if problems:
4052 return [output_api.PresubmitPromptWarning(
4053 'forward_variables_from("*") without exclusions',
4054 items=sorted(problems),
4055 long_text=('The variables "visibilty" and "test_only" should be '
4056 'explicitly listed in forward_variables_from(). For more '
4057 'details, see:\n'
4058 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4059 'build/docs/writing_gn_templates.md'
4060 '#Using-forward_variables_from'))]
4061 return []
4062
4063
Saagar Sanghavifceeaae2020-08-12 16:40:364064def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194065 """Checks that newly added header files have corresponding GN changes.
4066 Note that this is only a heuristic. To be precise, run script:
4067 build/check_gn_headers.py.
4068 """
4069
4070 def headers(f):
4071 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444072 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194073
4074 new_headers = []
4075 for f in input_api.AffectedSourceFiles(headers):
4076 if f.Action() != 'A':
4077 continue
4078 new_headers.append(f.LocalPath())
4079
4080 def gn_files(f):
James Cook24a504192020-07-23 00:08:444081 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194082
4083 all_gn_changed_contents = ''
4084 for f in input_api.AffectedSourceFiles(gn_files):
4085 for _, line in f.ChangedContents():
4086 all_gn_changed_contents += line
4087
4088 problems = []
4089 for header in new_headers:
4090 basename = input_api.os_path.basename(header)
4091 if basename not in all_gn_changed_contents:
4092 problems.append(header)
4093
4094 if problems:
4095 return [output_api.PresubmitPromptWarning(
4096 'Missing GN changes for new header files', items=sorted(problems),
4097 long_text='Please double check whether newly added header files need '
4098 'corresponding changes in gn or gni files.\nThis checking is only a '
4099 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4100 'Read https://crbug.com/661774 for more info.')]
4101 return []
4102
4103
Saagar Sanghavifceeaae2020-08-12 16:40:364104def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024105 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4106
4107 This assumes we won't intentionally reference one product from the other
4108 product.
4109 """
4110 all_problems = []
4111 test_cases = [{
4112 "filename_postfix": "google_chrome_strings.grd",
4113 "correct_name": "Chrome",
4114 "incorrect_name": "Chromium",
4115 }, {
4116 "filename_postfix": "chromium_strings.grd",
4117 "correct_name": "Chromium",
4118 "incorrect_name": "Chrome",
4119 }]
4120
4121 for test_case in test_cases:
4122 problems = []
4123 filename_filter = lambda x: x.LocalPath().endswith(
4124 test_case["filename_postfix"])
4125
4126 # Check each new line. Can yield false positives in multiline comments, but
4127 # easier than trying to parse the XML because messages can have nested
4128 # children, and associating message elements with affected lines is hard.
4129 for f in input_api.AffectedSourceFiles(filename_filter):
4130 for line_num, line in f.ChangedContents():
4131 if "<message" in line or "<!--" in line or "-->" in line:
4132 continue
4133 if test_case["incorrect_name"] in line:
4134 problems.append(
4135 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4136
4137 if problems:
4138 message = (
4139 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4140 % (test_case["correct_name"], test_case["correct_name"],
4141 test_case["incorrect_name"]))
4142 all_problems.append(
4143 output_api.PresubmitPromptWarning(message, items=problems))
4144
4145 return all_problems
4146
4147
Saagar Sanghavifceeaae2020-08-12 16:40:364148def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514149 # TODO(crbug.com/941824): We need to make sure the entries in
4150 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4151 # so that users of //buildtools in other projects get the same tooling
4152 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4153 # support to gclient, we can eliminate the duplication and delete
4154 # this presubmit check.
4155
4156 # Update this regexp if new revisions are added to the files.
4157 rev_regexp = input_api.re.compile(
Michael Savigny8b078012020-12-09 16:19:054158 ("'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version|"
4159 "reclient_version)':"))
Dirk Pranke3c18a382019-03-15 01:07:514160
4161 # If a user is changing one revision, they need to change the same
4162 # line in both files. This means that any given change should contain
4163 # exactly the same list of changed lines that match the regexps. The
4164 # replace(' ', '') call allows us to ignore whitespace changes to the
4165 # lines. The 'long_text' parameter to the error will contain the
4166 # list of changed lines in both files, which should make it easy enough
4167 # to spot the error without going overboard in this implementation.
Ola Rozenfeld355a1b4e2021-01-26 03:41:574168 buildtools_deps = input_api.os_path.join('buildtools', 'DEPS')
Dirk Pranke3c18a382019-03-15 01:07:514169 revs_changes = {
4170 'DEPS': {},
Ola Rozenfeld355a1b4e2021-01-26 03:41:574171 buildtools_deps: {},
Dirk Pranke3c18a382019-03-15 01:07:514172 }
4173 long_text = ''
4174
4175 for f in input_api.AffectedFiles(
Ola Rozenfeld355a1b4e2021-01-26 03:41:574176 file_filter=lambda f: f.LocalPath() in ('DEPS', buildtools_deps)):
Dirk Pranke3c18a382019-03-15 01:07:514177 for line_num, line in f.ChangedContents():
4178 if rev_regexp.search(line):
4179 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4180 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4181
Ola Rozenfeld355a1b4e2021-01-26 03:41:574182 if set(revs_changes['DEPS']) != set(revs_changes[buildtools_deps]):
Dirk Pranke3c18a382019-03-15 01:07:514183 return [output_api.PresubmitError(
Ola Rozenfeld355a1b4e2021-01-26 03:41:574184 'Change buildtools revisions in sync in both DEPS and ' +
4185 buildtools_deps + '.', long_text=long_text + '\n')]
Dirk Pranke3c18a382019-03-15 01:07:514186 else:
4187 return []
4188
4189
Saagar Sanghavifceeaae2020-08-12 16:40:364190def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364191 """Avoid large files, especially binary files, in the repository since
4192 git doesn't scale well for those. They will be in everyone's repo
4193 clones forever, forever making Chromium slower to clone and work
4194 with."""
4195
4196 # Uploading files to cloud storage is not trivial so we don't want
4197 # to set the limit too low, but the upper limit for "normal" large
4198 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4199 # anything over 20 MB is exceptional.
4200 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4201
4202 too_large_files = []
4203 for f in input_api.AffectedFiles():
4204 # Check both added and modified files (but not deleted files).
4205 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384206 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364207 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4208 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4209
4210 if too_large_files:
4211 message = (
4212 'Do not commit large files to git since git scales badly for those.\n' +
4213 'Instead put the large files in cloud storage and use DEPS to\n' +
4214 'fetch them.\n' + '\n'.join(too_large_files)
4215 )
4216 return [output_api.PresubmitError(
4217 'Too large files found in commit', long_text=message + '\n')]
4218 else:
4219 return []
4220
Max Morozb47503b2019-08-08 21:03:274221
Saagar Sanghavifceeaae2020-08-12 16:40:364222def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274223 """Checks specific for fuzz target sources."""
4224 EXPORTED_SYMBOLS = [
4225 'LLVMFuzzerInitialize',
4226 'LLVMFuzzerCustomMutator',
4227 'LLVMFuzzerCustomCrossOver',
4228 'LLVMFuzzerMutate',
4229 ]
4230
4231 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4232
4233 def FilterFile(affected_file):
4234 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444235 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4236 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274237
4238 return input_api.FilterSourceFile(
4239 affected_file,
James Cook24a504192020-07-23 00:08:444240 files_to_check=[files_to_check],
4241 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274242
4243 files_with_missing_header = []
4244 for f in input_api.AffectedSourceFiles(FilterFile):
4245 contents = input_api.ReadFile(f, 'r')
4246 if REQUIRED_HEADER in contents:
4247 continue
4248
4249 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4250 files_with_missing_header.append(f.LocalPath())
4251
4252 if not files_with_missing_header:
4253 return []
4254
4255 long_text = (
4256 'If you define any of the libFuzzer optional functions (%s), it is '
4257 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4258 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4259 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4260 'to access command line arguments passed to the fuzzer. Instead, prefer '
4261 'static initialization and shared resources as documented in '
4262 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4263 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4264 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4265 )
4266
4267 return [output_api.PresubmitPromptWarning(
4268 message="Missing '%s' in:" % REQUIRED_HEADER,
4269 items=files_with_missing_header,
4270 long_text=long_text)]
4271
4272
Mohamed Heikald048240a2019-11-12 16:57:374273def _CheckNewImagesWarning(input_api, output_api):
4274 """
4275 Warns authors who add images into the repo to make sure their images are
4276 optimized before committing.
4277 """
4278 images_added = False
4279 image_paths = []
4280 errors = []
4281 filter_lambda = lambda x: input_api.FilterSourceFile(
4282 x,
James Cook24a504192020-07-23 00:08:444283 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4284 + input_api.DEFAULT_FILES_TO_SKIP),
4285 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374286 )
4287 for f in input_api.AffectedFiles(
4288 include_deletes=False, file_filter=filter_lambda):
4289 local_path = f.LocalPath().lower()
4290 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4291 images_added = True
4292 image_paths.append(f)
4293 if images_added:
4294 errors.append(output_api.PresubmitPromptWarning(
4295 'It looks like you are trying to commit some images. If these are '
4296 'non-test-only images, please make sure to read and apply the tips in '
4297 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4298 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4299 'FYI only and will not block your CL on the CQ.', image_paths))
4300 return errors
4301
4302
Saagar Sanghavifceeaae2020-08-12 16:40:364303def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574304 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224305 results = []
dgnaa68d5e2015-06-10 10:08:224306 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174307 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224308 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294309 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064310 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4311 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424312 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184313 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574314 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374315 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154316 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574317 return results
4318
Saagar Sanghavifceeaae2020-08-12 16:40:364319def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574320 """Groups commit checks that target android code."""
4321 results = []
4322 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224323 return results
4324
Chris Hall59f8d0c72020-05-01 07:31:194325# TODO(chrishall): could we additionally match on any path owned by
4326# ui/accessibility/OWNERS ?
4327_ACCESSIBILITY_PATHS = (
4328 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4329 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4330 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4331 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4332 r"^content[\\/]browser[\\/]accessibility[\\/]",
4333 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4334 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4335 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4336 r"^ui[\\/]accessibility[\\/]",
4337 r"^ui[\\/]views[\\/]accessibility[\\/]",
4338)
4339
Saagar Sanghavifceeaae2020-08-12 16:40:364340def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194341 """Checks that commits to accessibility code contain an AX-Relnotes field in
4342 their commit message."""
4343 def FileFilter(affected_file):
4344 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444345 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194346
4347 # Only consider changes affecting accessibility paths.
4348 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4349 return []
4350
Akihiro Ota08108e542020-05-20 15:30:534351 # AX-Relnotes can appear in either the description or the footer.
4352 # When searching the description, require 'AX-Relnotes:' to appear at the
4353 # beginning of a line.
4354 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4355 description_has_relnotes = any(ax_regex.match(line)
4356 for line in input_api.change.DescriptionText().lower().splitlines())
4357
4358 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4359 'AX-Relnotes', [])
4360 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194361 return []
4362
4363 # TODO(chrishall): link to Relnotes documentation in message.
4364 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4365 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4366 "user-facing changes"
4367 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4368 "user-facing effects"
4369 "\n if this is confusing or annoying then please contact members "
4370 "of ui/accessibility/OWNERS.")
4371
4372 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224373
Saagar Sanghavifceeaae2020-08-12 16:40:364374def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394375 """Checks common to both upload and commit."""
4376 results = []
4377 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384378 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544379 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084380
4381 author = input_api.change.author_email
4382 if author and author not in _KNOWN_ROBOTS:
4383 results.extend(
4384 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4385
[email protected]9f919cc2013-07-31 03:04:044386 results.extend(
4387 input_api.canned_checks.CheckChangeHasNoTabs(
4388 input_api,
4389 output_api,
4390 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434391 results.extend(input_api.RunTests(
4392 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244393
Edward Lesmesce51df52020-08-04 22:10:174394 dirmd_bin = input_api.os_path.join(
4395 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4396 results.extend(input_api.RunTests(
4397 input_api.canned_checks.CheckDirMetadataFormat(
4398 input_api, output_api, dirmd_bin)))
4399 results.extend(
4400 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4401 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554402 results.extend(
4403 input_api.canned_checks.CheckNoNewMetadataInOwners(
4404 input_api, output_api))
Edward Lesmesce51df52020-08-04 22:10:174405
Vaclav Brozekcdc7defb2018-03-20 09:54:354406 for f in input_api.AffectedFiles():
4407 path, name = input_api.os_path.split(f.LocalPath())
4408 if name == 'PRESUBMIT.py':
4409 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004410 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4411 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074412 # The PRESUBMIT.py file (and the directory containing it) might
4413 # have been affected by being moved or removed, so only try to
4414 # run the tests if they still exist.
4415 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4416 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444417 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394418 return results
[email protected]1f7b4172010-01-28 01:17:344419
[email protected]b337cb5b2011-01-23 21:24:054420
Saagar Sanghavifceeaae2020-08-12 16:40:364421def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494422 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4423 if f.LocalPath().endswith(('.orig', '.rej'))]
4424 if problems:
4425 return [output_api.PresubmitError(
4426 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034427 else:
4428 return []
[email protected]b8079ae4a2012-12-05 19:56:494429
4430
Saagar Sanghavifceeaae2020-08-12 16:40:364431def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214432 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4433 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4434 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074435 include_re = input_api.re.compile(
4436 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4437 extension_re = input_api.re.compile(r'\.[a-z]+$')
4438 errors = []
4439 for f in input_api.AffectedFiles():
4440 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4441 continue
4442 found_line_number = None
4443 found_macro = None
4444 for line_num, line in f.ChangedContents():
4445 match = macro_re.search(line)
4446 if match:
4447 found_line_number = line_num
4448 found_macro = match.group(2)
4449 break
4450 if not found_line_number:
4451 continue
4452
4453 found_include = False
4454 for line in f.NewContents():
4455 if include_re.search(line):
4456 found_include = True
4457 break
4458 if found_include:
4459 continue
4460
4461 if not f.LocalPath().endswith('.h'):
4462 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4463 try:
4464 content = input_api.ReadFile(primary_header_path, 'r')
4465 if include_re.search(content):
4466 continue
4467 except IOError:
4468 pass
4469 errors.append('%s:%d %s macro is used without including build/'
4470 'build_config.h.'
4471 % (f.LocalPath(), found_line_number, found_macro))
4472 if errors:
4473 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4474 return []
4475
4476
[email protected]b00342e7f2013-03-26 16:21:544477def _DidYouMeanOSMacro(bad_macro):
4478 try:
4479 return {'A': 'OS_ANDROID',
4480 'B': 'OS_BSD',
4481 'C': 'OS_CHROMEOS',
4482 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444483 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544484 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444485 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544486 'N': 'OS_NACL',
4487 'O': 'OS_OPENBSD',
4488 'P': 'OS_POSIX',
4489 'S': 'OS_SOLARIS',
4490 'W': 'OS_WIN'}[bad_macro[3].upper()]
4491 except KeyError:
4492 return ''
4493
4494
4495def _CheckForInvalidOSMacrosInFile(input_api, f):
4496 """Check for sensible looking, totally invalid OS macros."""
4497 preprocessor_statement = input_api.re.compile(r'^\s*#')
4498 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4499 results = []
4500 for lnum, line in f.ChangedContents():
4501 if preprocessor_statement.search(line):
4502 for match in os_macro.finditer(line):
4503 if not match.group(1) in _VALID_OS_MACROS:
4504 good = _DidYouMeanOSMacro(match.group(1))
4505 did_you_mean = ' (did you mean %s?)' % good if good else ''
4506 results.append(' %s:%d %s%s' % (f.LocalPath(),
4507 lnum,
4508 match.group(1),
4509 did_you_mean))
4510 return results
4511
4512
Saagar Sanghavifceeaae2020-08-12 16:40:364513def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544514 """Check all affected files for invalid OS macros."""
4515 bad_macros = []
tzik3f295992018-12-04 20:32:234516 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474517 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544518 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4519
4520 if not bad_macros:
4521 return []
4522
4523 return [output_api.PresubmitError(
4524 'Possibly invalid OS macro[s] found. Please fix your code\n'
4525 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4526
lliabraa35bab3932014-10-01 12:16:444527
4528def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4529 """Check all affected files for invalid "if defined" macros."""
4530 ALWAYS_DEFINED_MACROS = (
4531 "TARGET_CPU_PPC",
4532 "TARGET_CPU_PPC64",
4533 "TARGET_CPU_68K",
4534 "TARGET_CPU_X86",
4535 "TARGET_CPU_ARM",
4536 "TARGET_CPU_MIPS",
4537 "TARGET_CPU_SPARC",
4538 "TARGET_CPU_ALPHA",
4539 "TARGET_IPHONE_SIMULATOR",
4540 "TARGET_OS_EMBEDDED",
4541 "TARGET_OS_IPHONE",
4542 "TARGET_OS_MAC",
4543 "TARGET_OS_UNIX",
4544 "TARGET_OS_WIN32",
4545 )
4546 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4547 results = []
4548 for lnum, line in f.ChangedContents():
4549 for match in ifdef_macro.finditer(line):
4550 if match.group(1) in ALWAYS_DEFINED_MACROS:
4551 always_defined = ' %s is always defined. ' % match.group(1)
4552 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4553 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4554 lnum,
4555 always_defined,
4556 did_you_mean))
4557 return results
4558
4559
Saagar Sanghavifceeaae2020-08-12 16:40:364560def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444561 """Check all affected files for invalid "if defined" macros."""
4562 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054563 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444564 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054565 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214566 continue
lliabraa35bab3932014-10-01 12:16:444567 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4568 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4569
4570 if not bad_macros:
4571 return []
4572
4573 return [output_api.PresubmitError(
4574 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4575 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4576 bad_macros)]
4577
4578
Saagar Sanghavifceeaae2020-08-12 16:40:364579def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044580 """Check for same IPC rules described in
4581 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4582 """
4583 base_pattern = r'IPC_ENUM_TRAITS\('
4584 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4585 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4586
4587 problems = []
4588 for f in input_api.AffectedSourceFiles(None):
4589 local_path = f.LocalPath()
4590 if not local_path.endswith('.h'):
4591 continue
4592 for line_number, line in f.ChangedContents():
4593 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4594 problems.append(
4595 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4596
4597 if problems:
4598 return [output_api.PresubmitPromptWarning(
4599 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4600 else:
4601 return []
4602
[email protected]b00342e7f2013-03-26 16:21:544603
Saagar Sanghavifceeaae2020-08-12 16:40:364604def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054605 """Check to make sure no files being submitted have long paths.
4606 This causes issues on Windows.
4607 """
4608 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194609 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054610 local_path = f.LocalPath()
4611 # Windows has a path limit of 260 characters. Limit path length to 200 so
4612 # that we have some extra for the prefix on dev machines and the bots.
4613 if len(local_path) > 200:
4614 problems.append(local_path)
4615
4616 if problems:
4617 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4618 else:
4619 return []
4620
4621
Saagar Sanghavifceeaae2020-08-12 16:40:364622def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144623 """Check that header files have proper guards against multiple inclusion.
4624 If a file should not have such guards (and it probably should) then it
4625 should include the string "no-include-guard-because-multiply-included".
4626 """
Daniel Bratell6a75baef62018-06-04 10:04:454627 def is_chromium_header_file(f):
4628 # We only check header files under the control of the Chromium
4629 # project. That is, those outside third_party apart from
4630 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324631 # We also exclude *_message_generator.h headers as they use
4632 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454633 file_with_path = input_api.os_path.normpath(f.LocalPath())
4634 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324635 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454636 (not file_with_path.startswith('third_party') or
4637 file_with_path.startswith(
4638 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144639
4640 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344641 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144642
4643 errors = []
4644
Daniel Bratell6a75baef62018-06-04 10:04:454645 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144646 guard_name = None
4647 guard_line_number = None
4648 seen_guard_end = False
4649
4650 file_with_path = input_api.os_path.normpath(f.LocalPath())
4651 base_file_name = input_api.os_path.splitext(
4652 input_api.os_path.basename(file_with_path))[0]
4653 upper_base_file_name = base_file_name.upper()
4654
4655 expected_guard = replace_special_with_underscore(
4656 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144657
4658 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574659 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4660 # are too many (1000+) files with slight deviations from the
4661 # coding style. The most important part is that the include guard
4662 # is there, and that it's unique, not the name so this check is
4663 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144664 #
4665 # As code becomes more uniform, this could be made stricter.
4666
4667 guard_name_pattern_list = [
4668 # Anything with the right suffix (maybe with an extra _).
4669 r'\w+_H__?',
4670
Daniel Bratell39b5b062018-05-16 18:09:574671 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144672 r'\w+_h',
4673
4674 # Anything including the uppercase name of the file.
4675 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4676 upper_base_file_name)) + r'\w*',
4677 ]
4678 guard_name_pattern = '|'.join(guard_name_pattern_list)
4679 guard_pattern = input_api.re.compile(
4680 r'#ifndef\s+(' + guard_name_pattern + ')')
4681
4682 for line_number, line in enumerate(f.NewContents()):
4683 if 'no-include-guard-because-multiply-included' in line:
4684 guard_name = 'DUMMY' # To not trigger check outside the loop.
4685 break
4686
4687 if guard_name is None:
4688 match = guard_pattern.match(line)
4689 if match:
4690 guard_name = match.group(1)
4691 guard_line_number = line_number
4692
Daniel Bratell39b5b062018-05-16 18:09:574693 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454694 # don't match the chromium style guide, but new files should
4695 # get it right.
4696 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574697 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144698 errors.append(output_api.PresubmitPromptWarning(
4699 'Header using the wrong include guard name %s' % guard_name,
4700 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574701 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144702 else:
4703 # The line after #ifndef should have a #define of the same name.
4704 if line_number == guard_line_number + 1:
4705 expected_line = '#define %s' % guard_name
4706 if line != expected_line:
4707 errors.append(output_api.PresubmitPromptWarning(
4708 'Missing "%s" for include guard' % expected_line,
4709 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4710 'Expected: %r\nGot: %r' % (expected_line, line)))
4711
4712 if not seen_guard_end and line == '#endif // %s' % guard_name:
4713 seen_guard_end = True
4714 elif seen_guard_end:
4715 if line.strip() != '':
4716 errors.append(output_api.PresubmitPromptWarning(
4717 'Include guard %s not covering the whole file' % (
4718 guard_name), [f.LocalPath()]))
4719 break # Nothing else to check and enough to warn once.
4720
4721 if guard_name is None:
4722 errors.append(output_api.PresubmitPromptWarning(
4723 'Missing include guard %s' % expected_guard,
4724 [f.LocalPath()],
4725 'Missing include guard in %s\n'
4726 'Recommended name: %s\n'
4727 'This check can be disabled by having the string\n'
4728 'no-include-guard-because-multiply-included in the header.' %
4729 (f.LocalPath(), expected_guard)))
4730
4731 return errors
4732
4733
Saagar Sanghavifceeaae2020-08-12 16:40:364734def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234735 """Check source code and known ascii text files for Windows style line
4736 endings.
4737 """
earthdok1b5e0ee2015-03-10 15:19:104738 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234739
4740 file_inclusion_pattern = (
4741 known_text_files,
4742 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4743 )
4744
mostynbb639aca52015-01-07 20:31:234745 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534746 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444747 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534748 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504749 include_file = False
4750 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234751 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504752 include_file = True
4753 if include_file:
4754 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234755
4756 if problems:
4757 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4758 'these files to contain Windows style line endings?\n' +
4759 '\n'.join(problems))]
4760
4761 return []
4762
4763
Saagar Sanghavifceeaae2020-08-12 16:40:364764def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134765 """Checks that all source files use SYSLOG properly."""
4766 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364767 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564768 for line_number, line in f.ChangedContents():
4769 if 'SYSLOG' in line:
4770 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4771
pastarmovj89f7ee12016-09-20 14:58:134772 if syslog_files:
4773 return [output_api.PresubmitPromptWarning(
4774 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4775 ' calls.\nFiles to check:\n', items=syslog_files)]
4776 return []
4777
4778
[email protected]1f7b4172010-01-28 01:17:344779def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364780 if input_api.version < [2, 0, 0]:
4781 return [output_api.PresubmitError("Your depot_tools is out of date. "
4782 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4783 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344784 results = []
scottmg39b29952014-12-08 18:31:284785 results.extend(
jam93a6ee792017-02-08 23:59:224786 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544787 return results
[email protected]ca8d1982009-02-19 16:33:124788
4789
[email protected]1bfb8322014-04-23 01:02:414790def GetTryServerMasterForBot(bot):
4791 """Returns the Try Server master for the given bot.
4792
[email protected]0bb112362014-07-26 04:38:324793 It tries to guess the master from the bot name, but may still fail
4794 and return None. There is no longer a default master.
4795 """
4796 # Potentially ambiguous bot names are listed explicitly.
4797 master_map = {
tandriie5587792016-07-14 00:34:504798 'chromium_presubmit': 'master.tryserver.chromium.linux',
4799 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414800 }
[email protected]0bb112362014-07-26 04:38:324801 master = master_map.get(bot)
4802 if not master:
wnwen4fbaab82016-05-25 12:54:364803 if 'android' in bot:
tandriie5587792016-07-14 00:34:504804 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364805 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504806 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324807 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504808 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324809 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504810 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324811 return master
[email protected]1bfb8322014-04-23 01:02:414812
4813
[email protected]ca8d1982009-02-19 16:33:124814def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364815 if input_api.version < [2, 0, 0]:
4816 return [output_api.PresubmitError("Your depot_tools is out of date. "
4817 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4818 "but your version is %d.%d.%d" % tuple(input_api.version))]
4819
[email protected]fe5f57c52009-06-05 14:25:544820 results = []
[email protected]fe5f57c52009-06-05 14:25:544821 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274822 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344823 input_api,
4824 output_api,
[email protected]2fdd1f362013-01-16 03:56:034825 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274826
jam93a6ee792017-02-08 23:59:224827 results.extend(
4828 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544829 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4830 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384831 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4832 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414833 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4834 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544835 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144836
4837
Saagar Sanghavifceeaae2020-08-12 16:40:364838def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264839 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024840 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4841 # footer is set to true.
4842 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264843 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024844 footer.lower()
4845 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264846 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024847
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144848 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264849 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144850 import sys
4851 from io import StringIO
4852
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144853 new_or_added_paths = set(f.LocalPath()
4854 for f in input_api.AffectedFiles()
4855 if (f.Action() == 'A' or f.Action() == 'M'))
4856 removed_paths = set(f.LocalPath()
4857 for f in input_api.AffectedFiles(include_deletes=True)
4858 if f.Action() == 'D')
4859
Andrew Grieve0e8790c2020-09-03 17:27:324860 affected_grds = [
4861 f for f in input_api.AffectedFiles()
4862 if f.LocalPath().endswith(('.grd', '.grdp'))
4863 ]
4864 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164865 if not affected_grds:
4866 return []
4867
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144868 affected_png_paths = [f.AbsoluteLocalPath()
4869 for f in input_api.AffectedFiles()
4870 if (f.LocalPath().endswith('.png'))]
4871
4872 # Check for screenshots. Developers can upload screenshots using
4873 # tools/translation/upload_screenshots.py which finds and uploads
4874 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4875 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4876 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4877 #
4878 # The logic here is as follows:
4879 #
4880 # - If the CL has a .png file under the screenshots directory for a grd
4881 # file, warn the developer. Actual images should never be checked into the
4882 # Chrome repo.
4883 #
4884 # - If the CL contains modified or new messages in grd files and doesn't
4885 # contain the corresponding .sha1 files, warn the developer to add images
4886 # and upload them via tools/translation/upload_screenshots.py.
4887 #
4888 # - If the CL contains modified or new messages in grd files and the
4889 # corresponding .sha1 files, everything looks good.
4890 #
4891 # - If the CL contains removed messages in grd files but the corresponding
4892 # .sha1 files aren't removed, warn the developer to remove them.
4893 unnecessary_screenshots = []
4894 missing_sha1 = []
4895 unnecessary_sha1_files = []
4896
Rainhard Findlingfc31844c52020-05-15 09:58:264897 # This checks verifies that the ICU syntax of messages this CL touched is
4898 # valid, and reports any found syntax errors.
4899 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4900 # without developers being aware of them. Later on, such ICU syntax errors
4901 # break message extraction for translation, hence would block Chromium
4902 # translations until they are fixed.
4903 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144904
4905 def _CheckScreenshotAdded(screenshots_dir, message_id):
4906 sha1_path = input_api.os_path.join(
4907 screenshots_dir, message_id + '.png.sha1')
4908 if sha1_path not in new_or_added_paths:
4909 missing_sha1.append(sha1_path)
4910
4911
4912 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4913 sha1_path = input_api.os_path.join(
4914 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034915 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144916 unnecessary_sha1_files.append(sha1_path)
4917
Rainhard Findlingfc31844c52020-05-15 09:58:264918
4919 def _ValidateIcuSyntax(text, level, signatures):
4920 """Validates ICU syntax of a text string.
4921
4922 Check if text looks similar to ICU and checks for ICU syntax correctness
4923 in this case. Reports various issues with ICU syntax and values of
4924 variants. Supports checking of nested messages. Accumulate information of
4925 each ICU messages found in the text for further checking.
4926
4927 Args:
4928 text: a string to check.
4929 level: a number of current nesting level.
4930 signatures: an accumulator, a list of tuple of (level, variable,
4931 kind, variants).
4932
4933 Returns:
4934 None if a string is not ICU or no issue detected.
4935 A tuple of (message, start index, end index) if an issue detected.
4936 """
4937 valid_types = {
4938 'plural': (frozenset(
4939 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4940 frozenset(['=1', 'other'])),
4941 'selectordinal': (frozenset(
4942 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4943 frozenset(['one', 'other'])),
4944 'select': (frozenset(), frozenset(['other'])),
4945 }
4946
4947 # Check if the message looks like an attempt to use ICU
4948 # plural. If yes - check if its syntax strictly matches ICU format.
4949 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4950 if not like:
4951 signatures.append((level, None, None, None))
4952 return
4953
4954 # Check for valid prefix and suffix
4955 m = re.match(
4956 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4957 r'(plural|selectordinal|select),\s*'
4958 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4959 if not m:
4960 return (('This message looks like an ICU plural, '
4961 'but does not follow ICU syntax.'), like.start(), like.end())
4962 starting, variable, kind, variant_pairs = m.groups()
4963 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4964 if depth:
4965 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4966 len(text))
4967 first = text[0]
4968 ending = text[last_pos:]
4969 if not starting:
4970 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4971 last_pos)
4972 if not ending or '}' not in ending:
4973 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4974 last_pos)
4975 elif first != '{':
4976 return (
4977 ('Invalid ICU format. Extra characters at the start of a complex '
4978 'message (go/icu-message-migration): "%s"') %
4979 starting, 0, len(starting))
4980 elif ending != '}':
4981 return (('Invalid ICU format. Extra characters at the end of a complex '
4982 'message (go/icu-message-migration): "%s"')
4983 % ending, last_pos - 1, len(text) - 1)
4984 if kind not in valid_types:
4985 return (('Unknown ICU message type %s. '
4986 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4987 known, required = valid_types[kind]
4988 defined_variants = set()
4989 for variant, variant_range, value, value_range in variants:
4990 start, end = variant_range
4991 if variant in defined_variants:
4992 return ('Variant "%s" is defined more than once' % variant,
4993 start, end)
4994 elif known and variant not in known:
4995 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4996 start, end)
4997 defined_variants.add(variant)
4998 # Check for nested structure
4999 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5000 if res:
5001 return (res[0], res[1] + value_range[0] + 1,
5002 res[2] + value_range[0] + 1)
5003 missing = required - defined_variants
5004 if missing:
5005 return ('Required variants missing: %s' % ', '.join(missing), 0,
5006 len(text))
5007 signatures.append((level, variable, kind, defined_variants))
5008
5009
5010 def _ParseIcuVariants(text, offset=0):
5011 """Parse variants part of ICU complex message.
5012
5013 Builds a tuple of variant names and values, as well as
5014 their offsets in the input string.
5015
5016 Args:
5017 text: a string to parse
5018 offset: additional offset to add to positions in the text to get correct
5019 position in the complete ICU string.
5020
5021 Returns:
5022 List of tuples, each tuple consist of four fields: variant name,
5023 variant name span (tuple of two integers), variant value, value
5024 span (tuple of two integers).
5025 """
5026 depth, start, end = 0, -1, -1
5027 variants = []
5028 key = None
5029 for idx, char in enumerate(text):
5030 if char == '{':
5031 if not depth:
5032 start = idx
5033 chunk = text[end + 1:start]
5034 key = chunk.strip()
5035 pos = offset + end + 1 + chunk.find(key)
5036 span = (pos, pos + len(key))
5037 depth += 1
5038 elif char == '}':
5039 if not depth:
5040 return variants, depth, offset + idx
5041 depth -= 1
5042 if not depth:
5043 end = idx
5044 variants.append((key, span, text[start:end + 1], (offset + start,
5045 offset + end + 1)))
5046 return variants, depth, offset + end + 1
5047
meacer8c0d3832019-12-26 21:46:165048 try:
5049 old_sys_path = sys.path
5050 sys.path = sys.path + [input_api.os_path.join(
5051 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5052 from helper import grd_helper
5053 finally:
5054 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145055
5056 for f in affected_grds:
5057 file_path = f.LocalPath()
5058 old_id_to_msg_map = {}
5059 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385060 # Note that this code doesn't check if the file has been deleted. This is
5061 # OK because it only uses the old and new file contents and doesn't load
5062 # the file via its path.
5063 # It's also possible that a file's content refers to a renamed or deleted
5064 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5065 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5066 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145067 if file_path.endswith('.grdp'):
5068 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585069 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395070 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145071 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585072 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395073 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145074 else:
meacerff8a9b62019-12-10 19:43:585075 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145076 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585077 old_id_to_msg_map = grd_helper.GetGrdMessages(
5078 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145079 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585080 new_id_to_msg_map = grd_helper.GetGrdMessages(
5081 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145082
Rainhard Findlingd8d04372020-08-13 13:30:095083 grd_name, ext = input_api.os_path.splitext(
5084 input_api.os_path.basename(file_path))
5085 screenshots_dir = input_api.os_path.join(
5086 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5087
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145088 # Compute added, removed and modified message IDs.
5089 old_ids = set(old_id_to_msg_map)
5090 new_ids = set(new_id_to_msg_map)
5091 added_ids = new_ids - old_ids
5092 removed_ids = old_ids - new_ids
5093 modified_ids = set([])
5094 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355095 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095096 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5097 # The message content itself changed. Require an updated screenshot.
5098 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355099 elif old_id_to_msg_map[key].attrs['meaning'] != \
5100 new_id_to_msg_map[key].attrs['meaning']:
5101 # The message meaning changed. Ensure there is a screenshot for it.
5102 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5103 if sha1_path not in new_or_added_paths and not \
5104 input_api.os_path.exists(sha1_path):
5105 # There is neither a previous screenshot nor is a new one added now.
5106 # Require a screenshot.
5107 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145108
Rainhard Findlingfc31844c52020-05-15 09:58:265109 if run_screenshot_check:
5110 # Check the screenshot directory for .png files. Warn if there is any.
5111 for png_path in affected_png_paths:
5112 if png_path.startswith(screenshots_dir):
5113 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145114
Rainhard Findlingfc31844c52020-05-15 09:58:265115 for added_id in added_ids:
5116 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145117
Rainhard Findlingfc31844c52020-05-15 09:58:265118 for modified_id in modified_ids:
5119 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145120
Rainhard Findlingfc31844c52020-05-15 09:58:265121 for removed_id in removed_ids:
5122 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5123
5124 # Check new and changed strings for ICU syntax errors.
5125 for key in added_ids.union(modified_ids):
5126 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5127 err = _ValidateIcuSyntax(msg, 0, [])
5128 if err is not None:
5129 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145130
5131 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265132 if run_screenshot_check:
5133 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005134 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265135 'Do not include actual screenshots in the changelist. Run '
5136 'tools/translate/upload_screenshots.py to upload them instead:',
5137 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145138
Rainhard Findlingfc31844c52020-05-15 09:58:265139 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005140 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265141 'You are adding or modifying UI strings.\n'
5142 'To ensure the best translations, take screenshots of the relevant UI '
5143 '(https://g.co/chrome/translation) and add these files to your '
5144 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145145
Rainhard Findlingfc31844c52020-05-15 09:58:265146 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005147 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265148 'You removed strings associated with these files. Remove:',
5149 sorted(unnecessary_sha1_files)))
5150 else:
5151 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5152 'screenshots check.'))
5153
5154 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075155 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265156 'ICU syntax errors were found in the following strings (problems or '
5157 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145158
5159 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125160
5161
Saagar Sanghavifceeaae2020-08-12 16:40:365162def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125163 repo_root=None,
5164 translation_expectations_path=None,
5165 grd_files=None):
5166 import sys
5167 affected_grds = [f for f in input_api.AffectedFiles()
5168 if (f.LocalPath().endswith('.grd') or
5169 f.LocalPath().endswith('.grdp'))]
5170 if not affected_grds:
5171 return []
5172
5173 try:
5174 old_sys_path = sys.path
5175 sys.path = sys.path + [
5176 input_api.os_path.join(
5177 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5178 from helper import git_helper
5179 from helper import translation_helper
5180 finally:
5181 sys.path = old_sys_path
5182
5183 # Check that translation expectations can be parsed and we can get a list of
5184 # translatable grd files. |repo_root| and |translation_expectations_path| are
5185 # only passed by tests.
5186 if not repo_root:
5187 repo_root = input_api.PresubmitLocalPath()
5188 if not translation_expectations_path:
5189 translation_expectations_path = input_api.os_path.join(
5190 repo_root, 'tools', 'gritsettings',
5191 'translation_expectations.pyl')
5192 if not grd_files:
5193 grd_files = git_helper.list_grds_in_repository(repo_root)
5194
dpapad8e21b472020-10-23 17:15:035195 # Ignore bogus grd files used only for testing
5196 # ui/webui/resoucres/tools/generate_grd.py.
5197 ignore_path = input_api.os_path.join(
5198 'ui', 'webui', 'resources', 'tools', 'tests')
5199 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5200
Mustafa Emre Acer51f2f742020-03-09 19:41:125201 try:
5202 translation_helper.get_translatable_grds(repo_root, grd_files,
5203 translation_expectations_path)
5204 except Exception as e:
5205 return [output_api.PresubmitNotifyResult(
5206 'Failed to get a list of translatable grd files. This happens when:\n'
5207 ' - One of the modified grd or grdp files cannot be parsed or\n'
5208 ' - %s is not updated.\n'
5209 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5210 return []
Ken Rockotc31f4832020-05-29 18:58:515211
5212
Saagar Sanghavifceeaae2020-08-12 16:40:365213def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515214 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095215 changed_mojoms = input_api.AffectedFiles(
5216 include_deletes=True,
5217 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515218 delta = []
5219 for mojom in changed_mojoms:
5220 old_contents = ''.join(mojom.OldContents()) or None
5221 new_contents = ''.join(mojom.NewContents()) or None
5222 delta.append({
5223 'filename': mojom.LocalPath(),
5224 'old': '\n'.join(mojom.OldContents()) or None,
5225 'new': '\n'.join(mojom.NewContents()) or None,
5226 })
5227
5228 process = input_api.subprocess.Popen(
5229 [input_api.python_executable,
5230 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5231 'public', 'tools', 'mojom',
5232 'check_stable_mojom_compatibility.py'),
5233 '--src-root', input_api.PresubmitLocalPath()],
5234 stdin=input_api.subprocess.PIPE,
5235 stdout=input_api.subprocess.PIPE,
5236 stderr=input_api.subprocess.PIPE,
5237 universal_newlines=True)
5238 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5239 if process.returncode:
5240 return [output_api.PresubmitError(
5241 'One or more [Stable] mojom definitions appears to have been changed '
5242 'in a way that is not backward-compatible.',
5243 long_text=error)]
5244 return []
Dominic Battre645d42342020-12-04 16:14:105245
5246def CheckDeprecationOfPreferences(input_api, output_api):
5247 """Removing a preference should come with a deprecation."""
5248
5249 def FilterFile(affected_file):
5250 """Accept only .cc files and the like."""
5251 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5252 files_to_skip = (_EXCLUDED_PATHS +
5253 _TEST_CODE_EXCLUDED_PATHS +
5254 input_api.DEFAULT_FILES_TO_SKIP)
5255 return input_api.FilterSourceFile(
5256 affected_file,
5257 files_to_check=file_inclusion_pattern,
5258 files_to_skip=files_to_skip)
5259
5260 def ModifiedLines(affected_file):
5261 """Returns a list of tuples (line number, line text) of added and removed
5262 lines.
5263
5264 Deleted lines share the same line number as the previous line.
5265
5266 This relies on the scm diff output describing each changed code section
5267 with a line of the form
5268
5269 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5270 """
5271 line_num = 0
5272 modified_lines = []
5273 for line in affected_file.GenerateScmDiff().splitlines():
5274 # Extract <new line num> of the patch fragment (see format above).
5275 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5276 if m:
5277 line_num = int(m.groups(1)[0])
5278 continue
5279 if ((line.startswith('+') and not line.startswith('++')) or
5280 (line.startswith('-') and not line.startswith('--'))):
5281 modified_lines.append((line_num, line))
5282
5283 if not line.startswith('-'):
5284 line_num += 1
5285 return modified_lines
5286
5287 def FindLineWith(lines, needle):
5288 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5289
5290 If 0 or >1 lines contain `needle`, -1 is returned.
5291 """
5292 matching_line_numbers = [
5293 # + 1 for 1-based counting of line numbers.
5294 i + 1 for i, line
5295 in enumerate(lines)
5296 if needle in line]
5297 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5298
5299 def ModifiedPrefMigration(affected_file):
5300 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5301 # Determine first and last lines of MigrateObsolete.*Pref functions.
5302 new_contents = affected_file.NewContents();
5303 range_1 = (
5304 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5305 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5306 range_2 = (
5307 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5308 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5309 if (-1 in range_1 + range_2):
5310 raise Exception(
5311 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5312
5313 # Check whether any of the modified lines are part of the
5314 # MigrateObsolete.*Pref functions.
5315 for line_nr, line in ModifiedLines(affected_file):
5316 if (range_1[0] <= line_nr <= range_1[1] or
5317 range_2[0] <= line_nr <= range_2[1]):
5318 return True
5319 return False
5320
5321 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5322 browser_prefs_file_pattern = input_api.re.compile(
5323 r'chrome/browser/prefs/browser_prefs.cc')
5324
5325 changes = input_api.AffectedFiles(include_deletes=True,
5326 file_filter=FilterFile)
5327 potential_problems = []
5328 for f in changes:
5329 for line in f.GenerateScmDiff().splitlines():
5330 # Check deleted lines for pref registrations.
5331 if (line.startswith('-') and not line.startswith('--') and
5332 register_pref_pattern.search(line)):
5333 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5334
5335 if browser_prefs_file_pattern.search(f.LocalPath()):
5336 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5337 # assume that they knew that they have to deprecate preferences and don't
5338 # warn.
5339 try:
5340 if ModifiedPrefMigration(f):
5341 return []
5342 except Exception as e:
5343 return [output_api.PresubmitError(str(e))]
5344
5345 if potential_problems:
5346 return [output_api.PresubmitPromptWarning(
5347 'Discovered possible removal of preference registrations.\n\n'
5348 'Please make sure to properly deprecate preferences by clearing their\n'
5349 'value for a couple of milestones before finally removing the code.\n'
5350 'Otherwise data may stay in the preferences files forever. See\n'
5351 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5352 'This may be a false positive warning (e.g. if you move preference\n'
5353 'registrations to a different place).\n',
5354 potential_problems
5355 )]
5356 return []