blob: 023d07c5592feec8a7df7c70de535c8aeb88a5e1 [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)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0559 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0460 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4761 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0462 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0863 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0464 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4165 # EarlGrey app side code for tests.
66 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1767 # Views Examples code
68 r'ui[\\/]views[\\/]examples[\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4469)
[email protected]ca8d1982009-02-19 16:33:1270
Daniel Bratell609102be2019-03-27 20:53:2171_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1572
[email protected]eea609a2011-11-18 13:10:1273_TEST_ONLY_WARNING = (
74 'You might be calling functions intended only for testing from\n'
75 'production code. It is OK to ignore this warning if you know what\n'
76 'you are doing, as the heuristics used to detect the situation are\n'
Mohamed Heikal5cf63162019-10-25 19:59:0777 'not perfect. The commit queue will not block on this warning,\n'
78 'however the android-binary-size trybot will block if the method\n'
79 'exists in the release apk.')
[email protected]eea609a2011-11-18 13:10:1280
81
[email protected]cf9b78f2012-11-14 11:40:2882_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4083 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2184 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
85 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2886
Michael Thiessen44457642020-02-06 00:24:1587# Format: Sequence of tuples containing:
88# * Full import path.
89# * Sequence of strings to show when the pattern matches.
90# * Sequence of path or filename exceptions to this rule
91_BANNED_JAVA_IMPORTS = (
92 (
Colin Blundell170d78c82020-03-12 13:56:0493 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:1594 (
95 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
96 ),
97 (
98 'net/android/javatests/src/org/chromium/net/'
99 'AndroidProxySelectorTest.java',
100 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04101 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15102 ),
103 ),
Michael Thiessened631912020-08-07 19:01:31104 (
105 'android.support.test.rule.UiThreadTestRule;',
106 (
107 'Do not use UiThreadTestRule, just use '
108 '@org.chromium.base.test.UiThreadTest on test methods that should run on '
109 'the UI thread. See https://crbug.com/1111893.',
110 ),
111 (),
112 ),
113 (
114 'android.support.test.annotation.UiThreadTest;',
115 (
116 'Do not use android.support.test.annotation.UiThreadTest, use '
117 'org.chromium.base.test.UiThreadTest instead. See '
118 'https://crbug.com/1111893.',
119 ),
120 ()
121 )
Michael Thiessen44457642020-02-06 00:24:15122)
wnwenbdc444e2016-05-25 13:44:15123
Daniel Bratell609102be2019-03-27 20:53:21124# Format: Sequence of tuples containing:
125# * String pattern or, if starting with a slash, a regular expression.
126# * Sequence of strings to show when the pattern matches.
127# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41128_BANNED_JAVA_FUNCTIONS = (
129 (
130 'StrictMode.allowThreadDiskReads()',
131 (
132 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
133 'directly.',
134 ),
135 False,
136 ),
137 (
138 'StrictMode.allowThreadDiskWrites()',
139 (
140 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
141 'directly.',
142 ),
143 False,
144 ),
Michael Thiessen0f2547e2020-07-27 21:55:36145 (
146 '.waitForIdleSync()',
147 (
148 'Do not use waitForIdleSync as it masks underlying issues. There is '
149 'almost always something else you should wait on instead.',
150 ),
151 False,
152 ),
Eric Stevensona9a980972017-09-23 00:04:41153)
154
Daniel Bratell609102be2019-03-27 20:53:21155# Format: Sequence of tuples containing:
156# * String pattern or, if starting with a slash, a regular expression.
157# * Sequence of strings to show when the pattern matches.
158# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59159_BANNED_OBJC_FUNCTIONS = (
160 (
161 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20162 (
163 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59164 'prohibited. Please use CrTrackingArea instead.',
165 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
166 ),
167 False,
168 ),
169 (
[email protected]eaae1972014-04-16 04:17:26170 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20171 (
172 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59173 'instead.',
174 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
175 ),
176 False,
177 ),
178 (
179 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20180 (
181 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59182 'Please use |convertPoint:(point) fromView:nil| instead.',
183 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
184 ),
185 True,
186 ),
187 (
188 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20189 (
190 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59191 'Please use |convertPoint:(point) toView:nil| instead.',
192 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
193 ),
194 True,
195 ),
196 (
197 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20198 (
199 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59200 'Please use |convertRect:(point) fromView:nil| instead.',
201 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
202 ),
203 True,
204 ),
205 (
206 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20207 (
208 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59209 'Please use |convertRect:(point) toView:nil| instead.',
210 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
211 ),
212 True,
213 ),
214 (
215 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20216 (
217 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59218 'Please use |convertSize:(point) fromView:nil| instead.',
219 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
220 ),
221 True,
222 ),
223 (
224 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20225 (
226 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59227 'Please use |convertSize:(point) toView:nil| instead.',
228 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
229 ),
230 True,
231 ),
jif65398702016-10-27 10:19:48232 (
233 r"/\s+UTF8String\s*]",
234 (
235 'The use of -[NSString UTF8String] is dangerous as it can return null',
236 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
237 'Please use |SysNSStringToUTF8| instead.',
238 ),
239 True,
240 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34241 (
242 r'__unsafe_unretained',
243 (
244 'The use of __unsafe_unretained is almost certainly wrong, unless',
245 'when interacting with NSFastEnumeration or NSInvocation.',
246 'Please use __weak in files build with ARC, nothing otherwise.',
247 ),
248 False,
249 ),
Avi Drissman7382afa02019-04-29 23:27:13250 (
251 'freeWhenDone:NO',
252 (
253 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
254 'Foundation types is prohibited.',
255 ),
256 True,
257 ),
[email protected]127f18ec2012-06-16 05:05:59258)
259
Daniel Bratell609102be2019-03-27 20:53:21260# Format: Sequence of tuples containing:
261# * String pattern or, if starting with a slash, a regular expression.
262# * Sequence of strings to show when the pattern matches.
263# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54264_BANNED_IOS_OBJC_FUNCTIONS = (
265 (
266 r'/\bTEST[(]',
267 (
268 'TEST() macro should not be used in Objective-C++ code as it does not ',
269 'drain the autorelease pool at the end of the test. Use TEST_F() ',
270 'macro instead with a fixture inheriting from PlatformTest (or a ',
271 'typedef).'
272 ),
273 True,
274 ),
275 (
276 r'/\btesting::Test\b',
277 (
278 'testing::Test should not be used in Objective-C++ code as it does ',
279 'not drain the autorelease pool at the end of the test. Use ',
280 'PlatformTest instead.'
281 ),
282 True,
283 ),
284)
285
Peter K. Lee6c03ccff2019-07-15 14:40:05286# Format: Sequence of tuples containing:
287# * String pattern or, if starting with a slash, a regular expression.
288# * Sequence of strings to show when the pattern matches.
289# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
290_BANNED_IOS_EGTEST_FUNCTIONS = (
291 (
292 r'/\bEXPECT_OCMOCK_VERIFY\b',
293 (
294 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
295 'it is meant for GTests. Use [mock verify] instead.'
296 ),
297 True,
298 ),
299)
300
danakj7a2b7082019-05-21 21:13:51301# Directories that contain deprecated Bind() or Callback types.
302# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36303# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51304# echo "-- $i"
danakj710b4c02019-11-28 16:08:45305# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51306# done
307#
308# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
309# when they have been converted to modern callback types (OnceCallback,
310# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
311# checks for them and prevent regressions.
312_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51313 '^base/callback.h', # Intentional.
Alexander Cooper6b447b22020-07-22 00:47:18314 '^chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc',
315 '^chrome/browser/apps/guest_view/',
316 '^chrome/browser/apps/platform_apps/shortcut_manager.cc',
317 '^chrome/browser/browsing_data/',
318 '^chrome/browser/captive_portal/captive_portal_browsertest.cc',
319 '^chrome/browser/chromeos/',
320 '^chrome/browser/component_updater/',
321 '^chrome/browser/custom_handlers/protocol_handler_registry.cc',
Peter Wen6367b882020-08-05 16:55:50322 '^chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc', # pylint: disable=line-too-long
Alexander Cooper6b447b22020-07-22 00:47:18323 '^chrome/browser/devtools/',
324 '^chrome/browser/download/',
325 '^chrome/browser/extensions/',
326 '^chrome/browser/external_protocol/external_protocol_handler.cc',
327 '^chrome/browser/history/',
328 '^chrome/browser/installable/installable_manager_browsertest.cc',
329 '^chrome/browser/lifetime/',
330 '^chrome/browser/media_galleries/',
331 '^chrome/browser/media/',
332 '^chrome/browser/metrics/',
333 '^chrome/browser/nacl_host/test/gdb_debug_stub_browsertest.cc',
Peter Wen6367b882020-08-05 16:55:50334 '^chrome/browser/nearby_sharing/client/nearby_share_api_call_flow_impl_unittest.cc', # pylint: disable=line-too-long
Alexander Cooper6b447b22020-07-22 00:47:18335 '^chrome/browser/net/',
336 '^chrome/browser/notifications/',
337 '^chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc',
338 '^chrome/browser/offline_pages/',
Peter Wen6367b882020-08-05 16:55:50339 '^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:18340 '^chrome/browser/password_manager/',
341 '^chrome/browser/payments/payment_manifest_parser_browsertest.cc',
342 '^chrome/browser/pdf/pdf_extension_test.cc',
343 '^chrome/browser/plugins/',
344 '^chrome/browser/policy/',
345 '^chrome/browser/portal/portal_browsertest.cc',
346 '^chrome/browser/prefs/profile_pref_store_manager_unittest.cc',
347 '^chrome/browser/prerender/',
348 '^chrome/browser/previews/',
349 '^chrome/browser/printing/printing_message_filter.cc',
350 '^chrome/browser/profiles/',
351 '^chrome/browser/profiling_host/profiling_process_host.cc',
352 '^chrome/browser/push_messaging/',
353 '^chrome/browser/recovery/recovery_install_global_error.cc',
354 '^chrome/browser/renderer_context_menu/',
355 '^chrome/browser/renderer_host/pepper/',
356 '^chrome/browser/resource_coordinator/',
357 '^chrome/browser/resources/chromeos/accessibility/',
358 '^chrome/browser/rlz/chrome_rlz_tracker_delegate.cc',
359 '^chrome/browser/safe_browsing/',
360 '^chrome/browser/search_engines/',
361 '^chrome/browser/service_process/',
362 '^chrome/browser/signin/',
363 '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
364 '^chrome/browser/ssl/',
365 '^chrome/browser/subresource_filter/',
366 '^chrome/browser/supervised_user/',
367 '^chrome/browser/sync_file_system/',
368 '^chrome/browser/sync/',
369 '^chrome/browser/themes/theme_service.cc',
370 '^chrome/browser/thumbnail/cc/',
371 '^chrome/browser/tracing/chrome_tracing_delegate_browsertest.cc',
372 '^chrome/browser/translate/',
373 '^chrome/browser/ui/',
Alexander Cooper6b447b22020-07-22 00:47:18374 '^chrome/browser/web_applications/',
375 '^chrome/browser/win/',
danakj7a2b7082019-05-21 21:13:51376 '^chrome/services/',
377 '^chrome/test/',
378 '^chrome/tools/',
danakj7a2b7082019-05-21 21:13:51379 '^chromecast/media/',
danakj7a2b7082019-05-21 21:13:51380 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51381 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51382 '^chromeos/services/',
danakj7a2b7082019-05-21 21:13:51383 '^components/arc/',
danakj7a2b7082019-05-21 21:13:51384 '^components/autofill/',
385 '^components/autofill_assistant/',
danakj7a2b7082019-05-21 21:13:51386 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51387 '^components/component_updater/',
388 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51389 '^components/drive/',
danakj7a2b7082019-05-21 21:13:51390 '^components/nacl/',
391 '^components/navigation_interception/',
danakj7a2b7082019-05-21 21:13:51392 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51393 '^components/password_manager/',
danakj7a2b7082019-05-21 21:13:51394 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51395 '^components/search_engines/',
danakj7a2b7082019-05-21 21:13:51396 '^components/security_interstitials/',
danakj7a2b7082019-05-21 21:13:51397 '^components/signin/',
danakj7a2b7082019-05-21 21:13:51398 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51399 '^components/ukm/',
danakj7a2b7082019-05-21 21:13:51400 '^components/webcrypto/',
Alan Cutter04a00642020-03-02 01:45:20401 '^extensions/browser/',
402 '^extensions/renderer/',
Alexander Cooper922f2112020-07-22 16:27:43403 '^google_apis/drive/',
danakj7a2b7082019-05-21 21:13:51404 '^ios/chrome/',
405 '^ios/components/',
406 '^ios/net/',
407 '^ios/web/',
408 '^ios/web_view/',
409 '^ipc/',
danakjc8576092019-11-26 19:01:36410 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51411 '^media/cast/',
412 '^media/cdm/',
danakj7a2b7082019-05-21 21:13:51413 '^media/filters/',
danakj7a2b7082019-05-21 21:13:51414 '^media/gpu/',
415 '^media/mojo/',
Steve Kobes334b6ed2020-07-09 07:26:31416 '^net/http/',
417 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51418 '^ppapi/proxy/',
danakj7a2b7082019-05-21 21:13:51419 '^services/',
danakj7a2b7082019-05-21 21:13:51420 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51421 '^tools/clang/base_bind_rewriters/', # Intentional.
422 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51423))
[email protected]127f18ec2012-06-16 05:05:59424
Daniel Bratell609102be2019-03-27 20:53:21425# Format: Sequence of tuples containing:
426# * String pattern or, if starting with a slash, a regular expression.
427# * Sequence of strings to show when the pattern matches.
428# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
429# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59430_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20431 (
Dave Tapuska98199b612019-07-10 13:30:44432 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53433 (
434 'New code should not use NULL. Use nullptr instead.',
435 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20436 False,
thomasandersone7caaa9b2017-03-29 19:22:53437 (),
438 ),
Peter Kasting94a56c42019-10-25 21:54:04439 (
440 r'/\busing namespace ',
441 (
442 'Using directives ("using namespace x") are banned by the Google Style',
443 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
444 'Explicitly qualify symbols or use using declarations ("using x::foo").',
445 ),
446 True,
447 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
448 ),
Antonio Gomes07300d02019-03-13 20:59:57449 # Make sure that gtest's FRIEND_TEST() macro is not used; the
450 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
451 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53452 (
[email protected]23e6cbc2012-06-16 18:51:20453 'FRIEND_TEST(',
454 (
[email protected]e3c945502012-06-26 20:01:49455 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20456 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
457 ),
458 False,
[email protected]7345da02012-11-27 14:31:49459 (),
[email protected]23e6cbc2012-06-16 18:51:20460 ),
461 (
Dave Tapuska98199b612019-07-10 13:30:44462 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53463 (
464 'Chrome clients wishing to select events on X windows should use',
465 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
466 'you are selecting events from the GPU process, or if you are using',
467 'an XDisplay other than gfx::GetXDisplay().',
468 ),
469 True,
470 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40471 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04472 r"^ui[\\/]gl[\\/].*\.cc$",
473 r"^media[\\/]gpu[\\/].*\.cc$",
474 r"^gpu[\\/].*\.cc$",
Maksim Sisova4d1cfbe2020-06-16 07:58:37475 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]xwmstartupcheck\.cc$",
476 ),
thomasanderson4b569052016-09-14 20:15:53477 ),
478 (
Tom Anderson74d064b2020-07-08 03:47:32479 r'/\WX?(((Width|Height)(MM)?OfScreen)|(Display(Width|Height)))\(',
480 (
481 'Use the corresponding fields in x11::Screen instead.',
482 ),
483 True,
484 (),
485 ),
486 (
Dave Tapuska98199b612019-07-10 13:30:44487 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20488 (
thomasanderson11aa41d2017-06-08 22:22:38489 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20490 ),
491 True,
492 (
Egor Paskoce145c42018-09-28 19:31:04493 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
494 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
495 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20496 ),
497 ),
498 (
tomhudsone2c14d552016-05-26 17:07:46499 'setMatrixClip',
500 (
501 'Overriding setMatrixClip() is prohibited; ',
502 'the base function is deprecated. ',
503 ),
504 True,
505 (),
506 ),
507 (
[email protected]52657f62013-05-20 05:30:31508 'SkRefPtr',
509 (
510 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22511 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31512 ),
513 True,
514 (),
515 ),
516 (
517 'SkAutoRef',
518 (
519 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22520 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31521 ),
522 True,
523 (),
524 ),
525 (
526 'SkAutoTUnref',
527 (
528 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22529 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31530 ),
531 True,
532 (),
533 ),
534 (
535 'SkAutoUnref',
536 (
537 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
538 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22539 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31540 ),
541 True,
542 (),
543 ),
[email protected]d89eec82013-12-03 14:10:59544 (
545 r'/HANDLE_EINTR\(.*close',
546 (
547 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
548 'descriptor will be closed, and it is incorrect to retry the close.',
549 'Either call close directly and ignore its return value, or wrap close',
550 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
551 ),
552 True,
553 (),
554 ),
555 (
556 r'/IGNORE_EINTR\((?!.*close)',
557 (
558 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
559 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
560 ),
561 True,
562 (
563 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04564 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
565 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59566 ),
567 ),
[email protected]ec5b3f02014-04-04 18:43:43568 (
569 r'/v8::Extension\(',
570 (
571 'Do not introduce new v8::Extensions into the code base, use',
572 'gin::Wrappable instead. See http://crbug.com/334679',
573 ),
574 True,
[email protected]f55c90ee62014-04-12 00:50:03575 (
Egor Paskoce145c42018-09-28 19:31:04576 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03577 ),
[email protected]ec5b3f02014-04-04 18:43:43578 ),
skyostilf9469f72015-04-20 10:38:52579 (
jame2d1a952016-04-02 00:27:10580 '#pragma comment(lib,',
581 (
582 'Specify libraries to link with in build files and not in the source.',
583 ),
584 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41585 (
tzik3f295992018-12-04 20:32:23586 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04587 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41588 ),
jame2d1a952016-04-02 00:27:10589 ),
fdorayc4ac18d2017-05-01 21:39:59590 (
Gabriel Charette7cc6c432018-04-25 20:52:02591 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59592 (
593 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
594 ),
595 False,
596 (),
597 ),
598 (
Gabriel Charette7cc6c432018-04-25 20:52:02599 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59600 (
601 'Consider using THREAD_CHECKER macros instead of the class directly.',
602 ),
603 False,
604 (),
605 ),
dbeamb6f4fde2017-06-15 04:03:06606 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06607 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
608 (
609 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
610 'deprecated (http://crbug.com/634507). Please avoid converting away',
611 'from the Time types in Chromium code, especially if any math is',
612 'being done on time values. For interfacing with platform/library',
613 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
614 'type converter methods instead. For faking TimeXXX values (for unit',
615 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
616 'other use cases, please contact base/time/OWNERS.',
617 ),
618 False,
619 (),
620 ),
621 (
dbeamb6f4fde2017-06-15 04:03:06622 'CallJavascriptFunctionUnsafe',
623 (
624 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
625 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
626 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
627 ),
628 False,
629 (
Egor Paskoce145c42018-09-28 19:31:04630 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
631 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
632 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06633 ),
634 ),
dskiba1474c2bfd62017-07-20 02:19:24635 (
636 'leveldb::DB::Open',
637 (
638 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
639 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
640 "Chrome's tracing, making their memory usage visible.",
641 ),
642 True,
643 (
644 r'^third_party/leveldatabase/.*\.(cc|h)$',
645 ),
Gabriel Charette0592c3a2017-07-26 12:02:04646 ),
647 (
Chris Mumfordc38afb62017-10-09 17:55:08648 'leveldb::NewMemEnv',
649 (
650 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58651 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
652 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08653 ),
654 True,
655 (
656 r'^third_party/leveldatabase/.*\.(cc|h)$',
657 ),
658 ),
659 (
Gabriel Charetted9839bc2017-07-29 14:17:47660 'RunLoop::QuitCurrent',
661 (
Robert Liao64b7ab22017-08-04 23:03:43662 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
663 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47664 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41665 False,
Gabriel Charetted9839bc2017-07-29 14:17:47666 (),
Gabriel Charettea44975052017-08-21 23:14:04667 ),
668 (
669 'base::ScopedMockTimeMessageLoopTaskRunner',
670 (
Gabriel Charette87cc1af2018-04-25 20:52:51671 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11672 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51673 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
674 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
675 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04676 ),
Gabriel Charette87cc1af2018-04-25 20:52:51677 False,
Gabriel Charettea44975052017-08-21 23:14:04678 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57679 ),
680 (
Dave Tapuska98199b612019-07-10 13:30:44681 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57682 (
683 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02684 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57685 ),
686 True,
687 (),
Francois Doray43670e32017-09-27 12:40:38688 ),
689 (
Peter Kasting991618a62019-06-17 22:00:09690 r'/\bstd::stoi\b',
691 (
692 'std::stoi uses exceptions to communicate results. ',
693 'Use base::StringToInt() instead.',
694 ),
695 True,
696 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
697 ),
698 (
699 r'/\bstd::stol\b',
700 (
701 'std::stol uses exceptions to communicate results. ',
702 'Use base::StringToInt() instead.',
703 ),
704 True,
705 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
706 ),
707 (
708 r'/\bstd::stoul\b',
709 (
710 'std::stoul uses exceptions to communicate results. ',
711 'Use base::StringToUint() instead.',
712 ),
713 True,
714 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
715 ),
716 (
717 r'/\bstd::stoll\b',
718 (
719 'std::stoll uses exceptions to communicate results. ',
720 'Use base::StringToInt64() instead.',
721 ),
722 True,
723 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
724 ),
725 (
726 r'/\bstd::stoull\b',
727 (
728 'std::stoull uses exceptions to communicate results. ',
729 'Use base::StringToUint64() instead.',
730 ),
731 True,
732 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
733 ),
734 (
735 r'/\bstd::stof\b',
736 (
737 'std::stof uses exceptions to communicate results. ',
738 'For locale-independent values, e.g. reading numbers from disk',
739 'profiles, use base::StringToDouble().',
740 'For user-visible values, parse using ICU.',
741 ),
742 True,
743 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
744 ),
745 (
746 r'/\bstd::stod\b',
747 (
748 'std::stod uses exceptions to communicate results. ',
749 'For locale-independent values, e.g. reading numbers from disk',
750 'profiles, use base::StringToDouble().',
751 'For user-visible values, parse using ICU.',
752 ),
753 True,
754 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
755 ),
756 (
757 r'/\bstd::stold\b',
758 (
759 'std::stold uses exceptions to communicate results. ',
760 'For locale-independent values, e.g. reading numbers from disk',
761 'profiles, use base::StringToDouble().',
762 'For user-visible values, parse using ICU.',
763 ),
764 True,
765 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
766 ),
767 (
Daniel Bratell69334cc2019-03-26 11:07:45768 r'/\bstd::to_string\b',
769 (
770 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09771 'For locale-independent strings, e.g. writing numbers to disk',
772 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45773 'For user-visible strings, use base::FormatNumber() and',
774 'the related functions in base/i18n/number_formatting.h.',
775 ),
Peter Kasting991618a62019-06-17 22:00:09776 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21777 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45778 ),
779 (
780 r'/\bstd::shared_ptr\b',
781 (
782 'std::shared_ptr should not be used. Use scoped_refptr instead.',
783 ),
784 True,
Alex Chau9eb03cdd52020-07-13 21:04:57785 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
786 'array_buffer_contents\.(cc|h)',
787 # Needed for interop with third-party library
788 'chrome/services/sharing/nearby/',
789 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21790 ),
791 (
Peter Kasting991618a62019-06-17 22:00:09792 r'/\bstd::weak_ptr\b',
793 (
794 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
795 ),
796 True,
797 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
798 ),
799 (
Daniel Bratell609102be2019-03-27 20:53:21800 r'/\blong long\b',
801 (
802 'long long is banned. Use stdint.h if you need a 64 bit number.',
803 ),
804 False, # Only a warning since it is already used.
805 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
806 ),
807 (
808 r'/\bstd::bind\b',
809 (
810 'std::bind is banned because of lifetime risks.',
811 'Use base::BindOnce or base::BindRepeating instead.',
812 ),
813 True,
814 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
815 ),
816 (
817 r'/\b#include <chrono>\b',
818 (
819 '<chrono> overlaps with Time APIs in base. Keep using',
820 'base classes.',
821 ),
822 True,
823 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
824 ),
825 (
826 r'/\b#include <exception>\b',
827 (
828 'Exceptions are banned and disabled in Chromium.',
829 ),
830 True,
831 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
832 ),
833 (
834 r'/\bstd::function\b',
835 (
836 'std::function is banned. Instead use base::Callback which directly',
837 'supports Chromium\'s weak pointers, ref counting and more.',
838 ),
Peter Kasting991618a62019-06-17 22:00:09839 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21840 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
841 ),
842 (
843 r'/\b#include <random>\b',
844 (
845 'Do not use any random number engines from <random>. Instead',
846 'use base::RandomBitGenerator.',
847 ),
848 True,
849 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
850 ),
851 (
852 r'/\bstd::ratio\b',
853 (
854 'std::ratio is banned by the Google Style Guide.',
855 ),
856 True,
857 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45858 ),
859 (
Francois Doray43670e32017-09-27 12:40:38860 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
861 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
862 (
863 'Use the new API in base/threading/thread_restrictions.h.',
864 ),
Gabriel Charette04b138f2018-08-06 00:03:22865 False,
Francois Doray43670e32017-09-27 12:40:38866 (),
867 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38868 (
danakj7a2b7082019-05-21 21:13:51869 r'/\bbase::Bind\(',
870 (
871 'Please use base::Bind{Once,Repeating} instead',
872 'of base::Bind. (crbug.com/714018)',
873 ),
874 False,
Erik Staaba737d7602019-11-25 18:41:07875 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51876 ),
877 (
878 r'/\bbase::Callback[<:]',
879 (
880 'Please use base::{Once,Repeating}Callback instead',
881 'of base::Callback. (crbug.com/714018)',
882 ),
883 False,
Erik Staaba737d7602019-11-25 18:41:07884 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51885 ),
886 (
887 r'/\bbase::Closure\b',
888 (
889 'Please use base::{Once,Repeating}Closure instead',
890 'of base::Closure. (crbug.com/714018)',
891 ),
892 False,
Erik Staaba737d7602019-11-25 18:41:07893 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51894 ),
895 (
Michael Giuffrida7f93d6922019-04-19 14:39:58896 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19897 (
898 'RunMessageLoop is deprecated, use RunLoop instead.',
899 ),
900 False,
901 (),
902 ),
903 (
Dave Tapuska98199b612019-07-10 13:30:44904 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19905 (
906 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
907 ),
908 False,
909 (),
910 ),
911 (
Dave Tapuska98199b612019-07-10 13:30:44912 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19913 (
914 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
915 "if you're convinced you need this.",
916 ),
917 False,
918 (),
919 ),
920 (
Dave Tapuska98199b612019-07-10 13:30:44921 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19922 (
923 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04924 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19925 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
926 'async events instead of flushing threads.',
927 ),
928 False,
929 (),
930 ),
931 (
932 r'MessageLoopRunner',
933 (
934 'MessageLoopRunner is deprecated, use RunLoop instead.',
935 ),
936 False,
937 (),
938 ),
939 (
Dave Tapuska98199b612019-07-10 13:30:44940 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19941 (
942 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
943 "gab@ if you found a use case where this is the only solution.",
944 ),
945 False,
946 (),
947 ),
948 (
Victor Costane48a2e82019-03-15 22:02:34949 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16950 (
Victor Costane48a2e82019-03-15 22:02:34951 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16952 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
953 ),
954 True,
955 (
956 r'^sql/initialization\.(cc|h)$',
957 r'^third_party/sqlite/.*\.(c|cc|h)$',
958 ),
959 ),
Matt Menke7f520a82018-03-28 21:38:37960 (
Dave Tapuska98199b612019-07-10 13:30:44961 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47962 (
963 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
964 'base::RandomShuffle instead.'
965 ),
966 True,
967 (),
968 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24969 (
970 'ios/web/public/test/http_server',
971 (
972 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
973 ),
974 False,
975 (),
976 ),
Robert Liao764c9492019-01-24 18:46:28977 (
978 'GetAddressOf',
979 (
980 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53981 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
982 'operator& is generally recommended. So always use operator& instead. '
983 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28984 ),
985 True,
986 (),
987 ),
Antonio Gomes07300d02019-03-13 20:59:57988 (
989 'DEFINE_TYPE_CASTS',
990 (
991 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
992 '//third_party/blink/renderer/platform/casting.h.'
993 ),
994 True,
995 (
996 r'^third_party/blink/renderer/.*\.(cc|h)$',
997 ),
998 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38999 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:451000 r'/\bIsHTML.+Element\(\b',
1001 (
1002 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
1003 ' helpers IsA<HTMLXXXXElement> from ',
1004 '//third_party/blink/renderer/platform/casting.h.'
1005 ),
1006 False,
1007 (
1008 r'^third_party/blink/renderer/.*\.(cc|h)$',
1009 ),
1010 ),
1011 (
1012 r'/\bToHTML.+Element(|OrNull)\(\b',
1013 (
1014 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
1015 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
1016 'and DynamicTo<HTMLXXXXElement> from ',
1017 '//third_party/blink/renderer/platform/casting.h.'
1018 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
1019 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
1020 ),
1021 False,
1022 (
1023 r'^third_party/blink/renderer/.*\.(cc|h)$',
1024 ),
1025 ),
1026 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371027 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381028 (
1029 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1030 ),
1031 True,
1032 (),
1033 ),
Ben Lewisa9514602019-04-29 17:53:051034 (
1035 'SHFileOperation',
1036 (
1037 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1038 'complex functions to achieve the same goals. Use IFileOperation for ',
1039 'any esoteric actions instead.'
1040 ),
1041 True,
1042 (),
1043 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181044 (
Cliff Smolinsky81951642019-04-30 21:39:511045 'StringFromGUID2',
1046 (
1047 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241048 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511049 ),
1050 True,
1051 (
1052 r'/base/win/win_util_unittest.cc'
1053 ),
1054 ),
1055 (
1056 'StringFromCLSID',
1057 (
1058 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241059 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511060 ),
1061 True,
1062 (
1063 r'/base/win/win_util_unittest.cc'
1064 ),
1065 ),
1066 (
Avi Drissman7382afa02019-04-29 23:27:131067 'kCFAllocatorNull',
1068 (
1069 'The use of kCFAllocatorNull with the NoCopy creation of ',
1070 'CoreFoundation types is prohibited.',
1071 ),
1072 True,
1073 (),
1074 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291075 (
1076 'mojo::ConvertTo',
1077 (
1078 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1079 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1080 'StringTraits if you would like to convert between custom types and',
1081 'the wire format of mojom types.'
1082 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221083 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291084 (
Wezf89dec092019-09-11 19:38:331085 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1086 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291087 r'^third_party/blink/.*\.(cc|h)$',
1088 r'^content/renderer/.*\.(cc|h)$',
1089 ),
1090 ),
Robert Liao1d78df52019-11-11 20:02:011091 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161092 'GetInterfaceProvider',
1093 (
1094 'InterfaceProvider is deprecated.',
1095 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1096 'or Platform::GetBrowserInterfaceBroker.'
1097 ),
1098 False,
1099 (),
1100 ),
1101 (
Robert Liao1d78df52019-11-11 20:02:011102 'CComPtr',
1103 (
1104 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1105 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1106 'details.'
1107 ),
1108 False,
1109 (),
1110 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201111 (
1112 r'/\b(IFACE|STD)METHOD_?\(',
1113 (
1114 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1115 'Instead, always use IFACEMETHODIMP in the declaration.'
1116 ),
1117 False,
1118 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1119 ),
Allen Bauer53b43fb12020-03-12 17:21:471120 (
1121 'set_owned_by_client',
1122 (
1123 'set_owned_by_client is deprecated.',
1124 'views::View already owns the child views by default. This introduces ',
1125 'a competing ownership model which makes the code difficult to reason ',
1126 'about. See http://crbug.com/1044687 for more details.'
1127 ),
1128 False,
1129 (),
1130 ),
Eric Secklerbe6f48d2020-05-06 18:09:121131 (
1132 r'/\bTRACE_EVENT_ASYNC_',
1133 (
1134 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1135 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1136 ),
1137 False,
1138 (
1139 r'^base/trace_event/.*',
1140 r'^base/tracing/.*',
1141 ),
1142 ),
[email protected]127f18ec2012-06-16 05:05:591143)
1144
Mario Sanchez Prada2472cab2019-09-18 10:58:311145# Format: Sequence of tuples containing:
1146# * String pattern or, if starting with a slash, a regular expression.
1147# * Sequence of strings to show when the pattern matches.
1148_DEPRECATED_MOJO_TYPES = (
1149 (
1150 r'/\bmojo::AssociatedBinding\b',
1151 (
1152 'mojo::AssociatedBinding<Interface> is deprecated.',
1153 'Use mojo::AssociatedReceiver<Interface> instead.',
1154 ),
1155 ),
1156 (
1157 r'/\bmojo::AssociatedBindingSet\b',
1158 (
1159 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1160 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1161 ),
1162 ),
1163 (
1164 r'/\bmojo::AssociatedInterfacePtr\b',
1165 (
1166 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1167 'Use mojo::AssociatedRemote<Interface> instead.',
1168 ),
1169 ),
1170 (
1171 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1172 (
1173 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1174 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1175 ),
1176 ),
1177 (
1178 r'/\bmojo::AssociatedInterfaceRequest\b',
1179 (
1180 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1181 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1182 ),
1183 ),
1184 (
1185 r'/\bmojo::Binding\b',
1186 (
1187 'mojo::Binding<Interface> is deprecated.',
1188 'Use mojo::Receiver<Interface> instead.',
1189 ),
1190 ),
1191 (
1192 r'/\bmojo::BindingSet\b',
1193 (
1194 'mojo::BindingSet<Interface> is deprecated.',
1195 'Use mojo::ReceiverSet<Interface> instead.',
1196 ),
1197 ),
1198 (
1199 r'/\bmojo::InterfacePtr\b',
1200 (
1201 'mojo::InterfacePtr<Interface> is deprecated.',
1202 'Use mojo::Remote<Interface> instead.',
1203 ),
1204 ),
1205 (
1206 r'/\bmojo::InterfacePtrInfo\b',
1207 (
1208 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1209 'Use mojo::PendingRemote<Interface> instead.',
1210 ),
1211 ),
1212 (
1213 r'/\bmojo::InterfaceRequest\b',
1214 (
1215 'mojo::InterfaceRequest<Interface> is deprecated.',
1216 'Use mojo::PendingReceiver<Interface> instead.',
1217 ),
1218 ),
1219 (
1220 r'/\bmojo::MakeRequest\b',
1221 (
1222 'mojo::MakeRequest is deprecated.',
1223 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1224 ),
1225 ),
1226 (
1227 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1228 (
1229 'mojo::MakeRequest is deprecated.',
1230 'Use mojo::AssociatedRemote::'
1231 'BindNewEndpointAndPassDedicatedReceiverForTesting() instead.',
1232 ),
1233 ),
1234 (
1235 r'/\bmojo::MakeStrongBinding\b',
1236 (
1237 'mojo::MakeStrongBinding is deprecated.',
1238 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1239 'mojo::MakeSelfOwnedReceiver() instead.',
1240 ),
1241 ),
1242 (
1243 r'/\bmojo::MakeStrongAssociatedBinding\b',
1244 (
1245 'mojo::MakeStrongAssociatedBinding is deprecated.',
1246 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1247 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1248 ),
1249 ),
1250 (
Gyuyoung Kim4952ba62020-07-07 07:33:441251 r'/\bmojo::StrongAssociatedBinding\b',
1252 (
1253 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1254 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1255 ),
1256 ),
1257 (
1258 r'/\bmojo::StrongBinding\b',
1259 (
1260 'mojo::StrongBinding<Interface> is deprecated.',
1261 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1262 ),
1263 ),
1264 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311265 r'/\bmojo::StrongAssociatedBindingSet\b',
1266 (
1267 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1268 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1269 ),
1270 ),
1271 (
1272 r'/\bmojo::StrongBindingSet\b',
1273 (
1274 'mojo::StrongBindingSet<Interface> is deprecated.',
1275 'Use mojo::UniqueReceiverSet<Interface> instead.',
1276 ),
1277 ),
1278)
wnwenbdc444e2016-05-25 13:44:151279
mlamouria82272622014-09-16 18:45:041280_IPC_ENUM_TRAITS_DEPRECATED = (
1281 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501282 'See http://www.chromium.org/Home/chromium-security/education/'
1283 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041284
Stephen Martinis97a394142018-06-07 23:06:051285_LONG_PATH_ERROR = (
1286 'Some files included in this CL have file names that are too long (> 200'
1287 ' characters). If committed, these files will cause issues on Windows. See'
1288 ' https://crbug.com/612667 for more details.'
1289)
1290
Shenghua Zhangbfaa38b82017-11-16 21:58:021291_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041292 r".*[\\/]BuildHooksAndroidImpl\.java",
1293 r".*[\\/]LicenseContentProvider\.java",
1294 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281295 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021296]
[email protected]127f18ec2012-06-16 05:05:591297
Mohamed Heikald048240a2019-11-12 16:57:371298# List of image extensions that are used as resources in chromium.
1299_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1300
Sean Kau46e29bc2017-08-28 16:31:161301# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401302_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041303 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401304 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041305 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1306 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041307 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431308 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161309]
1310
1311
[email protected]b00342e7f2013-03-26 16:21:541312_VALID_OS_MACROS = (
1313 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081314 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541315 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441316 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121317 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541318 'OS_BSD',
1319 'OS_CAT', # For testing.
1320 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041321 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541322 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371323 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541324 'OS_IOS',
1325 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441326 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541327 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211328 'OS_NACL_NONSFI',
1329 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121330 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541331 'OS_OPENBSD',
1332 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371333 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541334 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541335 'OS_WIN',
1336)
1337
1338
Andrew Grieveb773bad2020-06-05 18:00:381339# These are not checked on the public chromium-presubmit trybot.
1340# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041341# checkouts.
agrievef32bcc72016-04-04 14:57:401342_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381343 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381344]
1345
1346
1347_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041348 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361349 'base/android/jni_generator/jni_generator.pydeps',
1350 'base/android/jni_generator/jni_registration_generator.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041351 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361352 'build/android/gyp/aar.pydeps',
1353 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271354 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361355 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381356 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361357 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111358 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361359 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361360 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361361 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111362 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041363 'build/android/gyp/create_app_bundle_apks.pydeps',
1364 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361365 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121366 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221367 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001368 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361369 'build/android/gyp/desugar.pydeps',
1370 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421371 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041372 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361373 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361374 'build/android/gyp/filter_zip.pydeps',
1375 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361376 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361377 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581378 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361379 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261380 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011381 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041382 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361383 'build/android/gyp/lint.pydeps',
1384 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361385 'build/android/gyp/merge_manifest.pydeps',
1386 'build/android/gyp/prepare_resources.pydeps',
1387 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461388 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241389 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361390 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461391 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561392 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361393 'build/android/incremental_install/generate_android_manifest.pydeps',
1394 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041395 'build/android/resource_sizes.pydeps',
1396 'build/android/test_runner.pydeps',
1397 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361398 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361399 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271400 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1401 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001402 'components/cronet/tools/generate_javadoc.pydeps',
1403 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381404 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001405 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381406 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041407 'testing/scripts/run_android_wpt.pydeps',
1408 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421409 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1410 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131411 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191412 ('third_party/blink/renderer/bindings/scripts/'
1413 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061414 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221415 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401416]
1417
wnwenbdc444e2016-05-25 13:44:151418
agrievef32bcc72016-04-04 14:57:401419_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1420
1421
Eric Boren6fd2b932018-01-25 15:05:081422# Bypass the AUTHORS check for these accounts.
1423_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591424 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451425 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591426 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521427 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
1428 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041429 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271430 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041431 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301432 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081433
1434
Daniel Bratell65b033262019-04-23 08:17:061435def _IsCPlusPlusFile(input_api, file_path):
1436 """Returns True if this file contains C++-like code (and not Python,
1437 Go, Java, MarkDown, ...)"""
1438
1439 ext = input_api.os_path.splitext(file_path)[1]
1440 # This list is compatible with CppChecker.IsCppFile but we should
1441 # consider adding ".c" to it. If we do that we can use this function
1442 # at more places in the code.
1443 return ext in (
1444 '.h',
1445 '.cc',
1446 '.cpp',
1447 '.m',
1448 '.mm',
1449 )
1450
1451def _IsCPlusPlusHeaderFile(input_api, file_path):
1452 return input_api.os_path.splitext(file_path)[1] == ".h"
1453
1454
1455def _IsJavaFile(input_api, file_path):
1456 return input_api.os_path.splitext(file_path)[1] == ".java"
1457
1458
1459def _IsProtoFile(input_api, file_path):
1460 return input_api.os_path.splitext(file_path)[1] == ".proto"
1461
Saagar Sanghavifceeaae2020-08-12 16:40:361462def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191463 """Attempts to prevent use of functions intended only for testing in
1464 non-testing code. For now this is just a best-effort implementation
1465 that ignores header files and may have some false positives. A
1466 better implementation would probably need a proper C++ parser.
1467 """
1468 # We only scan .cc files and the like, as the declaration of
1469 # for-testing functions in header files are hard to distinguish from
1470 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491471 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191472
jochenc0d4808c2015-07-27 09:25:421473 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191474 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091475 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[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))
1479
1480 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441481 files_to_skip = (_EXCLUDED_PATHS +
1482 _TEST_CODE_EXCLUDED_PATHS +
1483 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191484 return input_api.FilterSourceFile(
1485 affected_file,
James Cook24a504192020-07-23 00:08:441486 files_to_check=file_inclusion_pattern,
1487 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191488
1489 problems = []
1490 for f in input_api.AffectedSourceFiles(FilterFile):
1491 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241492 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031493 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461494 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031495 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191496 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031497 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191498
1499 if problems:
[email protected]f7051d52013-04-02 18:31:421500 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031501 else:
1502 return []
[email protected]55459852011-08-10 15:17:191503
1504
Saagar Sanghavifceeaae2020-08-12 16:40:361505def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231506 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591507 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231508 """
1509 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1510 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1511 name_pattern = r'ForTest(s|ing)?'
1512 # Describes an occurrence of "ForTest*" inside a // comment.
1513 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501514 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1515 annotation_re = input_api.re.compile(r'@VisibleForTesting\(otherwise')
Vaclav Brozek7dbc28c2018-03-27 08:35:231516 # Catch calls.
1517 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1518 # Ignore definitions. (Comments are ignored separately.)
1519 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1520
1521 problems = []
1522 sources = lambda x: input_api.FilterSourceFile(
1523 x,
James Cook24a504192020-07-23 00:08:441524 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1525 + input_api.DEFAULT_FILES_TO_SKIP),
1526 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231527 )
1528 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1529 local_path = f.LocalPath()
1530 is_inside_javadoc = False
1531 for line_number, line in f.ChangedContents():
1532 if is_inside_javadoc and javadoc_end_re.search(line):
1533 is_inside_javadoc = False
1534 if not is_inside_javadoc and javadoc_start_re.search(line):
1535 is_inside_javadoc = True
1536 if is_inside_javadoc:
1537 continue
1538 if (inclusion_re.search(line) and
1539 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501540 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231541 not exclusion_re.search(line)):
1542 problems.append(
1543 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1544
1545 if problems:
1546 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1547 else:
1548 return []
1549
1550
Saagar Sanghavifceeaae2020-08-12 16:40:361551def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541552 """Checks to make sure no .h files include <iostream>."""
1553 files = []
1554 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1555 input_api.re.MULTILINE)
1556 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1557 if not f.LocalPath().endswith('.h'):
1558 continue
1559 contents = input_api.ReadFile(f)
1560 if pattern.search(contents):
1561 files.append(f)
1562
1563 if len(files):
yolandyandaabc6d2016-04-18 18:29:391564 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061565 'Do not #include <iostream> in header files, since it inserts static '
1566 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541567 '#include <ostream>. See http://crbug.com/94794',
1568 files) ]
1569 return []
1570
Danil Chapovalov3518f362018-08-11 16:13:431571def _CheckNoStrCatRedefines(input_api, output_api):
1572 """Checks no windows headers with StrCat redefined are included directly."""
1573 files = []
1574 pattern_deny = input_api.re.compile(
1575 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1576 input_api.re.MULTILINE)
1577 pattern_allow = input_api.re.compile(
1578 r'^#include\s"base/win/windows_defines.inc"',
1579 input_api.re.MULTILINE)
1580 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1581 contents = input_api.ReadFile(f)
1582 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1583 files.append(f.LocalPath())
1584
1585 if len(files):
1586 return [output_api.PresubmitError(
1587 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1588 'directly since they pollute code with StrCat macro. Instead, '
1589 'include matching header from base/win. See http://crbug.com/856536',
1590 files) ]
1591 return []
1592
[email protected]10689ca2011-09-02 02:31:541593
Saagar Sanghavifceeaae2020-08-12 16:40:361594def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521595 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181596 problems = []
1597 for f in input_api.AffectedFiles():
1598 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1599 continue
1600
1601 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041602 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181603 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1604
1605 if not problems:
1606 return []
1607 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1608 '\n'.join(problems))]
1609
Saagar Sanghavifceeaae2020-08-12 16:40:361610def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341611 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1612
1613 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1614 instead of DISABLED_. To filter false positives, reports are only generated
1615 if a corresponding MAYBE_ line exists.
1616 """
1617 problems = []
1618
1619 # The following two patterns are looked for in tandem - is a test labeled
1620 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1621 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1622 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1623
1624 # This is for the case that a test is disabled on all platforms.
1625 full_disable_pattern = input_api.re.compile(
1626 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1627 input_api.re.MULTILINE)
1628
Katie Df13948e2018-09-25 07:33:441629 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341630 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1631 continue
1632
1633 # Search for MABYE_, DISABLE_ pairs.
1634 disable_lines = {} # Maps of test name to line number.
1635 maybe_lines = {}
1636 for line_num, line in f.ChangedContents():
1637 disable_match = disable_pattern.search(line)
1638 if disable_match:
1639 disable_lines[disable_match.group(1)] = line_num
1640 maybe_match = maybe_pattern.search(line)
1641 if maybe_match:
1642 maybe_lines[maybe_match.group(1)] = line_num
1643
1644 # Search for DISABLE_ occurrences within a TEST() macro.
1645 disable_tests = set(disable_lines.keys())
1646 maybe_tests = set(maybe_lines.keys())
1647 for test in disable_tests.intersection(maybe_tests):
1648 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1649
1650 contents = input_api.ReadFile(f)
1651 full_disable_match = full_disable_pattern.search(contents)
1652 if full_disable_match:
1653 problems.append(' %s' % f.LocalPath())
1654
1655 if not problems:
1656 return []
1657 return [
1658 output_api.PresubmitPromptWarning(
1659 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1660 '\n'.join(problems))
1661 ]
1662
[email protected]72df4e782012-06-21 16:28:181663
Saagar Sanghavifceeaae2020-08-12 16:40:361664def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571665 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521666 errors = []
Hans Wennborg944479f2020-06-25 21:39:251667 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521668 input_api.re.MULTILINE)
1669 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1670 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1671 continue
1672 for lnum, line in f.ChangedContents():
1673 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171674 errors.append(output_api.PresubmitError(
1675 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571676 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171677 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521678 return errors
1679
1680
Makoto Shimazu3ad422cd2019-05-08 02:35:141681def _FindHistogramNameInChunk(histogram_name, chunk):
1682 """Tries to find a histogram name or prefix in a line.
1683
1684 Returns the existence of the histogram name, or None if it needs more chunk
1685 to determine."""
mcasasb7440c282015-02-04 14:52:191686 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1687 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141688 if '<affected-histogram' in chunk:
1689 # If the tag is not completed, needs more chunk to get the name.
1690 if not '>' in chunk:
1691 return None
1692 if not 'name="' in chunk:
1693 return False
1694 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1695 # expect the only attribute is the name.
1696 histogram_prefix = chunk.split('"')[1]
1697 return histogram_prefix in histogram_name
1698 # Typically the whole histogram name should in the line.
1699 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191700
1701
Saagar Sanghavifceeaae2020-08-12 16:40:361702def CheckUmaHistogramChangesOnUpload(input_api, output_api):
mcasasb7440c282015-02-04 14:52:191703 """Check that UMA histogram names in touched lines can still be found in other
1704 lines of the patch or in histograms.xml. Note that this check would not catch
1705 the reverse: changes in histograms.xml not matched in the code itself."""
1706 touched_histograms = []
1707 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471708 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1709 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1710 name_pattern = r'"(.*?)"'
1711 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1712 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1713 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1714 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1715 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171716 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191717 for f in input_api.AffectedFiles():
1718 # If histograms.xml itself is modified, keep the modified lines for later.
1719 if f.LocalPath().endswith(('histograms.xml')):
1720 histograms_xml_modifications = f.ChangedContents()
1721 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471722 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1723 single_line_re = single_line_c_re
1724 split_line_prefix_re = split_line_c_prefix_re
1725 elif f.LocalPath().endswith(('java')):
1726 single_line_re = single_line_java_re
1727 split_line_prefix_re = split_line_java_prefix_re
1728 else:
mcasasb7440c282015-02-04 14:52:191729 continue
1730 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171731 if last_line_matched_prefix:
1732 suffix_found = split_line_suffix_re.search(line)
1733 if suffix_found :
1734 touched_histograms.append([suffix_found.group(1), f, line_num])
1735 last_line_matched_prefix = False
1736 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061737 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191738 if found:
1739 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171740 continue
1741 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191742
1743 # Search for the touched histogram names in the local modifications to
1744 # histograms.xml, and, if not found, on the base histograms.xml file.
1745 unmatched_histograms = []
1746 for histogram_info in touched_histograms:
1747 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141748 chunk = ''
mcasasb7440c282015-02-04 14:52:191749 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141750 chunk += line
1751 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1752 if histogram_name_found is None:
1753 continue
1754 chunk = ''
mcasasb7440c282015-02-04 14:52:191755 if histogram_name_found:
1756 break
1757 if not histogram_name_found:
1758 unmatched_histograms.append(histogram_info)
1759
eromanb90c82e7e32015-04-01 15:13:491760 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191761 problems = []
1762 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491763 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191764 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451765 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191766 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141767 chunk = ''
mcasasb7440c282015-02-04 14:52:191768 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141769 chunk += line
1770 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1771 chunk)
1772 if histogram_name_found is None:
1773 continue
1774 chunk = ''
mcasasb7440c282015-02-04 14:52:191775 if histogram_name_found:
1776 break
1777 if not histogram_name_found:
1778 problems.append(' [%s:%d] %s' %
1779 (f.LocalPath(), line_num, histogram_name))
1780
1781 if not problems:
1782 return []
1783 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1784 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491785 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191786
wnwenbdc444e2016-05-25 13:44:151787
Saagar Sanghavifceeaae2020-08-12 16:40:361788def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391789 """Check that FlakyTest annotation is our own instead of the android one"""
1790 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1791 files = []
1792 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1793 if f.LocalPath().endswith('Test.java'):
1794 if pattern.search(input_api.ReadFile(f)):
1795 files.append(f)
1796 if len(files):
1797 return [output_api.PresubmitError(
1798 'Use org.chromium.base.test.util.FlakyTest instead of '
1799 'android.test.FlakyTest',
1800 files)]
1801 return []
mcasasb7440c282015-02-04 14:52:191802
wnwenbdc444e2016-05-25 13:44:151803
Saagar Sanghavifceeaae2020-08-12 16:40:361804def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221805 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271806 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221807 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201808 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571809 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341810 '/win/' in f.LocalPath() or
1811 'chrome_elf' in f.LocalPath() or
1812 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201813 continue
[email protected]8ea5d4b2011-09-13 21:49:221814
[email protected]a11dbe9b2012-08-07 01:32:581815 allowWString = False
[email protected]b5c24292011-11-28 14:38:201816 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581817 if 'presubmit: allow wstring' in line:
1818 allowWString = True
1819 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271820 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581821 allowWString = False
1822 else:
1823 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221824
[email protected]55463aa62011-10-12 00:48:271825 if not problems:
1826 return []
1827 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581828 ' If you are calling a cross-platform API that accepts a wstring, '
1829 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271830 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221831
1832
Saagar Sanghavifceeaae2020-08-12 16:40:361833def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441834 """Make sure .DEPS.git is never modified manually."""
1835 if any(f.LocalPath().endswith('.DEPS.git') for f in
1836 input_api.AffectedFiles()):
1837 return [output_api.PresubmitError(
1838 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1839 'automated system based on what\'s in DEPS and your changes will be\n'
1840 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501841 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1842 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441843 'for more information')]
1844 return []
1845
1846
Saagar Sanghavifceeaae2020-08-12 16:40:361847def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471848 """Checks that DEPS file deps are from allowed_hosts."""
1849 # Run only if DEPS file has been modified to annoy fewer bystanders.
1850 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1851 return []
1852 # Outsource work to gclient verify
1853 try:
John Budorickf20c0042019-04-25 23:23:401854 gclient_path = input_api.os_path.join(
1855 input_api.PresubmitLocalPath(),
1856 'third_party', 'depot_tools', 'gclient.py')
1857 input_api.subprocess.check_output(
1858 [input_api.python_executable, gclient_path, 'verify'],
1859 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471860 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201861 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471862 return [output_api.PresubmitError(
1863 'DEPS file must have only git dependencies.',
1864 long_text=error.output)]
1865
1866
Mario Sanchez Prada2472cab2019-09-18 10:58:311867def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1868 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591869 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311870
1871 Returns an string composed of the name of the file, the line number where the
1872 match has been found and the additional text passed as |message| in case the
1873 target type name matches the text inside the line passed as parameter.
1874 """
Peng Huang9c5949a02020-06-11 19:20:541875 result = []
1876
1877 if line.endswith(" nocheck"):
1878 return result
1879
Mario Sanchez Prada2472cab2019-09-18 10:58:311880 matched = False
1881 if type_name[0:1] == '/':
1882 regex = type_name[1:]
1883 if input_api.re.search(regex, line):
1884 matched = True
1885 elif type_name in line:
1886 matched = True
1887
Mario Sanchez Prada2472cab2019-09-18 10:58:311888 if matched:
1889 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1890 for message_line in message:
1891 result.append(' %s' % message_line)
1892
1893 return result
1894
1895
Saagar Sanghavifceeaae2020-08-12 16:40:361896def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591897 """Make sure that banned functions are not used."""
1898 warnings = []
1899 errors = []
1900
James Cook24a504192020-07-23 00:08:441901 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151902 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441903 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151904 if input_api.re.match(item, local_path):
1905 return True
1906 return False
1907
Peter K. Lee6c03ccff2019-07-15 14:40:051908 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541909 local_path = affected_file.LocalPath()
1910 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1911 return False
1912 basename = input_api.os_path.basename(local_path)
1913 if 'ios' in basename.split('_'):
1914 return True
1915 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1916 if sep and 'ios' in local_path.split(sep):
1917 return True
1918 return False
1919
wnwenbdc444e2016-05-25 13:44:151920 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311921 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1922 func_name, message)
1923 if problems:
wnwenbdc444e2016-05-25 13:44:151924 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311925 errors.extend(problems)
1926 else:
1927 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151928
Eric Stevensona9a980972017-09-23 00:04:411929 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1930 for f in input_api.AffectedFiles(file_filter=file_filter):
1931 for line_num, line in f.ChangedContents():
1932 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1933 CheckForMatch(f, line_num, line, func_name, message, error)
1934
[email protected]127f18ec2012-06-16 05:05:591935 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1936 for f in input_api.AffectedFiles(file_filter=file_filter):
1937 for line_num, line in f.ChangedContents():
1938 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151939 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591940
Peter K. Lee6c03ccff2019-07-15 14:40:051941 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541942 for line_num, line in f.ChangedContents():
1943 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1944 CheckForMatch(f, line_num, line, func_name, message, error)
1945
Peter K. Lee6c03ccff2019-07-15 14:40:051946 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1947 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1948 for line_num, line in f.ChangedContents():
1949 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1950 CheckForMatch(f, line_num, line, func_name, message, error)
1951
[email protected]127f18ec2012-06-16 05:05:591952 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1953 for f in input_api.AffectedFiles(file_filter=file_filter):
1954 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491955 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441956 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491957 continue
wnwenbdc444e2016-05-25 13:44:151958 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591959
1960 result = []
1961 if (warnings):
1962 result.append(output_api.PresubmitPromptWarning(
1963 'Banned functions were used.\n' + '\n'.join(warnings)))
1964 if (errors):
1965 result.append(output_api.PresubmitError(
1966 'Banned functions were used.\n' + '\n'.join(errors)))
1967 return result
1968
1969
Michael Thiessen44457642020-02-06 00:24:151970def _CheckAndroidNoBannedImports(input_api, output_api):
1971 """Make sure that banned java imports are not used."""
1972 errors = []
1973
1974 def IsException(path, exceptions):
1975 for exception in exceptions:
1976 if (path.startswith(exception)):
1977 return True
1978 return False
1979
1980 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1981 for f in input_api.AffectedFiles(file_filter=file_filter):
1982 for line_num, line in f.ChangedContents():
1983 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1984 if IsException(f.LocalPath(), exceptions):
1985 continue;
1986 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1987 'import ' + import_name, message)
1988 if problems:
1989 errors.extend(problems)
1990 result = []
1991 if (errors):
1992 result.append(output_api.PresubmitError(
1993 'Banned imports were used.\n' + '\n'.join(errors)))
1994 return result
1995
1996
Saagar Sanghavifceeaae2020-08-12 16:40:361997def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311998 """Make sure that old Mojo types are not used."""
1999 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:572000 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:312001
Mario Sanchez Pradaaab91382019-12-19 08:57:092002 # For any path that is not an "ok" or an "error" path, a warning will be
2003 # raised if deprecated mojo types are found.
2004 ok_paths = ['components/arc']
2005 error_paths = ['third_party/blink', 'content']
2006
Mario Sanchez Prada2472cab2019-09-18 10:58:312007 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2008 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:572009 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:092010 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:312011 continue
2012
2013 for line_num, line in f.ChangedContents():
2014 for func_name, message in _DEPRECATED_MOJO_TYPES:
2015 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
2016 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:572017
Mario Sanchez Prada2472cab2019-09-18 10:58:312018 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:092019 # Raise errors inside |error_paths| and warnings everywhere else.
2020 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:572021 errors.extend(problems)
2022 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:312023 warnings.extend(problems)
2024
2025 result = []
2026 if (warnings):
2027 result.append(output_api.PresubmitPromptWarning(
2028 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:572029 if (errors):
2030 result.append(output_api.PresubmitError(
2031 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:312032 return result
2033
2034
Saagar Sanghavifceeaae2020-08-12 16:40:362035def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:062036 """Make sure that banned functions are not used."""
2037 files = []
2038 pattern = input_api.re.compile(r'^#pragma\s+once',
2039 input_api.re.MULTILINE)
2040 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2041 if not f.LocalPath().endswith('.h'):
2042 continue
2043 contents = input_api.ReadFile(f)
2044 if pattern.search(contents):
2045 files.append(f)
2046
2047 if files:
2048 return [output_api.PresubmitError(
2049 'Do not use #pragma once in header files.\n'
2050 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2051 files)]
2052 return []
2053
[email protected]127f18ec2012-06-16 05:05:592054
Saagar Sanghavifceeaae2020-08-12 16:40:362055def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:122056 """Checks to make sure we don't introduce use of foo ? true : false."""
2057 problems = []
2058 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2059 for f in input_api.AffectedFiles():
2060 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2061 continue
2062
2063 for line_num, line in f.ChangedContents():
2064 if pattern.match(line):
2065 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2066
2067 if not problems:
2068 return []
2069 return [output_api.PresubmitPromptWarning(
2070 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2071 '\n'.join(problems))]
2072
2073
Saagar Sanghavifceeaae2020-08-12 16:40:362074def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282075 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182076 change. Breaking - rules is an error, breaking ! rules is a
2077 warning.
2078 """
mohan.reddyf21db962014-10-16 12:26:472079 import sys
[email protected]55f9f382012-07-31 11:02:182080 # We need to wait until we have an input_api object and use this
2081 # roundabout construct to import checkdeps because this file is
2082 # eval-ed and thus doesn't have __file__.
2083 original_sys_path = sys.path
2084 try:
2085 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472086 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182087 import checkdeps
[email protected]55f9f382012-07-31 11:02:182088 from rules import Rule
2089 finally:
2090 # Restore sys.path to what it was before.
2091 sys.path = original_sys_path
2092
2093 added_includes = []
rhalavati08acd232017-04-03 07:23:282094 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242095 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182096 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062097 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502098 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082099 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062100 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502101 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082102 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062103 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502104 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082105 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182106
[email protected]26385172013-05-09 23:11:352107 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182108
2109 error_descriptions = []
2110 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282111 error_subjects = set()
2112 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362113
[email protected]55f9f382012-07-31 11:02:182114 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2115 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082116 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182117 description_with_path = '%s\n %s' % (path, rule_description)
2118 if rule_type == Rule.DISALLOW:
2119 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282120 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182121 else:
2122 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282123 warning_subjects.add("#includes")
2124
2125 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2126 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082127 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282128 description_with_path = '%s\n %s' % (path, rule_description)
2129 if rule_type == Rule.DISALLOW:
2130 error_descriptions.append(description_with_path)
2131 error_subjects.add("imports")
2132 else:
2133 warning_descriptions.append(description_with_path)
2134 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182135
Jinsuk Kim5a092672017-10-24 22:42:242136 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022137 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082138 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242139 description_with_path = '%s\n %s' % (path, rule_description)
2140 if rule_type == Rule.DISALLOW:
2141 error_descriptions.append(description_with_path)
2142 error_subjects.add("imports")
2143 else:
2144 warning_descriptions.append(description_with_path)
2145 warning_subjects.add("imports")
2146
[email protected]55f9f382012-07-31 11:02:182147 results = []
2148 if error_descriptions:
2149 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282150 'You added one or more %s that violate checkdeps rules.'
2151 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182152 error_descriptions))
2153 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422154 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282155 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182156 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282157 '%s? See relevant DEPS file(s) for details and contacts.' %
2158 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182159 warning_descriptions))
2160 return results
2161
2162
Saagar Sanghavifceeaae2020-08-12 16:40:362163def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222164 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152165 if input_api.platform == 'win32':
2166 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292167 checkperms_tool = input_api.os_path.join(
2168 input_api.PresubmitLocalPath(),
2169 'tools', 'checkperms', 'checkperms.py')
2170 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472171 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392172 with input_api.CreateTemporaryFile() as file_list:
2173 for f in input_api.AffectedFiles():
2174 # checkperms.py file/directory arguments must be relative to the
2175 # repository.
2176 file_list.write(f.LocalPath() + '\n')
2177 file_list.close()
2178 args += ['--file-list', file_list.name]
2179 try:
2180 input_api.subprocess.check_output(args)
2181 return []
2182 except input_api.subprocess.CalledProcessError as error:
2183 return [output_api.PresubmitError(
2184 'checkperms.py failed:',
2185 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222186
2187
Saagar Sanghavifceeaae2020-08-12 16:40:362188def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492189 """Makes sure we don't include ui/aura/window_property.h
2190 in header files.
2191 """
2192 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2193 errors = []
2194 for f in input_api.AffectedFiles():
2195 if not f.LocalPath().endswith('.h'):
2196 continue
2197 for line_num, line in f.ChangedContents():
2198 if pattern.match(line):
2199 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2200
2201 results = []
2202 if errors:
2203 results.append(output_api.PresubmitError(
2204 'Header files should not include ui/aura/window_property.h', errors))
2205 return results
2206
2207
[email protected]70ca77752012-11-20 03:45:032208def _CheckForVersionControlConflictsInFile(input_api, f):
2209 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2210 errors = []
2211 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162212 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232213 # First-level headers in markdown look a lot like version control
2214 # conflict markers. http://daringfireball.net/projects/markdown/basics
2215 continue
[email protected]70ca77752012-11-20 03:45:032216 if pattern.match(line):
2217 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2218 return errors
2219
2220
Saagar Sanghavifceeaae2020-08-12 16:40:362221def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032222 """Usually this is not intentional and will cause a compile failure."""
2223 errors = []
2224 for f in input_api.AffectedFiles():
2225 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2226
2227 results = []
2228 if errors:
2229 results.append(output_api.PresubmitError(
2230 'Version control conflict markers found, please resolve.', errors))
2231 return results
2232
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202233
Saagar Sanghavifceeaae2020-08-12 16:40:362234def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162235 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2236 errors = []
2237 for f in input_api.AffectedFiles():
2238 for line_num, line in f.ChangedContents():
2239 if pattern.search(line):
2240 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2241
2242 results = []
2243 if errors:
2244 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502245 'Found Google support URL addressed by answer number. Please replace '
2246 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162247 return results
2248
[email protected]70ca77752012-11-20 03:45:032249
Saagar Sanghavifceeaae2020-08-12 16:40:362250def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442251 def FilterFile(affected_file):
2252 """Filter function for use with input_api.AffectedSourceFiles,
2253 below. This filters out everything except non-test files from
2254 top-level directories that generally speaking should not hard-code
2255 service URLs (e.g. src/android_webview/, src/content/ and others).
2256 """
2257 return input_api.FilterSourceFile(
2258 affected_file,
James Cook24a504192020-07-23 00:08:442259 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2260 files_to_skip=(_EXCLUDED_PATHS +
2261 _TEST_CODE_EXCLUDED_PATHS +
2262 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442263
reillyi38965732015-11-16 18:27:332264 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2265 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462266 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2267 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442268 problems = [] # items are (filename, line_number, line)
2269 for f in input_api.AffectedSourceFiles(FilterFile):
2270 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462271 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442272 problems.append((f.LocalPath(), line_num, line))
2273
2274 if problems:
[email protected]f7051d52013-04-02 18:31:422275 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442276 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582277 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442278 [' %s:%d: %s' % (
2279 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032280 else:
2281 return []
[email protected]06e6d0ff2012-12-11 01:36:442282
2283
Saagar Sanghavifceeaae2020-08-12 16:40:362284def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292285 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2286 def FileFilter(affected_file):
2287 """Includes directories known to be Chrome OS only."""
2288 return input_api.FilterSourceFile(
2289 affected_file,
James Cook24a504192020-07-23 00:08:442290 files_to_check=('^ash/',
2291 '^chromeos/', # Top-level src/chromeos.
2292 '/chromeos/', # Any path component.
2293 '^components/arc',
2294 '^components/exo'),
2295 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292296
2297 prefs = []
2298 priority_prefs = []
2299 for f in input_api.AffectedFiles(file_filter=FileFilter):
2300 for line_num, line in f.ChangedContents():
2301 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2302 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2303 prefs.append(' %s' % line)
2304 if input_api.re.search(
2305 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2306 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2307 priority_prefs.append(' %s' % line)
2308
2309 results = []
2310 if (prefs):
2311 results.append(output_api.PresubmitPromptWarning(
2312 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2313 'by browser sync settings. If these prefs should be controlled by OS '
2314 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2315 if (priority_prefs):
2316 results.append(output_api.PresubmitPromptWarning(
2317 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2318 'controlled by browser sync settings. If these prefs should be '
2319 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2320 'instead.\n' + '\n'.join(prefs)))
2321 return results
2322
2323
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492324# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362325def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272326 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312327 The native_client_sdk directory is excluded because it has auto-generated PNG
2328 files for documentation.
[email protected]d2530012013-01-25 16:39:272329 """
[email protected]d2530012013-01-25 16:39:272330 errors = []
James Cook24a504192020-07-23 00:08:442331 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2332 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312333 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442334 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312335 for f in input_api.AffectedFiles(include_deletes=False,
2336 file_filter=file_filter):
2337 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272338
2339 results = []
2340 if errors:
2341 results.append(output_api.PresubmitError(
2342 'The name of PNG files should not have abbreviations. \n'
2343 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2344 'Contact [email protected] if you have questions.', errors))
2345 return results
2346
2347
Daniel Cheng4dcdb6b2017-04-13 08:30:172348def _ExtractAddRulesFromParsedDeps(parsed_deps):
2349 """Extract the rules that add dependencies from a parsed DEPS file.
2350
2351 Args:
2352 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2353 add_rules = set()
2354 add_rules.update([
2355 rule[1:] for rule in parsed_deps.get('include_rules', [])
2356 if rule.startswith('+') or rule.startswith('!')
2357 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502358 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172359 {}).iteritems():
2360 add_rules.update([
2361 rule[1:] for rule in rules
2362 if rule.startswith('+') or rule.startswith('!')
2363 ])
2364 return add_rules
2365
2366
2367def _ParseDeps(contents):
2368 """Simple helper for parsing DEPS files."""
2369 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172370 class _VarImpl:
2371
2372 def __init__(self, local_scope):
2373 self._local_scope = local_scope
2374
2375 def Lookup(self, var_name):
2376 """Implements the Var syntax."""
2377 try:
2378 return self._local_scope['vars'][var_name]
2379 except KeyError:
2380 raise Exception('Var is not defined: %s' % var_name)
2381
2382 local_scope = {}
2383 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172384 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592385 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172386 }
2387 exec contents in global_scope, local_scope
2388 return local_scope
2389
2390
2391def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592392 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412393 a set of DEPS entries that we should look up.
2394
2395 For a directory (rather than a specific filename) we fake a path to
2396 a specific filename by adding /DEPS. This is chosen as a file that
2397 will seldom or never be subject to per-file include_rules.
2398 """
[email protected]2b438d62013-11-14 17:54:142399 # We ignore deps entries on auto-generated directories.
2400 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082401
Daniel Cheng4dcdb6b2017-04-13 08:30:172402 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2403 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2404
2405 added_deps = new_deps.difference(old_deps)
2406
[email protected]2b438d62013-11-14 17:54:142407 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172408 for added_dep in added_deps:
2409 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2410 continue
2411 # Assume that a rule that ends in .h is a rule for a specific file.
2412 if added_dep.endswith('.h'):
2413 results.add(added_dep)
2414 else:
2415 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082416 return results
2417
2418
Saagar Sanghavifceeaae2020-08-12 16:40:362419def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552420 """When a dependency prefixed with + is added to a DEPS file, we
2421 want to make sure that the change is reviewed by an OWNER of the
2422 target file or directory, to avoid layering violations from being
2423 introduced. This check verifies that this happens.
2424 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172425 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242426
2427 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492428 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242429 for f in input_api.AffectedFiles(include_deletes=False,
2430 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552431 filename = input_api.os_path.basename(f.LocalPath())
2432 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172433 virtual_depended_on_files.update(_CalculateAddedDeps(
2434 input_api.os_path,
2435 '\n'.join(f.OldContents()),
2436 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552437
[email protected]e871964c2013-05-13 14:14:552438 if not virtual_depended_on_files:
2439 return []
2440
2441 if input_api.is_committing:
2442 if input_api.tbr:
2443 return [output_api.PresubmitNotifyResult(
2444 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272445 if input_api.dry_run:
2446 return [output_api.PresubmitNotifyResult(
2447 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552448 if not input_api.change.issue:
2449 return [output_api.PresubmitError(
2450 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402451 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552452 output = output_api.PresubmitError
2453 else:
2454 output = output_api.PresubmitNotifyResult
2455
2456 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502457 owner_email, reviewers = (
2458 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2459 input_api,
2460 owners_db.email_regexp,
2461 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552462
2463 owner_email = owner_email or input_api.change.author_email
2464
[email protected]de4f7d22013-05-23 14:27:462465 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512466 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462467 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552468 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2469 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412470
2471 # We strip the /DEPS part that was added by
2472 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2473 # directory.
2474 def StripDeps(path):
2475 start_deps = path.rfind('/DEPS')
2476 if start_deps != -1:
2477 return path[:start_deps]
2478 else:
2479 return path
2480 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552481 for path in missing_files]
2482
2483 if unapproved_dependencies:
2484 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152485 output('You need LGTM from owners of depends-on paths in DEPS that were '
2486 'modified in this CL:\n %s' %
2487 '\n '.join(sorted(unapproved_dependencies)))]
2488 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2489 output_list.append(output(
2490 'Suggested missing target path OWNERS:\n %s' %
2491 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552492 return output_list
2493
2494 return []
2495
2496
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492497# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362498def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492499 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442500 files_to_skip = (_EXCLUDED_PATHS +
2501 _TEST_CODE_EXCLUDED_PATHS +
2502 input_api.DEFAULT_FILES_TO_SKIP +
2503 (r"^base[\\/]logging\.h$",
2504 r"^base[\\/]logging\.cc$",
2505 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2506 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2507 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2508 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2509 r"startup_browser_creator\.cc$",
2510 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2511 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2512 r"diagnostics_writer\.cc$",
2513 r"^chrome[\\/]chrome_cleaner[\\/].*",
2514 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2515 r"dll_hash_main\.cc$",
2516 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2517 r"^chromecast[\\/]",
2518 r"^cloud_print[\\/]",
2519 r"^components[\\/]browser_watcher[\\/]"
2520 r"dump_stability_report_main_win.cc$",
2521 r"^components[\\/]media_control[\\/]renderer[\\/]"
2522 r"media_playback_options\.cc$",
2523 r"^components[\\/]zucchini[\\/].*",
2524 # TODO(peter): Remove exception. https://crbug.com/534537
2525 r"^content[\\/]browser[\\/]notifications[\\/]"
2526 r"notification_event_dispatcher_impl\.cc$",
2527 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2528 r"gl_helper_benchmark\.cc$",
2529 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2530 r"^courgette[\\/]courgette_tool\.cc$",
2531 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2532 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2533 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2534 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2535 r"^ipc[\\/]ipc_logging\.cc$",
2536 r"^native_client_sdk[\\/]",
2537 r"^remoting[\\/]base[\\/]logging\.h$",
2538 r"^remoting[\\/]host[\\/].*",
2539 r"^sandbox[\\/]linux[\\/].*",
2540 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2541 r"dump_file_system.cc$",
2542 r"^tools[\\/]",
2543 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2544 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2545 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2546 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2547 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402548 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442549 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402550
thomasanderson625d3932017-03-29 07:16:582551 log_info = set([])
2552 printf = set([])
[email protected]85218562013-11-22 07:41:402553
2554 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582555 for _, line in f.ChangedContents():
2556 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2557 log_info.add(f.LocalPath())
2558 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2559 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372560
thomasanderson625d3932017-03-29 07:16:582561 if input_api.re.search(r"\bprintf\(", line):
2562 printf.add(f.LocalPath())
2563 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2564 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402565
2566 if log_info:
2567 return [output_api.PresubmitError(
2568 'These files spam the console log with LOG(INFO):',
2569 items=log_info)]
2570 if printf:
2571 return [output_api.PresubmitError(
2572 'These files spam the console log with printf/fprintf:',
2573 items=printf)]
2574 return []
2575
2576
Saagar Sanghavifceeaae2020-08-12 16:40:362577def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162578 """These types are all expected to hold locks while in scope and
2579 so should never be anonymous (which causes them to be immediately
2580 destroyed)."""
2581 they_who_must_be_named = [
2582 'base::AutoLock',
2583 'base::AutoReset',
2584 'base::AutoUnlock',
2585 'SkAutoAlphaRestore',
2586 'SkAutoBitmapShaderInstall',
2587 'SkAutoBlitterChoose',
2588 'SkAutoBounderCommit',
2589 'SkAutoCallProc',
2590 'SkAutoCanvasRestore',
2591 'SkAutoCommentBlock',
2592 'SkAutoDescriptor',
2593 'SkAutoDisableDirectionCheck',
2594 'SkAutoDisableOvalCheck',
2595 'SkAutoFree',
2596 'SkAutoGlyphCache',
2597 'SkAutoHDC',
2598 'SkAutoLockColors',
2599 'SkAutoLockPixels',
2600 'SkAutoMalloc',
2601 'SkAutoMaskFreeImage',
2602 'SkAutoMutexAcquire',
2603 'SkAutoPathBoundsUpdate',
2604 'SkAutoPDFRelease',
2605 'SkAutoRasterClipValidate',
2606 'SkAutoRef',
2607 'SkAutoTime',
2608 'SkAutoTrace',
2609 'SkAutoUnref',
2610 ]
2611 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2612 # bad: base::AutoLock(lock.get());
2613 # not bad: base::AutoLock lock(lock.get());
2614 bad_pattern = input_api.re.compile(anonymous)
2615 # good: new base::AutoLock(lock.get())
2616 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2617 errors = []
2618
2619 for f in input_api.AffectedFiles():
2620 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2621 continue
2622 for linenum, line in f.ChangedContents():
2623 if bad_pattern.search(line) and not good_pattern.search(line):
2624 errors.append('%s:%d' % (f.LocalPath(), linenum))
2625
2626 if errors:
2627 return [output_api.PresubmitError(
2628 'These lines create anonymous variables that need to be named:',
2629 items=errors)]
2630 return []
2631
2632
Saagar Sanghavifceeaae2020-08-12 16:40:362633def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532634 # Returns whether |template_str| is of the form <T, U...> for some types T
2635 # and U. Assumes that |template_str| is already in the form <...>.
2636 def HasMoreThanOneArg(template_str):
2637 # Level of <...> nesting.
2638 nesting = 0
2639 for c in template_str:
2640 if c == '<':
2641 nesting += 1
2642 elif c == '>':
2643 nesting -= 1
2644 elif c == ',' and nesting == 1:
2645 return True
2646 return False
2647
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492648 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102649 sources = lambda affected_file: input_api.FilterSourceFile(
2650 affected_file,
James Cook24a504192020-07-23 00:08:442651 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2652 input_api.DEFAULT_FILES_TO_SKIP),
2653 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552654
2655 # Pattern to capture a single "<...>" block of template arguments. It can
2656 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2657 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2658 # latter would likely require counting that < and > match, which is not
2659 # expressible in regular languages. Should the need arise, one can introduce
2660 # limited counting (matching up to a total number of nesting depth), which
2661 # should cover all practical cases for already a low nesting limit.
2662 template_arg_pattern = (
2663 r'<[^>]*' # Opening block of <.
2664 r'>([^<]*>)?') # Closing block of >.
2665 # Prefix expressing that whatever follows is not already inside a <...>
2666 # block.
2667 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102668 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552669 not_inside_template_arg_pattern
2670 + r'\bstd::unique_ptr'
2671 + template_arg_pattern
2672 + r'\(\)')
2673
2674 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2675 template_arg_no_array_pattern = (
2676 r'<[^>]*[^]]' # Opening block of <.
2677 r'>([^(<]*[^]]>)?') # Closing block of >.
2678 # Prefix saying that what follows is the start of an expression.
2679 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2680 # Suffix saying that what follows are call parentheses with a non-empty list
2681 # of arguments.
2682 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532683 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552684 return_construct_pattern = input_api.re.compile(
2685 start_of_expr_pattern
2686 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532687 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552688 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532689 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552690 + nonempty_arg_list_pattern)
2691
Vaclav Brozek851d9602018-04-04 16:13:052692 problems_constructor = []
2693 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102694 for f in input_api.AffectedSourceFiles(sources):
2695 for line_number, line in f.ChangedContents():
2696 # Disallow:
2697 # return std::unique_ptr<T>(foo);
2698 # bar = std::unique_ptr<T>(foo);
2699 # But allow:
2700 # return std::unique_ptr<T[]>(foo);
2701 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532702 # And also allow cases when the second template argument is present. Those
2703 # cases cannot be handled by std::make_unique:
2704 # return std::unique_ptr<T, U>(foo);
2705 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052706 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532707 return_construct_result = return_construct_pattern.search(line)
2708 if return_construct_result and not HasMoreThanOneArg(
2709 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052710 problems_constructor.append(
2711 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102712 # Disallow:
2713 # std::unique_ptr<T>()
2714 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052715 problems_nullptr.append(
2716 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2717
2718 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162719 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052720 errors.append(output_api.PresubmitError(
2721 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162722 problems_nullptr))
2723 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052724 errors.append(output_api.PresubmitError(
2725 'The following files use explicit std::unique_ptr constructor.'
2726 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162727 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102728 return errors
2729
2730
Saagar Sanghavifceeaae2020-08-12 16:40:362731def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082732 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522733 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082734 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522735 # If actions.xml is already included in the changelist, the PRESUBMIT
2736 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082737 return []
2738
[email protected]999261d2014-03-03 20:08:082739 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2740 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522741 current_actions = None
[email protected]999261d2014-03-03 20:08:082742 for f in input_api.AffectedFiles(file_filter=file_filter):
2743 for line_num, line in f.ChangedContents():
2744 match = input_api.re.search(action_re, line)
2745 if match:
[email protected]2f92dec2014-03-07 19:21:522746 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2747 # loaded only once.
2748 if not current_actions:
2749 with open('tools/metrics/actions/actions.xml') as actions_f:
2750 current_actions = actions_f.read()
2751 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082752 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522753 action = 'name="{0}"'.format(action_name)
2754 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082755 return [output_api.PresubmitPromptWarning(
2756 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522757 'tools/metrics/actions/actions.xml. Please run '
2758 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082759 % (f.LocalPath(), line_num, action_name))]
2760 return []
2761
2762
Daniel Cheng13ca61a882017-08-25 15:11:252763def _ImportJSONCommentEater(input_api):
2764 import sys
2765 sys.path = sys.path + [input_api.os_path.join(
2766 input_api.PresubmitLocalPath(),
2767 'tools', 'json_comment_eater')]
2768 import json_comment_eater
2769 return json_comment_eater
2770
2771
[email protected]99171a92014-06-03 08:44:472772def _GetJSONParseError(input_api, filename, eat_comments=True):
2773 try:
2774 contents = input_api.ReadFile(filename)
2775 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252776 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132777 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472778
2779 input_api.json.loads(contents)
2780 except ValueError as e:
2781 return e
2782 return None
2783
2784
2785def _GetIDLParseError(input_api, filename):
2786 try:
2787 contents = input_api.ReadFile(filename)
2788 idl_schema = input_api.os_path.join(
2789 input_api.PresubmitLocalPath(),
2790 'tools', 'json_schema_compiler', 'idl_schema.py')
2791 process = input_api.subprocess.Popen(
2792 [input_api.python_executable, idl_schema],
2793 stdin=input_api.subprocess.PIPE,
2794 stdout=input_api.subprocess.PIPE,
2795 stderr=input_api.subprocess.PIPE,
2796 universal_newlines=True)
2797 (_, error) = process.communicate(input=contents)
2798 return error or None
2799 except ValueError as e:
2800 return e
2801
2802
Saagar Sanghavifceeaae2020-08-12 16:40:362803def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472804 """Check that IDL and JSON files do not contain syntax errors."""
2805 actions = {
2806 '.idl': _GetIDLParseError,
2807 '.json': _GetJSONParseError,
2808 }
[email protected]99171a92014-06-03 08:44:472809 # Most JSON files are preprocessed and support comments, but these do not.
2810 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042811 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472812 ]
2813 # Only run IDL checker on files in these directories.
2814 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042815 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2816 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472817 ]
2818
2819 def get_action(affected_file):
2820 filename = affected_file.LocalPath()
2821 return actions.get(input_api.os_path.splitext(filename)[1])
2822
[email protected]99171a92014-06-03 08:44:472823 def FilterFile(affected_file):
2824 action = get_action(affected_file)
2825 if not action:
2826 return False
2827 path = affected_file.LocalPath()
2828
Erik Staab2dd72b12020-04-16 15:03:402829 if _MatchesFile(input_api,
2830 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2831 path):
[email protected]99171a92014-06-03 08:44:472832 return False
2833
2834 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162835 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472836 return False
2837 return True
2838
2839 results = []
2840 for affected_file in input_api.AffectedFiles(
2841 file_filter=FilterFile, include_deletes=False):
2842 action = get_action(affected_file)
2843 kwargs = {}
2844 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162845 _MatchesFile(input_api, json_no_comments_patterns,
2846 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472847 kwargs['eat_comments'] = False
2848 parse_error = action(input_api,
2849 affected_file.AbsoluteLocalPath(),
2850 **kwargs)
2851 if parse_error:
2852 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2853 (affected_file.LocalPath(), parse_error)))
2854 return results
2855
2856
Saagar Sanghavifceeaae2020-08-12 16:40:362857def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492858 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472859 import sys
[email protected]760deea2013-12-10 19:33:492860 original_sys_path = sys.path
2861 try:
2862 sys.path = sys.path + [input_api.os_path.join(
2863 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2864 import checkstyle
2865 finally:
2866 # Restore sys.path to what it was before.
2867 sys.path = original_sys_path
2868
2869 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092870 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442871 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492872
2873
Saagar Sanghavifceeaae2020-08-12 16:40:362874def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002875 """Checks to make sure devil is initialized correctly in python scripts."""
2876 script_common_initialize_pattern = input_api.re.compile(
2877 r'script_common\.InitializeEnvironment\(')
2878 devil_env_config_initialize = input_api.re.compile(
2879 r'devil_env\.config\.Initialize\(')
2880
2881 errors = []
2882
2883 sources = lambda affected_file: input_api.FilterSourceFile(
2884 affected_file,
James Cook24a504192020-07-23 00:08:442885 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2886 (r'^build[\\/]android[\\/]devil_chromium\.py',
2887 r'^third_party[\\/].*',)),
2888 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002889
2890 for f in input_api.AffectedSourceFiles(sources):
2891 for line_num, line in f.ChangedContents():
2892 if (script_common_initialize_pattern.search(line) or
2893 devil_env_config_initialize.search(line)):
2894 errors.append("%s:%d" % (f.LocalPath(), line_num))
2895
2896 results = []
2897
2898 if errors:
2899 results.append(output_api.PresubmitError(
2900 'Devil initialization should always be done using '
2901 'devil_chromium.Initialize() in the chromium project, to use better '
2902 'defaults for dependencies (ex. up-to-date version of adb).',
2903 errors))
2904
2905 return results
2906
2907
Sean Kau46e29bc2017-08-28 16:31:162908def _MatchesFile(input_api, patterns, path):
2909 for pattern in patterns:
2910 if input_api.re.search(pattern, path):
2911 return True
2912 return False
2913
2914
Daniel Cheng7052cdf2017-11-21 19:23:292915def _GetOwnersFilesToCheckForIpcOwners(input_api):
2916 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172917
Daniel Cheng7052cdf2017-11-21 19:23:292918 Returns:
2919 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2920 contain to cover IPC-related files with noparent reviewer rules.
2921 """
2922 # Whether or not a file affects IPC is (mostly) determined by a simple list
2923 # of filename patterns.
dchenge07de812016-06-20 19:27:172924 file_patterns = [
palmerb19a0932017-01-24 04:00:312925 # Legacy IPC:
dchenge07de812016-06-20 19:27:172926 '*_messages.cc',
2927 '*_messages*.h',
2928 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312929 # Mojo IPC:
dchenge07de812016-06-20 19:27:172930 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472931 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172932 '*_struct_traits*.*',
2933 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312934 '*.typemap',
2935 # Android native IPC:
2936 '*.aidl',
2937 # Blink uses a different file naming convention:
2938 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472939 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172940 '*StructTraits*.*',
2941 '*TypeConverter*.*',
2942 ]
2943
scottmg7a6ed5ba2016-11-04 18:22:042944 # These third_party directories do not contain IPCs, but contain files
2945 # matching the above patterns, which trigger false positives.
2946 exclude_paths = [
2947 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162948 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232949 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292950 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542951 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162952 # These files are just used to communicate between class loaders running
2953 # in the same process.
2954 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572955 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2956
scottmg7a6ed5ba2016-11-04 18:22:042957 ]
2958
dchenge07de812016-06-20 19:27:172959 # Dictionary mapping an OWNERS file path to Patterns.
2960 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2961 # rules ) to a PatternEntry.
2962 # PatternEntry is a dictionary with two keys:
2963 # - 'files': the files that are matched by this pattern
2964 # - 'rules': the per-file rules needed for this pattern
2965 # For example, if we expect OWNERS file to contain rules for *.mojom and
2966 # *_struct_traits*.*, Patterns might look like this:
2967 # {
2968 # '*.mojom': {
2969 # 'files': ...,
2970 # 'rules': [
2971 # 'per-file *.mojom=set noparent',
2972 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2973 # ],
2974 # },
2975 # '*_struct_traits*.*': {
2976 # 'files': ...,
2977 # 'rules': [
2978 # 'per-file *_struct_traits*.*=set noparent',
2979 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2980 # ],
2981 # },
2982 # }
2983 to_check = {}
2984
Daniel Cheng13ca61a882017-08-25 15:11:252985 def AddPatternToCheck(input_file, pattern):
2986 owners_file = input_api.os_path.join(
2987 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2988 if owners_file not in to_check:
2989 to_check[owners_file] = {}
2990 if pattern not in to_check[owners_file]:
2991 to_check[owners_file][pattern] = {
2992 'files': [],
2993 'rules': [
2994 'per-file %s=set noparent' % pattern,
2995 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2996 ]
2997 }
Vaclav Brozekd5de76a2018-03-17 07:57:502998 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252999
dchenge07de812016-06-20 19:27:173000 # Iterate through the affected files to see what we actually need to check
3001 # for. We should only nag patch authors about per-file rules if a file in that
3002 # directory would match that pattern. If a directory only contains *.mojom
3003 # files and no *_messages*.h files, we should only nag about rules for
3004 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:253005 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:263006 # Manifest files don't have a strong naming convention. Instead, try to find
3007 # affected .cc and .h files which look like they contain a manifest
3008 # definition.
3009 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3010 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3011 if (manifest_pattern.search(f.LocalPath()) and not
3012 test_manifest_pattern.search(f.LocalPath())):
3013 # We expect all actual service manifest files to contain at least one
3014 # qualified reference to service_manager::Manifest.
3015 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:253016 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:173017 for pattern in file_patterns:
3018 if input_api.fnmatch.fnmatch(
3019 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:043020 skip = False
3021 for exclude in exclude_paths:
3022 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
3023 skip = True
3024 break
3025 if skip:
3026 continue
Daniel Cheng13ca61a882017-08-25 15:11:253027 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173028 break
3029
Daniel Cheng7052cdf2017-11-21 19:23:293030 return to_check
3031
3032
Wez17c66962020-04-29 15:26:033033def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3034 """Adds OWNERS files to check for correct Fuchsia security owners."""
3035
3036 file_patterns = [
3037 # Component specifications.
3038 '*.cml', # Component Framework v2.
3039 '*.cmx', # Component Framework v1.
3040
3041 # Fuchsia IDL protocol specifications.
3042 '*.fidl',
3043 ]
3044
3045 def AddPatternToCheck(input_file, pattern):
3046 owners_file = input_api.os_path.join(
3047 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3048 if owners_file not in to_check:
3049 to_check[owners_file] = {}
3050 if pattern not in to_check[owners_file]:
3051 to_check[owners_file][pattern] = {
3052 'files': [],
3053 'rules': [
3054 'per-file %s=set noparent' % pattern,
3055 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3056 ]
3057 }
3058 to_check[owners_file][pattern]['files'].append(input_file)
3059
3060 # Iterate through the affected files to see what we actually need to check
3061 # for. We should only nag patch authors about per-file rules if a file in that
3062 # directory would match that pattern.
3063 for f in input_api.AffectedFiles(include_deletes=False):
3064 for pattern in file_patterns:
3065 if input_api.fnmatch.fnmatch(
3066 input_api.os_path.basename(f.LocalPath()), pattern):
3067 AddPatternToCheck(f, pattern)
3068 break
3069
3070 return to_check
3071
3072
Saagar Sanghavifceeaae2020-08-12 16:40:363073def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293074 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3075 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033076 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293077
3078 if to_check:
3079 # If there are any OWNERS files to check, there are IPC-related changes in
3080 # this CL. Auto-CC the review list.
3081 output_api.AppendCC('[email protected]')
3082
3083 # Go through the OWNERS files to check, filtering out rules that are already
3084 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173085 for owners_file, patterns in to_check.iteritems():
3086 try:
3087 with file(owners_file) as f:
3088 lines = set(f.read().splitlines())
3089 for entry in patterns.itervalues():
3090 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3091 ]
3092 except IOError:
3093 # No OWNERS file, so all the rules are definitely missing.
3094 continue
3095
3096 # All the remaining lines weren't found in OWNERS files, so emit an error.
3097 errors = []
3098 for owners_file, patterns in to_check.iteritems():
3099 missing_lines = []
3100 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503101 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173102 missing_lines.extend(entry['rules'])
3103 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3104 if missing_lines:
3105 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053106 'Because of the presence of files:\n%s\n\n'
3107 '%s needs the following %d lines added:\n\n%s' %
3108 ('\n'.join(files), owners_file, len(missing_lines),
3109 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173110
3111 results = []
3112 if errors:
vabrf5ce3bf92016-07-11 14:52:413113 if input_api.is_committing:
3114 output = output_api.PresubmitError
3115 else:
3116 output = output_api.PresubmitPromptWarning
3117 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593118 'Found OWNERS files that need to be updated for IPC security ' +
3119 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173120 long_text='\n\n'.join(errors)))
3121
3122 return results
3123
3124
Robert Sesek2c905332020-05-06 23:17:133125def _GetFilesUsingSecurityCriticalFunctions(input_api):
3126 """Checks affected files for changes to security-critical calls. This
3127 function checks the full change diff, to catch both additions/changes
3128 and removals.
3129
3130 Returns a dict keyed by file name, and the value is a set of detected
3131 functions.
3132 """
3133 # Map of function pretty name (displayed in an error) to the pattern to
3134 # match it with.
3135 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373136 'content::GetServiceSandboxType<>()':
3137 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133138 }
3139 _PATTERNS_TO_CHECK = {
3140 k: input_api.re.compile(v)
3141 for k, v in _PATTERNS_TO_CHECK.items()
3142 }
3143
3144 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3145 files_to_functions = {}
3146 for f in input_api.AffectedFiles():
3147 diff = f.GenerateScmDiff()
3148 for line in diff.split('\n'):
3149 # Not using just RightHandSideLines() because removing a
3150 # call to a security-critical function can be just as important
3151 # as adding or changing the arguments.
3152 if line.startswith('-') or (line.startswith('+') and
3153 not line.startswith('++')):
3154 for name, pattern in _PATTERNS_TO_CHECK.items():
3155 if pattern.search(line):
3156 path = f.LocalPath()
3157 if not path in files_to_functions:
3158 files_to_functions[path] = set()
3159 files_to_functions[path].add(name)
3160 return files_to_functions
3161
3162
Saagar Sanghavifceeaae2020-08-12 16:40:363163def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133164 """Checks that changes involving security-critical functions are reviewed
3165 by the security team.
3166 """
3167 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3168 if len(files_to_functions):
3169 owners_db = input_api.owners_db
3170 owner_email, reviewers = (
3171 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3172 input_api,
3173 owners_db.email_regexp,
3174 approval_needed=input_api.is_committing))
3175
3176 # Load the OWNERS file for security changes.
3177 owners_file = 'ipc/SECURITY_OWNERS'
3178 security_owners = owners_db.owners_rooted_at_file(owners_file)
3179
3180 has_security_owner = any([owner in reviewers for owner in security_owners])
3181 if not has_security_owner:
3182 msg = 'The following files change calls to security-sensive functions\n' \
3183 'that need to be reviewed by {}.\n'.format(owners_file)
3184 for path, names in files_to_functions.items():
3185 msg += ' {}\n'.format(path)
3186 for name in names:
3187 msg += ' {}\n'.format(name)
3188 msg += '\n'
3189
3190 if input_api.is_committing:
3191 output = output_api.PresubmitError
3192 else:
3193 output = output_api.PresubmitNotifyResult
3194 return [output(msg)]
3195
3196 return []
3197
3198
Saagar Sanghavifceeaae2020-08-12 16:40:363199def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263200 """Checks that set noparent is only used together with an OWNERS file in
3201 //build/OWNERS.setnoparent (see also
3202 //docs/code_reviews.md#owners-files-details)
3203 """
3204 errors = []
3205
3206 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3207 allowed_owners_files = set()
3208 with open(allowed_owners_files_file, 'r') as f:
3209 for line in f:
3210 line = line.strip()
3211 if not line or line.startswith('#'):
3212 continue
3213 allowed_owners_files.add(line)
3214
3215 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3216
3217 for f in input_api.AffectedFiles(include_deletes=False):
3218 if not f.LocalPath().endswith('OWNERS'):
3219 continue
3220
3221 found_owners_files = set()
3222 found_set_noparent_lines = dict()
3223
3224 # Parse the OWNERS file.
3225 for lineno, line in enumerate(f.NewContents(), 1):
3226 line = line.strip()
3227 if line.startswith('set noparent'):
3228 found_set_noparent_lines[''] = lineno
3229 if line.startswith('file://'):
3230 if line in allowed_owners_files:
3231 found_owners_files.add('')
3232 if line.startswith('per-file'):
3233 match = per_file_pattern.match(line)
3234 if match:
3235 glob = match.group(1).strip()
3236 directive = match.group(2).strip()
3237 if directive == 'set noparent':
3238 found_set_noparent_lines[glob] = lineno
3239 if directive.startswith('file://'):
3240 if directive in allowed_owners_files:
3241 found_owners_files.add(glob)
3242
3243 # Check that every set noparent line has a corresponding file:// line
3244 # listed in build/OWNERS.setnoparent.
3245 for set_noparent_line in found_set_noparent_lines:
3246 if set_noparent_line in found_owners_files:
3247 continue
3248 errors.append(' %s:%d' % (f.LocalPath(),
3249 found_set_noparent_lines[set_noparent_line]))
3250
3251 results = []
3252 if errors:
3253 if input_api.is_committing:
3254 output = output_api.PresubmitError
3255 else:
3256 output = output_api.PresubmitPromptWarning
3257 results.append(output(
3258 'Found the following "set noparent" restrictions in OWNERS files that '
3259 'do not include owners from build/OWNERS.setnoparent:',
3260 long_text='\n\n'.join(errors)))
3261 return results
3262
3263
Saagar Sanghavifceeaae2020-08-12 16:40:363264def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313265 """Checks that added or removed lines in non third party affected
3266 header files do not lead to new useless class or struct forward
3267 declaration.
jbriance9e12f162016-11-25 07:57:503268 """
3269 results = []
3270 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3271 input_api.re.MULTILINE)
3272 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3273 input_api.re.MULTILINE)
3274 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313275 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193276 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493277 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313278 continue
3279
jbriance9e12f162016-11-25 07:57:503280 if not f.LocalPath().endswith('.h'):
3281 continue
3282
3283 contents = input_api.ReadFile(f)
3284 fwd_decls = input_api.re.findall(class_pattern, contents)
3285 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3286
3287 useless_fwd_decls = []
3288 for decl in fwd_decls:
3289 count = sum(1 for _ in input_api.re.finditer(
3290 r'\b%s\b' % input_api.re.escape(decl), contents))
3291 if count == 1:
3292 useless_fwd_decls.append(decl)
3293
3294 if not useless_fwd_decls:
3295 continue
3296
3297 for line in f.GenerateScmDiff().splitlines():
3298 if (line.startswith('-') and not line.startswith('--') or
3299 line.startswith('+') and not line.startswith('++')):
3300 for decl in useless_fwd_decls:
3301 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3302 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243303 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503304 (f.LocalPath(), decl)))
3305 useless_fwd_decls.remove(decl)
3306
3307 return results
3308
Jinsong Fan91ebbbd2019-04-16 14:57:173309def _CheckAndroidDebuggableBuild(input_api, output_api):
3310 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3311 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3312 this is a debuggable build of Android.
3313 """
3314 build_type_check_pattern = input_api.re.compile(
3315 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3316
3317 errors = []
3318
3319 sources = lambda affected_file: input_api.FilterSourceFile(
3320 affected_file,
James Cook24a504192020-07-23 00:08:443321 files_to_skip=(_EXCLUDED_PATHS +
3322 _TEST_CODE_EXCLUDED_PATHS +
3323 input_api.DEFAULT_FILES_TO_SKIP +
3324 (r"^android_webview[\\/]support_library[\\/]"
3325 "boundary_interfaces[\\/]",
3326 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3327 r'^third_party[\\/].*',
3328 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3329 r"webview[\\/]chromium[\\/]License.*",)),
3330 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173331
3332 for f in input_api.AffectedSourceFiles(sources):
3333 for line_num, line in f.ChangedContents():
3334 if build_type_check_pattern.search(line):
3335 errors.append("%s:%d" % (f.LocalPath(), line_num))
3336
3337 results = []
3338
3339 if errors:
3340 results.append(output_api.PresubmitPromptWarning(
3341 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3342 ' Please use BuildInfo.isDebugAndroid() instead.',
3343 errors))
3344
3345 return results
jbriance9e12f162016-11-25 07:57:503346
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493347# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293348def _CheckAndroidToastUsage(input_api, output_api):
3349 """Checks that code uses org.chromium.ui.widget.Toast instead of
3350 android.widget.Toast (Chromium Toast doesn't force hardware
3351 acceleration on low-end devices, saving memory).
3352 """
3353 toast_import_pattern = input_api.re.compile(
3354 r'^import android\.widget\.Toast;$')
3355
3356 errors = []
3357
3358 sources = lambda affected_file: input_api.FilterSourceFile(
3359 affected_file,
James Cook24a504192020-07-23 00:08:443360 files_to_skip=(_EXCLUDED_PATHS +
3361 _TEST_CODE_EXCLUDED_PATHS +
3362 input_api.DEFAULT_FILES_TO_SKIP +
3363 (r'^chromecast[\\/].*',
3364 r'^remoting[\\/].*')),
3365 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293366
3367 for f in input_api.AffectedSourceFiles(sources):
3368 for line_num, line in f.ChangedContents():
3369 if toast_import_pattern.search(line):
3370 errors.append("%s:%d" % (f.LocalPath(), line_num))
3371
3372 results = []
3373
3374 if errors:
3375 results.append(output_api.PresubmitError(
3376 'android.widget.Toast usage is detected. Android toasts use hardware'
3377 ' acceleration, and can be\ncostly on low-end devices. Please use'
3378 ' org.chromium.ui.widget.Toast instead.\n'
3379 'Contact [email protected] if you have any questions.',
3380 errors))
3381
3382 return results
3383
3384
dgnaa68d5e2015-06-10 10:08:223385def _CheckAndroidCrLogUsage(input_api, output_api):
3386 """Checks that new logs using org.chromium.base.Log:
3387 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513388 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223389 """
pkotwicza1dd0b002016-05-16 14:41:043390
torne89540622017-03-24 19:41:303391 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043392 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303393 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043394 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303395 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043396 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3397 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093398 # The customtabs_benchmark is a small app that does not depend on Chromium
3399 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043400 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043401 ]
3402
dgnaa68d5e2015-06-10 10:08:223403 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123404 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3405 class_in_base_pattern = input_api.re.compile(
3406 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3407 has_some_log_import_pattern = input_api.re.compile(
3408 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223409 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553410 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223411 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463412 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553413 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223414
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463415 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443416 sources = lambda x: input_api.FilterSourceFile(x,
3417 files_to_check=[r'.*\.java$'],
3418 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123419
dgnaa68d5e2015-06-10 10:08:223420 tag_decl_errors = []
3421 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123422 tag_errors = []
dgn38736db2015-09-18 19:20:513423 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123424 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223425
3426 for f in input_api.AffectedSourceFiles(sources):
3427 file_content = input_api.ReadFile(f)
3428 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223429 # Per line checks
dgn87d9fb62015-06-12 09:15:123430 if (cr_log_import_pattern.search(file_content) or
3431 (class_in_base_pattern.search(file_content) and
3432 not has_some_log_import_pattern.search(file_content))):
3433 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223434 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553435 if rough_log_decl_pattern.search(line):
3436 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223437
3438 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123439 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223440 if match:
3441 has_modified_logs = True
3442
3443 # Make sure it uses "TAG"
3444 if not match.group('tag') == 'TAG':
3445 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123446 else:
3447 # Report non cr Log function calls in changed lines
3448 for line_num, line in f.ChangedContents():
3449 if log_call_pattern.search(line):
3450 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223451
3452 # Per file checks
3453 if has_modified_logs:
3454 # Make sure the tag is using the "cr" prefix and is not too long
3455 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513456 tag_name = match.group('name') if match else None
3457 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223458 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513459 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223460 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513461 elif '.' in tag_name:
3462 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223463
3464 results = []
3465 if tag_decl_errors:
3466 results.append(output_api.PresubmitPromptWarning(
3467 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513468 '"private static final String TAG = "<package tag>".\n'
3469 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223470 tag_decl_errors))
3471
3472 if tag_length_errors:
3473 results.append(output_api.PresubmitError(
3474 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513475 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223476 tag_length_errors))
3477
3478 if tag_errors:
3479 results.append(output_api.PresubmitPromptWarning(
3480 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3481 tag_errors))
3482
dgn87d9fb62015-06-12 09:15:123483 if util_log_errors:
dgn4401aa52015-04-29 16:26:173484 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123485 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3486 util_log_errors))
3487
dgn38736db2015-09-18 19:20:513488 if tag_with_dot_errors:
3489 results.append(output_api.PresubmitPromptWarning(
3490 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3491 tag_with_dot_errors))
3492
dgn4401aa52015-04-29 16:26:173493 return results
3494
3495
Yoland Yanb92fa522017-08-28 17:37:063496def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3497 """Checks that junit.framework.* is no longer used."""
3498 deprecated_junit_framework_pattern = input_api.re.compile(
3499 r'^import junit\.framework\..*;',
3500 input_api.re.MULTILINE)
3501 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443502 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063503 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133504 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063505 for line_num, line in f.ChangedContents():
3506 if deprecated_junit_framework_pattern.search(line):
3507 errors.append("%s:%d" % (f.LocalPath(), line_num))
3508
3509 results = []
3510 if errors:
3511 results.append(output_api.PresubmitError(
3512 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3513 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3514 ' if you have any question.', errors))
3515 return results
3516
3517
3518def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3519 """Checks that if new Java test classes have inheritance.
3520 Either the new test class is JUnit3 test or it is a JUnit4 test class
3521 with a base class, either case is undesirable.
3522 """
3523 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3524
3525 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443526 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063527 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133528 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063529 if not f.OldContents():
3530 class_declaration_start_flag = False
3531 for line_num, line in f.ChangedContents():
3532 if class_declaration_pattern.search(line):
3533 class_declaration_start_flag = True
3534 if class_declaration_start_flag and ' extends ' in line:
3535 errors.append('%s:%d' % (f.LocalPath(), line_num))
3536 if '{' in line:
3537 class_declaration_start_flag = False
3538
3539 results = []
3540 if errors:
3541 results.append(output_api.PresubmitPromptWarning(
3542 'The newly created files include Test classes that inherits from base'
3543 ' class. Please do not use inheritance in JUnit4 tests or add new'
3544 ' JUnit3 tests. Contact [email protected] if you have any'
3545 ' questions.', errors))
3546 return results
3547
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203548
yolandyan45001472016-12-21 21:12:423549def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3550 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3551 deprecated_annotation_import_pattern = input_api.re.compile(
3552 r'^import android\.test\.suitebuilder\.annotation\..*;',
3553 input_api.re.MULTILINE)
3554 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443555 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423556 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133557 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423558 for line_num, line in f.ChangedContents():
3559 if deprecated_annotation_import_pattern.search(line):
3560 errors.append("%s:%d" % (f.LocalPath(), line_num))
3561
3562 results = []
3563 if errors:
3564 results.append(output_api.PresubmitError(
3565 'Annotations in android.test.suitebuilder.annotation have been'
3566 ' deprecated since API level 24. Please use android.support.test.filters'
3567 ' from //third_party/android_support_test_runner:runner_java instead.'
3568 ' Contact [email protected] if you have any questions.', errors))
3569 return results
3570
3571
agrieve7b6479d82015-10-07 14:24:223572def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3573 """Checks if MDPI assets are placed in a correct directory."""
3574 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3575 ('/res/drawable/' in f.LocalPath() or
3576 '/res/drawable-ldrtl/' in f.LocalPath()))
3577 errors = []
3578 for f in input_api.AffectedFiles(include_deletes=False,
3579 file_filter=file_filter):
3580 errors.append(' %s' % f.LocalPath())
3581
3582 results = []
3583 if errors:
3584 results.append(output_api.PresubmitError(
3585 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3586 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3587 '/res/drawable-ldrtl/.\n'
3588 'Contact [email protected] if you have questions.', errors))
3589 return results
3590
3591
Nate Fischer535972b2017-09-16 01:06:183592def _CheckAndroidWebkitImports(input_api, output_api):
3593 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353594 android.webview.ValueCallback except in the WebView glue layer
3595 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183596 """
3597 valuecallback_import_pattern = input_api.re.compile(
3598 r'^import android\.webkit\.ValueCallback;$')
3599
3600 errors = []
3601
3602 sources = lambda affected_file: input_api.FilterSourceFile(
3603 affected_file,
James Cook24a504192020-07-23 00:08:443604 files_to_skip=(_EXCLUDED_PATHS +
3605 _TEST_CODE_EXCLUDED_PATHS +
3606 input_api.DEFAULT_FILES_TO_SKIP +
3607 (r'^android_webview[\\/]glue[\\/].*',
3608 r'^weblayer[\\/].*',)),
3609 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183610
3611 for f in input_api.AffectedSourceFiles(sources):
3612 for line_num, line in f.ChangedContents():
3613 if valuecallback_import_pattern.search(line):
3614 errors.append("%s:%d" % (f.LocalPath(), line_num))
3615
3616 results = []
3617
3618 if errors:
3619 results.append(output_api.PresubmitError(
3620 'android.webkit.ValueCallback usage is detected outside of the glue'
3621 ' layer. To stay compatible with the support library, android.webkit.*'
3622 ' classes should only be used inside the glue layer and'
3623 ' org.chromium.base.Callback should be used instead.',
3624 errors))
3625
3626 return results
3627
3628
Becky Zhou7c69b50992018-12-10 19:37:573629def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3630 """Checks Android XML styles """
3631 import sys
3632 original_sys_path = sys.path
3633 try:
3634 sys.path = sys.path + [input_api.os_path.join(
3635 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3636 import checkxmlstyle
3637 finally:
3638 # Restore sys.path to what it was before.
3639 sys.path = original_sys_path
3640
3641 if is_check_on_upload:
3642 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3643 else:
3644 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3645
3646
agrievef32bcc72016-04-04 14:57:403647class PydepsChecker(object):
3648 def __init__(self, input_api, pydeps_files):
3649 self._file_cache = {}
3650 self._input_api = input_api
3651 self._pydeps_files = pydeps_files
3652
3653 def _LoadFile(self, path):
3654 """Returns the list of paths within a .pydeps file relative to //."""
3655 if path not in self._file_cache:
3656 with open(path) as f:
3657 self._file_cache[path] = f.read()
3658 return self._file_cache[path]
3659
3660 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3661 """Returns an interable of paths within the .pydep, relativized to //."""
3662 os_path = self._input_api.os_path
3663 pydeps_dir = os_path.dirname(pydeps_path)
3664 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3665 if not l.startswith('*'))
3666 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3667
3668 def _CreateFilesToPydepsMap(self):
3669 """Returns a map of local_path -> list_of_pydeps."""
3670 ret = {}
3671 for pydep_local_path in self._pydeps_files:
3672 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3673 ret.setdefault(path, []).append(pydep_local_path)
3674 return ret
3675
3676 def ComputeAffectedPydeps(self):
3677 """Returns an iterable of .pydeps files that might need regenerating."""
3678 affected_pydeps = set()
3679 file_to_pydeps_map = None
3680 for f in self._input_api.AffectedFiles(include_deletes=True):
3681 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463682 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3683 # subrepositories. We can't figure out which files change, so re-check
3684 # all files.
3685 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383686 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3687 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403688 return self._pydeps_files
3689 elif local_path.endswith('.pydeps'):
3690 if local_path in self._pydeps_files:
3691 affected_pydeps.add(local_path)
3692 elif local_path.endswith('.py'):
3693 if file_to_pydeps_map is None:
3694 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3695 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3696 return affected_pydeps
3697
3698 def DetermineIfStale(self, pydeps_path):
3699 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413700 import difflib
John Budorick47ca3fe2018-02-10 00:53:103701 import os
3702
agrievef32bcc72016-04-04 14:57:403703 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033704 if old_pydeps_data:
3705 cmd = old_pydeps_data[1][1:].strip()
3706 old_contents = old_pydeps_data[2:]
3707 else:
3708 # A default cmd that should work in most cases (as long as pydeps filename
3709 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3710 # file is empty/new.
3711 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3712 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3713 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103714 env = dict(os.environ)
3715 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403716 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103717 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413718 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033719 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413720 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403721
3722
Tibor Goldschwendt360793f72019-06-25 18:23:493723def _ParseGclientArgs():
3724 args = {}
3725 with open('build/config/gclient_args.gni', 'r') as f:
3726 for line in f:
3727 line = line.strip()
3728 if not line or line.startswith('#'):
3729 continue
3730 attribute, value = line.split('=')
3731 args[attribute.strip()] = value.strip()
3732 return args
3733
3734
Saagar Sanghavifceeaae2020-08-12 16:40:363735def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403736 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403737 # This check is for Python dependency lists (.pydeps files), and involves
3738 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3739 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283740 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003741 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493742 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403743 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403744 results = []
3745 # First, check for new / deleted .pydeps.
3746 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033747 # Check whether we are running the presubmit check for a file in src.
3748 # f.LocalPath is relative to repo (src, or internal repo).
3749 # os_path.exists is relative to src repo.
3750 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3751 # to src and we can conclude that the pydeps is in src.
3752 if input_api.os_path.exists(f.LocalPath()):
3753 if f.LocalPath().endswith('.pydeps'):
3754 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3755 results.append(output_api.PresubmitError(
3756 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3757 'remove %s' % f.LocalPath()))
3758 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3759 results.append(output_api.PresubmitError(
3760 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3761 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403762
3763 if results:
3764 return results
3765
Mohamed Heikal7cd4d8312020-06-16 16:49:403766 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3767 affected_pydeps = set(checker.ComputeAffectedPydeps())
3768 affected_android_pydeps = affected_pydeps.intersection(
3769 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3770 if affected_android_pydeps and not is_android:
3771 results.append(output_api.PresubmitPromptOrNotify(
3772 'You have changed python files that may affect pydeps for android\n'
3773 'specific scripts. However, the relevant presumbit check cannot be\n'
3774 'run because you are not using an Android checkout. To validate that\n'
3775 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3776 'use the android-internal-presubmit optional trybot.\n'
3777 'Possibly stale pydeps files:\n{}'.format(
3778 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403779
Mohamed Heikal7cd4d8312020-06-16 16:49:403780 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3781 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403782 try:
phajdan.jr0d9878552016-11-04 10:49:413783 result = checker.DetermineIfStale(pydep_path)
3784 if result:
3785 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403786 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413787 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3788 'To regenerate, run:\n\n %s' %
3789 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403790 except input_api.subprocess.CalledProcessError as error:
3791 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3792 long_text=error.output)]
3793
3794 return results
3795
3796
Saagar Sanghavifceeaae2020-08-12 16:40:363797def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433798 """Checks to make sure no header files have |Singleton<|."""
3799 def FileFilter(affected_file):
3800 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443801 files_to_skip = (_EXCLUDED_PATHS +
3802 input_api.DEFAULT_FILES_TO_SKIP +
3803 (r"^base[\\/]memory[\\/]singleton\.h$",
3804 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3805 r"quic_singleton_impl\.h$"))
3806 return input_api.FilterSourceFile(affected_file,
3807 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433808
sergeyu34d21222015-09-16 00:11:443809 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433810 files = []
3811 for f in input_api.AffectedSourceFiles(FileFilter):
3812 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3813 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3814 contents = input_api.ReadFile(f)
3815 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243816 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433817 pattern.search(line)):
3818 files.append(f)
3819 break
3820
3821 if files:
yolandyandaabc6d2016-04-18 18:29:393822 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443823 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433824 'Please move them to an appropriate source file so that the ' +
3825 'template gets instantiated in a single compilation unit.',
3826 files) ]
3827 return []
3828
3829
[email protected]fd20b902014-05-09 02:14:533830_DEPRECATED_CSS = [
3831 # Values
3832 ( "-webkit-box", "flex" ),
3833 ( "-webkit-inline-box", "inline-flex" ),
3834 ( "-webkit-flex", "flex" ),
3835 ( "-webkit-inline-flex", "inline-flex" ),
3836 ( "-webkit-min-content", "min-content" ),
3837 ( "-webkit-max-content", "max-content" ),
3838
3839 # Properties
3840 ( "-webkit-background-clip", "background-clip" ),
3841 ( "-webkit-background-origin", "background-origin" ),
3842 ( "-webkit-background-size", "background-size" ),
3843 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443844 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533845
3846 # Functions
3847 ( "-webkit-gradient", "gradient" ),
3848 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3849 ( "-webkit-linear-gradient", "linear-gradient" ),
3850 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3851 ( "-webkit-radial-gradient", "radial-gradient" ),
3852 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3853]
3854
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203855
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493856# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363857def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533858 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253859 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343860 documentation and iOS CSS for dom distiller
3861 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253862 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533863 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493864 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443865 files_to_skip = (_EXCLUDED_PATHS +
3866 _TEST_CODE_EXCLUDED_PATHS +
3867 input_api.DEFAULT_FILES_TO_SKIP +
3868 (r"^chrome/common/extensions/docs",
3869 r"^chrome/docs",
3870 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3871 r"^components/neterror/resources/neterror.css",
3872 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253873 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443874 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533875 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3876 for line_num, line in fpath.ChangedContents():
3877 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023878 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533879 results.append(output_api.PresubmitError(
3880 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3881 (fpath.LocalPath(), line_num, deprecated_value, value)))
3882 return results
3883
mohan.reddyf21db962014-10-16 12:26:473884
Saagar Sanghavifceeaae2020-08-12 16:40:363885def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363886 bad_files = {}
3887 for f in input_api.AffectedFiles(include_deletes=False):
3888 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493889 not f.LocalPath().startswith('third_party/blink') and
3890 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363891 continue
3892
Daniel Bratell65b033262019-04-23 08:17:063893 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363894 continue
3895
Vaclav Brozekd5de76a2018-03-17 07:57:503896 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363897 if "#include" in line and "../" in line]
3898 if not relative_includes:
3899 continue
3900 bad_files[f.LocalPath()] = relative_includes
3901
3902 if not bad_files:
3903 return []
3904
3905 error_descriptions = []
3906 for file_path, bad_lines in bad_files.iteritems():
3907 error_description = file_path
3908 for line in bad_lines:
3909 error_description += '\n ' + line
3910 error_descriptions.append(error_description)
3911
3912 results = []
3913 results.append(output_api.PresubmitError(
3914 'You added one or more relative #include paths (including "../").\n'
3915 'These shouldn\'t be used because they can be used to include headers\n'
3916 'from code that\'s not correctly specified as a dependency in the\n'
3917 'relevant BUILD.gn file(s).',
3918 error_descriptions))
3919
3920 return results
3921
Takeshi Yoshinoe387aa32017-08-02 13:16:133922
Saagar Sanghavifceeaae2020-08-12 16:40:363923def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063924 """Check that nobody tries to include a cc file. It's a relatively
3925 common error which results in duplicate symbols in object
3926 files. This may not always break the build until someone later gets
3927 very confusing linking errors."""
3928 results = []
3929 for f in input_api.AffectedFiles(include_deletes=False):
3930 # We let third_party code do whatever it wants
3931 if (f.LocalPath().startswith('third_party') and
3932 not f.LocalPath().startswith('third_party/blink') and
3933 not f.LocalPath().startswith('third_party\\blink')):
3934 continue
3935
3936 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3937 continue
3938
3939 for _, line in f.ChangedContents():
3940 if line.startswith('#include "'):
3941 included_file = line.split('"')[1]
3942 if _IsCPlusPlusFile(input_api, included_file):
3943 # The most common naming for external files with C++ code,
3944 # apart from standard headers, is to call them foo.inc, but
3945 # Chromium sometimes uses foo-inc.cc so allow that as well.
3946 if not included_file.endswith(('.h', '-inc.cc')):
3947 results.append(output_api.PresubmitError(
3948 'Only header files or .inc files should be included in other\n'
3949 'C++ files. Compiling the contents of a cc file more than once\n'
3950 'will cause duplicate information in the build which may later\n'
3951 'result in strange link_errors.\n' +
3952 f.LocalPath() + ':\n ' +
3953 line))
3954
3955 return results
3956
3957
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203958def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3959 if not isinstance(key, ast.Str):
3960 return 'Key at line %d must be a string literal' % key.lineno
3961 if not isinstance(value, ast.Dict):
3962 return 'Value at line %d must be a dict' % value.lineno
3963 if len(value.keys) != 1:
3964 return 'Dict at line %d must have single entry' % value.lineno
3965 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3966 return (
3967 'Entry at line %d must have a string literal \'filepath\' as key' %
3968 value.lineno)
3969 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133970
Takeshi Yoshinoe387aa32017-08-02 13:16:133971
Sergey Ulanov4af16052018-11-08 02:41:463972def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203973 if not isinstance(key, ast.Str):
3974 return 'Key at line %d must be a string literal' % key.lineno
3975 if not isinstance(value, ast.List):
3976 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463977 for element in value.elts:
3978 if not isinstance(element, ast.Str):
3979 return 'Watchlist elements on line %d is not a string' % key.lineno
3980 if not email_regex.match(element.s):
3981 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3982 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203983 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133984
Takeshi Yoshinoe387aa32017-08-02 13:16:133985
Sergey Ulanov4af16052018-11-08 02:41:463986def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203987 mismatch_template = (
3988 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3989 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133990
Sergey Ulanov4af16052018-11-08 02:41:463991 email_regex = input_api.re.compile(
3992 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3993
3994 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203995 i = 0
3996 last_key = ''
3997 while True:
3998 if i >= len(wd_dict.keys):
3999 if i >= len(w_dict.keys):
4000 return None
4001 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
4002 elif i >= len(w_dict.keys):
4003 return (
4004 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134005
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204006 wd_key = wd_dict.keys[i]
4007 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134008
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204009 result = _CheckWatchlistDefinitionsEntrySyntax(
4010 wd_key, wd_dict.values[i], ast)
4011 if result is not None:
4012 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134013
Sergey Ulanov4af16052018-11-08 02:41:464014 result = _CheckWatchlistsEntrySyntax(
4015 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204016 if result is not None:
4017 return 'Bad entry in WATCHLISTS dict: %s' % result
4018
4019 if wd_key.s != w_key.s:
4020 return mismatch_template % (
4021 '%s at line %d' % (wd_key.s, wd_key.lineno),
4022 '%s at line %d' % (w_key.s, w_key.lineno))
4023
4024 if wd_key.s < last_key:
4025 return (
4026 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4027 (wd_key.lineno, w_key.lineno))
4028 last_key = wd_key.s
4029
4030 i = i + 1
4031
4032
Sergey Ulanov4af16052018-11-08 02:41:464033def _CheckWATCHLISTSSyntax(expression, input_api):
4034 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204035 if not isinstance(expression, ast.Expression):
4036 return 'WATCHLISTS file must contain a valid expression'
4037 dictionary = expression.body
4038 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4039 return 'WATCHLISTS file must have single dict with exactly two entries'
4040
4041 first_key = dictionary.keys[0]
4042 first_value = dictionary.values[0]
4043 second_key = dictionary.keys[1]
4044 second_value = dictionary.values[1]
4045
4046 if (not isinstance(first_key, ast.Str) or
4047 first_key.s != 'WATCHLIST_DEFINITIONS' or
4048 not isinstance(first_value, ast.Dict)):
4049 return (
4050 'The first entry of the dict in WATCHLISTS file must be '
4051 'WATCHLIST_DEFINITIONS dict')
4052
4053 if (not isinstance(second_key, ast.Str) or
4054 second_key.s != 'WATCHLISTS' or
4055 not isinstance(second_value, ast.Dict)):
4056 return (
4057 'The second entry of the dict in WATCHLISTS file must be '
4058 'WATCHLISTS dict')
4059
Sergey Ulanov4af16052018-11-08 02:41:464060 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134061
4062
Saagar Sanghavifceeaae2020-08-12 16:40:364063def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:134064 for f in input_api.AffectedFiles(include_deletes=False):
4065 if f.LocalPath() == 'WATCHLISTS':
4066 contents = input_api.ReadFile(f, 'r')
4067
4068 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204069 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134070 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204071 # Get an AST tree for it and scan the tree for detailed style checking.
4072 expression = input_api.ast.parse(
4073 contents, filename='WATCHLISTS', mode='eval')
4074 except ValueError as e:
4075 return [output_api.PresubmitError(
4076 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4077 except SyntaxError as e:
4078 return [output_api.PresubmitError(
4079 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4080 except TypeError as e:
4081 return [output_api.PresubmitError(
4082 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134083
Sergey Ulanov4af16052018-11-08 02:41:464084 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204085 if result is not None:
4086 return [output_api.PresubmitError(result)]
4087 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134088
4089 return []
4090
4091
Saagar Sanghavifceeaae2020-08-12 16:40:364092def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194093 """Checks that newly added header files have corresponding GN changes.
4094 Note that this is only a heuristic. To be precise, run script:
4095 build/check_gn_headers.py.
4096 """
4097
4098 def headers(f):
4099 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444100 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194101
4102 new_headers = []
4103 for f in input_api.AffectedSourceFiles(headers):
4104 if f.Action() != 'A':
4105 continue
4106 new_headers.append(f.LocalPath())
4107
4108 def gn_files(f):
James Cook24a504192020-07-23 00:08:444109 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194110
4111 all_gn_changed_contents = ''
4112 for f in input_api.AffectedSourceFiles(gn_files):
4113 for _, line in f.ChangedContents():
4114 all_gn_changed_contents += line
4115
4116 problems = []
4117 for header in new_headers:
4118 basename = input_api.os_path.basename(header)
4119 if basename not in all_gn_changed_contents:
4120 problems.append(header)
4121
4122 if problems:
4123 return [output_api.PresubmitPromptWarning(
4124 'Missing GN changes for new header files', items=sorted(problems),
4125 long_text='Please double check whether newly added header files need '
4126 'corresponding changes in gn or gni files.\nThis checking is only a '
4127 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4128 'Read https://crbug.com/661774 for more info.')]
4129 return []
4130
4131
Saagar Sanghavifceeaae2020-08-12 16:40:364132def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024133 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4134
4135 This assumes we won't intentionally reference one product from the other
4136 product.
4137 """
4138 all_problems = []
4139 test_cases = [{
4140 "filename_postfix": "google_chrome_strings.grd",
4141 "correct_name": "Chrome",
4142 "incorrect_name": "Chromium",
4143 }, {
4144 "filename_postfix": "chromium_strings.grd",
4145 "correct_name": "Chromium",
4146 "incorrect_name": "Chrome",
4147 }]
4148
4149 for test_case in test_cases:
4150 problems = []
4151 filename_filter = lambda x: x.LocalPath().endswith(
4152 test_case["filename_postfix"])
4153
4154 # Check each new line. Can yield false positives in multiline comments, but
4155 # easier than trying to parse the XML because messages can have nested
4156 # children, and associating message elements with affected lines is hard.
4157 for f in input_api.AffectedSourceFiles(filename_filter):
4158 for line_num, line in f.ChangedContents():
4159 if "<message" in line or "<!--" in line or "-->" in line:
4160 continue
4161 if test_case["incorrect_name"] in line:
4162 problems.append(
4163 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4164
4165 if problems:
4166 message = (
4167 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4168 % (test_case["correct_name"], test_case["correct_name"],
4169 test_case["incorrect_name"]))
4170 all_problems.append(
4171 output_api.PresubmitPromptWarning(message, items=problems))
4172
4173 return all_problems
4174
4175
Saagar Sanghavifceeaae2020-08-12 16:40:364176def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514177 # TODO(crbug.com/941824): We need to make sure the entries in
4178 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4179 # so that users of //buildtools in other projects get the same tooling
4180 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4181 # support to gclient, we can eliminate the duplication and delete
4182 # this presubmit check.
4183
4184 # Update this regexp if new revisions are added to the files.
4185 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264186 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514187
4188 # If a user is changing one revision, they need to change the same
4189 # line in both files. This means that any given change should contain
4190 # exactly the same list of changed lines that match the regexps. The
4191 # replace(' ', '') call allows us to ignore whitespace changes to the
4192 # lines. The 'long_text' parameter to the error will contain the
4193 # list of changed lines in both files, which should make it easy enough
4194 # to spot the error without going overboard in this implementation.
4195 revs_changes = {
4196 'DEPS': {},
4197 'buildtools/DEPS': {},
4198 }
4199 long_text = ''
4200
4201 for f in input_api.AffectedFiles(
4202 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4203 for line_num, line in f.ChangedContents():
4204 if rev_regexp.search(line):
4205 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4206 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4207
4208 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4209 return [output_api.PresubmitError(
4210 'Change buildtools revisions in sync in both //DEPS and '
4211 '//buildtools/DEPS.', long_text=long_text + '\n')]
4212 else:
4213 return []
4214
4215
Saagar Sanghavifceeaae2020-08-12 16:40:364216def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364217 """Avoid large files, especially binary files, in the repository since
4218 git doesn't scale well for those. They will be in everyone's repo
4219 clones forever, forever making Chromium slower to clone and work
4220 with."""
4221
4222 # Uploading files to cloud storage is not trivial so we don't want
4223 # to set the limit too low, but the upper limit for "normal" large
4224 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4225 # anything over 20 MB is exceptional.
4226 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4227
4228 too_large_files = []
4229 for f in input_api.AffectedFiles():
4230 # Check both added and modified files (but not deleted files).
4231 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384232 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364233 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4234 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4235
4236 if too_large_files:
4237 message = (
4238 'Do not commit large files to git since git scales badly for those.\n' +
4239 'Instead put the large files in cloud storage and use DEPS to\n' +
4240 'fetch them.\n' + '\n'.join(too_large_files)
4241 )
4242 return [output_api.PresubmitError(
4243 'Too large files found in commit', long_text=message + '\n')]
4244 else:
4245 return []
4246
Max Morozb47503b2019-08-08 21:03:274247
Saagar Sanghavifceeaae2020-08-12 16:40:364248def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274249 """Checks specific for fuzz target sources."""
4250 EXPORTED_SYMBOLS = [
4251 'LLVMFuzzerInitialize',
4252 'LLVMFuzzerCustomMutator',
4253 'LLVMFuzzerCustomCrossOver',
4254 'LLVMFuzzerMutate',
4255 ]
4256
4257 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4258
4259 def FilterFile(affected_file):
4260 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444261 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4262 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274263
4264 return input_api.FilterSourceFile(
4265 affected_file,
James Cook24a504192020-07-23 00:08:444266 files_to_check=[files_to_check],
4267 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274268
4269 files_with_missing_header = []
4270 for f in input_api.AffectedSourceFiles(FilterFile):
4271 contents = input_api.ReadFile(f, 'r')
4272 if REQUIRED_HEADER in contents:
4273 continue
4274
4275 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4276 files_with_missing_header.append(f.LocalPath())
4277
4278 if not files_with_missing_header:
4279 return []
4280
4281 long_text = (
4282 'If you define any of the libFuzzer optional functions (%s), it is '
4283 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4284 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4285 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4286 'to access command line arguments passed to the fuzzer. Instead, prefer '
4287 'static initialization and shared resources as documented in '
4288 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4289 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4290 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4291 )
4292
4293 return [output_api.PresubmitPromptWarning(
4294 message="Missing '%s' in:" % REQUIRED_HEADER,
4295 items=files_with_missing_header,
4296 long_text=long_text)]
4297
4298
Mohamed Heikald048240a2019-11-12 16:57:374299def _CheckNewImagesWarning(input_api, output_api):
4300 """
4301 Warns authors who add images into the repo to make sure their images are
4302 optimized before committing.
4303 """
4304 images_added = False
4305 image_paths = []
4306 errors = []
4307 filter_lambda = lambda x: input_api.FilterSourceFile(
4308 x,
James Cook24a504192020-07-23 00:08:444309 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4310 + input_api.DEFAULT_FILES_TO_SKIP),
4311 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374312 )
4313 for f in input_api.AffectedFiles(
4314 include_deletes=False, file_filter=filter_lambda):
4315 local_path = f.LocalPath().lower()
4316 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4317 images_added = True
4318 image_paths.append(f)
4319 if images_added:
4320 errors.append(output_api.PresubmitPromptWarning(
4321 'It looks like you are trying to commit some images. If these are '
4322 'non-test-only images, please make sure to read and apply the tips in '
4323 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4324 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4325 'FYI only and will not block your CL on the CQ.', image_paths))
4326 return errors
4327
4328
Saagar Sanghavifceeaae2020-08-12 16:40:364329def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574330 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224331 results = []
dgnaa68d5e2015-06-10 10:08:224332 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174333 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224334 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294335 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064336 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4337 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424338 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184339 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574340 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374341 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154342 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574343 return results
4344
Saagar Sanghavifceeaae2020-08-12 16:40:364345def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574346 """Groups commit checks that target android code."""
4347 results = []
4348 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224349 return results
4350
Chris Hall59f8d0c72020-05-01 07:31:194351# TODO(chrishall): could we additionally match on any path owned by
4352# ui/accessibility/OWNERS ?
4353_ACCESSIBILITY_PATHS = (
4354 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4355 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4356 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4357 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4358 r"^content[\\/]browser[\\/]accessibility[\\/]",
4359 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4360 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4361 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4362 r"^ui[\\/]accessibility[\\/]",
4363 r"^ui[\\/]views[\\/]accessibility[\\/]",
4364)
4365
Saagar Sanghavifceeaae2020-08-12 16:40:364366def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194367 """Checks that commits to accessibility code contain an AX-Relnotes field in
4368 their commit message."""
4369 def FileFilter(affected_file):
4370 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444371 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194372
4373 # Only consider changes affecting accessibility paths.
4374 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4375 return []
4376
Akihiro Ota08108e542020-05-20 15:30:534377 # AX-Relnotes can appear in either the description or the footer.
4378 # When searching the description, require 'AX-Relnotes:' to appear at the
4379 # beginning of a line.
4380 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4381 description_has_relnotes = any(ax_regex.match(line)
4382 for line in input_api.change.DescriptionText().lower().splitlines())
4383
4384 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4385 'AX-Relnotes', [])
4386 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194387 return []
4388
4389 # TODO(chrishall): link to Relnotes documentation in message.
4390 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4391 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4392 "user-facing changes"
4393 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4394 "user-facing effects"
4395 "\n if this is confusing or annoying then please contact members "
4396 "of ui/accessibility/OWNERS.")
4397
4398 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224399
Saagar Sanghavifceeaae2020-08-12 16:40:364400def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394401 """Checks common to both upload and commit."""
4402 results = []
4403 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384404 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544405 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084406
4407 author = input_api.change.author_email
4408 if author and author not in _KNOWN_ROBOTS:
4409 results.extend(
4410 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4411
[email protected]9f919cc2013-07-31 03:04:044412 results.extend(
4413 input_api.canned_checks.CheckChangeHasNoTabs(
4414 input_api,
4415 output_api,
4416 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434417 results.extend(input_api.RunTests(
4418 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244419
Edward Lesmesce51df52020-08-04 22:10:174420 dirmd_bin = input_api.os_path.join(
4421 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4422 results.extend(input_api.RunTests(
4423 input_api.canned_checks.CheckDirMetadataFormat(
4424 input_api, output_api, dirmd_bin)))
4425 results.extend(
4426 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4427 input_api, output_api))
4428
Vaclav Brozekcdc7defb2018-03-20 09:54:354429 for f in input_api.AffectedFiles():
4430 path, name = input_api.os_path.split(f.LocalPath())
4431 if name == 'PRESUBMIT.py':
4432 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004433 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4434 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074435 # The PRESUBMIT.py file (and the directory containing it) might
4436 # have been affected by being moved or removed, so only try to
4437 # run the tests if they still exist.
4438 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4439 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444440 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394441 return results
[email protected]1f7b4172010-01-28 01:17:344442
[email protected]b337cb5b2011-01-23 21:24:054443
Saagar Sanghavifceeaae2020-08-12 16:40:364444def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494445 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4446 if f.LocalPath().endswith(('.orig', '.rej'))]
4447 if problems:
4448 return [output_api.PresubmitError(
4449 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034450 else:
4451 return []
[email protected]b8079ae4a2012-12-05 19:56:494452
4453
Saagar Sanghavifceeaae2020-08-12 16:40:364454def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214455 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4456 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4457 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074458 include_re = input_api.re.compile(
4459 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4460 extension_re = input_api.re.compile(r'\.[a-z]+$')
4461 errors = []
4462 for f in input_api.AffectedFiles():
4463 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4464 continue
4465 found_line_number = None
4466 found_macro = None
4467 for line_num, line in f.ChangedContents():
4468 match = macro_re.search(line)
4469 if match:
4470 found_line_number = line_num
4471 found_macro = match.group(2)
4472 break
4473 if not found_line_number:
4474 continue
4475
4476 found_include = False
4477 for line in f.NewContents():
4478 if include_re.search(line):
4479 found_include = True
4480 break
4481 if found_include:
4482 continue
4483
4484 if not f.LocalPath().endswith('.h'):
4485 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4486 try:
4487 content = input_api.ReadFile(primary_header_path, 'r')
4488 if include_re.search(content):
4489 continue
4490 except IOError:
4491 pass
4492 errors.append('%s:%d %s macro is used without including build/'
4493 'build_config.h.'
4494 % (f.LocalPath(), found_line_number, found_macro))
4495 if errors:
4496 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4497 return []
4498
4499
[email protected]b00342e7f2013-03-26 16:21:544500def _DidYouMeanOSMacro(bad_macro):
4501 try:
4502 return {'A': 'OS_ANDROID',
4503 'B': 'OS_BSD',
4504 'C': 'OS_CHROMEOS',
4505 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444506 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544507 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444508 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544509 'N': 'OS_NACL',
4510 'O': 'OS_OPENBSD',
4511 'P': 'OS_POSIX',
4512 'S': 'OS_SOLARIS',
4513 'W': 'OS_WIN'}[bad_macro[3].upper()]
4514 except KeyError:
4515 return ''
4516
4517
4518def _CheckForInvalidOSMacrosInFile(input_api, f):
4519 """Check for sensible looking, totally invalid OS macros."""
4520 preprocessor_statement = input_api.re.compile(r'^\s*#')
4521 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4522 results = []
4523 for lnum, line in f.ChangedContents():
4524 if preprocessor_statement.search(line):
4525 for match in os_macro.finditer(line):
4526 if not match.group(1) in _VALID_OS_MACROS:
4527 good = _DidYouMeanOSMacro(match.group(1))
4528 did_you_mean = ' (did you mean %s?)' % good if good else ''
4529 results.append(' %s:%d %s%s' % (f.LocalPath(),
4530 lnum,
4531 match.group(1),
4532 did_you_mean))
4533 return results
4534
4535
Saagar Sanghavifceeaae2020-08-12 16:40:364536def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544537 """Check all affected files for invalid OS macros."""
4538 bad_macros = []
tzik3f295992018-12-04 20:32:234539 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474540 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544541 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4542
4543 if not bad_macros:
4544 return []
4545
4546 return [output_api.PresubmitError(
4547 'Possibly invalid OS macro[s] found. Please fix your code\n'
4548 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4549
lliabraa35bab3932014-10-01 12:16:444550
4551def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4552 """Check all affected files for invalid "if defined" macros."""
4553 ALWAYS_DEFINED_MACROS = (
4554 "TARGET_CPU_PPC",
4555 "TARGET_CPU_PPC64",
4556 "TARGET_CPU_68K",
4557 "TARGET_CPU_X86",
4558 "TARGET_CPU_ARM",
4559 "TARGET_CPU_MIPS",
4560 "TARGET_CPU_SPARC",
4561 "TARGET_CPU_ALPHA",
4562 "TARGET_IPHONE_SIMULATOR",
4563 "TARGET_OS_EMBEDDED",
4564 "TARGET_OS_IPHONE",
4565 "TARGET_OS_MAC",
4566 "TARGET_OS_UNIX",
4567 "TARGET_OS_WIN32",
4568 )
4569 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4570 results = []
4571 for lnum, line in f.ChangedContents():
4572 for match in ifdef_macro.finditer(line):
4573 if match.group(1) in ALWAYS_DEFINED_MACROS:
4574 always_defined = ' %s is always defined. ' % match.group(1)
4575 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4576 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4577 lnum,
4578 always_defined,
4579 did_you_mean))
4580 return results
4581
4582
Saagar Sanghavifceeaae2020-08-12 16:40:364583def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444584 """Check all affected files for invalid "if defined" macros."""
4585 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054586 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444587 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054588 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214589 continue
lliabraa35bab3932014-10-01 12:16:444590 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4591 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4592
4593 if not bad_macros:
4594 return []
4595
4596 return [output_api.PresubmitError(
4597 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4598 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4599 bad_macros)]
4600
4601
Saagar Sanghavifceeaae2020-08-12 16:40:364602def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044603 """Check for same IPC rules described in
4604 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4605 """
4606 base_pattern = r'IPC_ENUM_TRAITS\('
4607 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4608 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4609
4610 problems = []
4611 for f in input_api.AffectedSourceFiles(None):
4612 local_path = f.LocalPath()
4613 if not local_path.endswith('.h'):
4614 continue
4615 for line_number, line in f.ChangedContents():
4616 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4617 problems.append(
4618 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4619
4620 if problems:
4621 return [output_api.PresubmitPromptWarning(
4622 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4623 else:
4624 return []
4625
[email protected]b00342e7f2013-03-26 16:21:544626
Saagar Sanghavifceeaae2020-08-12 16:40:364627def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054628 """Check to make sure no files being submitted have long paths.
4629 This causes issues on Windows.
4630 """
4631 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194632 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054633 local_path = f.LocalPath()
4634 # Windows has a path limit of 260 characters. Limit path length to 200 so
4635 # that we have some extra for the prefix on dev machines and the bots.
4636 if len(local_path) > 200:
4637 problems.append(local_path)
4638
4639 if problems:
4640 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4641 else:
4642 return []
4643
4644
Saagar Sanghavifceeaae2020-08-12 16:40:364645def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144646 """Check that header files have proper guards against multiple inclusion.
4647 If a file should not have such guards (and it probably should) then it
4648 should include the string "no-include-guard-because-multiply-included".
4649 """
Daniel Bratell6a75baef62018-06-04 10:04:454650 def is_chromium_header_file(f):
4651 # We only check header files under the control of the Chromium
4652 # project. That is, those outside third_party apart from
4653 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324654 # We also exclude *_message_generator.h headers as they use
4655 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454656 file_with_path = input_api.os_path.normpath(f.LocalPath())
4657 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324658 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454659 (not file_with_path.startswith('third_party') or
4660 file_with_path.startswith(
4661 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144662
4663 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344664 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144665
4666 errors = []
4667
Daniel Bratell6a75baef62018-06-04 10:04:454668 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144669 guard_name = None
4670 guard_line_number = None
4671 seen_guard_end = False
4672
4673 file_with_path = input_api.os_path.normpath(f.LocalPath())
4674 base_file_name = input_api.os_path.splitext(
4675 input_api.os_path.basename(file_with_path))[0]
4676 upper_base_file_name = base_file_name.upper()
4677
4678 expected_guard = replace_special_with_underscore(
4679 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144680
4681 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574682 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4683 # are too many (1000+) files with slight deviations from the
4684 # coding style. The most important part is that the include guard
4685 # is there, and that it's unique, not the name so this check is
4686 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144687 #
4688 # As code becomes more uniform, this could be made stricter.
4689
4690 guard_name_pattern_list = [
4691 # Anything with the right suffix (maybe with an extra _).
4692 r'\w+_H__?',
4693
Daniel Bratell39b5b062018-05-16 18:09:574694 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144695 r'\w+_h',
4696
4697 # Anything including the uppercase name of the file.
4698 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4699 upper_base_file_name)) + r'\w*',
4700 ]
4701 guard_name_pattern = '|'.join(guard_name_pattern_list)
4702 guard_pattern = input_api.re.compile(
4703 r'#ifndef\s+(' + guard_name_pattern + ')')
4704
4705 for line_number, line in enumerate(f.NewContents()):
4706 if 'no-include-guard-because-multiply-included' in line:
4707 guard_name = 'DUMMY' # To not trigger check outside the loop.
4708 break
4709
4710 if guard_name is None:
4711 match = guard_pattern.match(line)
4712 if match:
4713 guard_name = match.group(1)
4714 guard_line_number = line_number
4715
Daniel Bratell39b5b062018-05-16 18:09:574716 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454717 # don't match the chromium style guide, but new files should
4718 # get it right.
4719 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574720 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144721 errors.append(output_api.PresubmitPromptWarning(
4722 'Header using the wrong include guard name %s' % guard_name,
4723 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574724 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144725 else:
4726 # The line after #ifndef should have a #define of the same name.
4727 if line_number == guard_line_number + 1:
4728 expected_line = '#define %s' % guard_name
4729 if line != expected_line:
4730 errors.append(output_api.PresubmitPromptWarning(
4731 'Missing "%s" for include guard' % expected_line,
4732 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4733 'Expected: %r\nGot: %r' % (expected_line, line)))
4734
4735 if not seen_guard_end and line == '#endif // %s' % guard_name:
4736 seen_guard_end = True
4737 elif seen_guard_end:
4738 if line.strip() != '':
4739 errors.append(output_api.PresubmitPromptWarning(
4740 'Include guard %s not covering the whole file' % (
4741 guard_name), [f.LocalPath()]))
4742 break # Nothing else to check and enough to warn once.
4743
4744 if guard_name is None:
4745 errors.append(output_api.PresubmitPromptWarning(
4746 'Missing include guard %s' % expected_guard,
4747 [f.LocalPath()],
4748 'Missing include guard in %s\n'
4749 'Recommended name: %s\n'
4750 'This check can be disabled by having the string\n'
4751 'no-include-guard-because-multiply-included in the header.' %
4752 (f.LocalPath(), expected_guard)))
4753
4754 return errors
4755
4756
Saagar Sanghavifceeaae2020-08-12 16:40:364757def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234758 """Check source code and known ascii text files for Windows style line
4759 endings.
4760 """
earthdok1b5e0ee2015-03-10 15:19:104761 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234762
4763 file_inclusion_pattern = (
4764 known_text_files,
4765 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4766 )
4767
mostynbb639aca52015-01-07 20:31:234768 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534769 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444770 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534771 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504772 include_file = False
4773 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234774 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504775 include_file = True
4776 if include_file:
4777 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234778
4779 if problems:
4780 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4781 'these files to contain Windows style line endings?\n' +
4782 '\n'.join(problems))]
4783
4784 return []
4785
4786
Saagar Sanghavifceeaae2020-08-12 16:40:364787def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134788 """Checks that all source files use SYSLOG properly."""
4789 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364790 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564791 for line_number, line in f.ChangedContents():
4792 if 'SYSLOG' in line:
4793 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4794
pastarmovj89f7ee12016-09-20 14:58:134795 if syslog_files:
4796 return [output_api.PresubmitPromptWarning(
4797 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4798 ' calls.\nFiles to check:\n', items=syslog_files)]
4799 return []
4800
4801
[email protected]1f7b4172010-01-28 01:17:344802def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364803 if input_api.version < [2, 0, 0]:
4804 return [output_api.PresubmitError("Your depot_tools is out of date. "
4805 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4806 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344807 results = []
scottmg39b29952014-12-08 18:31:284808 results.extend(
jam93a6ee792017-02-08 23:59:224809 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544810 return results
[email protected]ca8d1982009-02-19 16:33:124811
4812
[email protected]1bfb8322014-04-23 01:02:414813def GetTryServerMasterForBot(bot):
4814 """Returns the Try Server master for the given bot.
4815
[email protected]0bb112362014-07-26 04:38:324816 It tries to guess the master from the bot name, but may still fail
4817 and return None. There is no longer a default master.
4818 """
4819 # Potentially ambiguous bot names are listed explicitly.
4820 master_map = {
tandriie5587792016-07-14 00:34:504821 'chromium_presubmit': 'master.tryserver.chromium.linux',
4822 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414823 }
[email protected]0bb112362014-07-26 04:38:324824 master = master_map.get(bot)
4825 if not master:
wnwen4fbaab82016-05-25 12:54:364826 if 'android' in bot:
tandriie5587792016-07-14 00:34:504827 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364828 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504829 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324830 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504831 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324832 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504833 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324834 return master
[email protected]1bfb8322014-04-23 01:02:414835
4836
[email protected]ca8d1982009-02-19 16:33:124837def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364838 if input_api.version < [2, 0, 0]:
4839 return [output_api.PresubmitError("Your depot_tools is out of date. "
4840 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4841 "but your version is %d.%d.%d" % tuple(input_api.version))]
4842
[email protected]fe5f57c52009-06-05 14:25:544843 results = []
[email protected]fe5f57c52009-06-05 14:25:544844 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274845 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344846 input_api,
4847 output_api,
[email protected]2fdd1f362013-01-16 03:56:034848 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274849
jam93a6ee792017-02-08 23:59:224850 results.extend(
4851 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544852 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4853 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384854 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4855 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414856 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4857 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544858 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144859
4860
Saagar Sanghavifceeaae2020-08-12 16:40:364861def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264862 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024863 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4864 # footer is set to true.
4865 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264866 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024867 footer.lower()
4868 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264869 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024870
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144871 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264872 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144873 import sys
4874 from io import StringIO
4875
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144876 new_or_added_paths = set(f.LocalPath()
4877 for f in input_api.AffectedFiles()
4878 if (f.Action() == 'A' or f.Action() == 'M'))
4879 removed_paths = set(f.LocalPath()
4880 for f in input_api.AffectedFiles(include_deletes=True)
4881 if f.Action() == 'D')
4882
4883 affected_grds = [f for f in input_api.AffectedFiles()
Rainhard Findlingfc31844c52020-05-15 09:58:264884 if (f.LocalPath().endswith(('.grd', '.grdp')))]
meacer8c0d3832019-12-26 21:46:164885 if not affected_grds:
4886 return []
4887
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144888 affected_png_paths = [f.AbsoluteLocalPath()
4889 for f in input_api.AffectedFiles()
4890 if (f.LocalPath().endswith('.png'))]
4891
4892 # Check for screenshots. Developers can upload screenshots using
4893 # tools/translation/upload_screenshots.py which finds and uploads
4894 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4895 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4896 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4897 #
4898 # The logic here is as follows:
4899 #
4900 # - If the CL has a .png file under the screenshots directory for a grd
4901 # file, warn the developer. Actual images should never be checked into the
4902 # Chrome repo.
4903 #
4904 # - If the CL contains modified or new messages in grd files and doesn't
4905 # contain the corresponding .sha1 files, warn the developer to add images
4906 # and upload them via tools/translation/upload_screenshots.py.
4907 #
4908 # - If the CL contains modified or new messages in grd files and the
4909 # corresponding .sha1 files, everything looks good.
4910 #
4911 # - If the CL contains removed messages in grd files but the corresponding
4912 # .sha1 files aren't removed, warn the developer to remove them.
4913 unnecessary_screenshots = []
4914 missing_sha1 = []
4915 unnecessary_sha1_files = []
4916
Rainhard Findlingfc31844c52020-05-15 09:58:264917 # This checks verifies that the ICU syntax of messages this CL touched is
4918 # valid, and reports any found syntax errors.
4919 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4920 # without developers being aware of them. Later on, such ICU syntax errors
4921 # break message extraction for translation, hence would block Chromium
4922 # translations until they are fixed.
4923 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144924
4925 def _CheckScreenshotAdded(screenshots_dir, message_id):
4926 sha1_path = input_api.os_path.join(
4927 screenshots_dir, message_id + '.png.sha1')
4928 if sha1_path not in new_or_added_paths:
4929 missing_sha1.append(sha1_path)
4930
4931
4932 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4933 sha1_path = input_api.os_path.join(
4934 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034935 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144936 unnecessary_sha1_files.append(sha1_path)
4937
Rainhard Findlingfc31844c52020-05-15 09:58:264938
4939 def _ValidateIcuSyntax(text, level, signatures):
4940 """Validates ICU syntax of a text string.
4941
4942 Check if text looks similar to ICU and checks for ICU syntax correctness
4943 in this case. Reports various issues with ICU syntax and values of
4944 variants. Supports checking of nested messages. Accumulate information of
4945 each ICU messages found in the text for further checking.
4946
4947 Args:
4948 text: a string to check.
4949 level: a number of current nesting level.
4950 signatures: an accumulator, a list of tuple of (level, variable,
4951 kind, variants).
4952
4953 Returns:
4954 None if a string is not ICU or no issue detected.
4955 A tuple of (message, start index, end index) if an issue detected.
4956 """
4957 valid_types = {
4958 'plural': (frozenset(
4959 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4960 frozenset(['=1', 'other'])),
4961 'selectordinal': (frozenset(
4962 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4963 frozenset(['one', 'other'])),
4964 'select': (frozenset(), frozenset(['other'])),
4965 }
4966
4967 # Check if the message looks like an attempt to use ICU
4968 # plural. If yes - check if its syntax strictly matches ICU format.
4969 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4970 if not like:
4971 signatures.append((level, None, None, None))
4972 return
4973
4974 # Check for valid prefix and suffix
4975 m = re.match(
4976 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4977 r'(plural|selectordinal|select),\s*'
4978 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4979 if not m:
4980 return (('This message looks like an ICU plural, '
4981 'but does not follow ICU syntax.'), like.start(), like.end())
4982 starting, variable, kind, variant_pairs = m.groups()
4983 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4984 if depth:
4985 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4986 len(text))
4987 first = text[0]
4988 ending = text[last_pos:]
4989 if not starting:
4990 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4991 last_pos)
4992 if not ending or '}' not in ending:
4993 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4994 last_pos)
4995 elif first != '{':
4996 return (
4997 ('Invalid ICU format. Extra characters at the start of a complex '
4998 'message (go/icu-message-migration): "%s"') %
4999 starting, 0, len(starting))
5000 elif ending != '}':
5001 return (('Invalid ICU format. Extra characters at the end of a complex '
5002 'message (go/icu-message-migration): "%s"')
5003 % ending, last_pos - 1, len(text) - 1)
5004 if kind not in valid_types:
5005 return (('Unknown ICU message type %s. '
5006 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5007 known, required = valid_types[kind]
5008 defined_variants = set()
5009 for variant, variant_range, value, value_range in variants:
5010 start, end = variant_range
5011 if variant in defined_variants:
5012 return ('Variant "%s" is defined more than once' % variant,
5013 start, end)
5014 elif known and variant not in known:
5015 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5016 start, end)
5017 defined_variants.add(variant)
5018 # Check for nested structure
5019 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5020 if res:
5021 return (res[0], res[1] + value_range[0] + 1,
5022 res[2] + value_range[0] + 1)
5023 missing = required - defined_variants
5024 if missing:
5025 return ('Required variants missing: %s' % ', '.join(missing), 0,
5026 len(text))
5027 signatures.append((level, variable, kind, defined_variants))
5028
5029
5030 def _ParseIcuVariants(text, offset=0):
5031 """Parse variants part of ICU complex message.
5032
5033 Builds a tuple of variant names and values, as well as
5034 their offsets in the input string.
5035
5036 Args:
5037 text: a string to parse
5038 offset: additional offset to add to positions in the text to get correct
5039 position in the complete ICU string.
5040
5041 Returns:
5042 List of tuples, each tuple consist of four fields: variant name,
5043 variant name span (tuple of two integers), variant value, value
5044 span (tuple of two integers).
5045 """
5046 depth, start, end = 0, -1, -1
5047 variants = []
5048 key = None
5049 for idx, char in enumerate(text):
5050 if char == '{':
5051 if not depth:
5052 start = idx
5053 chunk = text[end + 1:start]
5054 key = chunk.strip()
5055 pos = offset + end + 1 + chunk.find(key)
5056 span = (pos, pos + len(key))
5057 depth += 1
5058 elif char == '}':
5059 if not depth:
5060 return variants, depth, offset + idx
5061 depth -= 1
5062 if not depth:
5063 end = idx
5064 variants.append((key, span, text[start:end + 1], (offset + start,
5065 offset + end + 1)))
5066 return variants, depth, offset + end + 1
5067
meacer8c0d3832019-12-26 21:46:165068 try:
5069 old_sys_path = sys.path
5070 sys.path = sys.path + [input_api.os_path.join(
5071 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5072 from helper import grd_helper
5073 finally:
5074 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145075
5076 for f in affected_grds:
5077 file_path = f.LocalPath()
5078 old_id_to_msg_map = {}
5079 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385080 # Note that this code doesn't check if the file has been deleted. This is
5081 # OK because it only uses the old and new file contents and doesn't load
5082 # the file via its path.
5083 # It's also possible that a file's content refers to a renamed or deleted
5084 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5085 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5086 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145087 if file_path.endswith('.grdp'):
5088 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585089 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395090 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145091 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585092 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395093 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145094 else:
meacerff8a9b62019-12-10 19:43:585095 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145096 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585097 old_id_to_msg_map = grd_helper.GetGrdMessages(
5098 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145099 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585100 new_id_to_msg_map = grd_helper.GetGrdMessages(
5101 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145102
Rainhard Findlingd8d04372020-08-13 13:30:095103 grd_name, ext = input_api.os_path.splitext(
5104 input_api.os_path.basename(file_path))
5105 screenshots_dir = input_api.os_path.join(
5106 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5107
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145108 # Compute added, removed and modified message IDs.
5109 old_ids = set(old_id_to_msg_map)
5110 new_ids = set(new_id_to_msg_map)
5111 added_ids = new_ids - old_ids
5112 removed_ids = old_ids - new_ids
5113 modified_ids = set([])
5114 for key in old_ids.intersection(new_ids):
5115 if (old_id_to_msg_map[key].FormatXml()
5116 != new_id_to_msg_map[key].FormatXml()):
Rainhard Findlingd8d04372020-08-13 13:30:095117 sha1_path = input_api.os_path.join(
5118 screenshots_dir, key + '.png.sha1')
5119 if sha1_path not in new_or_added_paths and \
5120 not input_api.os_path.exists(sha1_path):
5121 # This message does not yet have a screenshot. Require one.
5122 modified_ids.add(key)
5123 elif (old_id_to_msg_map[key].ContentsAsXml('', True)
5124 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5125 # The message content itself changed. Require an updated screenshot.
5126 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145127
Rainhard Findlingfc31844c52020-05-15 09:58:265128 if run_screenshot_check:
5129 # Check the screenshot directory for .png files. Warn if there is any.
5130 for png_path in affected_png_paths:
5131 if png_path.startswith(screenshots_dir):
5132 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145133
Rainhard Findlingfc31844c52020-05-15 09:58:265134 for added_id in added_ids:
5135 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145136
Rainhard Findlingfc31844c52020-05-15 09:58:265137 for modified_id in modified_ids:
5138 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145139
Rainhard Findlingfc31844c52020-05-15 09:58:265140 for removed_id in removed_ids:
5141 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5142
5143 # Check new and changed strings for ICU syntax errors.
5144 for key in added_ids.union(modified_ids):
5145 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5146 err = _ValidateIcuSyntax(msg, 0, [])
5147 if err is not None:
5148 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145149
5150 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265151 if run_screenshot_check:
5152 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005153 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265154 'Do not include actual screenshots in the changelist. Run '
5155 'tools/translate/upload_screenshots.py to upload them instead:',
5156 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145157
Rainhard Findlingfc31844c52020-05-15 09:58:265158 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005159 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265160 'You are adding or modifying UI strings.\n'
5161 'To ensure the best translations, take screenshots of the relevant UI '
5162 '(https://g.co/chrome/translation) and add these files to your '
5163 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145164
Rainhard Findlingfc31844c52020-05-15 09:58:265165 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005166 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265167 'You removed strings associated with these files. Remove:',
5168 sorted(unnecessary_sha1_files)))
5169 else:
5170 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5171 'screenshots check.'))
5172
5173 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075174 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265175 'ICU syntax errors were found in the following strings (problems or '
5176 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145177
5178 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125179
5180
Saagar Sanghavifceeaae2020-08-12 16:40:365181def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125182 repo_root=None,
5183 translation_expectations_path=None,
5184 grd_files=None):
5185 import sys
5186 affected_grds = [f for f in input_api.AffectedFiles()
5187 if (f.LocalPath().endswith('.grd') or
5188 f.LocalPath().endswith('.grdp'))]
5189 if not affected_grds:
5190 return []
5191
5192 try:
5193 old_sys_path = sys.path
5194 sys.path = sys.path + [
5195 input_api.os_path.join(
5196 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5197 from helper import git_helper
5198 from helper import translation_helper
5199 finally:
5200 sys.path = old_sys_path
5201
5202 # Check that translation expectations can be parsed and we can get a list of
5203 # translatable grd files. |repo_root| and |translation_expectations_path| are
5204 # only passed by tests.
5205 if not repo_root:
5206 repo_root = input_api.PresubmitLocalPath()
5207 if not translation_expectations_path:
5208 translation_expectations_path = input_api.os_path.join(
5209 repo_root, 'tools', 'gritsettings',
5210 'translation_expectations.pyl')
5211 if not grd_files:
5212 grd_files = git_helper.list_grds_in_repository(repo_root)
5213
5214 try:
5215 translation_helper.get_translatable_grds(repo_root, grd_files,
5216 translation_expectations_path)
5217 except Exception as e:
5218 return [output_api.PresubmitNotifyResult(
5219 'Failed to get a list of translatable grd files. This happens when:\n'
5220 ' - One of the modified grd or grdp files cannot be parsed or\n'
5221 ' - %s is not updated.\n'
5222 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5223 return []
Ken Rockotc31f4832020-05-29 18:58:515224
5225
Saagar Sanghavifceeaae2020-08-12 16:40:365226def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515227 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095228 changed_mojoms = input_api.AffectedFiles(
5229 include_deletes=True,
5230 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515231 delta = []
5232 for mojom in changed_mojoms:
5233 old_contents = ''.join(mojom.OldContents()) or None
5234 new_contents = ''.join(mojom.NewContents()) or None
5235 delta.append({
5236 'filename': mojom.LocalPath(),
5237 'old': '\n'.join(mojom.OldContents()) or None,
5238 'new': '\n'.join(mojom.NewContents()) or None,
5239 })
5240
5241 process = input_api.subprocess.Popen(
5242 [input_api.python_executable,
5243 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5244 'public', 'tools', 'mojom',
5245 'check_stable_mojom_compatibility.py'),
5246 '--src-root', input_api.PresubmitLocalPath()],
5247 stdin=input_api.subprocess.PIPE,
5248 stdout=input_api.subprocess.PIPE,
5249 stderr=input_api.subprocess.PIPE,
5250 universal_newlines=True)
5251 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5252 if process.returncode:
5253 return [output_api.PresubmitError(
5254 'One or more [Stable] mojom definitions appears to have been changed '
5255 'in a way that is not backward-compatible.',
5256 long_text=error)]
5257 return []