blob: be1c69e8a47d1fdbe6983d5654723148f32dca61 [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"""
10
[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[\\/]"
15 r"client_variations_parser.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"
1341# checkouts (e.g. //third_party/catapult).
agrievef32bcc72016-04-04 14:57:401342_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391343 'android_webview/tools/run_cts.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381344 'build/android/devil_chromium.pydeps',
1345 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1346 'build/android/gyp/jinja_template.pydeps',
1347 'build/android/resource_sizes.pydeps',
1348 'build/android/test_runner.pydeps',
1349 'build/android/test_wrapper/logdog_wrapper.pydeps',
1350 'chrome/android/features/create_stripped_java_factory.pydeps',
1351 'testing/scripts/run_android_wpt.pydeps',
1352 'third_party/android_platform/development/scripts/stack.pydeps',
1353]
1354
1355
1356_GENERIC_PYDEPS_FILES = [
David 'Digit' Turner0006f4732018-08-07 07:12:361357 'base/android/jni_generator/jni_generator.pydeps',
1358 'base/android/jni_generator/jni_registration_generator.pydeps',
1359 'build/android/gyp/aar.pydeps',
1360 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271361 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361362 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381363 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361364 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111365 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361366 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361367 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361368 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111369 'build/android/gyp/create_app_bundle_apks.pydeps',
1370 'build/android/gyp/create_app_bundle.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361371 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121372 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221373 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001374 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361375 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591376 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361377 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421378 'build/android/gyp/dex_jdk_libs.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361379 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361380 'build/android/gyp/filter_zip.pydeps',
1381 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361382 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361383 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581384 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361385 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261386 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011387 'build/android/gyp/jetify_jar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361388 'build/android/gyp/lint.pydeps',
1389 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361390 'build/android/gyp/merge_manifest.pydeps',
1391 'build/android/gyp/prepare_resources.pydeps',
1392 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461393 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241394 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361395 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461396 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561397 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361398 'build/android/incremental_install/generate_android_manifest.pydeps',
1399 'build/android/incremental_install/write_installer_json.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361400 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271401 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1402 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001403 'components/cronet/tools/generate_javadoc.pydeps',
1404 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381405 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001406 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381407 'net/tools/testserver/testserver.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421408 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1409 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131410 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191411 ('third_party/blink/renderer/bindings/scripts/'
1412 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061413 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221414 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401415]
1416
wnwenbdc444e2016-05-25 13:44:151417
agrievef32bcc72016-04-04 14:57:401418_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1419
1420
Eric Boren6fd2b932018-01-25 15:05:081421# Bypass the AUTHORS check for these accounts.
1422_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591423 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451424 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591425 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521426 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
1427 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041428 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271429 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041430 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301431 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081432
1433
Daniel Bratell65b033262019-04-23 08:17:061434def _IsCPlusPlusFile(input_api, file_path):
1435 """Returns True if this file contains C++-like code (and not Python,
1436 Go, Java, MarkDown, ...)"""
1437
1438 ext = input_api.os_path.splitext(file_path)[1]
1439 # This list is compatible with CppChecker.IsCppFile but we should
1440 # consider adding ".c" to it. If we do that we can use this function
1441 # at more places in the code.
1442 return ext in (
1443 '.h',
1444 '.cc',
1445 '.cpp',
1446 '.m',
1447 '.mm',
1448 )
1449
1450def _IsCPlusPlusHeaderFile(input_api, file_path):
1451 return input_api.os_path.splitext(file_path)[1] == ".h"
1452
1453
1454def _IsJavaFile(input_api, file_path):
1455 return input_api.os_path.splitext(file_path)[1] == ".java"
1456
1457
1458def _IsProtoFile(input_api, file_path):
1459 return input_api.os_path.splitext(file_path)[1] == ".proto"
1460
[email protected]55459852011-08-10 15:17:191461def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1462 """Attempts to prevent use of functions intended only for testing in
1463 non-testing code. For now this is just a best-effort implementation
1464 that ignores header files and may have some false positives. A
1465 better implementation would probably need a proper C++ parser.
1466 """
1467 # We only scan .cc files and the like, as the declaration of
1468 # for-testing functions in header files are hard to distinguish from
1469 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491470 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191471
jochenc0d4808c2015-07-27 09:25:421472 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191473 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091474 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191475 exclusion_pattern = input_api.re.compile(
1476 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1477 base_function_pattern, base_function_pattern))
1478
1479 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441480 files_to_skip = (_EXCLUDED_PATHS +
1481 _TEST_CODE_EXCLUDED_PATHS +
1482 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191483 return input_api.FilterSourceFile(
1484 affected_file,
James Cook24a504192020-07-23 00:08:441485 files_to_check=file_inclusion_pattern,
1486 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191487
1488 problems = []
1489 for f in input_api.AffectedSourceFiles(FilterFile):
1490 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241491 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031492 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461493 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031494 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191495 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031496 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191497
1498 if problems:
[email protected]f7051d52013-04-02 18:31:421499 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031500 else:
1501 return []
[email protected]55459852011-08-10 15:17:191502
1503
Vaclav Brozek7dbc28c2018-03-27 08:35:231504def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1505 """This is a simplified version of
1506 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1507 """
1508 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1509 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1510 name_pattern = r'ForTest(s|ing)?'
1511 # Describes an occurrence of "ForTest*" inside a // comment.
1512 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501513 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1514 annotation_re = input_api.re.compile(r'@VisibleForTesting\(otherwise')
Vaclav Brozek7dbc28c2018-03-27 08:35:231515 # Catch calls.
1516 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1517 # Ignore definitions. (Comments are ignored separately.)
1518 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1519
1520 problems = []
1521 sources = lambda x: input_api.FilterSourceFile(
1522 x,
James Cook24a504192020-07-23 00:08:441523 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1524 + input_api.DEFAULT_FILES_TO_SKIP),
1525 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231526 )
1527 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1528 local_path = f.LocalPath()
1529 is_inside_javadoc = False
1530 for line_number, line in f.ChangedContents():
1531 if is_inside_javadoc and javadoc_end_re.search(line):
1532 is_inside_javadoc = False
1533 if not is_inside_javadoc and javadoc_start_re.search(line):
1534 is_inside_javadoc = True
1535 if is_inside_javadoc:
1536 continue
1537 if (inclusion_re.search(line) and
1538 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501539 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231540 not exclusion_re.search(line)):
1541 problems.append(
1542 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1543
1544 if problems:
1545 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1546 else:
1547 return []
1548
1549
[email protected]10689ca2011-09-02 02:31:541550def _CheckNoIOStreamInHeaders(input_api, output_api):
1551 """Checks to make sure no .h files include <iostream>."""
1552 files = []
1553 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1554 input_api.re.MULTILINE)
1555 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1556 if not f.LocalPath().endswith('.h'):
1557 continue
1558 contents = input_api.ReadFile(f)
1559 if pattern.search(contents):
1560 files.append(f)
1561
1562 if len(files):
yolandyandaabc6d2016-04-18 18:29:391563 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061564 'Do not #include <iostream> in header files, since it inserts static '
1565 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541566 '#include <ostream>. See http://crbug.com/94794',
1567 files) ]
1568 return []
1569
Danil Chapovalov3518f362018-08-11 16:13:431570def _CheckNoStrCatRedefines(input_api, output_api):
1571 """Checks no windows headers with StrCat redefined are included directly."""
1572 files = []
1573 pattern_deny = input_api.re.compile(
1574 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1575 input_api.re.MULTILINE)
1576 pattern_allow = input_api.re.compile(
1577 r'^#include\s"base/win/windows_defines.inc"',
1578 input_api.re.MULTILINE)
1579 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1580 contents = input_api.ReadFile(f)
1581 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1582 files.append(f.LocalPath())
1583
1584 if len(files):
1585 return [output_api.PresubmitError(
1586 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1587 'directly since they pollute code with StrCat macro. Instead, '
1588 'include matching header from base/win. See http://crbug.com/856536',
1589 files) ]
1590 return []
1591
[email protected]10689ca2011-09-02 02:31:541592
[email protected]72df4e782012-06-21 16:28:181593def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521594 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181595 problems = []
1596 for f in input_api.AffectedFiles():
1597 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1598 continue
1599
1600 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041601 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181602 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1603
1604 if not problems:
1605 return []
1606 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1607 '\n'.join(problems))]
1608
Dominic Battre033531052018-09-24 15:45:341609def _CheckNoDISABLETypoInTests(input_api, output_api):
1610 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1611
1612 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1613 instead of DISABLED_. To filter false positives, reports are only generated
1614 if a corresponding MAYBE_ line exists.
1615 """
1616 problems = []
1617
1618 # The following two patterns are looked for in tandem - is a test labeled
1619 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1620 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1621 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1622
1623 # This is for the case that a test is disabled on all platforms.
1624 full_disable_pattern = input_api.re.compile(
1625 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1626 input_api.re.MULTILINE)
1627
Katie Df13948e2018-09-25 07:33:441628 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341629 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1630 continue
1631
1632 # Search for MABYE_, DISABLE_ pairs.
1633 disable_lines = {} # Maps of test name to line number.
1634 maybe_lines = {}
1635 for line_num, line in f.ChangedContents():
1636 disable_match = disable_pattern.search(line)
1637 if disable_match:
1638 disable_lines[disable_match.group(1)] = line_num
1639 maybe_match = maybe_pattern.search(line)
1640 if maybe_match:
1641 maybe_lines[maybe_match.group(1)] = line_num
1642
1643 # Search for DISABLE_ occurrences within a TEST() macro.
1644 disable_tests = set(disable_lines.keys())
1645 maybe_tests = set(maybe_lines.keys())
1646 for test in disable_tests.intersection(maybe_tests):
1647 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1648
1649 contents = input_api.ReadFile(f)
1650 full_disable_match = full_disable_pattern.search(contents)
1651 if full_disable_match:
1652 problems.append(' %s' % f.LocalPath())
1653
1654 if not problems:
1655 return []
1656 return [
1657 output_api.PresubmitPromptWarning(
1658 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1659 '\n'.join(problems))
1660 ]
1661
[email protected]72df4e782012-06-21 16:28:181662
danakj61c1aa22015-10-26 19:55:521663def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571664 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521665 errors = []
Hans Wennborg944479f2020-06-25 21:39:251666 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521667 input_api.re.MULTILINE)
1668 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1669 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1670 continue
1671 for lnum, line in f.ChangedContents():
1672 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171673 errors.append(output_api.PresubmitError(
1674 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571675 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171676 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521677 return errors
1678
1679
Makoto Shimazu3ad422cd2019-05-08 02:35:141680def _FindHistogramNameInChunk(histogram_name, chunk):
1681 """Tries to find a histogram name or prefix in a line.
1682
1683 Returns the existence of the histogram name, or None if it needs more chunk
1684 to determine."""
mcasasb7440c282015-02-04 14:52:191685 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1686 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141687 if '<affected-histogram' in chunk:
1688 # If the tag is not completed, needs more chunk to get the name.
1689 if not '>' in chunk:
1690 return None
1691 if not 'name="' in chunk:
1692 return False
1693 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1694 # expect the only attribute is the name.
1695 histogram_prefix = chunk.split('"')[1]
1696 return histogram_prefix in histogram_name
1697 # Typically the whole histogram name should in the line.
1698 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191699
1700
1701def _CheckUmaHistogramChanges(input_api, output_api):
1702 """Check that UMA histogram names in touched lines can still be found in other
1703 lines of the patch or in histograms.xml. Note that this check would not catch
1704 the reverse: changes in histograms.xml not matched in the code itself."""
1705 touched_histograms = []
1706 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471707 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1708 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1709 name_pattern = r'"(.*?)"'
1710 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1711 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1712 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1713 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1714 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171715 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191716 for f in input_api.AffectedFiles():
1717 # If histograms.xml itself is modified, keep the modified lines for later.
1718 if f.LocalPath().endswith(('histograms.xml')):
1719 histograms_xml_modifications = f.ChangedContents()
1720 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471721 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1722 single_line_re = single_line_c_re
1723 split_line_prefix_re = split_line_c_prefix_re
1724 elif f.LocalPath().endswith(('java')):
1725 single_line_re = single_line_java_re
1726 split_line_prefix_re = split_line_java_prefix_re
1727 else:
mcasasb7440c282015-02-04 14:52:191728 continue
1729 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171730 if last_line_matched_prefix:
1731 suffix_found = split_line_suffix_re.search(line)
1732 if suffix_found :
1733 touched_histograms.append([suffix_found.group(1), f, line_num])
1734 last_line_matched_prefix = False
1735 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061736 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191737 if found:
1738 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171739 continue
1740 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191741
1742 # Search for the touched histogram names in the local modifications to
1743 # histograms.xml, and, if not found, on the base histograms.xml file.
1744 unmatched_histograms = []
1745 for histogram_info in touched_histograms:
1746 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141747 chunk = ''
mcasasb7440c282015-02-04 14:52:191748 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141749 chunk += line
1750 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1751 if histogram_name_found is None:
1752 continue
1753 chunk = ''
mcasasb7440c282015-02-04 14:52:191754 if histogram_name_found:
1755 break
1756 if not histogram_name_found:
1757 unmatched_histograms.append(histogram_info)
1758
eromanb90c82e7e32015-04-01 15:13:491759 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191760 problems = []
1761 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491762 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191763 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451764 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191765 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141766 chunk = ''
mcasasb7440c282015-02-04 14:52:191767 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141768 chunk += line
1769 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1770 chunk)
1771 if histogram_name_found is None:
1772 continue
1773 chunk = ''
mcasasb7440c282015-02-04 14:52:191774 if histogram_name_found:
1775 break
1776 if not histogram_name_found:
1777 problems.append(' [%s:%d] %s' %
1778 (f.LocalPath(), line_num, histogram_name))
1779
1780 if not problems:
1781 return []
1782 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1783 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491784 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191785
wnwenbdc444e2016-05-25 13:44:151786
yolandyandaabc6d2016-04-18 18:29:391787def _CheckFlakyTestUsage(input_api, output_api):
1788 """Check that FlakyTest annotation is our own instead of the android one"""
1789 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1790 files = []
1791 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1792 if f.LocalPath().endswith('Test.java'):
1793 if pattern.search(input_api.ReadFile(f)):
1794 files.append(f)
1795 if len(files):
1796 return [output_api.PresubmitError(
1797 'Use org.chromium.base.test.util.FlakyTest instead of '
1798 'android.test.FlakyTest',
1799 files)]
1800 return []
mcasasb7440c282015-02-04 14:52:191801
wnwenbdc444e2016-05-25 13:44:151802
[email protected]8ea5d4b2011-09-13 21:49:221803def _CheckNoNewWStrings(input_api, output_api):
1804 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271805 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221806 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201807 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571808 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341809 '/win/' in f.LocalPath() or
1810 'chrome_elf' in f.LocalPath() or
1811 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201812 continue
[email protected]8ea5d4b2011-09-13 21:49:221813
[email protected]a11dbe9b2012-08-07 01:32:581814 allowWString = False
[email protected]b5c24292011-11-28 14:38:201815 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581816 if 'presubmit: allow wstring' in line:
1817 allowWString = True
1818 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271819 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581820 allowWString = False
1821 else:
1822 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221823
[email protected]55463aa62011-10-12 00:48:271824 if not problems:
1825 return []
1826 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581827 ' If you are calling a cross-platform API that accepts a wstring, '
1828 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271829 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221830
1831
[email protected]2a8ac9c2011-10-19 17:20:441832def _CheckNoDEPSGIT(input_api, output_api):
1833 """Make sure .DEPS.git is never modified manually."""
1834 if any(f.LocalPath().endswith('.DEPS.git') for f in
1835 input_api.AffectedFiles()):
1836 return [output_api.PresubmitError(
1837 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1838 'automated system based on what\'s in DEPS and your changes will be\n'
1839 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501840 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1841 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441842 'for more information')]
1843 return []
1844
1845
tandriief664692014-09-23 14:51:471846def _CheckValidHostsInDEPS(input_api, output_api):
1847 """Checks that DEPS file deps are from allowed_hosts."""
1848 # Run only if DEPS file has been modified to annoy fewer bystanders.
1849 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1850 return []
1851 # Outsource work to gclient verify
1852 try:
John Budorickf20c0042019-04-25 23:23:401853 gclient_path = input_api.os_path.join(
1854 input_api.PresubmitLocalPath(),
1855 'third_party', 'depot_tools', 'gclient.py')
1856 input_api.subprocess.check_output(
1857 [input_api.python_executable, gclient_path, 'verify'],
1858 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471859 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201860 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471861 return [output_api.PresubmitError(
1862 'DEPS file must have only git dependencies.',
1863 long_text=error.output)]
1864
1865
Mario Sanchez Prada2472cab2019-09-18 10:58:311866def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1867 type_name, message):
1868 """Helper method for _CheckNoBannedFunctions and _CheckNoDeprecatedMojoTypes.
1869
1870 Returns an string composed of the name of the file, the line number where the
1871 match has been found and the additional text passed as |message| in case the
1872 target type name matches the text inside the line passed as parameter.
1873 """
Peng Huang9c5949a02020-06-11 19:20:541874 result = []
1875
1876 if line.endswith(" nocheck"):
1877 return result
1878
Mario Sanchez Prada2472cab2019-09-18 10:58:311879 matched = False
1880 if type_name[0:1] == '/':
1881 regex = type_name[1:]
1882 if input_api.re.search(regex, line):
1883 matched = True
1884 elif type_name in line:
1885 matched = True
1886
Mario Sanchez Prada2472cab2019-09-18 10:58:311887 if matched:
1888 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1889 for message_line in message:
1890 result.append(' %s' % message_line)
1891
1892 return result
1893
1894
[email protected]127f18ec2012-06-16 05:05:591895def _CheckNoBannedFunctions(input_api, output_api):
1896 """Make sure that banned functions are not used."""
1897 warnings = []
1898 errors = []
1899
James Cook24a504192020-07-23 00:08:441900 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151901 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441902 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151903 if input_api.re.match(item, local_path):
1904 return True
1905 return False
1906
Peter K. Lee6c03ccff2019-07-15 14:40:051907 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541908 local_path = affected_file.LocalPath()
1909 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1910 return False
1911 basename = input_api.os_path.basename(local_path)
1912 if 'ios' in basename.split('_'):
1913 return True
1914 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1915 if sep and 'ios' in local_path.split(sep):
1916 return True
1917 return False
1918
wnwenbdc444e2016-05-25 13:44:151919 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311920 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1921 func_name, message)
1922 if problems:
wnwenbdc444e2016-05-25 13:44:151923 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311924 errors.extend(problems)
1925 else:
1926 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151927
Eric Stevensona9a980972017-09-23 00:04:411928 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1929 for f in input_api.AffectedFiles(file_filter=file_filter):
1930 for line_num, line in f.ChangedContents():
1931 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1932 CheckForMatch(f, line_num, line, func_name, message, error)
1933
[email protected]127f18ec2012-06-16 05:05:591934 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1935 for f in input_api.AffectedFiles(file_filter=file_filter):
1936 for line_num, line in f.ChangedContents():
1937 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151938 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591939
Peter K. Lee6c03ccff2019-07-15 14:40:051940 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541941 for line_num, line in f.ChangedContents():
1942 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1943 CheckForMatch(f, line_num, line, func_name, message, error)
1944
Peter K. Lee6c03ccff2019-07-15 14:40:051945 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1946 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1947 for line_num, line in f.ChangedContents():
1948 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1949 CheckForMatch(f, line_num, line, func_name, message, error)
1950
[email protected]127f18ec2012-06-16 05:05:591951 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1952 for f in input_api.AffectedFiles(file_filter=file_filter):
1953 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491954 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441955 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491956 continue
wnwenbdc444e2016-05-25 13:44:151957 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591958
1959 result = []
1960 if (warnings):
1961 result.append(output_api.PresubmitPromptWarning(
1962 'Banned functions were used.\n' + '\n'.join(warnings)))
1963 if (errors):
1964 result.append(output_api.PresubmitError(
1965 'Banned functions were used.\n' + '\n'.join(errors)))
1966 return result
1967
1968
Michael Thiessen44457642020-02-06 00:24:151969def _CheckAndroidNoBannedImports(input_api, output_api):
1970 """Make sure that banned java imports are not used."""
1971 errors = []
1972
1973 def IsException(path, exceptions):
1974 for exception in exceptions:
1975 if (path.startswith(exception)):
1976 return True
1977 return False
1978
1979 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1980 for f in input_api.AffectedFiles(file_filter=file_filter):
1981 for line_num, line in f.ChangedContents():
1982 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1983 if IsException(f.LocalPath(), exceptions):
1984 continue;
1985 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1986 'import ' + import_name, message)
1987 if problems:
1988 errors.extend(problems)
1989 result = []
1990 if (errors):
1991 result.append(output_api.PresubmitError(
1992 'Banned imports were used.\n' + '\n'.join(errors)))
1993 return result
1994
1995
Mario Sanchez Prada2472cab2019-09-18 10:58:311996def _CheckNoDeprecatedMojoTypes(input_api, output_api):
1997 """Make sure that old Mojo types are not used."""
1998 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571999 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:312000
Mario Sanchez Pradaaab91382019-12-19 08:57:092001 # For any path that is not an "ok" or an "error" path, a warning will be
2002 # raised if deprecated mojo types are found.
2003 ok_paths = ['components/arc']
2004 error_paths = ['third_party/blink', 'content']
2005
Mario Sanchez Prada2472cab2019-09-18 10:58:312006 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2007 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:572008 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:092009 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:312010 continue
2011
2012 for line_num, line in f.ChangedContents():
2013 for func_name, message in _DEPRECATED_MOJO_TYPES:
2014 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
2015 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:572016
Mario Sanchez Prada2472cab2019-09-18 10:58:312017 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:092018 # Raise errors inside |error_paths| and warnings everywhere else.
2019 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:572020 errors.extend(problems)
2021 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:312022 warnings.extend(problems)
2023
2024 result = []
2025 if (warnings):
2026 result.append(output_api.PresubmitPromptWarning(
2027 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:572028 if (errors):
2029 result.append(output_api.PresubmitError(
2030 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:312031 return result
2032
2033
[email protected]6c063c62012-07-11 19:11:062034def _CheckNoPragmaOnce(input_api, output_api):
2035 """Make sure that banned functions are not used."""
2036 files = []
2037 pattern = input_api.re.compile(r'^#pragma\s+once',
2038 input_api.re.MULTILINE)
2039 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2040 if not f.LocalPath().endswith('.h'):
2041 continue
2042 contents = input_api.ReadFile(f)
2043 if pattern.search(contents):
2044 files.append(f)
2045
2046 if files:
2047 return [output_api.PresubmitError(
2048 'Do not use #pragma once in header files.\n'
2049 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2050 files)]
2051 return []
2052
[email protected]127f18ec2012-06-16 05:05:592053
[email protected]e7479052012-09-19 00:26:122054def _CheckNoTrinaryTrueFalse(input_api, output_api):
2055 """Checks to make sure we don't introduce use of foo ? true : false."""
2056 problems = []
2057 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2058 for f in input_api.AffectedFiles():
2059 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2060 continue
2061
2062 for line_num, line in f.ChangedContents():
2063 if pattern.match(line):
2064 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2065
2066 if not problems:
2067 return []
2068 return [output_api.PresubmitPromptWarning(
2069 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2070 '\n'.join(problems))]
2071
2072
[email protected]55f9f382012-07-31 11:02:182073def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282074 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182075 change. Breaking - rules is an error, breaking ! rules is a
2076 warning.
2077 """
mohan.reddyf21db962014-10-16 12:26:472078 import sys
[email protected]55f9f382012-07-31 11:02:182079 # We need to wait until we have an input_api object and use this
2080 # roundabout construct to import checkdeps because this file is
2081 # eval-ed and thus doesn't have __file__.
2082 original_sys_path = sys.path
2083 try:
2084 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472085 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182086 import checkdeps
[email protected]55f9f382012-07-31 11:02:182087 from rules import Rule
2088 finally:
2089 # Restore sys.path to what it was before.
2090 sys.path = original_sys_path
2091
2092 added_includes = []
rhalavati08acd232017-04-03 07:23:282093 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242094 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182095 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062096 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502097 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082098 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062099 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502100 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082101 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062102 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502103 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082104 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182105
[email protected]26385172013-05-09 23:11:352106 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182107
2108 error_descriptions = []
2109 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282110 error_subjects = set()
2111 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:182112 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2113 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082114 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182115 description_with_path = '%s\n %s' % (path, rule_description)
2116 if rule_type == Rule.DISALLOW:
2117 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282118 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182119 else:
2120 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282121 warning_subjects.add("#includes")
2122
2123 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2124 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082125 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282126 description_with_path = '%s\n %s' % (path, rule_description)
2127 if rule_type == Rule.DISALLOW:
2128 error_descriptions.append(description_with_path)
2129 error_subjects.add("imports")
2130 else:
2131 warning_descriptions.append(description_with_path)
2132 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182133
Jinsuk Kim5a092672017-10-24 22:42:242134 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022135 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082136 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242137 description_with_path = '%s\n %s' % (path, rule_description)
2138 if rule_type == Rule.DISALLOW:
2139 error_descriptions.append(description_with_path)
2140 error_subjects.add("imports")
2141 else:
2142 warning_descriptions.append(description_with_path)
2143 warning_subjects.add("imports")
2144
[email protected]55f9f382012-07-31 11:02:182145 results = []
2146 if error_descriptions:
2147 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282148 'You added one or more %s that violate checkdeps rules.'
2149 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182150 error_descriptions))
2151 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422152 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282153 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182154 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282155 '%s? See relevant DEPS file(s) for details and contacts.' %
2156 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182157 warning_descriptions))
2158 return results
2159
2160
[email protected]fbcafe5a2012-08-08 15:31:222161def _CheckFilePermissions(input_api, output_api):
2162 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152163 if input_api.platform == 'win32':
2164 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292165 checkperms_tool = input_api.os_path.join(
2166 input_api.PresubmitLocalPath(),
2167 'tools', 'checkperms', 'checkperms.py')
2168 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472169 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392170 with input_api.CreateTemporaryFile() as file_list:
2171 for f in input_api.AffectedFiles():
2172 # checkperms.py file/directory arguments must be relative to the
2173 # repository.
2174 file_list.write(f.LocalPath() + '\n')
2175 file_list.close()
2176 args += ['--file-list', file_list.name]
2177 try:
2178 input_api.subprocess.check_output(args)
2179 return []
2180 except input_api.subprocess.CalledProcessError as error:
2181 return [output_api.PresubmitError(
2182 'checkperms.py failed:',
2183 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222184
2185
[email protected]c8278b32012-10-30 20:35:492186def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
2187 """Makes sure we don't include ui/aura/window_property.h
2188 in header files.
2189 """
2190 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2191 errors = []
2192 for f in input_api.AffectedFiles():
2193 if not f.LocalPath().endswith('.h'):
2194 continue
2195 for line_num, line in f.ChangedContents():
2196 if pattern.match(line):
2197 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2198
2199 results = []
2200 if errors:
2201 results.append(output_api.PresubmitError(
2202 'Header files should not include ui/aura/window_property.h', errors))
2203 return results
2204
2205
[email protected]70ca77752012-11-20 03:45:032206def _CheckForVersionControlConflictsInFile(input_api, f):
2207 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2208 errors = []
2209 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162210 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232211 # First-level headers in markdown look a lot like version control
2212 # conflict markers. http://daringfireball.net/projects/markdown/basics
2213 continue
[email protected]70ca77752012-11-20 03:45:032214 if pattern.match(line):
2215 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2216 return errors
2217
2218
2219def _CheckForVersionControlConflicts(input_api, output_api):
2220 """Usually this is not intentional and will cause a compile failure."""
2221 errors = []
2222 for f in input_api.AffectedFiles():
2223 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2224
2225 results = []
2226 if errors:
2227 results.append(output_api.PresubmitError(
2228 'Version control conflict markers found, please resolve.', errors))
2229 return results
2230
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202231
estadee17314a02017-01-12 16:22:162232def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2233 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2234 errors = []
2235 for f in input_api.AffectedFiles():
2236 for line_num, line in f.ChangedContents():
2237 if pattern.search(line):
2238 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2239
2240 results = []
2241 if errors:
2242 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502243 'Found Google support URL addressed by answer number. Please replace '
2244 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162245 return results
2246
[email protected]70ca77752012-11-20 03:45:032247
[email protected]06e6d0ff2012-12-11 01:36:442248def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2249 def FilterFile(affected_file):
2250 """Filter function for use with input_api.AffectedSourceFiles,
2251 below. This filters out everything except non-test files from
2252 top-level directories that generally speaking should not hard-code
2253 service URLs (e.g. src/android_webview/, src/content/ and others).
2254 """
2255 return input_api.FilterSourceFile(
2256 affected_file,
James Cook24a504192020-07-23 00:08:442257 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2258 files_to_skip=(_EXCLUDED_PATHS +
2259 _TEST_CODE_EXCLUDED_PATHS +
2260 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442261
reillyi38965732015-11-16 18:27:332262 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2263 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462264 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2265 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442266 problems = [] # items are (filename, line_number, line)
2267 for f in input_api.AffectedSourceFiles(FilterFile):
2268 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462269 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442270 problems.append((f.LocalPath(), line_num, line))
2271
2272 if problems:
[email protected]f7051d52013-04-02 18:31:422273 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442274 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582275 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442276 [' %s:%d: %s' % (
2277 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032278 else:
2279 return []
[email protected]06e6d0ff2012-12-11 01:36:442280
2281
James Cook6b6597c2019-11-06 22:05:292282def _CheckChromeOsSyncedPrefRegistration(input_api, output_api):
2283 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2284 def FileFilter(affected_file):
2285 """Includes directories known to be Chrome OS only."""
2286 return input_api.FilterSourceFile(
2287 affected_file,
James Cook24a504192020-07-23 00:08:442288 files_to_check=('^ash/',
2289 '^chromeos/', # Top-level src/chromeos.
2290 '/chromeos/', # Any path component.
2291 '^components/arc',
2292 '^components/exo'),
2293 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292294
2295 prefs = []
2296 priority_prefs = []
2297 for f in input_api.AffectedFiles(file_filter=FileFilter):
2298 for line_num, line in f.ChangedContents():
2299 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2300 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2301 prefs.append(' %s' % line)
2302 if input_api.re.search(
2303 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2304 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2305 priority_prefs.append(' %s' % line)
2306
2307 results = []
2308 if (prefs):
2309 results.append(output_api.PresubmitPromptWarning(
2310 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2311 'by browser sync settings. If these prefs should be controlled by OS '
2312 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2313 if (priority_prefs):
2314 results.append(output_api.PresubmitPromptWarning(
2315 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2316 'controlled by browser sync settings. If these prefs should be '
2317 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2318 'instead.\n' + '\n'.join(prefs)))
2319 return results
2320
2321
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492322# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272323def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2324 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312325 The native_client_sdk directory is excluded because it has auto-generated PNG
2326 files for documentation.
[email protected]d2530012013-01-25 16:39:272327 """
[email protected]d2530012013-01-25 16:39:272328 errors = []
James Cook24a504192020-07-23 00:08:442329 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2330 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312331 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442332 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312333 for f in input_api.AffectedFiles(include_deletes=False,
2334 file_filter=file_filter):
2335 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272336
2337 results = []
2338 if errors:
2339 results.append(output_api.PresubmitError(
2340 'The name of PNG files should not have abbreviations. \n'
2341 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2342 'Contact [email protected] if you have questions.', errors))
2343 return results
2344
2345
Daniel Cheng4dcdb6b2017-04-13 08:30:172346def _ExtractAddRulesFromParsedDeps(parsed_deps):
2347 """Extract the rules that add dependencies from a parsed DEPS file.
2348
2349 Args:
2350 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2351 add_rules = set()
2352 add_rules.update([
2353 rule[1:] for rule in parsed_deps.get('include_rules', [])
2354 if rule.startswith('+') or rule.startswith('!')
2355 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502356 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172357 {}).iteritems():
2358 add_rules.update([
2359 rule[1:] for rule in rules
2360 if rule.startswith('+') or rule.startswith('!')
2361 ])
2362 return add_rules
2363
2364
2365def _ParseDeps(contents):
2366 """Simple helper for parsing DEPS files."""
2367 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172368 class _VarImpl:
2369
2370 def __init__(self, local_scope):
2371 self._local_scope = local_scope
2372
2373 def Lookup(self, var_name):
2374 """Implements the Var syntax."""
2375 try:
2376 return self._local_scope['vars'][var_name]
2377 except KeyError:
2378 raise Exception('Var is not defined: %s' % var_name)
2379
2380 local_scope = {}
2381 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172382 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592383 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172384 }
2385 exec contents in global_scope, local_scope
2386 return local_scope
2387
2388
2389def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082390 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412391 a set of DEPS entries that we should look up.
2392
2393 For a directory (rather than a specific filename) we fake a path to
2394 a specific filename by adding /DEPS. This is chosen as a file that
2395 will seldom or never be subject to per-file include_rules.
2396 """
[email protected]2b438d62013-11-14 17:54:142397 # We ignore deps entries on auto-generated directories.
2398 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082399
Daniel Cheng4dcdb6b2017-04-13 08:30:172400 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2401 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2402
2403 added_deps = new_deps.difference(old_deps)
2404
[email protected]2b438d62013-11-14 17:54:142405 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172406 for added_dep in added_deps:
2407 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2408 continue
2409 # Assume that a rule that ends in .h is a rule for a specific file.
2410 if added_dep.endswith('.h'):
2411 results.add(added_dep)
2412 else:
2413 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082414 return results
2415
2416
[email protected]e871964c2013-05-13 14:14:552417def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2418 """When a dependency prefixed with + is added to a DEPS file, we
2419 want to make sure that the change is reviewed by an OWNER of the
2420 target file or directory, to avoid layering violations from being
2421 introduced. This check verifies that this happens.
2422 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172423 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242424
2425 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492426 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242427 for f in input_api.AffectedFiles(include_deletes=False,
2428 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552429 filename = input_api.os_path.basename(f.LocalPath())
2430 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172431 virtual_depended_on_files.update(_CalculateAddedDeps(
2432 input_api.os_path,
2433 '\n'.join(f.OldContents()),
2434 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552435
[email protected]e871964c2013-05-13 14:14:552436 if not virtual_depended_on_files:
2437 return []
2438
2439 if input_api.is_committing:
2440 if input_api.tbr:
2441 return [output_api.PresubmitNotifyResult(
2442 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272443 if input_api.dry_run:
2444 return [output_api.PresubmitNotifyResult(
2445 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552446 if not input_api.change.issue:
2447 return [output_api.PresubmitError(
2448 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402449 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552450 output = output_api.PresubmitError
2451 else:
2452 output = output_api.PresubmitNotifyResult
2453
2454 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502455 owner_email, reviewers = (
2456 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2457 input_api,
2458 owners_db.email_regexp,
2459 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552460
2461 owner_email = owner_email or input_api.change.author_email
2462
[email protected]de4f7d22013-05-23 14:27:462463 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512464 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462465 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552466 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2467 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412468
2469 # We strip the /DEPS part that was added by
2470 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2471 # directory.
2472 def StripDeps(path):
2473 start_deps = path.rfind('/DEPS')
2474 if start_deps != -1:
2475 return path[:start_deps]
2476 else:
2477 return path
2478 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552479 for path in missing_files]
2480
2481 if unapproved_dependencies:
2482 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152483 output('You need LGTM from owners of depends-on paths in DEPS that were '
2484 'modified in this CL:\n %s' %
2485 '\n '.join(sorted(unapproved_dependencies)))]
2486 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2487 output_list.append(output(
2488 'Suggested missing target path OWNERS:\n %s' %
2489 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552490 return output_list
2491
2492 return []
2493
2494
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492495# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402496def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492497 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442498 files_to_skip = (_EXCLUDED_PATHS +
2499 _TEST_CODE_EXCLUDED_PATHS +
2500 input_api.DEFAULT_FILES_TO_SKIP +
2501 (r"^base[\\/]logging\.h$",
2502 r"^base[\\/]logging\.cc$",
2503 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2504 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2505 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2506 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2507 r"startup_browser_creator\.cc$",
2508 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2509 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2510 r"diagnostics_writer\.cc$",
2511 r"^chrome[\\/]chrome_cleaner[\\/].*",
2512 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2513 r"dll_hash_main\.cc$",
2514 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2515 r"^chromecast[\\/]",
2516 r"^cloud_print[\\/]",
2517 r"^components[\\/]browser_watcher[\\/]"
2518 r"dump_stability_report_main_win.cc$",
2519 r"^components[\\/]media_control[\\/]renderer[\\/]"
2520 r"media_playback_options\.cc$",
2521 r"^components[\\/]zucchini[\\/].*",
2522 # TODO(peter): Remove exception. https://crbug.com/534537
2523 r"^content[\\/]browser[\\/]notifications[\\/]"
2524 r"notification_event_dispatcher_impl\.cc$",
2525 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2526 r"gl_helper_benchmark\.cc$",
2527 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2528 r"^courgette[\\/]courgette_tool\.cc$",
2529 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2530 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2531 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2532 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2533 r"^ipc[\\/]ipc_logging\.cc$",
2534 r"^native_client_sdk[\\/]",
2535 r"^remoting[\\/]base[\\/]logging\.h$",
2536 r"^remoting[\\/]host[\\/].*",
2537 r"^sandbox[\\/]linux[\\/].*",
2538 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2539 r"dump_file_system.cc$",
2540 r"^tools[\\/]",
2541 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2542 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2543 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2544 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2545 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402546 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442547 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402548
thomasanderson625d3932017-03-29 07:16:582549 log_info = set([])
2550 printf = set([])
[email protected]85218562013-11-22 07:41:402551
2552 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582553 for _, line in f.ChangedContents():
2554 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2555 log_info.add(f.LocalPath())
2556 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2557 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372558
thomasanderson625d3932017-03-29 07:16:582559 if input_api.re.search(r"\bprintf\(", line):
2560 printf.add(f.LocalPath())
2561 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2562 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402563
2564 if log_info:
2565 return [output_api.PresubmitError(
2566 'These files spam the console log with LOG(INFO):',
2567 items=log_info)]
2568 if printf:
2569 return [output_api.PresubmitError(
2570 'These files spam the console log with printf/fprintf:',
2571 items=printf)]
2572 return []
2573
2574
[email protected]49aa76a2013-12-04 06:59:162575def _CheckForAnonymousVariables(input_api, output_api):
2576 """These types are all expected to hold locks while in scope and
2577 so should never be anonymous (which causes them to be immediately
2578 destroyed)."""
2579 they_who_must_be_named = [
2580 'base::AutoLock',
2581 'base::AutoReset',
2582 'base::AutoUnlock',
2583 'SkAutoAlphaRestore',
2584 'SkAutoBitmapShaderInstall',
2585 'SkAutoBlitterChoose',
2586 'SkAutoBounderCommit',
2587 'SkAutoCallProc',
2588 'SkAutoCanvasRestore',
2589 'SkAutoCommentBlock',
2590 'SkAutoDescriptor',
2591 'SkAutoDisableDirectionCheck',
2592 'SkAutoDisableOvalCheck',
2593 'SkAutoFree',
2594 'SkAutoGlyphCache',
2595 'SkAutoHDC',
2596 'SkAutoLockColors',
2597 'SkAutoLockPixels',
2598 'SkAutoMalloc',
2599 'SkAutoMaskFreeImage',
2600 'SkAutoMutexAcquire',
2601 'SkAutoPathBoundsUpdate',
2602 'SkAutoPDFRelease',
2603 'SkAutoRasterClipValidate',
2604 'SkAutoRef',
2605 'SkAutoTime',
2606 'SkAutoTrace',
2607 'SkAutoUnref',
2608 ]
2609 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2610 # bad: base::AutoLock(lock.get());
2611 # not bad: base::AutoLock lock(lock.get());
2612 bad_pattern = input_api.re.compile(anonymous)
2613 # good: new base::AutoLock(lock.get())
2614 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2615 errors = []
2616
2617 for f in input_api.AffectedFiles():
2618 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2619 continue
2620 for linenum, line in f.ChangedContents():
2621 if bad_pattern.search(line) and not good_pattern.search(line):
2622 errors.append('%s:%d' % (f.LocalPath(), linenum))
2623
2624 if errors:
2625 return [output_api.PresubmitError(
2626 'These lines create anonymous variables that need to be named:',
2627 items=errors)]
2628 return []
2629
2630
Peter Kasting4844e46e2018-02-23 07:27:102631def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532632 # Returns whether |template_str| is of the form <T, U...> for some types T
2633 # and U. Assumes that |template_str| is already in the form <...>.
2634 def HasMoreThanOneArg(template_str):
2635 # Level of <...> nesting.
2636 nesting = 0
2637 for c in template_str:
2638 if c == '<':
2639 nesting += 1
2640 elif c == '>':
2641 nesting -= 1
2642 elif c == ',' and nesting == 1:
2643 return True
2644 return False
2645
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492646 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102647 sources = lambda affected_file: input_api.FilterSourceFile(
2648 affected_file,
James Cook24a504192020-07-23 00:08:442649 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2650 input_api.DEFAULT_FILES_TO_SKIP),
2651 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552652
2653 # Pattern to capture a single "<...>" block of template arguments. It can
2654 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2655 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2656 # latter would likely require counting that < and > match, which is not
2657 # expressible in regular languages. Should the need arise, one can introduce
2658 # limited counting (matching up to a total number of nesting depth), which
2659 # should cover all practical cases for already a low nesting limit.
2660 template_arg_pattern = (
2661 r'<[^>]*' # Opening block of <.
2662 r'>([^<]*>)?') # Closing block of >.
2663 # Prefix expressing that whatever follows is not already inside a <...>
2664 # block.
2665 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102666 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552667 not_inside_template_arg_pattern
2668 + r'\bstd::unique_ptr'
2669 + template_arg_pattern
2670 + r'\(\)')
2671
2672 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2673 template_arg_no_array_pattern = (
2674 r'<[^>]*[^]]' # Opening block of <.
2675 r'>([^(<]*[^]]>)?') # Closing block of >.
2676 # Prefix saying that what follows is the start of an expression.
2677 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2678 # Suffix saying that what follows are call parentheses with a non-empty list
2679 # of arguments.
2680 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532681 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552682 return_construct_pattern = input_api.re.compile(
2683 start_of_expr_pattern
2684 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532685 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552686 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532687 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552688 + nonempty_arg_list_pattern)
2689
Vaclav Brozek851d9602018-04-04 16:13:052690 problems_constructor = []
2691 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102692 for f in input_api.AffectedSourceFiles(sources):
2693 for line_number, line in f.ChangedContents():
2694 # Disallow:
2695 # return std::unique_ptr<T>(foo);
2696 # bar = std::unique_ptr<T>(foo);
2697 # But allow:
2698 # return std::unique_ptr<T[]>(foo);
2699 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532700 # And also allow cases when the second template argument is present. Those
2701 # cases cannot be handled by std::make_unique:
2702 # return std::unique_ptr<T, U>(foo);
2703 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052704 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532705 return_construct_result = return_construct_pattern.search(line)
2706 if return_construct_result and not HasMoreThanOneArg(
2707 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052708 problems_constructor.append(
2709 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102710 # Disallow:
2711 # std::unique_ptr<T>()
2712 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052713 problems_nullptr.append(
2714 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2715
2716 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162717 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052718 errors.append(output_api.PresubmitError(
2719 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162720 problems_nullptr))
2721 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052722 errors.append(output_api.PresubmitError(
2723 'The following files use explicit std::unique_ptr constructor.'
2724 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162725 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102726 return errors
2727
2728
[email protected]999261d2014-03-03 20:08:082729def _CheckUserActionUpdate(input_api, output_api):
2730 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522731 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082732 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522733 # If actions.xml is already included in the changelist, the PRESUBMIT
2734 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082735 return []
2736
[email protected]999261d2014-03-03 20:08:082737 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2738 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522739 current_actions = None
[email protected]999261d2014-03-03 20:08:082740 for f in input_api.AffectedFiles(file_filter=file_filter):
2741 for line_num, line in f.ChangedContents():
2742 match = input_api.re.search(action_re, line)
2743 if match:
[email protected]2f92dec2014-03-07 19:21:522744 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2745 # loaded only once.
2746 if not current_actions:
2747 with open('tools/metrics/actions/actions.xml') as actions_f:
2748 current_actions = actions_f.read()
2749 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082750 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522751 action = 'name="{0}"'.format(action_name)
2752 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082753 return [output_api.PresubmitPromptWarning(
2754 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522755 'tools/metrics/actions/actions.xml. Please run '
2756 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082757 % (f.LocalPath(), line_num, action_name))]
2758 return []
2759
2760
Daniel Cheng13ca61a882017-08-25 15:11:252761def _ImportJSONCommentEater(input_api):
2762 import sys
2763 sys.path = sys.path + [input_api.os_path.join(
2764 input_api.PresubmitLocalPath(),
2765 'tools', 'json_comment_eater')]
2766 import json_comment_eater
2767 return json_comment_eater
2768
2769
[email protected]99171a92014-06-03 08:44:472770def _GetJSONParseError(input_api, filename, eat_comments=True):
2771 try:
2772 contents = input_api.ReadFile(filename)
2773 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252774 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132775 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472776
2777 input_api.json.loads(contents)
2778 except ValueError as e:
2779 return e
2780 return None
2781
2782
2783def _GetIDLParseError(input_api, filename):
2784 try:
2785 contents = input_api.ReadFile(filename)
2786 idl_schema = input_api.os_path.join(
2787 input_api.PresubmitLocalPath(),
2788 'tools', 'json_schema_compiler', 'idl_schema.py')
2789 process = input_api.subprocess.Popen(
2790 [input_api.python_executable, idl_schema],
2791 stdin=input_api.subprocess.PIPE,
2792 stdout=input_api.subprocess.PIPE,
2793 stderr=input_api.subprocess.PIPE,
2794 universal_newlines=True)
2795 (_, error) = process.communicate(input=contents)
2796 return error or None
2797 except ValueError as e:
2798 return e
2799
2800
2801def _CheckParseErrors(input_api, output_api):
2802 """Check that IDL and JSON files do not contain syntax errors."""
2803 actions = {
2804 '.idl': _GetIDLParseError,
2805 '.json': _GetJSONParseError,
2806 }
[email protected]99171a92014-06-03 08:44:472807 # Most JSON files are preprocessed and support comments, but these do not.
2808 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042809 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472810 ]
2811 # Only run IDL checker on files in these directories.
2812 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042813 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2814 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472815 ]
2816
2817 def get_action(affected_file):
2818 filename = affected_file.LocalPath()
2819 return actions.get(input_api.os_path.splitext(filename)[1])
2820
[email protected]99171a92014-06-03 08:44:472821 def FilterFile(affected_file):
2822 action = get_action(affected_file)
2823 if not action:
2824 return False
2825 path = affected_file.LocalPath()
2826
Erik Staab2dd72b12020-04-16 15:03:402827 if _MatchesFile(input_api,
2828 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2829 path):
[email protected]99171a92014-06-03 08:44:472830 return False
2831
2832 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162833 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472834 return False
2835 return True
2836
2837 results = []
2838 for affected_file in input_api.AffectedFiles(
2839 file_filter=FilterFile, include_deletes=False):
2840 action = get_action(affected_file)
2841 kwargs = {}
2842 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162843 _MatchesFile(input_api, json_no_comments_patterns,
2844 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472845 kwargs['eat_comments'] = False
2846 parse_error = action(input_api,
2847 affected_file.AbsoluteLocalPath(),
2848 **kwargs)
2849 if parse_error:
2850 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2851 (affected_file.LocalPath(), parse_error)))
2852 return results
2853
2854
[email protected]760deea2013-12-10 19:33:492855def _CheckJavaStyle(input_api, output_api):
2856 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472857 import sys
[email protected]760deea2013-12-10 19:33:492858 original_sys_path = sys.path
2859 try:
2860 sys.path = sys.path + [input_api.os_path.join(
2861 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2862 import checkstyle
2863 finally:
2864 # Restore sys.path to what it was before.
2865 sys.path = original_sys_path
2866
2867 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092868 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442869 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492870
2871
Nate Fischerdfd9812e2019-07-18 22:03:002872def _CheckPythonDevilInit(input_api, output_api):
2873 """Checks to make sure devil is initialized correctly in python scripts."""
2874 script_common_initialize_pattern = input_api.re.compile(
2875 r'script_common\.InitializeEnvironment\(')
2876 devil_env_config_initialize = input_api.re.compile(
2877 r'devil_env\.config\.Initialize\(')
2878
2879 errors = []
2880
2881 sources = lambda affected_file: input_api.FilterSourceFile(
2882 affected_file,
James Cook24a504192020-07-23 00:08:442883 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2884 (r'^build[\\/]android[\\/]devil_chromium\.py',
2885 r'^third_party[\\/].*',)),
2886 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002887
2888 for f in input_api.AffectedSourceFiles(sources):
2889 for line_num, line in f.ChangedContents():
2890 if (script_common_initialize_pattern.search(line) or
2891 devil_env_config_initialize.search(line)):
2892 errors.append("%s:%d" % (f.LocalPath(), line_num))
2893
2894 results = []
2895
2896 if errors:
2897 results.append(output_api.PresubmitError(
2898 'Devil initialization should always be done using '
2899 'devil_chromium.Initialize() in the chromium project, to use better '
2900 'defaults for dependencies (ex. up-to-date version of adb).',
2901 errors))
2902
2903 return results
2904
2905
Sean Kau46e29bc2017-08-28 16:31:162906def _MatchesFile(input_api, patterns, path):
2907 for pattern in patterns:
2908 if input_api.re.search(pattern, path):
2909 return True
2910 return False
2911
2912
Daniel Cheng7052cdf2017-11-21 19:23:292913def _GetOwnersFilesToCheckForIpcOwners(input_api):
2914 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172915
Daniel Cheng7052cdf2017-11-21 19:23:292916 Returns:
2917 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2918 contain to cover IPC-related files with noparent reviewer rules.
2919 """
2920 # Whether or not a file affects IPC is (mostly) determined by a simple list
2921 # of filename patterns.
dchenge07de812016-06-20 19:27:172922 file_patterns = [
palmerb19a0932017-01-24 04:00:312923 # Legacy IPC:
dchenge07de812016-06-20 19:27:172924 '*_messages.cc',
2925 '*_messages*.h',
2926 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312927 # Mojo IPC:
dchenge07de812016-06-20 19:27:172928 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472929 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172930 '*_struct_traits*.*',
2931 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312932 '*.typemap',
2933 # Android native IPC:
2934 '*.aidl',
2935 # Blink uses a different file naming convention:
2936 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472937 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172938 '*StructTraits*.*',
2939 '*TypeConverter*.*',
2940 ]
2941
scottmg7a6ed5ba2016-11-04 18:22:042942 # These third_party directories do not contain IPCs, but contain files
2943 # matching the above patterns, which trigger false positives.
2944 exclude_paths = [
2945 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162946 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232947 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292948 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542949 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162950 # These files are just used to communicate between class loaders running
2951 # in the same process.
2952 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572953 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2954
scottmg7a6ed5ba2016-11-04 18:22:042955 ]
2956
dchenge07de812016-06-20 19:27:172957 # Dictionary mapping an OWNERS file path to Patterns.
2958 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2959 # rules ) to a PatternEntry.
2960 # PatternEntry is a dictionary with two keys:
2961 # - 'files': the files that are matched by this pattern
2962 # - 'rules': the per-file rules needed for this pattern
2963 # For example, if we expect OWNERS file to contain rules for *.mojom and
2964 # *_struct_traits*.*, Patterns might look like this:
2965 # {
2966 # '*.mojom': {
2967 # 'files': ...,
2968 # 'rules': [
2969 # 'per-file *.mojom=set noparent',
2970 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2971 # ],
2972 # },
2973 # '*_struct_traits*.*': {
2974 # 'files': ...,
2975 # 'rules': [
2976 # 'per-file *_struct_traits*.*=set noparent',
2977 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2978 # ],
2979 # },
2980 # }
2981 to_check = {}
2982
Daniel Cheng13ca61a882017-08-25 15:11:252983 def AddPatternToCheck(input_file, pattern):
2984 owners_file = input_api.os_path.join(
2985 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2986 if owners_file not in to_check:
2987 to_check[owners_file] = {}
2988 if pattern not in to_check[owners_file]:
2989 to_check[owners_file][pattern] = {
2990 'files': [],
2991 'rules': [
2992 'per-file %s=set noparent' % pattern,
2993 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2994 ]
2995 }
Vaclav Brozekd5de76a2018-03-17 07:57:502996 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252997
dchenge07de812016-06-20 19:27:172998 # Iterate through the affected files to see what we actually need to check
2999 # for. We should only nag patch authors about per-file rules if a file in that
3000 # directory would match that pattern. If a directory only contains *.mojom
3001 # files and no *_messages*.h files, we should only nag about rules for
3002 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:253003 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:263004 # Manifest files don't have a strong naming convention. Instead, try to find
3005 # affected .cc and .h files which look like they contain a manifest
3006 # definition.
3007 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3008 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3009 if (manifest_pattern.search(f.LocalPath()) and not
3010 test_manifest_pattern.search(f.LocalPath())):
3011 # We expect all actual service manifest files to contain at least one
3012 # qualified reference to service_manager::Manifest.
3013 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:253014 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:173015 for pattern in file_patterns:
3016 if input_api.fnmatch.fnmatch(
3017 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:043018 skip = False
3019 for exclude in exclude_paths:
3020 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
3021 skip = True
3022 break
3023 if skip:
3024 continue
Daniel Cheng13ca61a882017-08-25 15:11:253025 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173026 break
3027
Daniel Cheng7052cdf2017-11-21 19:23:293028 return to_check
3029
3030
Wez17c66962020-04-29 15:26:033031def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3032 """Adds OWNERS files to check for correct Fuchsia security owners."""
3033
3034 file_patterns = [
3035 # Component specifications.
3036 '*.cml', # Component Framework v2.
3037 '*.cmx', # Component Framework v1.
3038
3039 # Fuchsia IDL protocol specifications.
3040 '*.fidl',
3041 ]
3042
3043 def AddPatternToCheck(input_file, pattern):
3044 owners_file = input_api.os_path.join(
3045 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3046 if owners_file not in to_check:
3047 to_check[owners_file] = {}
3048 if pattern not in to_check[owners_file]:
3049 to_check[owners_file][pattern] = {
3050 'files': [],
3051 'rules': [
3052 'per-file %s=set noparent' % pattern,
3053 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3054 ]
3055 }
3056 to_check[owners_file][pattern]['files'].append(input_file)
3057
3058 # Iterate through the affected files to see what we actually need to check
3059 # for. We should only nag patch authors about per-file rules if a file in that
3060 # directory would match that pattern.
3061 for f in input_api.AffectedFiles(include_deletes=False):
3062 for pattern in file_patterns:
3063 if input_api.fnmatch.fnmatch(
3064 input_api.os_path.basename(f.LocalPath()), pattern):
3065 AddPatternToCheck(f, pattern)
3066 break
3067
3068 return to_check
3069
3070
3071def _CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293072 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3073 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033074 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293075
3076 if to_check:
3077 # If there are any OWNERS files to check, there are IPC-related changes in
3078 # this CL. Auto-CC the review list.
3079 output_api.AppendCC('[email protected]')
3080
3081 # Go through the OWNERS files to check, filtering out rules that are already
3082 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173083 for owners_file, patterns in to_check.iteritems():
3084 try:
3085 with file(owners_file) as f:
3086 lines = set(f.read().splitlines())
3087 for entry in patterns.itervalues():
3088 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3089 ]
3090 except IOError:
3091 # No OWNERS file, so all the rules are definitely missing.
3092 continue
3093
3094 # All the remaining lines weren't found in OWNERS files, so emit an error.
3095 errors = []
3096 for owners_file, patterns in to_check.iteritems():
3097 missing_lines = []
3098 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503099 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173100 missing_lines.extend(entry['rules'])
3101 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3102 if missing_lines:
3103 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053104 'Because of the presence of files:\n%s\n\n'
3105 '%s needs the following %d lines added:\n\n%s' %
3106 ('\n'.join(files), owners_file, len(missing_lines),
3107 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173108
3109 results = []
3110 if errors:
vabrf5ce3bf92016-07-11 14:52:413111 if input_api.is_committing:
3112 output = output_api.PresubmitError
3113 else:
3114 output = output_api.PresubmitPromptWarning
3115 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593116 'Found OWNERS files that need to be updated for IPC security ' +
3117 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173118 long_text='\n\n'.join(errors)))
3119
3120 return results
3121
3122
Robert Sesek2c905332020-05-06 23:17:133123def _GetFilesUsingSecurityCriticalFunctions(input_api):
3124 """Checks affected files for changes to security-critical calls. This
3125 function checks the full change diff, to catch both additions/changes
3126 and removals.
3127
3128 Returns a dict keyed by file name, and the value is a set of detected
3129 functions.
3130 """
3131 # Map of function pretty name (displayed in an error) to the pattern to
3132 # match it with.
3133 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373134 'content::GetServiceSandboxType<>()':
3135 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133136 }
3137 _PATTERNS_TO_CHECK = {
3138 k: input_api.re.compile(v)
3139 for k, v in _PATTERNS_TO_CHECK.items()
3140 }
3141
3142 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3143 files_to_functions = {}
3144 for f in input_api.AffectedFiles():
3145 diff = f.GenerateScmDiff()
3146 for line in diff.split('\n'):
3147 # Not using just RightHandSideLines() because removing a
3148 # call to a security-critical function can be just as important
3149 # as adding or changing the arguments.
3150 if line.startswith('-') or (line.startswith('+') and
3151 not line.startswith('++')):
3152 for name, pattern in _PATTERNS_TO_CHECK.items():
3153 if pattern.search(line):
3154 path = f.LocalPath()
3155 if not path in files_to_functions:
3156 files_to_functions[path] = set()
3157 files_to_functions[path].add(name)
3158 return files_to_functions
3159
3160
3161def _CheckSecurityChanges(input_api, output_api):
3162 """Checks that changes involving security-critical functions are reviewed
3163 by the security team.
3164 """
3165 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3166 if len(files_to_functions):
3167 owners_db = input_api.owners_db
3168 owner_email, reviewers = (
3169 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3170 input_api,
3171 owners_db.email_regexp,
3172 approval_needed=input_api.is_committing))
3173
3174 # Load the OWNERS file for security changes.
3175 owners_file = 'ipc/SECURITY_OWNERS'
3176 security_owners = owners_db.owners_rooted_at_file(owners_file)
3177
3178 has_security_owner = any([owner in reviewers for owner in security_owners])
3179 if not has_security_owner:
3180 msg = 'The following files change calls to security-sensive functions\n' \
3181 'that need to be reviewed by {}.\n'.format(owners_file)
3182 for path, names in files_to_functions.items():
3183 msg += ' {}\n'.format(path)
3184 for name in names:
3185 msg += ' {}\n'.format(name)
3186 msg += '\n'
3187
3188 if input_api.is_committing:
3189 output = output_api.PresubmitError
3190 else:
3191 output = output_api.PresubmitNotifyResult
3192 return [output(msg)]
3193
3194 return []
3195
3196
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263197def _CheckSetNoParent(input_api, output_api):
3198 """Checks that set noparent is only used together with an OWNERS file in
3199 //build/OWNERS.setnoparent (see also
3200 //docs/code_reviews.md#owners-files-details)
3201 """
3202 errors = []
3203
3204 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3205 allowed_owners_files = set()
3206 with open(allowed_owners_files_file, 'r') as f:
3207 for line in f:
3208 line = line.strip()
3209 if not line or line.startswith('#'):
3210 continue
3211 allowed_owners_files.add(line)
3212
3213 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3214
3215 for f in input_api.AffectedFiles(include_deletes=False):
3216 if not f.LocalPath().endswith('OWNERS'):
3217 continue
3218
3219 found_owners_files = set()
3220 found_set_noparent_lines = dict()
3221
3222 # Parse the OWNERS file.
3223 for lineno, line in enumerate(f.NewContents(), 1):
3224 line = line.strip()
3225 if line.startswith('set noparent'):
3226 found_set_noparent_lines[''] = lineno
3227 if line.startswith('file://'):
3228 if line in allowed_owners_files:
3229 found_owners_files.add('')
3230 if line.startswith('per-file'):
3231 match = per_file_pattern.match(line)
3232 if match:
3233 glob = match.group(1).strip()
3234 directive = match.group(2).strip()
3235 if directive == 'set noparent':
3236 found_set_noparent_lines[glob] = lineno
3237 if directive.startswith('file://'):
3238 if directive in allowed_owners_files:
3239 found_owners_files.add(glob)
3240
3241 # Check that every set noparent line has a corresponding file:// line
3242 # listed in build/OWNERS.setnoparent.
3243 for set_noparent_line in found_set_noparent_lines:
3244 if set_noparent_line in found_owners_files:
3245 continue
3246 errors.append(' %s:%d' % (f.LocalPath(),
3247 found_set_noparent_lines[set_noparent_line]))
3248
3249 results = []
3250 if errors:
3251 if input_api.is_committing:
3252 output = output_api.PresubmitError
3253 else:
3254 output = output_api.PresubmitPromptWarning
3255 results.append(output(
3256 'Found the following "set noparent" restrictions in OWNERS files that '
3257 'do not include owners from build/OWNERS.setnoparent:',
3258 long_text='\n\n'.join(errors)))
3259 return results
3260
3261
jbriance9e12f162016-11-25 07:57:503262def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313263 """Checks that added or removed lines in non third party affected
3264 header files do not lead to new useless class or struct forward
3265 declaration.
jbriance9e12f162016-11-25 07:57:503266 """
3267 results = []
3268 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3269 input_api.re.MULTILINE)
3270 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3271 input_api.re.MULTILINE)
3272 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313273 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193274 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493275 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313276 continue
3277
jbriance9e12f162016-11-25 07:57:503278 if not f.LocalPath().endswith('.h'):
3279 continue
3280
3281 contents = input_api.ReadFile(f)
3282 fwd_decls = input_api.re.findall(class_pattern, contents)
3283 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3284
3285 useless_fwd_decls = []
3286 for decl in fwd_decls:
3287 count = sum(1 for _ in input_api.re.finditer(
3288 r'\b%s\b' % input_api.re.escape(decl), contents))
3289 if count == 1:
3290 useless_fwd_decls.append(decl)
3291
3292 if not useless_fwd_decls:
3293 continue
3294
3295 for line in f.GenerateScmDiff().splitlines():
3296 if (line.startswith('-') and not line.startswith('--') or
3297 line.startswith('+') and not line.startswith('++')):
3298 for decl in useless_fwd_decls:
3299 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3300 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243301 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503302 (f.LocalPath(), decl)))
3303 useless_fwd_decls.remove(decl)
3304
3305 return results
3306
Jinsong Fan91ebbbd2019-04-16 14:57:173307def _CheckAndroidDebuggableBuild(input_api, output_api):
3308 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3309 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3310 this is a debuggable build of Android.
3311 """
3312 build_type_check_pattern = input_api.re.compile(
3313 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3314
3315 errors = []
3316
3317 sources = lambda affected_file: input_api.FilterSourceFile(
3318 affected_file,
James Cook24a504192020-07-23 00:08:443319 files_to_skip=(_EXCLUDED_PATHS +
3320 _TEST_CODE_EXCLUDED_PATHS +
3321 input_api.DEFAULT_FILES_TO_SKIP +
3322 (r"^android_webview[\\/]support_library[\\/]"
3323 "boundary_interfaces[\\/]",
3324 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3325 r'^third_party[\\/].*',
3326 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3327 r"webview[\\/]chromium[\\/]License.*",)),
3328 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173329
3330 for f in input_api.AffectedSourceFiles(sources):
3331 for line_num, line in f.ChangedContents():
3332 if build_type_check_pattern.search(line):
3333 errors.append("%s:%d" % (f.LocalPath(), line_num))
3334
3335 results = []
3336
3337 if errors:
3338 results.append(output_api.PresubmitPromptWarning(
3339 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3340 ' Please use BuildInfo.isDebugAndroid() instead.',
3341 errors))
3342
3343 return results
jbriance9e12f162016-11-25 07:57:503344
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493345# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293346def _CheckAndroidToastUsage(input_api, output_api):
3347 """Checks that code uses org.chromium.ui.widget.Toast instead of
3348 android.widget.Toast (Chromium Toast doesn't force hardware
3349 acceleration on low-end devices, saving memory).
3350 """
3351 toast_import_pattern = input_api.re.compile(
3352 r'^import android\.widget\.Toast;$')
3353
3354 errors = []
3355
3356 sources = lambda affected_file: input_api.FilterSourceFile(
3357 affected_file,
James Cook24a504192020-07-23 00:08:443358 files_to_skip=(_EXCLUDED_PATHS +
3359 _TEST_CODE_EXCLUDED_PATHS +
3360 input_api.DEFAULT_FILES_TO_SKIP +
3361 (r'^chromecast[\\/].*',
3362 r'^remoting[\\/].*')),
3363 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293364
3365 for f in input_api.AffectedSourceFiles(sources):
3366 for line_num, line in f.ChangedContents():
3367 if toast_import_pattern.search(line):
3368 errors.append("%s:%d" % (f.LocalPath(), line_num))
3369
3370 results = []
3371
3372 if errors:
3373 results.append(output_api.PresubmitError(
3374 'android.widget.Toast usage is detected. Android toasts use hardware'
3375 ' acceleration, and can be\ncostly on low-end devices. Please use'
3376 ' org.chromium.ui.widget.Toast instead.\n'
3377 'Contact [email protected] if you have any questions.',
3378 errors))
3379
3380 return results
3381
3382
dgnaa68d5e2015-06-10 10:08:223383def _CheckAndroidCrLogUsage(input_api, output_api):
3384 """Checks that new logs using org.chromium.base.Log:
3385 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513386 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223387 """
pkotwicza1dd0b002016-05-16 14:41:043388
torne89540622017-03-24 19:41:303389 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043390 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303391 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043392 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303393 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043394 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3395 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093396 # The customtabs_benchmark is a small app that does not depend on Chromium
3397 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043398 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043399 ]
3400
dgnaa68d5e2015-06-10 10:08:223401 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123402 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3403 class_in_base_pattern = input_api.re.compile(
3404 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3405 has_some_log_import_pattern = input_api.re.compile(
3406 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223407 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553408 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223409 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463410 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553411 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223412
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463413 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443414 sources = lambda x: input_api.FilterSourceFile(x,
3415 files_to_check=[r'.*\.java$'],
3416 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123417
dgnaa68d5e2015-06-10 10:08:223418 tag_decl_errors = []
3419 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123420 tag_errors = []
dgn38736db2015-09-18 19:20:513421 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123422 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223423
3424 for f in input_api.AffectedSourceFiles(sources):
3425 file_content = input_api.ReadFile(f)
3426 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223427 # Per line checks
dgn87d9fb62015-06-12 09:15:123428 if (cr_log_import_pattern.search(file_content) or
3429 (class_in_base_pattern.search(file_content) and
3430 not has_some_log_import_pattern.search(file_content))):
3431 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223432 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553433 if rough_log_decl_pattern.search(line):
3434 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223435
3436 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123437 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223438 if match:
3439 has_modified_logs = True
3440
3441 # Make sure it uses "TAG"
3442 if not match.group('tag') == 'TAG':
3443 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123444 else:
3445 # Report non cr Log function calls in changed lines
3446 for line_num, line in f.ChangedContents():
3447 if log_call_pattern.search(line):
3448 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223449
3450 # Per file checks
3451 if has_modified_logs:
3452 # Make sure the tag is using the "cr" prefix and is not too long
3453 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513454 tag_name = match.group('name') if match else None
3455 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223456 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513457 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223458 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513459 elif '.' in tag_name:
3460 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223461
3462 results = []
3463 if tag_decl_errors:
3464 results.append(output_api.PresubmitPromptWarning(
3465 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513466 '"private static final String TAG = "<package tag>".\n'
3467 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223468 tag_decl_errors))
3469
3470 if tag_length_errors:
3471 results.append(output_api.PresubmitError(
3472 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513473 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223474 tag_length_errors))
3475
3476 if tag_errors:
3477 results.append(output_api.PresubmitPromptWarning(
3478 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3479 tag_errors))
3480
dgn87d9fb62015-06-12 09:15:123481 if util_log_errors:
dgn4401aa52015-04-29 16:26:173482 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123483 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3484 util_log_errors))
3485
dgn38736db2015-09-18 19:20:513486 if tag_with_dot_errors:
3487 results.append(output_api.PresubmitPromptWarning(
3488 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3489 tag_with_dot_errors))
3490
dgn4401aa52015-04-29 16:26:173491 return results
3492
3493
Yoland Yanb92fa522017-08-28 17:37:063494def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3495 """Checks that junit.framework.* is no longer used."""
3496 deprecated_junit_framework_pattern = input_api.re.compile(
3497 r'^import junit\.framework\..*;',
3498 input_api.re.MULTILINE)
3499 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443500 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063501 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133502 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063503 for line_num, line in f.ChangedContents():
3504 if deprecated_junit_framework_pattern.search(line):
3505 errors.append("%s:%d" % (f.LocalPath(), line_num))
3506
3507 results = []
3508 if errors:
3509 results.append(output_api.PresubmitError(
3510 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3511 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3512 ' if you have any question.', errors))
3513 return results
3514
3515
3516def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3517 """Checks that if new Java test classes have inheritance.
3518 Either the new test class is JUnit3 test or it is a JUnit4 test class
3519 with a base class, either case is undesirable.
3520 """
3521 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3522
3523 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443524 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063525 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133526 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063527 if not f.OldContents():
3528 class_declaration_start_flag = False
3529 for line_num, line in f.ChangedContents():
3530 if class_declaration_pattern.search(line):
3531 class_declaration_start_flag = True
3532 if class_declaration_start_flag and ' extends ' in line:
3533 errors.append('%s:%d' % (f.LocalPath(), line_num))
3534 if '{' in line:
3535 class_declaration_start_flag = False
3536
3537 results = []
3538 if errors:
3539 results.append(output_api.PresubmitPromptWarning(
3540 'The newly created files include Test classes that inherits from base'
3541 ' class. Please do not use inheritance in JUnit4 tests or add new'
3542 ' JUnit3 tests. Contact [email protected] if you have any'
3543 ' questions.', errors))
3544 return results
3545
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203546
yolandyan45001472016-12-21 21:12:423547def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3548 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3549 deprecated_annotation_import_pattern = input_api.re.compile(
3550 r'^import android\.test\.suitebuilder\.annotation\..*;',
3551 input_api.re.MULTILINE)
3552 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443553 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423554 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133555 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423556 for line_num, line in f.ChangedContents():
3557 if deprecated_annotation_import_pattern.search(line):
3558 errors.append("%s:%d" % (f.LocalPath(), line_num))
3559
3560 results = []
3561 if errors:
3562 results.append(output_api.PresubmitError(
3563 'Annotations in android.test.suitebuilder.annotation have been'
3564 ' deprecated since API level 24. Please use android.support.test.filters'
3565 ' from //third_party/android_support_test_runner:runner_java instead.'
3566 ' Contact [email protected] if you have any questions.', errors))
3567 return results
3568
3569
agrieve7b6479d82015-10-07 14:24:223570def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3571 """Checks if MDPI assets are placed in a correct directory."""
3572 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3573 ('/res/drawable/' in f.LocalPath() or
3574 '/res/drawable-ldrtl/' in f.LocalPath()))
3575 errors = []
3576 for f in input_api.AffectedFiles(include_deletes=False,
3577 file_filter=file_filter):
3578 errors.append(' %s' % f.LocalPath())
3579
3580 results = []
3581 if errors:
3582 results.append(output_api.PresubmitError(
3583 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3584 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3585 '/res/drawable-ldrtl/.\n'
3586 'Contact [email protected] if you have questions.', errors))
3587 return results
3588
3589
Nate Fischer535972b2017-09-16 01:06:183590def _CheckAndroidWebkitImports(input_api, output_api):
3591 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353592 android.webview.ValueCallback except in the WebView glue layer
3593 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183594 """
3595 valuecallback_import_pattern = input_api.re.compile(
3596 r'^import android\.webkit\.ValueCallback;$')
3597
3598 errors = []
3599
3600 sources = lambda affected_file: input_api.FilterSourceFile(
3601 affected_file,
James Cook24a504192020-07-23 00:08:443602 files_to_skip=(_EXCLUDED_PATHS +
3603 _TEST_CODE_EXCLUDED_PATHS +
3604 input_api.DEFAULT_FILES_TO_SKIP +
3605 (r'^android_webview[\\/]glue[\\/].*',
3606 r'^weblayer[\\/].*',)),
3607 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183608
3609 for f in input_api.AffectedSourceFiles(sources):
3610 for line_num, line in f.ChangedContents():
3611 if valuecallback_import_pattern.search(line):
3612 errors.append("%s:%d" % (f.LocalPath(), line_num))
3613
3614 results = []
3615
3616 if errors:
3617 results.append(output_api.PresubmitError(
3618 'android.webkit.ValueCallback usage is detected outside of the glue'
3619 ' layer. To stay compatible with the support library, android.webkit.*'
3620 ' classes should only be used inside the glue layer and'
3621 ' org.chromium.base.Callback should be used instead.',
3622 errors))
3623
3624 return results
3625
3626
Becky Zhou7c69b50992018-12-10 19:37:573627def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3628 """Checks Android XML styles """
3629 import sys
3630 original_sys_path = sys.path
3631 try:
3632 sys.path = sys.path + [input_api.os_path.join(
3633 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3634 import checkxmlstyle
3635 finally:
3636 # Restore sys.path to what it was before.
3637 sys.path = original_sys_path
3638
3639 if is_check_on_upload:
3640 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3641 else:
3642 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3643
3644
agrievef32bcc72016-04-04 14:57:403645class PydepsChecker(object):
3646 def __init__(self, input_api, pydeps_files):
3647 self._file_cache = {}
3648 self._input_api = input_api
3649 self._pydeps_files = pydeps_files
3650
3651 def _LoadFile(self, path):
3652 """Returns the list of paths within a .pydeps file relative to //."""
3653 if path not in self._file_cache:
3654 with open(path) as f:
3655 self._file_cache[path] = f.read()
3656 return self._file_cache[path]
3657
3658 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3659 """Returns an interable of paths within the .pydep, relativized to //."""
3660 os_path = self._input_api.os_path
3661 pydeps_dir = os_path.dirname(pydeps_path)
3662 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3663 if not l.startswith('*'))
3664 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3665
3666 def _CreateFilesToPydepsMap(self):
3667 """Returns a map of local_path -> list_of_pydeps."""
3668 ret = {}
3669 for pydep_local_path in self._pydeps_files:
3670 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3671 ret.setdefault(path, []).append(pydep_local_path)
3672 return ret
3673
3674 def ComputeAffectedPydeps(self):
3675 """Returns an iterable of .pydeps files that might need regenerating."""
3676 affected_pydeps = set()
3677 file_to_pydeps_map = None
3678 for f in self._input_api.AffectedFiles(include_deletes=True):
3679 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463680 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3681 # subrepositories. We can't figure out which files change, so re-check
3682 # all files.
3683 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383684 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3685 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403686 return self._pydeps_files
3687 elif local_path.endswith('.pydeps'):
3688 if local_path in self._pydeps_files:
3689 affected_pydeps.add(local_path)
3690 elif local_path.endswith('.py'):
3691 if file_to_pydeps_map is None:
3692 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3693 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3694 return affected_pydeps
3695
3696 def DetermineIfStale(self, pydeps_path):
3697 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413698 import difflib
John Budorick47ca3fe2018-02-10 00:53:103699 import os
3700
agrievef32bcc72016-04-04 14:57:403701 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033702 if old_pydeps_data:
3703 cmd = old_pydeps_data[1][1:].strip()
3704 old_contents = old_pydeps_data[2:]
3705 else:
3706 # A default cmd that should work in most cases (as long as pydeps filename
3707 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3708 # file is empty/new.
3709 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3710 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3711 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103712 env = dict(os.environ)
3713 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403714 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103715 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413716 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033717 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413718 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403719
3720
Tibor Goldschwendt360793f72019-06-25 18:23:493721def _ParseGclientArgs():
3722 args = {}
3723 with open('build/config/gclient_args.gni', 'r') as f:
3724 for line in f:
3725 line = line.strip()
3726 if not line or line.startswith('#'):
3727 continue
3728 attribute, value = line.split('=')
3729 args[attribute.strip()] = value.strip()
3730 return args
3731
3732
agrievef32bcc72016-04-04 14:57:403733def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3734 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403735 # This check is for Python dependency lists (.pydeps files), and involves
3736 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3737 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283738 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003739 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493740 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403741 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403742 results = []
3743 # First, check for new / deleted .pydeps.
3744 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033745 # Check whether we are running the presubmit check for a file in src.
3746 # f.LocalPath is relative to repo (src, or internal repo).
3747 # os_path.exists is relative to src repo.
3748 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3749 # to src and we can conclude that the pydeps is in src.
3750 if input_api.os_path.exists(f.LocalPath()):
3751 if f.LocalPath().endswith('.pydeps'):
3752 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3753 results.append(output_api.PresubmitError(
3754 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3755 'remove %s' % f.LocalPath()))
3756 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3757 results.append(output_api.PresubmitError(
3758 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3759 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403760
3761 if results:
3762 return results
3763
Mohamed Heikal7cd4d8312020-06-16 16:49:403764 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3765 affected_pydeps = set(checker.ComputeAffectedPydeps())
3766 affected_android_pydeps = affected_pydeps.intersection(
3767 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3768 if affected_android_pydeps and not is_android:
3769 results.append(output_api.PresubmitPromptOrNotify(
3770 'You have changed python files that may affect pydeps for android\n'
3771 'specific scripts. However, the relevant presumbit check cannot be\n'
3772 'run because you are not using an Android checkout. To validate that\n'
3773 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3774 'use the android-internal-presubmit optional trybot.\n'
3775 'Possibly stale pydeps files:\n{}'.format(
3776 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403777
Mohamed Heikal7cd4d8312020-06-16 16:49:403778 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3779 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403780 try:
phajdan.jr0d9878552016-11-04 10:49:413781 result = checker.DetermineIfStale(pydep_path)
3782 if result:
3783 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403784 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413785 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3786 'To regenerate, run:\n\n %s' %
3787 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403788 except input_api.subprocess.CalledProcessError as error:
3789 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3790 long_text=error.output)]
3791
3792 return results
3793
3794
glidere61efad2015-02-18 17:39:433795def _CheckSingletonInHeaders(input_api, output_api):
3796 """Checks to make sure no header files have |Singleton<|."""
3797 def FileFilter(affected_file):
3798 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443799 files_to_skip = (_EXCLUDED_PATHS +
3800 input_api.DEFAULT_FILES_TO_SKIP +
3801 (r"^base[\\/]memory[\\/]singleton\.h$",
3802 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3803 r"quic_singleton_impl\.h$"))
3804 return input_api.FilterSourceFile(affected_file,
3805 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433806
sergeyu34d21222015-09-16 00:11:443807 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433808 files = []
3809 for f in input_api.AffectedSourceFiles(FileFilter):
3810 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3811 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3812 contents = input_api.ReadFile(f)
3813 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243814 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433815 pattern.search(line)):
3816 files.append(f)
3817 break
3818
3819 if files:
yolandyandaabc6d2016-04-18 18:29:393820 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443821 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433822 'Please move them to an appropriate source file so that the ' +
3823 'template gets instantiated in a single compilation unit.',
3824 files) ]
3825 return []
3826
3827
[email protected]fd20b902014-05-09 02:14:533828_DEPRECATED_CSS = [
3829 # Values
3830 ( "-webkit-box", "flex" ),
3831 ( "-webkit-inline-box", "inline-flex" ),
3832 ( "-webkit-flex", "flex" ),
3833 ( "-webkit-inline-flex", "inline-flex" ),
3834 ( "-webkit-min-content", "min-content" ),
3835 ( "-webkit-max-content", "max-content" ),
3836
3837 # Properties
3838 ( "-webkit-background-clip", "background-clip" ),
3839 ( "-webkit-background-origin", "background-origin" ),
3840 ( "-webkit-background-size", "background-size" ),
3841 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443842 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533843
3844 # Functions
3845 ( "-webkit-gradient", "gradient" ),
3846 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3847 ( "-webkit-linear-gradient", "linear-gradient" ),
3848 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3849 ( "-webkit-radial-gradient", "radial-gradient" ),
3850 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3851]
3852
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203853
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493854# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243855def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533856 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253857 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343858 documentation and iOS CSS for dom distiller
3859 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253860 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533861 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493862 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443863 files_to_skip = (_EXCLUDED_PATHS +
3864 _TEST_CODE_EXCLUDED_PATHS +
3865 input_api.DEFAULT_FILES_TO_SKIP +
3866 (r"^chrome/common/extensions/docs",
3867 r"^chrome/docs",
3868 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3869 r"^components/neterror/resources/neterror.css",
3870 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253871 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443872 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533873 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3874 for line_num, line in fpath.ChangedContents():
3875 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023876 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533877 results.append(output_api.PresubmitError(
3878 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3879 (fpath.LocalPath(), line_num, deprecated_value, value)))
3880 return results
3881
mohan.reddyf21db962014-10-16 12:26:473882
rlanday6802cf632017-05-30 17:48:363883def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363884 bad_files = {}
3885 for f in input_api.AffectedFiles(include_deletes=False):
3886 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493887 not f.LocalPath().startswith('third_party/blink') and
3888 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363889 continue
3890
Daniel Bratell65b033262019-04-23 08:17:063891 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363892 continue
3893
Vaclav Brozekd5de76a2018-03-17 07:57:503894 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363895 if "#include" in line and "../" in line]
3896 if not relative_includes:
3897 continue
3898 bad_files[f.LocalPath()] = relative_includes
3899
3900 if not bad_files:
3901 return []
3902
3903 error_descriptions = []
3904 for file_path, bad_lines in bad_files.iteritems():
3905 error_description = file_path
3906 for line in bad_lines:
3907 error_description += '\n ' + line
3908 error_descriptions.append(error_description)
3909
3910 results = []
3911 results.append(output_api.PresubmitError(
3912 'You added one or more relative #include paths (including "../").\n'
3913 'These shouldn\'t be used because they can be used to include headers\n'
3914 'from code that\'s not correctly specified as a dependency in the\n'
3915 'relevant BUILD.gn file(s).',
3916 error_descriptions))
3917
3918 return results
3919
Takeshi Yoshinoe387aa32017-08-02 13:16:133920
Daniel Bratell65b033262019-04-23 08:17:063921def _CheckForCcIncludes(input_api, output_api):
3922 """Check that nobody tries to include a cc file. It's a relatively
3923 common error which results in duplicate symbols in object
3924 files. This may not always break the build until someone later gets
3925 very confusing linking errors."""
3926 results = []
3927 for f in input_api.AffectedFiles(include_deletes=False):
3928 # We let third_party code do whatever it wants
3929 if (f.LocalPath().startswith('third_party') and
3930 not f.LocalPath().startswith('third_party/blink') and
3931 not f.LocalPath().startswith('third_party\\blink')):
3932 continue
3933
3934 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3935 continue
3936
3937 for _, line in f.ChangedContents():
3938 if line.startswith('#include "'):
3939 included_file = line.split('"')[1]
3940 if _IsCPlusPlusFile(input_api, included_file):
3941 # The most common naming for external files with C++ code,
3942 # apart from standard headers, is to call them foo.inc, but
3943 # Chromium sometimes uses foo-inc.cc so allow that as well.
3944 if not included_file.endswith(('.h', '-inc.cc')):
3945 results.append(output_api.PresubmitError(
3946 'Only header files or .inc files should be included in other\n'
3947 'C++ files. Compiling the contents of a cc file more than once\n'
3948 'will cause duplicate information in the build which may later\n'
3949 'result in strange link_errors.\n' +
3950 f.LocalPath() + ':\n ' +
3951 line))
3952
3953 return results
3954
3955
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203956def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3957 if not isinstance(key, ast.Str):
3958 return 'Key at line %d must be a string literal' % key.lineno
3959 if not isinstance(value, ast.Dict):
3960 return 'Value at line %d must be a dict' % value.lineno
3961 if len(value.keys) != 1:
3962 return 'Dict at line %d must have single entry' % value.lineno
3963 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3964 return (
3965 'Entry at line %d must have a string literal \'filepath\' as key' %
3966 value.lineno)
3967 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133968
Takeshi Yoshinoe387aa32017-08-02 13:16:133969
Sergey Ulanov4af16052018-11-08 02:41:463970def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203971 if not isinstance(key, ast.Str):
3972 return 'Key at line %d must be a string literal' % key.lineno
3973 if not isinstance(value, ast.List):
3974 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463975 for element in value.elts:
3976 if not isinstance(element, ast.Str):
3977 return 'Watchlist elements on line %d is not a string' % key.lineno
3978 if not email_regex.match(element.s):
3979 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3980 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203981 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133982
Takeshi Yoshinoe387aa32017-08-02 13:16:133983
Sergey Ulanov4af16052018-11-08 02:41:463984def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203985 mismatch_template = (
3986 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3987 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133988
Sergey Ulanov4af16052018-11-08 02:41:463989 email_regex = input_api.re.compile(
3990 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3991
3992 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203993 i = 0
3994 last_key = ''
3995 while True:
3996 if i >= len(wd_dict.keys):
3997 if i >= len(w_dict.keys):
3998 return None
3999 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
4000 elif i >= len(w_dict.keys):
4001 return (
4002 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134003
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204004 wd_key = wd_dict.keys[i]
4005 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134006
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204007 result = _CheckWatchlistDefinitionsEntrySyntax(
4008 wd_key, wd_dict.values[i], ast)
4009 if result is not None:
4010 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134011
Sergey Ulanov4af16052018-11-08 02:41:464012 result = _CheckWatchlistsEntrySyntax(
4013 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204014 if result is not None:
4015 return 'Bad entry in WATCHLISTS dict: %s' % result
4016
4017 if wd_key.s != w_key.s:
4018 return mismatch_template % (
4019 '%s at line %d' % (wd_key.s, wd_key.lineno),
4020 '%s at line %d' % (w_key.s, w_key.lineno))
4021
4022 if wd_key.s < last_key:
4023 return (
4024 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4025 (wd_key.lineno, w_key.lineno))
4026 last_key = wd_key.s
4027
4028 i = i + 1
4029
4030
Sergey Ulanov4af16052018-11-08 02:41:464031def _CheckWATCHLISTSSyntax(expression, input_api):
4032 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204033 if not isinstance(expression, ast.Expression):
4034 return 'WATCHLISTS file must contain a valid expression'
4035 dictionary = expression.body
4036 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4037 return 'WATCHLISTS file must have single dict with exactly two entries'
4038
4039 first_key = dictionary.keys[0]
4040 first_value = dictionary.values[0]
4041 second_key = dictionary.keys[1]
4042 second_value = dictionary.values[1]
4043
4044 if (not isinstance(first_key, ast.Str) or
4045 first_key.s != 'WATCHLIST_DEFINITIONS' or
4046 not isinstance(first_value, ast.Dict)):
4047 return (
4048 'The first entry of the dict in WATCHLISTS file must be '
4049 'WATCHLIST_DEFINITIONS dict')
4050
4051 if (not isinstance(second_key, ast.Str) or
4052 second_key.s != 'WATCHLISTS' or
4053 not isinstance(second_value, ast.Dict)):
4054 return (
4055 'The second entry of the dict in WATCHLISTS file must be '
4056 'WATCHLISTS dict')
4057
Sergey Ulanov4af16052018-11-08 02:41:464058 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134059
4060
4061def _CheckWATCHLISTS(input_api, output_api):
4062 for f in input_api.AffectedFiles(include_deletes=False):
4063 if f.LocalPath() == 'WATCHLISTS':
4064 contents = input_api.ReadFile(f, 'r')
4065
4066 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204067 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134068 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204069 # Get an AST tree for it and scan the tree for detailed style checking.
4070 expression = input_api.ast.parse(
4071 contents, filename='WATCHLISTS', mode='eval')
4072 except ValueError as e:
4073 return [output_api.PresubmitError(
4074 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4075 except SyntaxError as e:
4076 return [output_api.PresubmitError(
4077 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4078 except TypeError as e:
4079 return [output_api.PresubmitError(
4080 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134081
Sergey Ulanov4af16052018-11-08 02:41:464082 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204083 if result is not None:
4084 return [output_api.PresubmitError(result)]
4085 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134086
4087 return []
4088
4089
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194090def _CheckNewHeaderWithoutGnChange(input_api, output_api):
4091 """Checks that newly added header files have corresponding GN changes.
4092 Note that this is only a heuristic. To be precise, run script:
4093 build/check_gn_headers.py.
4094 """
4095
4096 def headers(f):
4097 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444098 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194099
4100 new_headers = []
4101 for f in input_api.AffectedSourceFiles(headers):
4102 if f.Action() != 'A':
4103 continue
4104 new_headers.append(f.LocalPath())
4105
4106 def gn_files(f):
James Cook24a504192020-07-23 00:08:444107 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194108
4109 all_gn_changed_contents = ''
4110 for f in input_api.AffectedSourceFiles(gn_files):
4111 for _, line in f.ChangedContents():
4112 all_gn_changed_contents += line
4113
4114 problems = []
4115 for header in new_headers:
4116 basename = input_api.os_path.basename(header)
4117 if basename not in all_gn_changed_contents:
4118 problems.append(header)
4119
4120 if problems:
4121 return [output_api.PresubmitPromptWarning(
4122 'Missing GN changes for new header files', items=sorted(problems),
4123 long_text='Please double check whether newly added header files need '
4124 'corresponding changes in gn or gni files.\nThis checking is only a '
4125 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4126 'Read https://crbug.com/661774 for more info.')]
4127 return []
4128
4129
Michael Giuffridad3bc8672018-10-25 22:48:024130def _CheckCorrectProductNameInMessages(input_api, output_api):
4131 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4132
4133 This assumes we won't intentionally reference one product from the other
4134 product.
4135 """
4136 all_problems = []
4137 test_cases = [{
4138 "filename_postfix": "google_chrome_strings.grd",
4139 "correct_name": "Chrome",
4140 "incorrect_name": "Chromium",
4141 }, {
4142 "filename_postfix": "chromium_strings.grd",
4143 "correct_name": "Chromium",
4144 "incorrect_name": "Chrome",
4145 }]
4146
4147 for test_case in test_cases:
4148 problems = []
4149 filename_filter = lambda x: x.LocalPath().endswith(
4150 test_case["filename_postfix"])
4151
4152 # Check each new line. Can yield false positives in multiline comments, but
4153 # easier than trying to parse the XML because messages can have nested
4154 # children, and associating message elements with affected lines is hard.
4155 for f in input_api.AffectedSourceFiles(filename_filter):
4156 for line_num, line in f.ChangedContents():
4157 if "<message" in line or "<!--" in line or "-->" in line:
4158 continue
4159 if test_case["incorrect_name"] in line:
4160 problems.append(
4161 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4162
4163 if problems:
4164 message = (
4165 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4166 % (test_case["correct_name"], test_case["correct_name"],
4167 test_case["incorrect_name"]))
4168 all_problems.append(
4169 output_api.PresubmitPromptWarning(message, items=problems))
4170
4171 return all_problems
4172
4173
Dirk Pranke3c18a382019-03-15 01:07:514174def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
4175 # TODO(crbug.com/941824): We need to make sure the entries in
4176 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4177 # so that users of //buildtools in other projects get the same tooling
4178 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4179 # support to gclient, we can eliminate the duplication and delete
4180 # this presubmit check.
4181
4182 # Update this regexp if new revisions are added to the files.
4183 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264184 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514185
4186 # If a user is changing one revision, they need to change the same
4187 # line in both files. This means that any given change should contain
4188 # exactly the same list of changed lines that match the regexps. The
4189 # replace(' ', '') call allows us to ignore whitespace changes to the
4190 # lines. The 'long_text' parameter to the error will contain the
4191 # list of changed lines in both files, which should make it easy enough
4192 # to spot the error without going overboard in this implementation.
4193 revs_changes = {
4194 'DEPS': {},
4195 'buildtools/DEPS': {},
4196 }
4197 long_text = ''
4198
4199 for f in input_api.AffectedFiles(
4200 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4201 for line_num, line in f.ChangedContents():
4202 if rev_regexp.search(line):
4203 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4204 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4205
4206 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4207 return [output_api.PresubmitError(
4208 'Change buildtools revisions in sync in both //DEPS and '
4209 '//buildtools/DEPS.', long_text=long_text + '\n')]
4210 else:
4211 return []
4212
4213
Daniel Bratell93eb6c62019-04-29 20:13:364214def _CheckForTooLargeFiles(input_api, output_api):
4215 """Avoid large files, especially binary files, in the repository since
4216 git doesn't scale well for those. They will be in everyone's repo
4217 clones forever, forever making Chromium slower to clone and work
4218 with."""
4219
4220 # Uploading files to cloud storage is not trivial so we don't want
4221 # to set the limit too low, but the upper limit for "normal" large
4222 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4223 # anything over 20 MB is exceptional.
4224 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4225
4226 too_large_files = []
4227 for f in input_api.AffectedFiles():
4228 # Check both added and modified files (but not deleted files).
4229 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384230 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364231 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4232 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4233
4234 if too_large_files:
4235 message = (
4236 'Do not commit large files to git since git scales badly for those.\n' +
4237 'Instead put the large files in cloud storage and use DEPS to\n' +
4238 'fetch them.\n' + '\n'.join(too_large_files)
4239 )
4240 return [output_api.PresubmitError(
4241 'Too large files found in commit', long_text=message + '\n')]
4242 else:
4243 return []
4244
Max Morozb47503b2019-08-08 21:03:274245
4246def _CheckFuzzTargets(input_api, output_api):
4247 """Checks specific for fuzz target sources."""
4248 EXPORTED_SYMBOLS = [
4249 'LLVMFuzzerInitialize',
4250 'LLVMFuzzerCustomMutator',
4251 'LLVMFuzzerCustomCrossOver',
4252 'LLVMFuzzerMutate',
4253 ]
4254
4255 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4256
4257 def FilterFile(affected_file):
4258 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444259 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4260 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274261
4262 return input_api.FilterSourceFile(
4263 affected_file,
James Cook24a504192020-07-23 00:08:444264 files_to_check=[files_to_check],
4265 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274266
4267 files_with_missing_header = []
4268 for f in input_api.AffectedSourceFiles(FilterFile):
4269 contents = input_api.ReadFile(f, 'r')
4270 if REQUIRED_HEADER in contents:
4271 continue
4272
4273 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4274 files_with_missing_header.append(f.LocalPath())
4275
4276 if not files_with_missing_header:
4277 return []
4278
4279 long_text = (
4280 'If you define any of the libFuzzer optional functions (%s), it is '
4281 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4282 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4283 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4284 'to access command line arguments passed to the fuzzer. Instead, prefer '
4285 'static initialization and shared resources as documented in '
4286 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4287 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4288 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4289 )
4290
4291 return [output_api.PresubmitPromptWarning(
4292 message="Missing '%s' in:" % REQUIRED_HEADER,
4293 items=files_with_missing_header,
4294 long_text=long_text)]
4295
4296
Mohamed Heikald048240a2019-11-12 16:57:374297def _CheckNewImagesWarning(input_api, output_api):
4298 """
4299 Warns authors who add images into the repo to make sure their images are
4300 optimized before committing.
4301 """
4302 images_added = False
4303 image_paths = []
4304 errors = []
4305 filter_lambda = lambda x: input_api.FilterSourceFile(
4306 x,
James Cook24a504192020-07-23 00:08:444307 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4308 + input_api.DEFAULT_FILES_TO_SKIP),
4309 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374310 )
4311 for f in input_api.AffectedFiles(
4312 include_deletes=False, file_filter=filter_lambda):
4313 local_path = f.LocalPath().lower()
4314 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4315 images_added = True
4316 image_paths.append(f)
4317 if images_added:
4318 errors.append(output_api.PresubmitPromptWarning(
4319 'It looks like you are trying to commit some images. If these are '
4320 'non-test-only images, please make sure to read and apply the tips in '
4321 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4322 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4323 'FYI only and will not block your CL on the CQ.', image_paths))
4324 return errors
4325
4326
dgnaa68d5e2015-06-10 10:08:224327def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574328 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224329 results = []
dgnaa68d5e2015-06-10 10:08:224330 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174331 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224332 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294333 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064334 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4335 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424336 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184337 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574338 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374339 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154340 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574341 return results
4342
4343def _AndroidSpecificOnCommitChecks(input_api, output_api):
4344 """Groups commit checks that target android code."""
4345 results = []
4346 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224347 return results
4348
Chris Hall59f8d0c72020-05-01 07:31:194349# TODO(chrishall): could we additionally match on any path owned by
4350# ui/accessibility/OWNERS ?
4351_ACCESSIBILITY_PATHS = (
4352 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4353 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4354 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4355 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4356 r"^content[\\/]browser[\\/]accessibility[\\/]",
4357 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4358 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4359 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4360 r"^ui[\\/]accessibility[\\/]",
4361 r"^ui[\\/]views[\\/]accessibility[\\/]",
4362)
4363
4364def _CheckAccessibilityRelnotesField(input_api, output_api):
4365 """Checks that commits to accessibility code contain an AX-Relnotes field in
4366 their commit message."""
4367 def FileFilter(affected_file):
4368 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444369 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194370
4371 # Only consider changes affecting accessibility paths.
4372 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4373 return []
4374
Akihiro Ota08108e542020-05-20 15:30:534375 # AX-Relnotes can appear in either the description or the footer.
4376 # When searching the description, require 'AX-Relnotes:' to appear at the
4377 # beginning of a line.
4378 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4379 description_has_relnotes = any(ax_regex.match(line)
4380 for line in input_api.change.DescriptionText().lower().splitlines())
4381
4382 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4383 'AX-Relnotes', [])
4384 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194385 return []
4386
4387 # TODO(chrishall): link to Relnotes documentation in message.
4388 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4389 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4390 "user-facing changes"
4391 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4392 "user-facing effects"
4393 "\n if this is confusing or annoying then please contact members "
4394 "of ui/accessibility/OWNERS.")
4395
4396 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224397
[email protected]22c9bd72011-03-27 16:47:394398def _CommonChecks(input_api, output_api):
4399 """Checks common to both upload and commit."""
4400 results = []
4401 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384402 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544403 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084404
4405 author = input_api.change.author_email
4406 if author and author not in _KNOWN_ROBOTS:
4407 results.extend(
4408 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4409
Chris Hall59f8d0c72020-05-01 07:31:194410 results.extend(_CheckAccessibilityRelnotesField(input_api, output_api))
[email protected]55459852011-08-10 15:17:194411 results.extend(
[email protected]760deea2013-12-10 19:33:494412 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234413 results.extend(
4414 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544415 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184416 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344417 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524418 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224419 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444420 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594421 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314422 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064423 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124424 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184425 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224426 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494427 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034428 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494429 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444430 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
James Cook6b6597c2019-11-06 22:05:294431 results.extend(_CheckChromeOsSyncedPrefRegistration(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274432 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074433 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544434 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444435 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394436 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554437 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044438 results.extend(
4439 input_api.canned_checks.CheckChangeHasNoTabs(
4440 input_api,
4441 output_api,
4442 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404443 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164444 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084445 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244446 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474447 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044448 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054449 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144450 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234451 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434452 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404453 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154454 results.extend(_CheckJavaStyle(input_api, output_api))
Wez17c66962020-04-29 15:26:034455 results.extend(_CheckSecurityOwners(input_api, output_api))
Robert Sesek2c905332020-05-06 23:17:134456 results.extend(_CheckSecurityChanges(input_api, output_api))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264457 results.extend(_CheckSetNoParent(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504458 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364459 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064460 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134461 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434462 results.extend(input_api.RunTests(
4463 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Rainhard Findlingfc31844c52020-05-15 09:58:264464 results.extend(_CheckStrings(input_api, output_api))
Mustafa Emre Acer51f2f742020-03-09 19:41:124465 results.extend(_CheckTranslationExpectations(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024466 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514467 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364468 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004469 results.extend(_CheckPythonDevilInit(input_api, output_api))
Ken Rockotc31f4832020-05-29 18:58:514470 results.extend(_CheckStableMojomChanges(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244471
Edward Lesmesce51df52020-08-04 22:10:174472 dirmd_bin = input_api.os_path.join(
4473 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4474 results.extend(input_api.RunTests(
4475 input_api.canned_checks.CheckDirMetadataFormat(
4476 input_api, output_api, dirmd_bin)))
4477 results.extend(
4478 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4479 input_api, output_api))
4480
Vaclav Brozekcdc7defb2018-03-20 09:54:354481 for f in input_api.AffectedFiles():
4482 path, name = input_api.os_path.split(f.LocalPath())
4483 if name == 'PRESUBMIT.py':
4484 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004485 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4486 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074487 # The PRESUBMIT.py file (and the directory containing it) might
4488 # have been affected by being moved or removed, so only try to
4489 # run the tests if they still exist.
4490 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4491 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444492 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394493 return results
[email protected]1f7b4172010-01-28 01:17:344494
[email protected]b337cb5b2011-01-23 21:24:054495
[email protected]b8079ae4a2012-12-05 19:56:494496def _CheckPatchFiles(input_api, output_api):
4497 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4498 if f.LocalPath().endswith(('.orig', '.rej'))]
4499 if problems:
4500 return [output_api.PresubmitError(
4501 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034502 else:
4503 return []
[email protected]b8079ae4a2012-12-05 19:56:494504
4505
Kent Tamura5a8755d2017-06-29 23:37:074506def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214507 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4508 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4509 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074510 include_re = input_api.re.compile(
4511 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4512 extension_re = input_api.re.compile(r'\.[a-z]+$')
4513 errors = []
4514 for f in input_api.AffectedFiles():
4515 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4516 continue
4517 found_line_number = None
4518 found_macro = None
4519 for line_num, line in f.ChangedContents():
4520 match = macro_re.search(line)
4521 if match:
4522 found_line_number = line_num
4523 found_macro = match.group(2)
4524 break
4525 if not found_line_number:
4526 continue
4527
4528 found_include = False
4529 for line in f.NewContents():
4530 if include_re.search(line):
4531 found_include = True
4532 break
4533 if found_include:
4534 continue
4535
4536 if not f.LocalPath().endswith('.h'):
4537 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4538 try:
4539 content = input_api.ReadFile(primary_header_path, 'r')
4540 if include_re.search(content):
4541 continue
4542 except IOError:
4543 pass
4544 errors.append('%s:%d %s macro is used without including build/'
4545 'build_config.h.'
4546 % (f.LocalPath(), found_line_number, found_macro))
4547 if errors:
4548 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4549 return []
4550
4551
[email protected]b00342e7f2013-03-26 16:21:544552def _DidYouMeanOSMacro(bad_macro):
4553 try:
4554 return {'A': 'OS_ANDROID',
4555 'B': 'OS_BSD',
4556 'C': 'OS_CHROMEOS',
4557 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444558 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544559 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444560 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544561 'N': 'OS_NACL',
4562 'O': 'OS_OPENBSD',
4563 'P': 'OS_POSIX',
4564 'S': 'OS_SOLARIS',
4565 'W': 'OS_WIN'}[bad_macro[3].upper()]
4566 except KeyError:
4567 return ''
4568
4569
4570def _CheckForInvalidOSMacrosInFile(input_api, f):
4571 """Check for sensible looking, totally invalid OS macros."""
4572 preprocessor_statement = input_api.re.compile(r'^\s*#')
4573 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4574 results = []
4575 for lnum, line in f.ChangedContents():
4576 if preprocessor_statement.search(line):
4577 for match in os_macro.finditer(line):
4578 if not match.group(1) in _VALID_OS_MACROS:
4579 good = _DidYouMeanOSMacro(match.group(1))
4580 did_you_mean = ' (did you mean %s?)' % good if good else ''
4581 results.append(' %s:%d %s%s' % (f.LocalPath(),
4582 lnum,
4583 match.group(1),
4584 did_you_mean))
4585 return results
4586
4587
4588def _CheckForInvalidOSMacros(input_api, output_api):
4589 """Check all affected files for invalid OS macros."""
4590 bad_macros = []
tzik3f295992018-12-04 20:32:234591 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474592 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544593 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4594
4595 if not bad_macros:
4596 return []
4597
4598 return [output_api.PresubmitError(
4599 'Possibly invalid OS macro[s] found. Please fix your code\n'
4600 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4601
lliabraa35bab3932014-10-01 12:16:444602
4603def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4604 """Check all affected files for invalid "if defined" macros."""
4605 ALWAYS_DEFINED_MACROS = (
4606 "TARGET_CPU_PPC",
4607 "TARGET_CPU_PPC64",
4608 "TARGET_CPU_68K",
4609 "TARGET_CPU_X86",
4610 "TARGET_CPU_ARM",
4611 "TARGET_CPU_MIPS",
4612 "TARGET_CPU_SPARC",
4613 "TARGET_CPU_ALPHA",
4614 "TARGET_IPHONE_SIMULATOR",
4615 "TARGET_OS_EMBEDDED",
4616 "TARGET_OS_IPHONE",
4617 "TARGET_OS_MAC",
4618 "TARGET_OS_UNIX",
4619 "TARGET_OS_WIN32",
4620 )
4621 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4622 results = []
4623 for lnum, line in f.ChangedContents():
4624 for match in ifdef_macro.finditer(line):
4625 if match.group(1) in ALWAYS_DEFINED_MACROS:
4626 always_defined = ' %s is always defined. ' % match.group(1)
4627 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4628 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4629 lnum,
4630 always_defined,
4631 did_you_mean))
4632 return results
4633
4634
4635def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4636 """Check all affected files for invalid "if defined" macros."""
4637 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054638 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444639 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054640 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214641 continue
lliabraa35bab3932014-10-01 12:16:444642 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4643 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4644
4645 if not bad_macros:
4646 return []
4647
4648 return [output_api.PresubmitError(
4649 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4650 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4651 bad_macros)]
4652
4653
mlamouria82272622014-09-16 18:45:044654def _CheckForIPCRules(input_api, output_api):
4655 """Check for same IPC rules described in
4656 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4657 """
4658 base_pattern = r'IPC_ENUM_TRAITS\('
4659 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4660 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4661
4662 problems = []
4663 for f in input_api.AffectedSourceFiles(None):
4664 local_path = f.LocalPath()
4665 if not local_path.endswith('.h'):
4666 continue
4667 for line_number, line in f.ChangedContents():
4668 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4669 problems.append(
4670 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4671
4672 if problems:
4673 return [output_api.PresubmitPromptWarning(
4674 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4675 else:
4676 return []
4677
[email protected]b00342e7f2013-03-26 16:21:544678
Stephen Martinis97a394142018-06-07 23:06:054679def _CheckForLongPathnames(input_api, output_api):
4680 """Check to make sure no files being submitted have long paths.
4681 This causes issues on Windows.
4682 """
4683 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194684 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054685 local_path = f.LocalPath()
4686 # Windows has a path limit of 260 characters. Limit path length to 200 so
4687 # that we have some extra for the prefix on dev machines and the bots.
4688 if len(local_path) > 200:
4689 problems.append(local_path)
4690
4691 if problems:
4692 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4693 else:
4694 return []
4695
4696
Daniel Bratell8ba52722018-03-02 16:06:144697def _CheckForIncludeGuards(input_api, output_api):
4698 """Check that header files have proper guards against multiple inclusion.
4699 If a file should not have such guards (and it probably should) then it
4700 should include the string "no-include-guard-because-multiply-included".
4701 """
Daniel Bratell6a75baef62018-06-04 10:04:454702 def is_chromium_header_file(f):
4703 # We only check header files under the control of the Chromium
4704 # project. That is, those outside third_party apart from
4705 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324706 # We also exclude *_message_generator.h headers as they use
4707 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454708 file_with_path = input_api.os_path.normpath(f.LocalPath())
4709 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324710 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454711 (not file_with_path.startswith('third_party') or
4712 file_with_path.startswith(
4713 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144714
4715 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344716 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144717
4718 errors = []
4719
Daniel Bratell6a75baef62018-06-04 10:04:454720 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144721 guard_name = None
4722 guard_line_number = None
4723 seen_guard_end = False
4724
4725 file_with_path = input_api.os_path.normpath(f.LocalPath())
4726 base_file_name = input_api.os_path.splitext(
4727 input_api.os_path.basename(file_with_path))[0]
4728 upper_base_file_name = base_file_name.upper()
4729
4730 expected_guard = replace_special_with_underscore(
4731 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144732
4733 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574734 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4735 # are too many (1000+) files with slight deviations from the
4736 # coding style. The most important part is that the include guard
4737 # is there, and that it's unique, not the name so this check is
4738 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144739 #
4740 # As code becomes more uniform, this could be made stricter.
4741
4742 guard_name_pattern_list = [
4743 # Anything with the right suffix (maybe with an extra _).
4744 r'\w+_H__?',
4745
Daniel Bratell39b5b062018-05-16 18:09:574746 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144747 r'\w+_h',
4748
4749 # Anything including the uppercase name of the file.
4750 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4751 upper_base_file_name)) + r'\w*',
4752 ]
4753 guard_name_pattern = '|'.join(guard_name_pattern_list)
4754 guard_pattern = input_api.re.compile(
4755 r'#ifndef\s+(' + guard_name_pattern + ')')
4756
4757 for line_number, line in enumerate(f.NewContents()):
4758 if 'no-include-guard-because-multiply-included' in line:
4759 guard_name = 'DUMMY' # To not trigger check outside the loop.
4760 break
4761
4762 if guard_name is None:
4763 match = guard_pattern.match(line)
4764 if match:
4765 guard_name = match.group(1)
4766 guard_line_number = line_number
4767
Daniel Bratell39b5b062018-05-16 18:09:574768 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454769 # don't match the chromium style guide, but new files should
4770 # get it right.
4771 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574772 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144773 errors.append(output_api.PresubmitPromptWarning(
4774 'Header using the wrong include guard name %s' % guard_name,
4775 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574776 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144777 else:
4778 # The line after #ifndef should have a #define of the same name.
4779 if line_number == guard_line_number + 1:
4780 expected_line = '#define %s' % guard_name
4781 if line != expected_line:
4782 errors.append(output_api.PresubmitPromptWarning(
4783 'Missing "%s" for include guard' % expected_line,
4784 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4785 'Expected: %r\nGot: %r' % (expected_line, line)))
4786
4787 if not seen_guard_end and line == '#endif // %s' % guard_name:
4788 seen_guard_end = True
4789 elif seen_guard_end:
4790 if line.strip() != '':
4791 errors.append(output_api.PresubmitPromptWarning(
4792 'Include guard %s not covering the whole file' % (
4793 guard_name), [f.LocalPath()]))
4794 break # Nothing else to check and enough to warn once.
4795
4796 if guard_name is None:
4797 errors.append(output_api.PresubmitPromptWarning(
4798 'Missing include guard %s' % expected_guard,
4799 [f.LocalPath()],
4800 'Missing include guard in %s\n'
4801 'Recommended name: %s\n'
4802 'This check can be disabled by having the string\n'
4803 'no-include-guard-because-multiply-included in the header.' %
4804 (f.LocalPath(), expected_guard)))
4805
4806 return errors
4807
4808
mostynbb639aca52015-01-07 20:31:234809def _CheckForWindowsLineEndings(input_api, output_api):
4810 """Check source code and known ascii text files for Windows style line
4811 endings.
4812 """
earthdok1b5e0ee2015-03-10 15:19:104813 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234814
4815 file_inclusion_pattern = (
4816 known_text_files,
4817 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4818 )
4819
mostynbb639aca52015-01-07 20:31:234820 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534821 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444822 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534823 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504824 include_file = False
4825 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234826 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504827 include_file = True
4828 if include_file:
4829 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234830
4831 if problems:
4832 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4833 'these files to contain Windows style line endings?\n' +
4834 '\n'.join(problems))]
4835
4836 return []
4837
4838
Vaclav Brozekd5de76a2018-03-17 07:57:504839def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134840 """Checks that all source files use SYSLOG properly."""
4841 syslog_files = []
4842 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564843 for line_number, line in f.ChangedContents():
4844 if 'SYSLOG' in line:
4845 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4846
pastarmovj89f7ee12016-09-20 14:58:134847 if syslog_files:
4848 return [output_api.PresubmitPromptWarning(
4849 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4850 ' calls.\nFiles to check:\n', items=syslog_files)]
4851 return []
4852
4853
[email protected]1f7b4172010-01-28 01:17:344854def CheckChangeOnUpload(input_api, output_api):
4855 results = []
4856 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474857 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284858 results.extend(
jam93a6ee792017-02-08 23:59:224859 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194860 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224861 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134862 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164863 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534864 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194865 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274866 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544867 return results
[email protected]ca8d1982009-02-19 16:33:124868
4869
[email protected]1bfb8322014-04-23 01:02:414870def GetTryServerMasterForBot(bot):
4871 """Returns the Try Server master for the given bot.
4872
[email protected]0bb112362014-07-26 04:38:324873 It tries to guess the master from the bot name, but may still fail
4874 and return None. There is no longer a default master.
4875 """
4876 # Potentially ambiguous bot names are listed explicitly.
4877 master_map = {
tandriie5587792016-07-14 00:34:504878 'chromium_presubmit': 'master.tryserver.chromium.linux',
4879 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414880 }
[email protected]0bb112362014-07-26 04:38:324881 master = master_map.get(bot)
4882 if not master:
wnwen4fbaab82016-05-25 12:54:364883 if 'android' in bot:
tandriie5587792016-07-14 00:34:504884 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364885 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504886 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324887 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504888 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324889 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504890 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324891 return master
[email protected]1bfb8322014-04-23 01:02:414892
4893
[email protected]ca8d1982009-02-19 16:33:124894def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544895 results = []
[email protected]1f7b4172010-01-28 01:17:344896 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574897 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544898 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274899 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344900 input_api,
4901 output_api,
[email protected]2fdd1f362013-01-16 03:56:034902 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274903
jam93a6ee792017-02-08 23:59:224904 results.extend(
4905 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544906 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4907 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384908 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4909 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414910 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4911 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544912 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144913
4914
Rainhard Findlingfc31844c52020-05-15 09:58:264915def _CheckStrings(input_api, output_api):
4916 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024917 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4918 # footer is set to true.
4919 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264920 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024921 footer.lower()
4922 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264923 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024924
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144925 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264926 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144927 import sys
4928 from io import StringIO
4929
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144930 new_or_added_paths = set(f.LocalPath()
4931 for f in input_api.AffectedFiles()
4932 if (f.Action() == 'A' or f.Action() == 'M'))
4933 removed_paths = set(f.LocalPath()
4934 for f in input_api.AffectedFiles(include_deletes=True)
4935 if f.Action() == 'D')
4936
4937 affected_grds = [f for f in input_api.AffectedFiles()
Rainhard Findlingfc31844c52020-05-15 09:58:264938 if (f.LocalPath().endswith(('.grd', '.grdp')))]
meacer8c0d3832019-12-26 21:46:164939 if not affected_grds:
4940 return []
4941
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144942 affected_png_paths = [f.AbsoluteLocalPath()
4943 for f in input_api.AffectedFiles()
4944 if (f.LocalPath().endswith('.png'))]
4945
4946 # Check for screenshots. Developers can upload screenshots using
4947 # tools/translation/upload_screenshots.py which finds and uploads
4948 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4949 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4950 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4951 #
4952 # The logic here is as follows:
4953 #
4954 # - If the CL has a .png file under the screenshots directory for a grd
4955 # file, warn the developer. Actual images should never be checked into the
4956 # Chrome repo.
4957 #
4958 # - If the CL contains modified or new messages in grd files and doesn't
4959 # contain the corresponding .sha1 files, warn the developer to add images
4960 # and upload them via tools/translation/upload_screenshots.py.
4961 #
4962 # - If the CL contains modified or new messages in grd files and the
4963 # corresponding .sha1 files, everything looks good.
4964 #
4965 # - If the CL contains removed messages in grd files but the corresponding
4966 # .sha1 files aren't removed, warn the developer to remove them.
4967 unnecessary_screenshots = []
4968 missing_sha1 = []
4969 unnecessary_sha1_files = []
4970
Rainhard Findlingfc31844c52020-05-15 09:58:264971 # This checks verifies that the ICU syntax of messages this CL touched is
4972 # valid, and reports any found syntax errors.
4973 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4974 # without developers being aware of them. Later on, such ICU syntax errors
4975 # break message extraction for translation, hence would block Chromium
4976 # translations until they are fixed.
4977 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144978
4979 def _CheckScreenshotAdded(screenshots_dir, message_id):
4980 sha1_path = input_api.os_path.join(
4981 screenshots_dir, message_id + '.png.sha1')
4982 if sha1_path not in new_or_added_paths:
4983 missing_sha1.append(sha1_path)
4984
4985
4986 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4987 sha1_path = input_api.os_path.join(
4988 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034989 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144990 unnecessary_sha1_files.append(sha1_path)
4991
Rainhard Findlingfc31844c52020-05-15 09:58:264992
4993 def _ValidateIcuSyntax(text, level, signatures):
4994 """Validates ICU syntax of a text string.
4995
4996 Check if text looks similar to ICU and checks for ICU syntax correctness
4997 in this case. Reports various issues with ICU syntax and values of
4998 variants. Supports checking of nested messages. Accumulate information of
4999 each ICU messages found in the text for further checking.
5000
5001 Args:
5002 text: a string to check.
5003 level: a number of current nesting level.
5004 signatures: an accumulator, a list of tuple of (level, variable,
5005 kind, variants).
5006
5007 Returns:
5008 None if a string is not ICU or no issue detected.
5009 A tuple of (message, start index, end index) if an issue detected.
5010 """
5011 valid_types = {
5012 'plural': (frozenset(
5013 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5014 frozenset(['=1', 'other'])),
5015 'selectordinal': (frozenset(
5016 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5017 frozenset(['one', 'other'])),
5018 'select': (frozenset(), frozenset(['other'])),
5019 }
5020
5021 # Check if the message looks like an attempt to use ICU
5022 # plural. If yes - check if its syntax strictly matches ICU format.
5023 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
5024 if not like:
5025 signatures.append((level, None, None, None))
5026 return
5027
5028 # Check for valid prefix and suffix
5029 m = re.match(
5030 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5031 r'(plural|selectordinal|select),\s*'
5032 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5033 if not m:
5034 return (('This message looks like an ICU plural, '
5035 'but does not follow ICU syntax.'), like.start(), like.end())
5036 starting, variable, kind, variant_pairs = m.groups()
5037 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5038 if depth:
5039 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5040 len(text))
5041 first = text[0]
5042 ending = text[last_pos:]
5043 if not starting:
5044 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5045 last_pos)
5046 if not ending or '}' not in ending:
5047 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5048 last_pos)
5049 elif first != '{':
5050 return (
5051 ('Invalid ICU format. Extra characters at the start of a complex '
5052 'message (go/icu-message-migration): "%s"') %
5053 starting, 0, len(starting))
5054 elif ending != '}':
5055 return (('Invalid ICU format. Extra characters at the end of a complex '
5056 'message (go/icu-message-migration): "%s"')
5057 % ending, last_pos - 1, len(text) - 1)
5058 if kind not in valid_types:
5059 return (('Unknown ICU message type %s. '
5060 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5061 known, required = valid_types[kind]
5062 defined_variants = set()
5063 for variant, variant_range, value, value_range in variants:
5064 start, end = variant_range
5065 if variant in defined_variants:
5066 return ('Variant "%s" is defined more than once' % variant,
5067 start, end)
5068 elif known and variant not in known:
5069 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5070 start, end)
5071 defined_variants.add(variant)
5072 # Check for nested structure
5073 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5074 if res:
5075 return (res[0], res[1] + value_range[0] + 1,
5076 res[2] + value_range[0] + 1)
5077 missing = required - defined_variants
5078 if missing:
5079 return ('Required variants missing: %s' % ', '.join(missing), 0,
5080 len(text))
5081 signatures.append((level, variable, kind, defined_variants))
5082
5083
5084 def _ParseIcuVariants(text, offset=0):
5085 """Parse variants part of ICU complex message.
5086
5087 Builds a tuple of variant names and values, as well as
5088 their offsets in the input string.
5089
5090 Args:
5091 text: a string to parse
5092 offset: additional offset to add to positions in the text to get correct
5093 position in the complete ICU string.
5094
5095 Returns:
5096 List of tuples, each tuple consist of four fields: variant name,
5097 variant name span (tuple of two integers), variant value, value
5098 span (tuple of two integers).
5099 """
5100 depth, start, end = 0, -1, -1
5101 variants = []
5102 key = None
5103 for idx, char in enumerate(text):
5104 if char == '{':
5105 if not depth:
5106 start = idx
5107 chunk = text[end + 1:start]
5108 key = chunk.strip()
5109 pos = offset + end + 1 + chunk.find(key)
5110 span = (pos, pos + len(key))
5111 depth += 1
5112 elif char == '}':
5113 if not depth:
5114 return variants, depth, offset + idx
5115 depth -= 1
5116 if not depth:
5117 end = idx
5118 variants.append((key, span, text[start:end + 1], (offset + start,
5119 offset + end + 1)))
5120 return variants, depth, offset + end + 1
5121
meacer8c0d3832019-12-26 21:46:165122 try:
5123 old_sys_path = sys.path
5124 sys.path = sys.path + [input_api.os_path.join(
5125 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5126 from helper import grd_helper
5127 finally:
5128 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145129
5130 for f in affected_grds:
5131 file_path = f.LocalPath()
5132 old_id_to_msg_map = {}
5133 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385134 # Note that this code doesn't check if the file has been deleted. This is
5135 # OK because it only uses the old and new file contents and doesn't load
5136 # the file via its path.
5137 # It's also possible that a file's content refers to a renamed or deleted
5138 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5139 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5140 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145141 if file_path.endswith('.grdp'):
5142 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585143 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395144 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145145 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585146 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395147 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145148 else:
meacerff8a9b62019-12-10 19:43:585149 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145150 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585151 old_id_to_msg_map = grd_helper.GetGrdMessages(
5152 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145153 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585154 new_id_to_msg_map = grd_helper.GetGrdMessages(
5155 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145156
5157 # Compute added, removed and modified message IDs.
5158 old_ids = set(old_id_to_msg_map)
5159 new_ids = set(new_id_to_msg_map)
5160 added_ids = new_ids - old_ids
5161 removed_ids = old_ids - new_ids
5162 modified_ids = set([])
5163 for key in old_ids.intersection(new_ids):
5164 if (old_id_to_msg_map[key].FormatXml()
5165 != new_id_to_msg_map[key].FormatXml()):
5166 modified_ids.add(key)
5167
5168 grd_name, ext = input_api.os_path.splitext(
5169 input_api.os_path.basename(file_path))
5170 screenshots_dir = input_api.os_path.join(
5171 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5172
Rainhard Findlingfc31844c52020-05-15 09:58:265173 if run_screenshot_check:
5174 # Check the screenshot directory for .png files. Warn if there is any.
5175 for png_path in affected_png_paths:
5176 if png_path.startswith(screenshots_dir):
5177 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145178
Rainhard Findlingfc31844c52020-05-15 09:58:265179 for added_id in added_ids:
5180 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145181
Rainhard Findlingfc31844c52020-05-15 09:58:265182 for modified_id in modified_ids:
5183 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145184
Rainhard Findlingfc31844c52020-05-15 09:58:265185 for removed_id in removed_ids:
5186 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5187
5188 # Check new and changed strings for ICU syntax errors.
5189 for key in added_ids.union(modified_ids):
5190 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5191 err = _ValidateIcuSyntax(msg, 0, [])
5192 if err is not None:
5193 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145194
5195 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265196 if run_screenshot_check:
5197 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005198 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265199 'Do not include actual screenshots in the changelist. Run '
5200 'tools/translate/upload_screenshots.py to upload them instead:',
5201 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145202
Rainhard Findlingfc31844c52020-05-15 09:58:265203 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005204 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265205 'You are adding or modifying UI strings.\n'
5206 'To ensure the best translations, take screenshots of the relevant UI '
5207 '(https://g.co/chrome/translation) and add these files to your '
5208 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145209
Rainhard Findlingfc31844c52020-05-15 09:58:265210 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005211 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265212 'You removed strings associated with these files. Remove:',
5213 sorted(unnecessary_sha1_files)))
5214 else:
5215 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5216 'screenshots check.'))
5217
5218 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075219 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265220 'ICU syntax errors were found in the following strings (problems or '
5221 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145222
5223 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125224
5225
5226def _CheckTranslationExpectations(input_api, output_api,
5227 repo_root=None,
5228 translation_expectations_path=None,
5229 grd_files=None):
5230 import sys
5231 affected_grds = [f for f in input_api.AffectedFiles()
5232 if (f.LocalPath().endswith('.grd') or
5233 f.LocalPath().endswith('.grdp'))]
5234 if not affected_grds:
5235 return []
5236
5237 try:
5238 old_sys_path = sys.path
5239 sys.path = sys.path + [
5240 input_api.os_path.join(
5241 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5242 from helper import git_helper
5243 from helper import translation_helper
5244 finally:
5245 sys.path = old_sys_path
5246
5247 # Check that translation expectations can be parsed and we can get a list of
5248 # translatable grd files. |repo_root| and |translation_expectations_path| are
5249 # only passed by tests.
5250 if not repo_root:
5251 repo_root = input_api.PresubmitLocalPath()
5252 if not translation_expectations_path:
5253 translation_expectations_path = input_api.os_path.join(
5254 repo_root, 'tools', 'gritsettings',
5255 'translation_expectations.pyl')
5256 if not grd_files:
5257 grd_files = git_helper.list_grds_in_repository(repo_root)
5258
5259 try:
5260 translation_helper.get_translatable_grds(repo_root, grd_files,
5261 translation_expectations_path)
5262 except Exception as e:
5263 return [output_api.PresubmitNotifyResult(
5264 'Failed to get a list of translatable grd files. This happens when:\n'
5265 ' - One of the modified grd or grdp files cannot be parsed or\n'
5266 ' - %s is not updated.\n'
5267 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5268 return []
Ken Rockotc31f4832020-05-29 18:58:515269
5270
5271def _CheckStableMojomChanges(input_api, output_api):
5272 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095273 changed_mojoms = input_api.AffectedFiles(
5274 include_deletes=True,
5275 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515276 delta = []
5277 for mojom in changed_mojoms:
5278 old_contents = ''.join(mojom.OldContents()) or None
5279 new_contents = ''.join(mojom.NewContents()) or None
5280 delta.append({
5281 'filename': mojom.LocalPath(),
5282 'old': '\n'.join(mojom.OldContents()) or None,
5283 'new': '\n'.join(mojom.NewContents()) or None,
5284 })
5285
5286 process = input_api.subprocess.Popen(
5287 [input_api.python_executable,
5288 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5289 'public', 'tools', 'mojom',
5290 'check_stable_mojom_compatibility.py'),
5291 '--src-root', input_api.PresubmitLocalPath()],
5292 stdin=input_api.subprocess.PIPE,
5293 stdout=input_api.subprocess.PIPE,
5294 stderr=input_api.subprocess.PIPE,
5295 universal_newlines=True)
5296 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5297 if process.returncode:
5298 return [output_api.PresubmitError(
5299 'One or more [Stable] mojom definitions appears to have been changed '
5300 'in a way that is not backward-compatible.',
5301 long_text=error)]
5302 return []