blob: 5bab2b53f4d3789f2d4bd970dda2722ae5764b1e [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Saagar Sanghavifceeaae2020-08-12 16:40:3610PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Ilya Shermane8a7d2d2020-07-25 04:33:4713 # Generated file.
14 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2615 r"client_variations.js"),
Egor Paskoce145c42018-09-28 19:31:0416 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
17 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
18 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
19 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
20 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4921 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4623 # sqlite is an imported third party dependency.
24 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0425 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5426 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5327 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1228 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0429 r".+[\\/]pnacl_shim\.c$",
30 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0431 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1432 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0433 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5434 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0435 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4036)
[email protected]ca8d1982009-02-19 16:33:1237
wnwenbdc444e2016-05-25 13:44:1538
[email protected]06e6d0ff2012-12-11 01:36:4439# Fragment of a regular expression that matches C++ and Objective-C++
40# implementation files.
41_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
42
wnwenbdc444e2016-05-25 13:44:1543
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1944# Fragment of a regular expression that matches C++ and Objective-C++
45# header files.
46_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
47
48
[email protected]06e6d0ff2012-12-11 01:36:4449# Regular expression that matches code only used for test binaries
50# (best effort).
51_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0452 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4453 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4454 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1255 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1856 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4457 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0458 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4359 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0460 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4361 # Web test harness.
62 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4763 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0464 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0865 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0466 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4167 # EarlGrey app side code for tests.
68 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1769 # Views Examples code
70 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4171 # Chromium Codelab
72 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4473)
[email protected]ca8d1982009-02-19 16:33:1274
Daniel Bratell609102be2019-03-27 20:53:2175_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1576
[email protected]eea609a2011-11-18 13:10:1277_TEST_ONLY_WARNING = (
78 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5579 'production code. If you are doing this from inside another method\n'
80 'named as *ForTesting(), then consider exposing things to have tests\n'
81 'make that same call directly.\n'
82 'If that is not possible, you may put a comment on the same line with\n'
83 ' // IN-TEST \n'
84 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
85 'method and can be ignored. Do not do this inside production code.\n'
86 'The android-binary-size trybot will block if the method exists in the\n'
87 'release apk.')
[email protected]eea609a2011-11-18 13:10:1288
89
[email protected]cf9b78f2012-11-14 11:40:2890_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4091 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2192 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
93 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2894
Michael Thiessen44457642020-02-06 00:24:1595# Format: Sequence of tuples containing:
96# * Full import path.
97# * Sequence of strings to show when the pattern matches.
98# * Sequence of path or filename exceptions to this rule
99_BANNED_JAVA_IMPORTS = (
100 (
Colin Blundell170d78c82020-03-12 13:56:04101 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15102 (
103 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
104 ),
105 (
106 'net/android/javatests/src/org/chromium/net/'
107 'AndroidProxySelectorTest.java',
108 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04109 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15110 ),
111 ),
Michael Thiessened631912020-08-07 19:01:31112 (
113 'android.support.test.rule.UiThreadTestRule;',
114 (
115 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43116 '@org.chromium.base.test.UiThreadTest on test methods that should run '
117 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31118 ),
119 (),
120 ),
121 (
122 'android.support.test.annotation.UiThreadTest;',
123 (
124 'Do not use android.support.test.annotation.UiThreadTest, use '
125 'org.chromium.base.test.UiThreadTest instead. See '
126 'https://crbug.com/1111893.',
127 ),
128 ()
129 )
Michael Thiessen44457642020-02-06 00:24:15130)
wnwenbdc444e2016-05-25 13:44:15131
Daniel Bratell609102be2019-03-27 20:53:21132# Format: Sequence of tuples containing:
133# * String pattern or, if starting with a slash, a regular expression.
134# * Sequence of strings to show when the pattern matches.
135# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41136_BANNED_JAVA_FUNCTIONS = (
137 (
138 'StrictMode.allowThreadDiskReads()',
139 (
140 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
141 'directly.',
142 ),
143 False,
144 ),
145 (
146 'StrictMode.allowThreadDiskWrites()',
147 (
148 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
149 'directly.',
150 ),
151 False,
152 ),
Michael Thiessen0f2547e2020-07-27 21:55:36153 (
154 '.waitForIdleSync()',
155 (
156 'Do not use waitForIdleSync as it masks underlying issues. There is '
157 'almost always something else you should wait on instead.',
158 ),
159 False,
160 ),
Eric Stevensona9a980972017-09-23 00:04:41161)
162
Daniel Bratell609102be2019-03-27 20:53:21163# Format: Sequence of tuples containing:
164# * String pattern or, if starting with a slash, a regular expression.
165# * Sequence of strings to show when the pattern matches.
166# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59167_BANNED_OBJC_FUNCTIONS = (
168 (
169 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20170 (
171 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59172 'prohibited. Please use CrTrackingArea instead.',
173 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
174 ),
175 False,
176 ),
177 (
[email protected]eaae1972014-04-16 04:17:26178 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20179 (
180 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59181 'instead.',
182 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
183 ),
184 False,
185 ),
186 (
187 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20188 (
189 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59190 'Please use |convertPoint:(point) fromView:nil| instead.',
191 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
192 ),
193 True,
194 ),
195 (
196 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20197 (
198 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59199 'Please use |convertPoint:(point) toView:nil| instead.',
200 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
201 ),
202 True,
203 ),
204 (
205 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20206 (
207 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59208 'Please use |convertRect:(point) fromView:nil| instead.',
209 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
210 ),
211 True,
212 ),
213 (
214 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20215 (
216 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59217 'Please use |convertRect:(point) toView:nil| instead.',
218 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
219 ),
220 True,
221 ),
222 (
223 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20224 (
225 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59226 'Please use |convertSize:(point) fromView:nil| instead.',
227 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
228 ),
229 True,
230 ),
231 (
232 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20233 (
234 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59235 'Please use |convertSize:(point) toView:nil| instead.',
236 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
237 ),
238 True,
239 ),
jif65398702016-10-27 10:19:48240 (
241 r"/\s+UTF8String\s*]",
242 (
243 'The use of -[NSString UTF8String] is dangerous as it can return null',
244 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
245 'Please use |SysNSStringToUTF8| instead.',
246 ),
247 True,
248 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34249 (
250 r'__unsafe_unretained',
251 (
252 'The use of __unsafe_unretained is almost certainly wrong, unless',
253 'when interacting with NSFastEnumeration or NSInvocation.',
254 'Please use __weak in files build with ARC, nothing otherwise.',
255 ),
256 False,
257 ),
Avi Drissman7382afa02019-04-29 23:27:13258 (
259 'freeWhenDone:NO',
260 (
261 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
262 'Foundation types is prohibited.',
263 ),
264 True,
265 ),
[email protected]127f18ec2012-06-16 05:05:59266)
267
Daniel Bratell609102be2019-03-27 20:53:21268# Format: Sequence of tuples containing:
269# * String pattern or, if starting with a slash, a regular expression.
270# * Sequence of strings to show when the pattern matches.
271# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54272_BANNED_IOS_OBJC_FUNCTIONS = (
273 (
274 r'/\bTEST[(]',
275 (
276 'TEST() macro should not be used in Objective-C++ code as it does not ',
277 'drain the autorelease pool at the end of the test. Use TEST_F() ',
278 'macro instead with a fixture inheriting from PlatformTest (or a ',
279 'typedef).'
280 ),
281 True,
282 ),
283 (
284 r'/\btesting::Test\b',
285 (
286 'testing::Test should not be used in Objective-C++ code as it does ',
287 'not drain the autorelease pool at the end of the test. Use ',
288 'PlatformTest instead.'
289 ),
290 True,
291 ),
292)
293
Peter K. Lee6c03ccff2019-07-15 14:40:05294# Format: Sequence of tuples containing:
295# * String pattern or, if starting with a slash, a regular expression.
296# * Sequence of strings to show when the pattern matches.
297# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
298_BANNED_IOS_EGTEST_FUNCTIONS = (
299 (
300 r'/\bEXPECT_OCMOCK_VERIFY\b',
301 (
302 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
303 'it is meant for GTests. Use [mock verify] instead.'
304 ),
305 True,
306 ),
307)
308
danakj7a2b7082019-05-21 21:13:51309# Directories that contain deprecated Bind() or Callback types.
310# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36311# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51312# echo "-- $i"
danakj710b4c02019-11-28 16:08:45313# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51314# done
315#
316# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
317# when they have been converted to modern callback types (OnceCallback,
318# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
319# checks for them and prevent regressions.
320_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51321 '^base/callback.h', # Intentional.
Alex Turnerb3ea38c2020-11-25 18:03:07322 '^base/cancelable_callback.h', # Intentional.
Alexander Cooper6b447b22020-07-22 00:47:18323 '^chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc',
324 '^chrome/browser/apps/guest_view/',
Alexander Cooper6b447b22020-07-22 00:47:18325 '^chrome/browser/browsing_data/',
326 '^chrome/browser/captive_portal/captive_portal_browsertest.cc',
327 '^chrome/browser/chromeos/',
328 '^chrome/browser/component_updater/',
Peter Wen6367b882020-08-05 16:55:50329 '^chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc', # pylint: disable=line-too-long
Alexander Cooper6b447b22020-07-22 00:47:18330 '^chrome/browser/devtools/',
331 '^chrome/browser/download/',
332 '^chrome/browser/extensions/',
Alexander Cooper6b447b22020-07-22 00:47:18333 '^chrome/browser/history/',
Alexander Cooper6b447b22020-07-22 00:47:18334 '^chrome/browser/lifetime/',
335 '^chrome/browser/media_galleries/',
Alexander Cooper6b447b22020-07-22 00:47:18336 '^chrome/browser/net/',
337 '^chrome/browser/notifications/',
338 '^chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc',
339 '^chrome/browser/offline_pages/',
Peter Wen6367b882020-08-05 16:55:50340 '^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:18341 '^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',
Alexander Cooper6b447b22020-07-22 00:47:18359 '^chrome/browser/search_engines/',
360 '^chrome/browser/service_process/',
361 '^chrome/browser/signin/',
362 '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
Alexander Cooper6b447b22020-07-22 00:47:18363 '^chrome/browser/supervised_user/',
364 '^chrome/browser/sync_file_system/',
Alexander Cooper6b447b22020-07-22 00:47:18365 '^chrome/browser/translate/',
366 '^chrome/browser/ui/',
Alexander Cooper6b447b22020-07-22 00:47:18367 '^chrome/browser/web_applications/',
368 '^chrome/browser/win/',
Alex Turner1dc2e1022020-10-22 16:31:54369 '^chrome/test/chromedriver/server/http_handler.cc',
danakj7a2b7082019-05-21 21:13:51370 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51371 '^components/drive/',
danakj7a2b7082019-05-21 21:13:51372 '^components/search_engines/',
danakj7a2b7082019-05-21 21:13:51373 '^components/webcrypto/',
Alan Cutter04a00642020-03-02 01:45:20374 '^extensions/browser/',
375 '^extensions/renderer/',
David Bienvenu0cf6ec02020-12-04 21:03:21376 '^media/blink/',
Daniel Hosseinian41af1882020-10-29 23:10:10377 '^media/cdm/',
Steve Kobes334b6ed2020-07-09 07:26:31378 '^net/http/',
379 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51380 '^ppapi/proxy/',
danakj7a2b7082019-05-21 21:13:51381 '^services/',
danakj7a2b7082019-05-21 21:13:51382 '^tools/clang/base_bind_rewriters/', # Intentional.
383 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51384))
[email protected]127f18ec2012-06-16 05:05:59385
Daniel Bratell609102be2019-03-27 20:53:21386# Format: Sequence of tuples containing:
387# * String pattern or, if starting with a slash, a regular expression.
388# * Sequence of strings to show when the pattern matches.
389# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
390# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59391_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20392 (
Dave Tapuska98199b612019-07-10 13:30:44393 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53394 (
395 'New code should not use NULL. Use nullptr instead.',
396 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20397 False,
thomasandersone7caaa9b2017-03-29 19:22:53398 (),
399 ),
Peter Kasting94a56c42019-10-25 21:54:04400 (
401 r'/\busing namespace ',
402 (
403 'Using directives ("using namespace x") are banned by the Google Style',
404 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
405 'Explicitly qualify symbols or use using declarations ("using x::foo").',
406 ),
407 True,
408 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
409 ),
Antonio Gomes07300d02019-03-13 20:59:57410 # Make sure that gtest's FRIEND_TEST() macro is not used; the
411 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
412 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53413 (
[email protected]23e6cbc2012-06-16 18:51:20414 'FRIEND_TEST(',
415 (
[email protected]e3c945502012-06-26 20:01:49416 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20417 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
418 ),
419 False,
[email protected]7345da02012-11-27 14:31:49420 (),
[email protected]23e6cbc2012-06-16 18:51:20421 ),
422 (
tomhudsone2c14d552016-05-26 17:07:46423 'setMatrixClip',
424 (
425 'Overriding setMatrixClip() is prohibited; ',
426 'the base function is deprecated. ',
427 ),
428 True,
429 (),
430 ),
431 (
[email protected]52657f62013-05-20 05:30:31432 'SkRefPtr',
433 (
434 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22435 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31436 ),
437 True,
438 (),
439 ),
440 (
441 'SkAutoRef',
442 (
443 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22444 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31445 ),
446 True,
447 (),
448 ),
449 (
450 'SkAutoTUnref',
451 (
452 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22453 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31454 ),
455 True,
456 (),
457 ),
458 (
459 'SkAutoUnref',
460 (
461 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
462 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22463 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31464 ),
465 True,
466 (),
467 ),
[email protected]d89eec82013-12-03 14:10:59468 (
469 r'/HANDLE_EINTR\(.*close',
470 (
471 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
472 'descriptor will be closed, and it is incorrect to retry the close.',
473 'Either call close directly and ignore its return value, or wrap close',
474 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
475 ),
476 True,
477 (),
478 ),
479 (
480 r'/IGNORE_EINTR\((?!.*close)',
481 (
482 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
483 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
484 ),
485 True,
486 (
487 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04488 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
489 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59490 ),
491 ),
[email protected]ec5b3f02014-04-04 18:43:43492 (
493 r'/v8::Extension\(',
494 (
495 'Do not introduce new v8::Extensions into the code base, use',
496 'gin::Wrappable instead. See http://crbug.com/334679',
497 ),
498 True,
[email protected]f55c90ee62014-04-12 00:50:03499 (
Egor Paskoce145c42018-09-28 19:31:04500 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03501 ),
[email protected]ec5b3f02014-04-04 18:43:43502 ),
skyostilf9469f72015-04-20 10:38:52503 (
jame2d1a952016-04-02 00:27:10504 '#pragma comment(lib,',
505 (
506 'Specify libraries to link with in build files and not in the source.',
507 ),
508 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41509 (
tzik3f295992018-12-04 20:32:23510 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04511 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41512 ),
jame2d1a952016-04-02 00:27:10513 ),
fdorayc4ac18d2017-05-01 21:39:59514 (
Gabriel Charette7cc6c432018-04-25 20:52:02515 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59516 (
517 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
518 ),
519 False,
520 (),
521 ),
522 (
Gabriel Charette7cc6c432018-04-25 20:52:02523 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59524 (
525 'Consider using THREAD_CHECKER macros instead of the class directly.',
526 ),
527 False,
528 (),
529 ),
dbeamb6f4fde2017-06-15 04:03:06530 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06531 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
532 (
533 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
534 'deprecated (http://crbug.com/634507). Please avoid converting away',
535 'from the Time types in Chromium code, especially if any math is',
536 'being done on time values. For interfacing with platform/library',
537 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
538 'type converter methods instead. For faking TimeXXX values (for unit',
539 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
540 'other use cases, please contact base/time/OWNERS.',
541 ),
542 False,
543 (),
544 ),
545 (
dbeamb6f4fde2017-06-15 04:03:06546 'CallJavascriptFunctionUnsafe',
547 (
548 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
549 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
550 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
551 ),
552 False,
553 (
Egor Paskoce145c42018-09-28 19:31:04554 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
555 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
556 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06557 ),
558 ),
dskiba1474c2bfd62017-07-20 02:19:24559 (
560 'leveldb::DB::Open',
561 (
562 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
563 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
564 "Chrome's tracing, making their memory usage visible.",
565 ),
566 True,
567 (
568 r'^third_party/leveldatabase/.*\.(cc|h)$',
569 ),
Gabriel Charette0592c3a2017-07-26 12:02:04570 ),
571 (
Chris Mumfordc38afb62017-10-09 17:55:08572 'leveldb::NewMemEnv',
573 (
574 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58575 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
576 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08577 ),
578 True,
579 (
580 r'^third_party/leveldatabase/.*\.(cc|h)$',
581 ),
582 ),
583 (
Gabriel Charetted9839bc2017-07-29 14:17:47584 'RunLoop::QuitCurrent',
585 (
Robert Liao64b7ab22017-08-04 23:03:43586 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
587 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47588 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41589 False,
Gabriel Charetted9839bc2017-07-29 14:17:47590 (),
Gabriel Charettea44975052017-08-21 23:14:04591 ),
592 (
593 'base::ScopedMockTimeMessageLoopTaskRunner',
594 (
Gabriel Charette87cc1af2018-04-25 20:52:51595 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11596 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51597 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
598 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
599 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04600 ),
Gabriel Charette87cc1af2018-04-25 20:52:51601 False,
Gabriel Charettea44975052017-08-21 23:14:04602 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57603 ),
604 (
Dave Tapuska98199b612019-07-10 13:30:44605 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57606 (
607 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02608 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57609 ),
610 True,
611 (),
Francois Doray43670e32017-09-27 12:40:38612 ),
613 (
Peter Kasting991618a62019-06-17 22:00:09614 r'/\bstd::stoi\b',
615 (
616 'std::stoi uses exceptions to communicate results. ',
617 'Use base::StringToInt() instead.',
618 ),
619 True,
620 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
621 ),
622 (
623 r'/\bstd::stol\b',
624 (
625 'std::stol uses exceptions to communicate results. ',
626 'Use base::StringToInt() instead.',
627 ),
628 True,
629 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
630 ),
631 (
632 r'/\bstd::stoul\b',
633 (
634 'std::stoul uses exceptions to communicate results. ',
635 'Use base::StringToUint() instead.',
636 ),
637 True,
638 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
639 ),
640 (
641 r'/\bstd::stoll\b',
642 (
643 'std::stoll uses exceptions to communicate results. ',
644 'Use base::StringToInt64() instead.',
645 ),
646 True,
647 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
648 ),
649 (
650 r'/\bstd::stoull\b',
651 (
652 'std::stoull uses exceptions to communicate results. ',
653 'Use base::StringToUint64() instead.',
654 ),
655 True,
656 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
657 ),
658 (
659 r'/\bstd::stof\b',
660 (
661 'std::stof uses exceptions to communicate results. ',
662 'For locale-independent values, e.g. reading numbers from disk',
663 'profiles, use base::StringToDouble().',
664 'For user-visible values, parse using ICU.',
665 ),
666 True,
667 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
668 ),
669 (
670 r'/\bstd::stod\b',
671 (
672 'std::stod uses exceptions to communicate results. ',
673 'For locale-independent values, e.g. reading numbers from disk',
674 'profiles, use base::StringToDouble().',
675 'For user-visible values, parse using ICU.',
676 ),
677 True,
678 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
679 ),
680 (
681 r'/\bstd::stold\b',
682 (
683 'std::stold uses exceptions to communicate results. ',
684 'For locale-independent values, e.g. reading numbers from disk',
685 'profiles, use base::StringToDouble().',
686 'For user-visible values, parse using ICU.',
687 ),
688 True,
689 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
690 ),
691 (
Daniel Bratell69334cc2019-03-26 11:07:45692 r'/\bstd::to_string\b',
693 (
694 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09695 'For locale-independent strings, e.g. writing numbers to disk',
696 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45697 'For user-visible strings, use base::FormatNumber() and',
698 'the related functions in base/i18n/number_formatting.h.',
699 ),
Peter Kasting991618a62019-06-17 22:00:09700 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21701 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45702 ),
703 (
704 r'/\bstd::shared_ptr\b',
705 (
706 'std::shared_ptr should not be used. Use scoped_refptr instead.',
707 ),
708 True,
Alex Chau9eb03cdd52020-07-13 21:04:57709 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
710 'array_buffer_contents\.(cc|h)',
711 # Needed for interop with third-party library
712 'chrome/services/sharing/nearby/',
713 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21714 ),
715 (
Peter Kasting991618a62019-06-17 22:00:09716 r'/\bstd::weak_ptr\b',
717 (
718 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
719 ),
720 True,
721 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
722 ),
723 (
Daniel Bratell609102be2019-03-27 20:53:21724 r'/\blong long\b',
725 (
726 'long long is banned. Use stdint.h if you need a 64 bit number.',
727 ),
728 False, # Only a warning since it is already used.
729 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
730 ),
731 (
732 r'/\bstd::bind\b',
733 (
734 'std::bind is banned because of lifetime risks.',
735 'Use base::BindOnce or base::BindRepeating instead.',
736 ),
737 True,
738 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
739 ),
740 (
741 r'/\b#include <chrono>\b',
742 (
743 '<chrono> overlaps with Time APIs in base. Keep using',
744 'base classes.',
745 ),
746 True,
747 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
748 ),
749 (
750 r'/\b#include <exception>\b',
751 (
752 'Exceptions are banned and disabled in Chromium.',
753 ),
754 True,
755 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
756 ),
757 (
758 r'/\bstd::function\b',
759 (
760 'std::function is banned. Instead use base::Callback which directly',
761 'supports Chromium\'s weak pointers, ref counting and more.',
762 ),
Peter Kasting991618a62019-06-17 22:00:09763 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21764 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
765 ),
766 (
767 r'/\b#include <random>\b',
768 (
769 'Do not use any random number engines from <random>. Instead',
770 'use base::RandomBitGenerator.',
771 ),
772 True,
773 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
774 ),
775 (
Tom Andersona95e12042020-09-09 23:08:00776 r'/\b#include <X11/',
777 (
778 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
779 ),
780 True,
781 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
782 ),
783 (
Daniel Bratell609102be2019-03-27 20:53:21784 r'/\bstd::ratio\b',
785 (
786 'std::ratio is banned by the Google Style Guide.',
787 ),
788 True,
789 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45790 ),
791 (
Francois Doray43670e32017-09-27 12:40:38792 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
793 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
794 (
795 'Use the new API in base/threading/thread_restrictions.h.',
796 ),
Gabriel Charette04b138f2018-08-06 00:03:22797 False,
Francois Doray43670e32017-09-27 12:40:38798 (),
799 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38800 (
danakj7a2b7082019-05-21 21:13:51801 r'/\bbase::Bind\(',
802 (
803 'Please use base::Bind{Once,Repeating} instead',
804 'of base::Bind. (crbug.com/714018)',
805 ),
806 False,
Erik Staaba737d7602019-11-25 18:41:07807 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51808 ),
809 (
810 r'/\bbase::Callback[<:]',
811 (
812 'Please use base::{Once,Repeating}Callback instead',
813 'of base::Callback. (crbug.com/714018)',
814 ),
815 False,
Erik Staaba737d7602019-11-25 18:41:07816 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51817 ),
818 (
819 r'/\bbase::Closure\b',
820 (
821 'Please use base::{Once,Repeating}Closure instead',
822 'of base::Closure. (crbug.com/714018)',
823 ),
824 False,
Erik Staaba737d7602019-11-25 18:41:07825 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51826 ),
827 (
Alex Turnerb3ea38c2020-11-25 18:03:07828 r'/\bbase::CancelableCallback[<:]',
829 (
830 'Please use base::Cancelable{Once,Repeating}Callback instead',
831 'of base::CancelableCallback. (crbug.com/714018)',
832 ),
833 False,
834 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
835 ),
836 (
837 r'/\bbase::CancelableClosure\b',
838 (
839 'Please use base::Cancelable{Once,Repeating}Closure instead',
840 'of base::CancelableClosure. (crbug.com/714018)',
841 ),
842 False,
843 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
844 ),
845 (
Michael Giuffrida7f93d6922019-04-19 14:39:58846 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19847 (
848 'RunMessageLoop is deprecated, use RunLoop instead.',
849 ),
850 False,
851 (),
852 ),
853 (
Dave Tapuska98199b612019-07-10 13:30:44854 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19855 (
856 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
857 ),
858 False,
859 (),
860 ),
861 (
Dave Tapuska98199b612019-07-10 13:30:44862 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19863 (
864 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
865 "if you're convinced you need this.",
866 ),
867 False,
868 (),
869 ),
870 (
Dave Tapuska98199b612019-07-10 13:30:44871 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19872 (
873 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04874 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19875 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
876 'async events instead of flushing threads.',
877 ),
878 False,
879 (),
880 ),
881 (
882 r'MessageLoopRunner',
883 (
884 'MessageLoopRunner is deprecated, use RunLoop instead.',
885 ),
886 False,
887 (),
888 ),
889 (
Dave Tapuska98199b612019-07-10 13:30:44890 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19891 (
892 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
893 "gab@ if you found a use case where this is the only solution.",
894 ),
895 False,
896 (),
897 ),
898 (
Victor Costane48a2e82019-03-15 22:02:34899 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16900 (
Victor Costane48a2e82019-03-15 22:02:34901 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16902 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
903 ),
904 True,
905 (
906 r'^sql/initialization\.(cc|h)$',
907 r'^third_party/sqlite/.*\.(c|cc|h)$',
908 ),
909 ),
Matt Menke7f520a82018-03-28 21:38:37910 (
Dave Tapuska98199b612019-07-10 13:30:44911 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47912 (
913 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
914 'base::RandomShuffle instead.'
915 ),
916 True,
917 (),
918 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24919 (
920 'ios/web/public/test/http_server',
921 (
922 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
923 ),
924 False,
925 (),
926 ),
Robert Liao764c9492019-01-24 18:46:28927 (
928 'GetAddressOf',
929 (
930 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53931 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11932 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53933 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28934 ),
935 True,
936 (),
937 ),
Antonio Gomes07300d02019-03-13 20:59:57938 (
939 'DEFINE_TYPE_CASTS',
940 (
941 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
942 '//third_party/blink/renderer/platform/casting.h.'
943 ),
944 True,
945 (
946 r'^third_party/blink/renderer/.*\.(cc|h)$',
947 ),
948 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38949 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45950 r'/\bIsHTML.+Element\(\b',
951 (
952 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
953 ' helpers IsA<HTMLXXXXElement> from ',
954 '//third_party/blink/renderer/platform/casting.h.'
955 ),
956 False,
957 (
958 r'^third_party/blink/renderer/.*\.(cc|h)$',
959 ),
960 ),
961 (
962 r'/\bToHTML.+Element(|OrNull)\(\b',
963 (
964 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
965 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
966 'and DynamicTo<HTMLXXXXElement> from ',
967 '//third_party/blink/renderer/platform/casting.h.'
968 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
969 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
970 ),
971 False,
972 (
973 r'^third_party/blink/renderer/.*\.(cc|h)$',
974 ),
975 ),
976 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37977 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38978 (
979 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
980 ),
981 True,
982 (),
983 ),
Ben Lewisa9514602019-04-29 17:53:05984 (
985 'SHFileOperation',
986 (
987 'SHFileOperation was deprecated in Windows Vista, and there are less ',
988 'complex functions to achieve the same goals. Use IFileOperation for ',
989 'any esoteric actions instead.'
990 ),
991 True,
992 (),
993 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18994 (
Cliff Smolinsky81951642019-04-30 21:39:51995 'StringFromGUID2',
996 (
997 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24998 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51999 ),
1000 True,
1001 (
1002 r'/base/win/win_util_unittest.cc'
1003 ),
1004 ),
1005 (
1006 'StringFromCLSID',
1007 (
1008 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241009 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511010 ),
1011 True,
1012 (
1013 r'/base/win/win_util_unittest.cc'
1014 ),
1015 ),
1016 (
Avi Drissman7382afa02019-04-29 23:27:131017 'kCFAllocatorNull',
1018 (
1019 'The use of kCFAllocatorNull with the NoCopy creation of ',
1020 'CoreFoundation types is prohibited.',
1021 ),
1022 True,
1023 (),
1024 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291025 (
1026 'mojo::ConvertTo',
1027 (
1028 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1029 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1030 'StringTraits if you would like to convert between custom types and',
1031 'the wire format of mojom types.'
1032 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221033 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291034 (
Wezf89dec092019-09-11 19:38:331035 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1036 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291037 r'^third_party/blink/.*\.(cc|h)$',
1038 r'^content/renderer/.*\.(cc|h)$',
1039 ),
1040 ),
Robert Liao1d78df52019-11-11 20:02:011041 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161042 'GetInterfaceProvider',
1043 (
1044 'InterfaceProvider is deprecated.',
1045 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1046 'or Platform::GetBrowserInterfaceBroker.'
1047 ),
1048 False,
1049 (),
1050 ),
1051 (
Robert Liao1d78df52019-11-11 20:02:011052 'CComPtr',
1053 (
1054 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1055 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1056 'details.'
1057 ),
1058 False,
1059 (),
1060 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201061 (
1062 r'/\b(IFACE|STD)METHOD_?\(',
1063 (
1064 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1065 'Instead, always use IFACEMETHODIMP in the declaration.'
1066 ),
1067 False,
1068 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1069 ),
Allen Bauer53b43fb12020-03-12 17:21:471070 (
1071 'set_owned_by_client',
1072 (
1073 'set_owned_by_client is deprecated.',
1074 'views::View already owns the child views by default. This introduces ',
1075 'a competing ownership model which makes the code difficult to reason ',
1076 'about. See http://crbug.com/1044687 for more details.'
1077 ),
1078 False,
1079 (),
1080 ),
Eric Secklerbe6f48d2020-05-06 18:09:121081 (
1082 r'/\bTRACE_EVENT_ASYNC_',
1083 (
1084 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1085 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1086 ),
1087 False,
1088 (
1089 r'^base/trace_event/.*',
1090 r'^base/tracing/.*',
1091 ),
1092 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:261093 (
1094 r'/\bScopedObserver',
1095 (
1096 'ScopedObserver is deprecated.',
1097 'Please use base::ScopedObservation for observing a single source,',
1098 'or base::ScopedMultiSourceObservation for observing multple sources',
1099 ),
1100 False,
1101 (),
1102 ),
[email protected]127f18ec2012-06-16 05:05:591103)
1104
Mario Sanchez Prada2472cab2019-09-18 10:58:311105# Format: Sequence of tuples containing:
1106# * String pattern or, if starting with a slash, a regular expression.
1107# * Sequence of strings to show when the pattern matches.
1108_DEPRECATED_MOJO_TYPES = (
1109 (
1110 r'/\bmojo::AssociatedBinding\b',
1111 (
1112 'mojo::AssociatedBinding<Interface> is deprecated.',
1113 'Use mojo::AssociatedReceiver<Interface> instead.',
1114 ),
1115 ),
1116 (
1117 r'/\bmojo::AssociatedBindingSet\b',
1118 (
1119 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1120 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1121 ),
1122 ),
1123 (
1124 r'/\bmojo::AssociatedInterfacePtr\b',
1125 (
1126 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1127 'Use mojo::AssociatedRemote<Interface> instead.',
1128 ),
1129 ),
1130 (
1131 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1132 (
1133 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1134 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1135 ),
1136 ),
1137 (
1138 r'/\bmojo::AssociatedInterfaceRequest\b',
1139 (
1140 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1141 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1142 ),
1143 ),
1144 (
1145 r'/\bmojo::Binding\b',
1146 (
1147 'mojo::Binding<Interface> is deprecated.',
1148 'Use mojo::Receiver<Interface> instead.',
1149 ),
1150 ),
1151 (
1152 r'/\bmojo::BindingSet\b',
1153 (
1154 'mojo::BindingSet<Interface> is deprecated.',
1155 'Use mojo::ReceiverSet<Interface> instead.',
1156 ),
1157 ),
1158 (
1159 r'/\bmojo::InterfacePtr\b',
1160 (
1161 'mojo::InterfacePtr<Interface> is deprecated.',
1162 'Use mojo::Remote<Interface> instead.',
1163 ),
1164 ),
1165 (
1166 r'/\bmojo::InterfacePtrInfo\b',
1167 (
1168 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1169 'Use mojo::PendingRemote<Interface> instead.',
1170 ),
1171 ),
1172 (
1173 r'/\bmojo::InterfaceRequest\b',
1174 (
1175 'mojo::InterfaceRequest<Interface> is deprecated.',
1176 'Use mojo::PendingReceiver<Interface> instead.',
1177 ),
1178 ),
1179 (
1180 r'/\bmojo::MakeRequest\b',
1181 (
1182 'mojo::MakeRequest is deprecated.',
1183 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1184 ),
1185 ),
1186 (
1187 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1188 (
1189 'mojo::MakeRequest is deprecated.',
1190 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181191 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311192 ),
1193 ),
1194 (
1195 r'/\bmojo::MakeStrongBinding\b',
1196 (
1197 'mojo::MakeStrongBinding is deprecated.',
1198 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1199 'mojo::MakeSelfOwnedReceiver() instead.',
1200 ),
1201 ),
1202 (
1203 r'/\bmojo::MakeStrongAssociatedBinding\b',
1204 (
1205 'mojo::MakeStrongAssociatedBinding is deprecated.',
1206 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1207 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1208 ),
1209 ),
1210 (
Gyuyoung Kim4952ba62020-07-07 07:33:441211 r'/\bmojo::StrongAssociatedBinding\b',
1212 (
1213 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1214 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1215 ),
1216 ),
1217 (
1218 r'/\bmojo::StrongBinding\b',
1219 (
1220 'mojo::StrongBinding<Interface> is deprecated.',
1221 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1222 ),
1223 ),
1224 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311225 r'/\bmojo::StrongAssociatedBindingSet\b',
1226 (
1227 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1228 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1229 ),
1230 ),
1231 (
1232 r'/\bmojo::StrongBindingSet\b',
1233 (
1234 'mojo::StrongBindingSet<Interface> is deprecated.',
1235 'Use mojo::UniqueReceiverSet<Interface> instead.',
1236 ),
1237 ),
1238)
wnwenbdc444e2016-05-25 13:44:151239
mlamouria82272622014-09-16 18:45:041240_IPC_ENUM_TRAITS_DEPRECATED = (
1241 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501242 'See http://www.chromium.org/Home/chromium-security/education/'
1243 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041244
Stephen Martinis97a394142018-06-07 23:06:051245_LONG_PATH_ERROR = (
1246 'Some files included in this CL have file names that are too long (> 200'
1247 ' characters). If committed, these files will cause issues on Windows. See'
1248 ' https://crbug.com/612667 for more details.'
1249)
1250
Shenghua Zhangbfaa38b82017-11-16 21:58:021251_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041252 r".*[\\/]BuildHooksAndroidImpl\.java",
1253 r".*[\\/]LicenseContentProvider\.java",
1254 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281255 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021256]
[email protected]127f18ec2012-06-16 05:05:591257
Mohamed Heikald048240a2019-11-12 16:57:371258# List of image extensions that are used as resources in chromium.
1259_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1260
Sean Kau46e29bc2017-08-28 16:31:161261# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401262_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041263 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401264 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041265 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1266 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041267 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431268 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161269]
1270
1271
[email protected]b00342e7f2013-03-26 16:21:541272_VALID_OS_MACROS = (
1273 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081274 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541275 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441276 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121277 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541278 'OS_BSD',
1279 'OS_CAT', # For testing.
1280 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041281 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541282 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371283 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541284 'OS_IOS',
1285 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441286 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541287 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211288 'OS_NACL_NONSFI',
1289 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121290 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541291 'OS_OPENBSD',
1292 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371293 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541294 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541295 'OS_WIN',
1296)
1297
1298
Andrew Grieveb773bad2020-06-05 18:00:381299# These are not checked on the public chromium-presubmit trybot.
1300# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041301# checkouts.
agrievef32bcc72016-04-04 14:57:401302_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381303 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381304]
1305
1306
1307_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041308 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361309 'base/android/jni_generator/jni_generator.pydeps',
1310 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361311 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041312 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361313 'build/android/gyp/aar.pydeps',
1314 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271315 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361316 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381317 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361318 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021319 'build/android/gyp/bytecode_rewriter.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111320 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361321 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361322 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361323 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111324 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041325 'build/android/gyp/create_app_bundle_apks.pydeps',
1326 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361327 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121328 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221329 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001330 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361331 'build/android/gyp/desugar.pydeps',
1332 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421333 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041334 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361335 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361336 'build/android/gyp/filter_zip.pydeps',
1337 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361338 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361339 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581340 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361341 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141342 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261343 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011344 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041345 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361346 'build/android/gyp/lint.pydeps',
1347 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361348 'build/android/gyp/merge_manifest.pydeps',
1349 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221350 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361351 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461352 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241353 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361354 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461355 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561356 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361357 'build/android/incremental_install/generate_android_manifest.pydeps',
1358 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041359 'build/android/resource_sizes.pydeps',
1360 'build/android/test_runner.pydeps',
1361 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361362 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361363 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321364 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271365 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1366 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001367 'components/cronet/tools/generate_javadoc.pydeps',
1368 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381369 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001370 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381371 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041372 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181373 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041374 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421375 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1376 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131377 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061378 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221379 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401380]
1381
wnwenbdc444e2016-05-25 13:44:151382
agrievef32bcc72016-04-04 14:57:401383_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1384
1385
Eric Boren6fd2b932018-01-25 15:05:081386# Bypass the AUTHORS check for these accounts.
1387_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591388 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451389 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591390 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521391 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071392 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041393 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271394 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041395 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301396 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081397
1398
Daniel Bratell65b033262019-04-23 08:17:061399def _IsCPlusPlusFile(input_api, file_path):
1400 """Returns True if this file contains C++-like code (and not Python,
1401 Go, Java, MarkDown, ...)"""
1402
1403 ext = input_api.os_path.splitext(file_path)[1]
1404 # This list is compatible with CppChecker.IsCppFile but we should
1405 # consider adding ".c" to it. If we do that we can use this function
1406 # at more places in the code.
1407 return ext in (
1408 '.h',
1409 '.cc',
1410 '.cpp',
1411 '.m',
1412 '.mm',
1413 )
1414
1415def _IsCPlusPlusHeaderFile(input_api, file_path):
1416 return input_api.os_path.splitext(file_path)[1] == ".h"
1417
1418
1419def _IsJavaFile(input_api, file_path):
1420 return input_api.os_path.splitext(file_path)[1] == ".java"
1421
1422
1423def _IsProtoFile(input_api, file_path):
1424 return input_api.os_path.splitext(file_path)[1] == ".proto"
1425
Mohamed Heikal5e5b7922020-10-29 18:57:591426
1427def CheckNoUpstreamDepsOnClank(input_api, output_api):
1428 """Prevent additions of dependencies from the upstream repo on //clank."""
1429 # clank can depend on clank
1430 if input_api.change.RepositoryRoot().endswith('clank'):
1431 return []
1432 build_file_patterns = [
1433 r'(.+/)?BUILD\.gn',
1434 r'.+\.gni',
1435 ]
1436 excluded_files = [
1437 r'build[/\\]config[/\\]android[/\\]config\.gni'
1438 ]
1439 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1440
1441 error_message = 'Disallowed import on //clank in an upstream build file:'
1442
1443 def FilterFile(affected_file):
1444 return input_api.FilterSourceFile(
1445 affected_file,
1446 files_to_check=build_file_patterns,
1447 files_to_skip=excluded_files)
1448
1449 problems = []
1450 for f in input_api.AffectedSourceFiles(FilterFile):
1451 local_path = f.LocalPath()
1452 for line_number, line in f.ChangedContents():
1453 if (bad_pattern.search(line)):
1454 problems.append(
1455 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1456 if problems:
1457 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1458 else:
1459 return []
1460
1461
Saagar Sanghavifceeaae2020-08-12 16:40:361462def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191463 """Attempts to prevent use of functions intended only for testing in
1464 non-testing code. For now this is just a best-effort implementation
1465 that ignores header files and may have some false positives. A
1466 better implementation would probably need a proper C++ parser.
1467 """
1468 # We only scan .cc files and the like, as the declaration of
1469 # for-testing functions in header files are hard to distinguish from
1470 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491471 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191472
jochenc0d4808c2015-07-27 09:25:421473 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191474 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091475 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131476 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191477 exclusion_pattern = input_api.re.compile(
1478 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1479 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131480 # Avoid a false positive in this case, where the method name, the ::, and
1481 # the closing { are all on different lines due to line wrapping.
1482 # HelperClassForTesting::
1483 # HelperClassForTesting(
1484 # args)
1485 # : member(0) {}
1486 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191487
1488 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441489 files_to_skip = (_EXCLUDED_PATHS +
1490 _TEST_CODE_EXCLUDED_PATHS +
1491 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191492 return input_api.FilterSourceFile(
1493 affected_file,
James Cook24a504192020-07-23 00:08:441494 files_to_check=file_inclusion_pattern,
1495 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191496
1497 problems = []
1498 for f in input_api.AffectedSourceFiles(FilterFile):
1499 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131500 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241501 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031502 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461503 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131504 not exclusion_pattern.search(line) and
1505 not allowlist_pattern.search(line) and
1506 not in_method_defn):
[email protected]55459852011-08-10 15:17:191507 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031508 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131509 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191510
1511 if problems:
[email protected]f7051d52013-04-02 18:31:421512 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031513 else:
1514 return []
[email protected]55459852011-08-10 15:17:191515
1516
Saagar Sanghavifceeaae2020-08-12 16:40:361517def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231518 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591519 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231520 """
1521 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1522 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1523 name_pattern = r'ForTest(s|ing)?'
1524 # Describes an occurrence of "ForTest*" inside a // comment.
1525 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501526 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551527 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231528 # Catch calls.
1529 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1530 # Ignore definitions. (Comments are ignored separately.)
1531 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1532
1533 problems = []
1534 sources = lambda x: input_api.FilterSourceFile(
1535 x,
James Cook24a504192020-07-23 00:08:441536 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1537 + input_api.DEFAULT_FILES_TO_SKIP),
1538 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231539 )
1540 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1541 local_path = f.LocalPath()
1542 is_inside_javadoc = False
1543 for line_number, line in f.ChangedContents():
1544 if is_inside_javadoc and javadoc_end_re.search(line):
1545 is_inside_javadoc = False
1546 if not is_inside_javadoc and javadoc_start_re.search(line):
1547 is_inside_javadoc = True
1548 if is_inside_javadoc:
1549 continue
1550 if (inclusion_re.search(line) and
1551 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501552 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231553 not exclusion_re.search(line)):
1554 problems.append(
1555 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1556
1557 if problems:
1558 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1559 else:
1560 return []
1561
1562
Saagar Sanghavifceeaae2020-08-12 16:40:361563def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541564 """Checks to make sure no .h files include <iostream>."""
1565 files = []
1566 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1567 input_api.re.MULTILINE)
1568 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1569 if not f.LocalPath().endswith('.h'):
1570 continue
1571 contents = input_api.ReadFile(f)
1572 if pattern.search(contents):
1573 files.append(f)
1574
1575 if len(files):
yolandyandaabc6d2016-04-18 18:29:391576 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061577 'Do not #include <iostream> in header files, since it inserts static '
1578 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541579 '#include <ostream>. See http://crbug.com/94794',
1580 files) ]
1581 return []
1582
Danil Chapovalov3518f362018-08-11 16:13:431583def _CheckNoStrCatRedefines(input_api, output_api):
1584 """Checks no windows headers with StrCat redefined are included directly."""
1585 files = []
1586 pattern_deny = input_api.re.compile(
1587 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1588 input_api.re.MULTILINE)
1589 pattern_allow = input_api.re.compile(
1590 r'^#include\s"base/win/windows_defines.inc"',
1591 input_api.re.MULTILINE)
1592 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1593 contents = input_api.ReadFile(f)
1594 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1595 files.append(f.LocalPath())
1596
1597 if len(files):
1598 return [output_api.PresubmitError(
1599 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1600 'directly since they pollute code with StrCat macro. Instead, '
1601 'include matching header from base/win. See http://crbug.com/856536',
1602 files) ]
1603 return []
1604
[email protected]10689ca2011-09-02 02:31:541605
Saagar Sanghavifceeaae2020-08-12 16:40:361606def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521607 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181608 problems = []
1609 for f in input_api.AffectedFiles():
1610 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1611 continue
1612
1613 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041614 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181615 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1616
1617 if not problems:
1618 return []
1619 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1620 '\n'.join(problems))]
1621
Saagar Sanghavifceeaae2020-08-12 16:40:361622def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341623 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1624
1625 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1626 instead of DISABLED_. To filter false positives, reports are only generated
1627 if a corresponding MAYBE_ line exists.
1628 """
1629 problems = []
1630
1631 # The following two patterns are looked for in tandem - is a test labeled
1632 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1633 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1634 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1635
1636 # This is for the case that a test is disabled on all platforms.
1637 full_disable_pattern = input_api.re.compile(
1638 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1639 input_api.re.MULTILINE)
1640
Katie Df13948e2018-09-25 07:33:441641 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341642 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1643 continue
1644
1645 # Search for MABYE_, DISABLE_ pairs.
1646 disable_lines = {} # Maps of test name to line number.
1647 maybe_lines = {}
1648 for line_num, line in f.ChangedContents():
1649 disable_match = disable_pattern.search(line)
1650 if disable_match:
1651 disable_lines[disable_match.group(1)] = line_num
1652 maybe_match = maybe_pattern.search(line)
1653 if maybe_match:
1654 maybe_lines[maybe_match.group(1)] = line_num
1655
1656 # Search for DISABLE_ occurrences within a TEST() macro.
1657 disable_tests = set(disable_lines.keys())
1658 maybe_tests = set(maybe_lines.keys())
1659 for test in disable_tests.intersection(maybe_tests):
1660 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1661
1662 contents = input_api.ReadFile(f)
1663 full_disable_match = full_disable_pattern.search(contents)
1664 if full_disable_match:
1665 problems.append(' %s' % f.LocalPath())
1666
1667 if not problems:
1668 return []
1669 return [
1670 output_api.PresubmitPromptWarning(
1671 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1672 '\n'.join(problems))
1673 ]
1674
[email protected]72df4e782012-06-21 16:28:181675
Saagar Sanghavifceeaae2020-08-12 16:40:361676def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571677 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521678 errors = []
Hans Wennborg944479f2020-06-25 21:39:251679 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521680 input_api.re.MULTILINE)
1681 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1682 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1683 continue
1684 for lnum, line in f.ChangedContents():
1685 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171686 errors.append(output_api.PresubmitError(
1687 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571688 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171689 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521690 return errors
1691
1692
Weilun Shia487fad2020-10-28 00:10:341693# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1694# more reliable way. See
1695# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191696
wnwenbdc444e2016-05-25 13:44:151697
Saagar Sanghavifceeaae2020-08-12 16:40:361698def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391699 """Check that FlakyTest annotation is our own instead of the android one"""
1700 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1701 files = []
1702 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1703 if f.LocalPath().endswith('Test.java'):
1704 if pattern.search(input_api.ReadFile(f)):
1705 files.append(f)
1706 if len(files):
1707 return [output_api.PresubmitError(
1708 'Use org.chromium.base.test.util.FlakyTest instead of '
1709 'android.test.FlakyTest',
1710 files)]
1711 return []
mcasasb7440c282015-02-04 14:52:191712
wnwenbdc444e2016-05-25 13:44:151713
Saagar Sanghavifceeaae2020-08-12 16:40:361714def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221715 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271716 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221717 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201718 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571719 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341720 '/win/' in f.LocalPath() or
1721 'chrome_elf' in f.LocalPath() or
1722 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201723 continue
[email protected]8ea5d4b2011-09-13 21:49:221724
[email protected]a11dbe9b2012-08-07 01:32:581725 allowWString = False
[email protected]b5c24292011-11-28 14:38:201726 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581727 if 'presubmit: allow wstring' in line:
1728 allowWString = True
1729 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271730 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581731 allowWString = False
1732 else:
1733 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221734
[email protected]55463aa62011-10-12 00:48:271735 if not problems:
1736 return []
1737 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581738 ' If you are calling a cross-platform API that accepts a wstring, '
1739 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271740 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221741
1742
Saagar Sanghavifceeaae2020-08-12 16:40:361743def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441744 """Make sure .DEPS.git is never modified manually."""
1745 if any(f.LocalPath().endswith('.DEPS.git') for f in
1746 input_api.AffectedFiles()):
1747 return [output_api.PresubmitError(
1748 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1749 'automated system based on what\'s in DEPS and your changes will be\n'
1750 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501751 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1752 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441753 'for more information')]
1754 return []
1755
1756
Saagar Sanghavifceeaae2020-08-12 16:40:361757def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471758 """Checks that DEPS file deps are from allowed_hosts."""
1759 # Run only if DEPS file has been modified to annoy fewer bystanders.
1760 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1761 return []
1762 # Outsource work to gclient verify
1763 try:
John Budorickf20c0042019-04-25 23:23:401764 gclient_path = input_api.os_path.join(
1765 input_api.PresubmitLocalPath(),
1766 'third_party', 'depot_tools', 'gclient.py')
1767 input_api.subprocess.check_output(
1768 [input_api.python_executable, gclient_path, 'verify'],
1769 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471770 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201771 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471772 return [output_api.PresubmitError(
1773 'DEPS file must have only git dependencies.',
1774 long_text=error.output)]
1775
1776
Mario Sanchez Prada2472cab2019-09-18 10:58:311777def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1778 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591779 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311780
1781 Returns an string composed of the name of the file, the line number where the
1782 match has been found and the additional text passed as |message| in case the
1783 target type name matches the text inside the line passed as parameter.
1784 """
Peng Huang9c5949a02020-06-11 19:20:541785 result = []
1786
1787 if line.endswith(" nocheck"):
1788 return result
1789
Mario Sanchez Prada2472cab2019-09-18 10:58:311790 matched = False
1791 if type_name[0:1] == '/':
1792 regex = type_name[1:]
1793 if input_api.re.search(regex, line):
1794 matched = True
1795 elif type_name in line:
1796 matched = True
1797
Mario Sanchez Prada2472cab2019-09-18 10:58:311798 if matched:
1799 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1800 for message_line in message:
1801 result.append(' %s' % message_line)
1802
1803 return result
1804
1805
Saagar Sanghavifceeaae2020-08-12 16:40:361806def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591807 """Make sure that banned functions are not used."""
1808 warnings = []
1809 errors = []
1810
James Cook24a504192020-07-23 00:08:441811 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151812 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441813 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151814 if input_api.re.match(item, local_path):
1815 return True
1816 return False
1817
Peter K. Lee6c03ccff2019-07-15 14:40:051818 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541819 local_path = affected_file.LocalPath()
1820 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1821 return False
1822 basename = input_api.os_path.basename(local_path)
1823 if 'ios' in basename.split('_'):
1824 return True
1825 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1826 if sep and 'ios' in local_path.split(sep):
1827 return True
1828 return False
1829
wnwenbdc444e2016-05-25 13:44:151830 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311831 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1832 func_name, message)
1833 if problems:
wnwenbdc444e2016-05-25 13:44:151834 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311835 errors.extend(problems)
1836 else:
1837 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151838
Eric Stevensona9a980972017-09-23 00:04:411839 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1840 for f in input_api.AffectedFiles(file_filter=file_filter):
1841 for line_num, line in f.ChangedContents():
1842 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1843 CheckForMatch(f, line_num, line, func_name, message, error)
1844
[email protected]127f18ec2012-06-16 05:05:591845 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1846 for f in input_api.AffectedFiles(file_filter=file_filter):
1847 for line_num, line in f.ChangedContents():
1848 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151849 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591850
Peter K. Lee6c03ccff2019-07-15 14:40:051851 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541852 for line_num, line in f.ChangedContents():
1853 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1854 CheckForMatch(f, line_num, line, func_name, message, error)
1855
Peter K. Lee6c03ccff2019-07-15 14:40:051856 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1857 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1858 for line_num, line in f.ChangedContents():
1859 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1860 CheckForMatch(f, line_num, line, func_name, message, error)
1861
[email protected]127f18ec2012-06-16 05:05:591862 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1863 for f in input_api.AffectedFiles(file_filter=file_filter):
1864 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491865 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441866 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491867 continue
wnwenbdc444e2016-05-25 13:44:151868 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591869
1870 result = []
1871 if (warnings):
1872 result.append(output_api.PresubmitPromptWarning(
1873 'Banned functions were used.\n' + '\n'.join(warnings)))
1874 if (errors):
1875 result.append(output_api.PresubmitError(
1876 'Banned functions were used.\n' + '\n'.join(errors)))
1877 return result
1878
1879
Michael Thiessen44457642020-02-06 00:24:151880def _CheckAndroidNoBannedImports(input_api, output_api):
1881 """Make sure that banned java imports are not used."""
1882 errors = []
1883
1884 def IsException(path, exceptions):
1885 for exception in exceptions:
1886 if (path.startswith(exception)):
1887 return True
1888 return False
1889
1890 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1891 for f in input_api.AffectedFiles(file_filter=file_filter):
1892 for line_num, line in f.ChangedContents():
1893 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1894 if IsException(f.LocalPath(), exceptions):
1895 continue;
1896 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1897 'import ' + import_name, message)
1898 if problems:
1899 errors.extend(problems)
1900 result = []
1901 if (errors):
1902 result.append(output_api.PresubmitError(
1903 'Banned imports were used.\n' + '\n'.join(errors)))
1904 return result
1905
1906
Saagar Sanghavifceeaae2020-08-12 16:40:361907def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311908 """Make sure that old Mojo types are not used."""
1909 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571910 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311911
Mario Sanchez Pradaaab91382019-12-19 08:57:091912 # For any path that is not an "ok" or an "error" path, a warning will be
1913 # raised if deprecated mojo types are found.
1914 ok_paths = ['components/arc']
1915 error_paths = ['third_party/blink', 'content']
1916
Mario Sanchez Prada2472cab2019-09-18 10:58:311917 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1918 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571919 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091920 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311921 continue
1922
1923 for line_num, line in f.ChangedContents():
1924 for func_name, message in _DEPRECATED_MOJO_TYPES:
1925 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1926 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571927
Mario Sanchez Prada2472cab2019-09-18 10:58:311928 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091929 # Raise errors inside |error_paths| and warnings everywhere else.
1930 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571931 errors.extend(problems)
1932 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311933 warnings.extend(problems)
1934
1935 result = []
1936 if (warnings):
1937 result.append(output_api.PresubmitPromptWarning(
1938 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571939 if (errors):
1940 result.append(output_api.PresubmitError(
1941 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311942 return result
1943
1944
Saagar Sanghavifceeaae2020-08-12 16:40:361945def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061946 """Make sure that banned functions are not used."""
1947 files = []
1948 pattern = input_api.re.compile(r'^#pragma\s+once',
1949 input_api.re.MULTILINE)
1950 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1951 if not f.LocalPath().endswith('.h'):
1952 continue
1953 contents = input_api.ReadFile(f)
1954 if pattern.search(contents):
1955 files.append(f)
1956
1957 if files:
1958 return [output_api.PresubmitError(
1959 'Do not use #pragma once in header files.\n'
1960 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1961 files)]
1962 return []
1963
[email protected]127f18ec2012-06-16 05:05:591964
Saagar Sanghavifceeaae2020-08-12 16:40:361965def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121966 """Checks to make sure we don't introduce use of foo ? true : false."""
1967 problems = []
1968 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1969 for f in input_api.AffectedFiles():
1970 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1971 continue
1972
1973 for line_num, line in f.ChangedContents():
1974 if pattern.match(line):
1975 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1976
1977 if not problems:
1978 return []
1979 return [output_api.PresubmitPromptWarning(
1980 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1981 '\n'.join(problems))]
1982
1983
Saagar Sanghavifceeaae2020-08-12 16:40:361984def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281985 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181986 change. Breaking - rules is an error, breaking ! rules is a
1987 warning.
1988 """
mohan.reddyf21db962014-10-16 12:26:471989 import sys
[email protected]55f9f382012-07-31 11:02:181990 # We need to wait until we have an input_api object and use this
1991 # roundabout construct to import checkdeps because this file is
1992 # eval-ed and thus doesn't have __file__.
1993 original_sys_path = sys.path
1994 try:
1995 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471996 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181997 import checkdeps
[email protected]55f9f382012-07-31 11:02:181998 from rules import Rule
1999 finally:
2000 # Restore sys.path to what it was before.
2001 sys.path = original_sys_path
2002
2003 added_includes = []
rhalavati08acd232017-04-03 07:23:282004 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242005 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182006 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062007 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502008 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082009 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062010 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502011 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082012 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062013 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502014 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082015 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182016
[email protected]26385172013-05-09 23:11:352017 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182018
2019 error_descriptions = []
2020 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282021 error_subjects = set()
2022 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362023
[email protected]55f9f382012-07-31 11:02:182024 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2025 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082026 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182027 description_with_path = '%s\n %s' % (path, rule_description)
2028 if rule_type == Rule.DISALLOW:
2029 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282030 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182031 else:
2032 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282033 warning_subjects.add("#includes")
2034
2035 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2036 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082037 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282038 description_with_path = '%s\n %s' % (path, rule_description)
2039 if rule_type == Rule.DISALLOW:
2040 error_descriptions.append(description_with_path)
2041 error_subjects.add("imports")
2042 else:
2043 warning_descriptions.append(description_with_path)
2044 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182045
Jinsuk Kim5a092672017-10-24 22:42:242046 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022047 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082048 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242049 description_with_path = '%s\n %s' % (path, rule_description)
2050 if rule_type == Rule.DISALLOW:
2051 error_descriptions.append(description_with_path)
2052 error_subjects.add("imports")
2053 else:
2054 warning_descriptions.append(description_with_path)
2055 warning_subjects.add("imports")
2056
[email protected]55f9f382012-07-31 11:02:182057 results = []
2058 if error_descriptions:
2059 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282060 'You added one or more %s that violate checkdeps rules.'
2061 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182062 error_descriptions))
2063 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422064 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282065 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182066 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282067 '%s? See relevant DEPS file(s) for details and contacts.' %
2068 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182069 warning_descriptions))
2070 return results
2071
2072
Saagar Sanghavifceeaae2020-08-12 16:40:362073def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222074 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152075 if input_api.platform == 'win32':
2076 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292077 checkperms_tool = input_api.os_path.join(
2078 input_api.PresubmitLocalPath(),
2079 'tools', 'checkperms', 'checkperms.py')
2080 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472081 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392082 with input_api.CreateTemporaryFile() as file_list:
2083 for f in input_api.AffectedFiles():
2084 # checkperms.py file/directory arguments must be relative to the
2085 # repository.
2086 file_list.write(f.LocalPath() + '\n')
2087 file_list.close()
2088 args += ['--file-list', file_list.name]
2089 try:
2090 input_api.subprocess.check_output(args)
2091 return []
2092 except input_api.subprocess.CalledProcessError as error:
2093 return [output_api.PresubmitError(
2094 'checkperms.py failed:',
2095 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222096
2097
Saagar Sanghavifceeaae2020-08-12 16:40:362098def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492099 """Makes sure we don't include ui/aura/window_property.h
2100 in header files.
2101 """
2102 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2103 errors = []
2104 for f in input_api.AffectedFiles():
2105 if not f.LocalPath().endswith('.h'):
2106 continue
2107 for line_num, line in f.ChangedContents():
2108 if pattern.match(line):
2109 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2110
2111 results = []
2112 if errors:
2113 results.append(output_api.PresubmitError(
2114 'Header files should not include ui/aura/window_property.h', errors))
2115 return results
2116
2117
[email protected]70ca77752012-11-20 03:45:032118def _CheckForVersionControlConflictsInFile(input_api, f):
2119 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2120 errors = []
2121 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162122 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232123 # First-level headers in markdown look a lot like version control
2124 # conflict markers. http://daringfireball.net/projects/markdown/basics
2125 continue
[email protected]70ca77752012-11-20 03:45:032126 if pattern.match(line):
2127 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2128 return errors
2129
2130
Saagar Sanghavifceeaae2020-08-12 16:40:362131def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032132 """Usually this is not intentional and will cause a compile failure."""
2133 errors = []
2134 for f in input_api.AffectedFiles():
2135 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2136
2137 results = []
2138 if errors:
2139 results.append(output_api.PresubmitError(
2140 'Version control conflict markers found, please resolve.', errors))
2141 return results
2142
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202143
Saagar Sanghavifceeaae2020-08-12 16:40:362144def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162145 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2146 errors = []
2147 for f in input_api.AffectedFiles():
2148 for line_num, line in f.ChangedContents():
2149 if pattern.search(line):
2150 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2151
2152 results = []
2153 if errors:
2154 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502155 'Found Google support URL addressed by answer number. Please replace '
2156 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162157 return results
2158
[email protected]70ca77752012-11-20 03:45:032159
Saagar Sanghavifceeaae2020-08-12 16:40:362160def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442161 def FilterFile(affected_file):
2162 """Filter function for use with input_api.AffectedSourceFiles,
2163 below. This filters out everything except non-test files from
2164 top-level directories that generally speaking should not hard-code
2165 service URLs (e.g. src/android_webview/, src/content/ and others).
2166 """
2167 return input_api.FilterSourceFile(
2168 affected_file,
James Cook24a504192020-07-23 00:08:442169 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2170 files_to_skip=(_EXCLUDED_PATHS +
2171 _TEST_CODE_EXCLUDED_PATHS +
2172 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442173
reillyi38965732015-11-16 18:27:332174 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2175 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462176 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2177 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442178 problems = [] # items are (filename, line_number, line)
2179 for f in input_api.AffectedSourceFiles(FilterFile):
2180 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462181 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442182 problems.append((f.LocalPath(), line_num, line))
2183
2184 if problems:
[email protected]f7051d52013-04-02 18:31:422185 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442186 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582187 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442188 [' %s:%d: %s' % (
2189 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032190 else:
2191 return []
[email protected]06e6d0ff2012-12-11 01:36:442192
2193
Saagar Sanghavifceeaae2020-08-12 16:40:362194def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292195 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2196 def FileFilter(affected_file):
2197 """Includes directories known to be Chrome OS only."""
2198 return input_api.FilterSourceFile(
2199 affected_file,
James Cook24a504192020-07-23 00:08:442200 files_to_check=('^ash/',
2201 '^chromeos/', # Top-level src/chromeos.
2202 '/chromeos/', # Any path component.
2203 '^components/arc',
2204 '^components/exo'),
2205 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292206
2207 prefs = []
2208 priority_prefs = []
2209 for f in input_api.AffectedFiles(file_filter=FileFilter):
2210 for line_num, line in f.ChangedContents():
2211 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2212 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2213 prefs.append(' %s' % line)
2214 if input_api.re.search(
2215 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2216 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2217 priority_prefs.append(' %s' % line)
2218
2219 results = []
2220 if (prefs):
2221 results.append(output_api.PresubmitPromptWarning(
2222 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2223 'by browser sync settings. If these prefs should be controlled by OS '
2224 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2225 if (priority_prefs):
2226 results.append(output_api.PresubmitPromptWarning(
2227 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2228 'controlled by browser sync settings. If these prefs should be '
2229 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2230 'instead.\n' + '\n'.join(prefs)))
2231 return results
2232
2233
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492234# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362235def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272236 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312237 The native_client_sdk directory is excluded because it has auto-generated PNG
2238 files for documentation.
[email protected]d2530012013-01-25 16:39:272239 """
[email protected]d2530012013-01-25 16:39:272240 errors = []
James Cook24a504192020-07-23 00:08:442241 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2242 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312243 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442244 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312245 for f in input_api.AffectedFiles(include_deletes=False,
2246 file_filter=file_filter):
2247 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272248
2249 results = []
2250 if errors:
2251 results.append(output_api.PresubmitError(
2252 'The name of PNG files should not have abbreviations. \n'
2253 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2254 'Contact [email protected] if you have questions.', errors))
2255 return results
2256
2257
Daniel Cheng4dcdb6b2017-04-13 08:30:172258def _ExtractAddRulesFromParsedDeps(parsed_deps):
2259 """Extract the rules that add dependencies from a parsed DEPS file.
2260
2261 Args:
2262 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2263 add_rules = set()
2264 add_rules.update([
2265 rule[1:] for rule in parsed_deps.get('include_rules', [])
2266 if rule.startswith('+') or rule.startswith('!')
2267 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502268 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172269 {}).iteritems():
2270 add_rules.update([
2271 rule[1:] for rule in rules
2272 if rule.startswith('+') or rule.startswith('!')
2273 ])
2274 return add_rules
2275
2276
2277def _ParseDeps(contents):
2278 """Simple helper for parsing DEPS files."""
2279 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172280 class _VarImpl:
2281
2282 def __init__(self, local_scope):
2283 self._local_scope = local_scope
2284
2285 def Lookup(self, var_name):
2286 """Implements the Var syntax."""
2287 try:
2288 return self._local_scope['vars'][var_name]
2289 except KeyError:
2290 raise Exception('Var is not defined: %s' % var_name)
2291
2292 local_scope = {}
2293 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172294 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592295 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172296 }
2297 exec contents in global_scope, local_scope
2298 return local_scope
2299
2300
2301def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592302 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412303 a set of DEPS entries that we should look up.
2304
2305 For a directory (rather than a specific filename) we fake a path to
2306 a specific filename by adding /DEPS. This is chosen as a file that
2307 will seldom or never be subject to per-file include_rules.
2308 """
[email protected]2b438d62013-11-14 17:54:142309 # We ignore deps entries on auto-generated directories.
2310 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082311
Daniel Cheng4dcdb6b2017-04-13 08:30:172312 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2313 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2314
2315 added_deps = new_deps.difference(old_deps)
2316
[email protected]2b438d62013-11-14 17:54:142317 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172318 for added_dep in added_deps:
2319 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2320 continue
2321 # Assume that a rule that ends in .h is a rule for a specific file.
2322 if added_dep.endswith('.h'):
2323 results.add(added_dep)
2324 else:
2325 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082326 return results
2327
2328
Saagar Sanghavifceeaae2020-08-12 16:40:362329def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552330 """When a dependency prefixed with + is added to a DEPS file, we
2331 want to make sure that the change is reviewed by an OWNER of the
2332 target file or directory, to avoid layering violations from being
2333 introduced. This check verifies that this happens.
2334 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172335 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242336
2337 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492338 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242339 for f in input_api.AffectedFiles(include_deletes=False,
2340 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552341 filename = input_api.os_path.basename(f.LocalPath())
2342 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172343 virtual_depended_on_files.update(_CalculateAddedDeps(
2344 input_api.os_path,
2345 '\n'.join(f.OldContents()),
2346 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552347
[email protected]e871964c2013-05-13 14:14:552348 if not virtual_depended_on_files:
2349 return []
2350
2351 if input_api.is_committing:
2352 if input_api.tbr:
2353 return [output_api.PresubmitNotifyResult(
2354 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272355 if input_api.dry_run:
2356 return [output_api.PresubmitNotifyResult(
2357 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552358 if not input_api.change.issue:
2359 return [output_api.PresubmitError(
2360 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402361 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552362 output = output_api.PresubmitError
2363 else:
2364 output = output_api.PresubmitNotifyResult
2365
2366 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502367 owner_email, reviewers = (
2368 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2369 input_api,
2370 owners_db.email_regexp,
2371 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552372
2373 owner_email = owner_email or input_api.change.author_email
2374
[email protected]de4f7d22013-05-23 14:27:462375 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512376 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462377 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552378 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2379 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412380
2381 # We strip the /DEPS part that was added by
2382 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2383 # directory.
2384 def StripDeps(path):
2385 start_deps = path.rfind('/DEPS')
2386 if start_deps != -1:
2387 return path[:start_deps]
2388 else:
2389 return path
2390 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552391 for path in missing_files]
2392
2393 if unapproved_dependencies:
2394 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152395 output('You need LGTM from owners of depends-on paths in DEPS that were '
2396 'modified in this CL:\n %s' %
2397 '\n '.join(sorted(unapproved_dependencies)))]
2398 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2399 output_list.append(output(
2400 'Suggested missing target path OWNERS:\n %s' %
2401 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552402 return output_list
2403
2404 return []
2405
2406
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492407# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362408def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492409 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442410 files_to_skip = (_EXCLUDED_PATHS +
2411 _TEST_CODE_EXCLUDED_PATHS +
2412 input_api.DEFAULT_FILES_TO_SKIP +
2413 (r"^base[\\/]logging\.h$",
2414 r"^base[\\/]logging\.cc$",
2415 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2416 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2417 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2418 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2419 r"startup_browser_creator\.cc$",
2420 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2421 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2422 r"diagnostics_writer\.cc$",
2423 r"^chrome[\\/]chrome_cleaner[\\/].*",
2424 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2425 r"dll_hash_main\.cc$",
2426 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2427 r"^chromecast[\\/]",
2428 r"^cloud_print[\\/]",
2429 r"^components[\\/]browser_watcher[\\/]"
2430 r"dump_stability_report_main_win.cc$",
2431 r"^components[\\/]media_control[\\/]renderer[\\/]"
2432 r"media_playback_options\.cc$",
2433 r"^components[\\/]zucchini[\\/].*",
2434 # TODO(peter): Remove exception. https://crbug.com/534537
2435 r"^content[\\/]browser[\\/]notifications[\\/]"
2436 r"notification_event_dispatcher_impl\.cc$",
2437 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2438 r"gl_helper_benchmark\.cc$",
2439 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2440 r"^courgette[\\/]courgette_tool\.cc$",
2441 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2442 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2443 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2444 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2445 r"^ipc[\\/]ipc_logging\.cc$",
2446 r"^native_client_sdk[\\/]",
2447 r"^remoting[\\/]base[\\/]logging\.h$",
2448 r"^remoting[\\/]host[\\/].*",
2449 r"^sandbox[\\/]linux[\\/].*",
2450 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2451 r"dump_file_system.cc$",
2452 r"^tools[\\/]",
2453 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2454 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2455 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2456 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2457 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402458 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442459 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402460
thomasanderson625d3932017-03-29 07:16:582461 log_info = set([])
2462 printf = set([])
[email protected]85218562013-11-22 07:41:402463
2464 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582465 for _, line in f.ChangedContents():
2466 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2467 log_info.add(f.LocalPath())
2468 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2469 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372470
thomasanderson625d3932017-03-29 07:16:582471 if input_api.re.search(r"\bprintf\(", line):
2472 printf.add(f.LocalPath())
2473 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2474 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402475
2476 if log_info:
2477 return [output_api.PresubmitError(
2478 'These files spam the console log with LOG(INFO):',
2479 items=log_info)]
2480 if printf:
2481 return [output_api.PresubmitError(
2482 'These files spam the console log with printf/fprintf:',
2483 items=printf)]
2484 return []
2485
2486
Saagar Sanghavifceeaae2020-08-12 16:40:362487def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162488 """These types are all expected to hold locks while in scope and
2489 so should never be anonymous (which causes them to be immediately
2490 destroyed)."""
2491 they_who_must_be_named = [
2492 'base::AutoLock',
2493 'base::AutoReset',
2494 'base::AutoUnlock',
2495 'SkAutoAlphaRestore',
2496 'SkAutoBitmapShaderInstall',
2497 'SkAutoBlitterChoose',
2498 'SkAutoBounderCommit',
2499 'SkAutoCallProc',
2500 'SkAutoCanvasRestore',
2501 'SkAutoCommentBlock',
2502 'SkAutoDescriptor',
2503 'SkAutoDisableDirectionCheck',
2504 'SkAutoDisableOvalCheck',
2505 'SkAutoFree',
2506 'SkAutoGlyphCache',
2507 'SkAutoHDC',
2508 'SkAutoLockColors',
2509 'SkAutoLockPixels',
2510 'SkAutoMalloc',
2511 'SkAutoMaskFreeImage',
2512 'SkAutoMutexAcquire',
2513 'SkAutoPathBoundsUpdate',
2514 'SkAutoPDFRelease',
2515 'SkAutoRasterClipValidate',
2516 'SkAutoRef',
2517 'SkAutoTime',
2518 'SkAutoTrace',
2519 'SkAutoUnref',
2520 ]
2521 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2522 # bad: base::AutoLock(lock.get());
2523 # not bad: base::AutoLock lock(lock.get());
2524 bad_pattern = input_api.re.compile(anonymous)
2525 # good: new base::AutoLock(lock.get())
2526 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2527 errors = []
2528
2529 for f in input_api.AffectedFiles():
2530 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2531 continue
2532 for linenum, line in f.ChangedContents():
2533 if bad_pattern.search(line) and not good_pattern.search(line):
2534 errors.append('%s:%d' % (f.LocalPath(), linenum))
2535
2536 if errors:
2537 return [output_api.PresubmitError(
2538 'These lines create anonymous variables that need to be named:',
2539 items=errors)]
2540 return []
2541
2542
Saagar Sanghavifceeaae2020-08-12 16:40:362543def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532544 # Returns whether |template_str| is of the form <T, U...> for some types T
2545 # and U. Assumes that |template_str| is already in the form <...>.
2546 def HasMoreThanOneArg(template_str):
2547 # Level of <...> nesting.
2548 nesting = 0
2549 for c in template_str:
2550 if c == '<':
2551 nesting += 1
2552 elif c == '>':
2553 nesting -= 1
2554 elif c == ',' and nesting == 1:
2555 return True
2556 return False
2557
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492558 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102559 sources = lambda affected_file: input_api.FilterSourceFile(
2560 affected_file,
James Cook24a504192020-07-23 00:08:442561 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2562 input_api.DEFAULT_FILES_TO_SKIP),
2563 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552564
2565 # Pattern to capture a single "<...>" block of template arguments. It can
2566 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2567 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2568 # latter would likely require counting that < and > match, which is not
2569 # expressible in regular languages. Should the need arise, one can introduce
2570 # limited counting (matching up to a total number of nesting depth), which
2571 # should cover all practical cases for already a low nesting limit.
2572 template_arg_pattern = (
2573 r'<[^>]*' # Opening block of <.
2574 r'>([^<]*>)?') # Closing block of >.
2575 # Prefix expressing that whatever follows is not already inside a <...>
2576 # block.
2577 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102578 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552579 not_inside_template_arg_pattern
2580 + r'\bstd::unique_ptr'
2581 + template_arg_pattern
2582 + r'\(\)')
2583
2584 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2585 template_arg_no_array_pattern = (
2586 r'<[^>]*[^]]' # Opening block of <.
2587 r'>([^(<]*[^]]>)?') # Closing block of >.
2588 # Prefix saying that what follows is the start of an expression.
2589 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2590 # Suffix saying that what follows are call parentheses with a non-empty list
2591 # of arguments.
2592 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532593 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552594 return_construct_pattern = input_api.re.compile(
2595 start_of_expr_pattern
2596 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532597 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552598 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532599 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552600 + nonempty_arg_list_pattern)
2601
Vaclav Brozek851d9602018-04-04 16:13:052602 problems_constructor = []
2603 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102604 for f in input_api.AffectedSourceFiles(sources):
2605 for line_number, line in f.ChangedContents():
2606 # Disallow:
2607 # return std::unique_ptr<T>(foo);
2608 # bar = std::unique_ptr<T>(foo);
2609 # But allow:
2610 # return std::unique_ptr<T[]>(foo);
2611 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532612 # And also allow cases when the second template argument is present. Those
2613 # cases cannot be handled by std::make_unique:
2614 # return std::unique_ptr<T, U>(foo);
2615 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052616 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532617 return_construct_result = return_construct_pattern.search(line)
2618 if return_construct_result and not HasMoreThanOneArg(
2619 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052620 problems_constructor.append(
2621 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102622 # Disallow:
2623 # std::unique_ptr<T>()
2624 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052625 problems_nullptr.append(
2626 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2627
2628 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162629 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052630 errors.append(output_api.PresubmitError(
2631 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162632 problems_nullptr))
2633 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052634 errors.append(output_api.PresubmitError(
2635 'The following files use explicit std::unique_ptr constructor.'
2636 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162637 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102638 return errors
2639
2640
Saagar Sanghavifceeaae2020-08-12 16:40:362641def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082642 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522643 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082644 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522645 # If actions.xml is already included in the changelist, the PRESUBMIT
2646 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082647 return []
2648
[email protected]999261d2014-03-03 20:08:082649 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2650 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522651 current_actions = None
[email protected]999261d2014-03-03 20:08:082652 for f in input_api.AffectedFiles(file_filter=file_filter):
2653 for line_num, line in f.ChangedContents():
2654 match = input_api.re.search(action_re, line)
2655 if match:
[email protected]2f92dec2014-03-07 19:21:522656 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2657 # loaded only once.
2658 if not current_actions:
2659 with open('tools/metrics/actions/actions.xml') as actions_f:
2660 current_actions = actions_f.read()
2661 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082662 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522663 action = 'name="{0}"'.format(action_name)
2664 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082665 return [output_api.PresubmitPromptWarning(
2666 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522667 'tools/metrics/actions/actions.xml. Please run '
2668 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082669 % (f.LocalPath(), line_num, action_name))]
2670 return []
2671
2672
Daniel Cheng13ca61a882017-08-25 15:11:252673def _ImportJSONCommentEater(input_api):
2674 import sys
2675 sys.path = sys.path + [input_api.os_path.join(
2676 input_api.PresubmitLocalPath(),
2677 'tools', 'json_comment_eater')]
2678 import json_comment_eater
2679 return json_comment_eater
2680
2681
[email protected]99171a92014-06-03 08:44:472682def _GetJSONParseError(input_api, filename, eat_comments=True):
2683 try:
2684 contents = input_api.ReadFile(filename)
2685 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252686 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132687 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472688
2689 input_api.json.loads(contents)
2690 except ValueError as e:
2691 return e
2692 return None
2693
2694
2695def _GetIDLParseError(input_api, filename):
2696 try:
2697 contents = input_api.ReadFile(filename)
2698 idl_schema = input_api.os_path.join(
2699 input_api.PresubmitLocalPath(),
2700 'tools', 'json_schema_compiler', 'idl_schema.py')
2701 process = input_api.subprocess.Popen(
2702 [input_api.python_executable, idl_schema],
2703 stdin=input_api.subprocess.PIPE,
2704 stdout=input_api.subprocess.PIPE,
2705 stderr=input_api.subprocess.PIPE,
2706 universal_newlines=True)
2707 (_, error) = process.communicate(input=contents)
2708 return error or None
2709 except ValueError as e:
2710 return e
2711
2712
Saagar Sanghavifceeaae2020-08-12 16:40:362713def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472714 """Check that IDL and JSON files do not contain syntax errors."""
2715 actions = {
2716 '.idl': _GetIDLParseError,
2717 '.json': _GetJSONParseError,
2718 }
[email protected]99171a92014-06-03 08:44:472719 # Most JSON files are preprocessed and support comments, but these do not.
2720 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042721 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472722 ]
2723 # Only run IDL checker on files in these directories.
2724 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042725 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2726 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472727 ]
2728
2729 def get_action(affected_file):
2730 filename = affected_file.LocalPath()
2731 return actions.get(input_api.os_path.splitext(filename)[1])
2732
[email protected]99171a92014-06-03 08:44:472733 def FilterFile(affected_file):
2734 action = get_action(affected_file)
2735 if not action:
2736 return False
2737 path = affected_file.LocalPath()
2738
Erik Staab2dd72b12020-04-16 15:03:402739 if _MatchesFile(input_api,
2740 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2741 path):
[email protected]99171a92014-06-03 08:44:472742 return False
2743
2744 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162745 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472746 return False
2747 return True
2748
2749 results = []
2750 for affected_file in input_api.AffectedFiles(
2751 file_filter=FilterFile, include_deletes=False):
2752 action = get_action(affected_file)
2753 kwargs = {}
2754 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162755 _MatchesFile(input_api, json_no_comments_patterns,
2756 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472757 kwargs['eat_comments'] = False
2758 parse_error = action(input_api,
2759 affected_file.AbsoluteLocalPath(),
2760 **kwargs)
2761 if parse_error:
2762 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2763 (affected_file.LocalPath(), parse_error)))
2764 return results
2765
2766
Saagar Sanghavifceeaae2020-08-12 16:40:362767def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492768 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472769 import sys
[email protected]760deea2013-12-10 19:33:492770 original_sys_path = sys.path
2771 try:
2772 sys.path = sys.path + [input_api.os_path.join(
2773 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2774 import checkstyle
2775 finally:
2776 # Restore sys.path to what it was before.
2777 sys.path = original_sys_path
2778
2779 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092780 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442781 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492782
2783
Saagar Sanghavifceeaae2020-08-12 16:40:362784def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002785 """Checks to make sure devil is initialized correctly in python scripts."""
2786 script_common_initialize_pattern = input_api.re.compile(
2787 r'script_common\.InitializeEnvironment\(')
2788 devil_env_config_initialize = input_api.re.compile(
2789 r'devil_env\.config\.Initialize\(')
2790
2791 errors = []
2792
2793 sources = lambda affected_file: input_api.FilterSourceFile(
2794 affected_file,
James Cook24a504192020-07-23 00:08:442795 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2796 (r'^build[\\/]android[\\/]devil_chromium\.py',
2797 r'^third_party[\\/].*',)),
2798 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002799
2800 for f in input_api.AffectedSourceFiles(sources):
2801 for line_num, line in f.ChangedContents():
2802 if (script_common_initialize_pattern.search(line) or
2803 devil_env_config_initialize.search(line)):
2804 errors.append("%s:%d" % (f.LocalPath(), line_num))
2805
2806 results = []
2807
2808 if errors:
2809 results.append(output_api.PresubmitError(
2810 'Devil initialization should always be done using '
2811 'devil_chromium.Initialize() in the chromium project, to use better '
2812 'defaults for dependencies (ex. up-to-date version of adb).',
2813 errors))
2814
2815 return results
2816
2817
Sean Kau46e29bc2017-08-28 16:31:162818def _MatchesFile(input_api, patterns, path):
2819 for pattern in patterns:
2820 if input_api.re.search(pattern, path):
2821 return True
2822 return False
2823
2824
Daniel Cheng7052cdf2017-11-21 19:23:292825def _GetOwnersFilesToCheckForIpcOwners(input_api):
2826 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172827
Daniel Cheng7052cdf2017-11-21 19:23:292828 Returns:
2829 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2830 contain to cover IPC-related files with noparent reviewer rules.
2831 """
2832 # Whether or not a file affects IPC is (mostly) determined by a simple list
2833 # of filename patterns.
dchenge07de812016-06-20 19:27:172834 file_patterns = [
palmerb19a0932017-01-24 04:00:312835 # Legacy IPC:
dchenge07de812016-06-20 19:27:172836 '*_messages.cc',
2837 '*_messages*.h',
2838 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312839 # Mojo IPC:
dchenge07de812016-06-20 19:27:172840 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472841 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172842 '*_struct_traits*.*',
2843 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312844 '*.typemap',
2845 # Android native IPC:
2846 '*.aidl',
2847 # Blink uses a different file naming convention:
2848 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472849 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172850 '*StructTraits*.*',
2851 '*TypeConverter*.*',
2852 ]
2853
scottmg7a6ed5ba2016-11-04 18:22:042854 # These third_party directories do not contain IPCs, but contain files
2855 # matching the above patterns, which trigger false positives.
2856 exclude_paths = [
2857 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162858 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232859 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292860 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542861 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162862 # These files are just used to communicate between class loaders running
2863 # in the same process.
2864 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572865 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2866
scottmg7a6ed5ba2016-11-04 18:22:042867 ]
2868
dchenge07de812016-06-20 19:27:172869 # Dictionary mapping an OWNERS file path to Patterns.
2870 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2871 # rules ) to a PatternEntry.
2872 # PatternEntry is a dictionary with two keys:
2873 # - 'files': the files that are matched by this pattern
2874 # - 'rules': the per-file rules needed for this pattern
2875 # For example, if we expect OWNERS file to contain rules for *.mojom and
2876 # *_struct_traits*.*, Patterns might look like this:
2877 # {
2878 # '*.mojom': {
2879 # 'files': ...,
2880 # 'rules': [
2881 # 'per-file *.mojom=set noparent',
2882 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2883 # ],
2884 # },
2885 # '*_struct_traits*.*': {
2886 # 'files': ...,
2887 # 'rules': [
2888 # 'per-file *_struct_traits*.*=set noparent',
2889 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2890 # ],
2891 # },
2892 # }
2893 to_check = {}
2894
Daniel Cheng13ca61a882017-08-25 15:11:252895 def AddPatternToCheck(input_file, pattern):
2896 owners_file = input_api.os_path.join(
2897 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2898 if owners_file not in to_check:
2899 to_check[owners_file] = {}
2900 if pattern not in to_check[owners_file]:
2901 to_check[owners_file][pattern] = {
2902 'files': [],
2903 'rules': [
2904 'per-file %s=set noparent' % pattern,
2905 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2906 ]
2907 }
Vaclav Brozekd5de76a2018-03-17 07:57:502908 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252909
dchenge07de812016-06-20 19:27:172910 # Iterate through the affected files to see what we actually need to check
2911 # for. We should only nag patch authors about per-file rules if a file in that
2912 # directory would match that pattern. If a directory only contains *.mojom
2913 # files and no *_messages*.h files, we should only nag about rules for
2914 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252915 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262916 # Manifest files don't have a strong naming convention. Instead, try to find
2917 # affected .cc and .h files which look like they contain a manifest
2918 # definition.
2919 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2920 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2921 if (manifest_pattern.search(f.LocalPath()) and not
2922 test_manifest_pattern.search(f.LocalPath())):
2923 # We expect all actual service manifest files to contain at least one
2924 # qualified reference to service_manager::Manifest.
2925 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252926 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172927 for pattern in file_patterns:
2928 if input_api.fnmatch.fnmatch(
2929 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042930 skip = False
2931 for exclude in exclude_paths:
2932 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2933 skip = True
2934 break
2935 if skip:
2936 continue
Daniel Cheng13ca61a882017-08-25 15:11:252937 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172938 break
2939
Daniel Cheng7052cdf2017-11-21 19:23:292940 return to_check
2941
2942
Wez17c66962020-04-29 15:26:032943def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2944 """Adds OWNERS files to check for correct Fuchsia security owners."""
2945
2946 file_patterns = [
2947 # Component specifications.
2948 '*.cml', # Component Framework v2.
2949 '*.cmx', # Component Framework v1.
2950
2951 # Fuchsia IDL protocol specifications.
2952 '*.fidl',
2953 ]
2954
Joshua Peraza1ca6d392020-12-08 00:14:092955 # Don't check for owners files for changes in these directories.
2956 exclude_paths = [
2957 'third_party/crashpad/*',
2958 ]
2959
Wez17c66962020-04-29 15:26:032960 def AddPatternToCheck(input_file, pattern):
2961 owners_file = input_api.os_path.join(
2962 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2963 if owners_file not in to_check:
2964 to_check[owners_file] = {}
2965 if pattern not in to_check[owners_file]:
2966 to_check[owners_file][pattern] = {
2967 'files': [],
2968 'rules': [
2969 'per-file %s=set noparent' % pattern,
2970 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2971 ]
2972 }
2973 to_check[owners_file][pattern]['files'].append(input_file)
2974
2975 # Iterate through the affected files to see what we actually need to check
2976 # for. We should only nag patch authors about per-file rules if a file in that
2977 # directory would match that pattern.
2978 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092979 skip = False
2980 for exclude in exclude_paths:
2981 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2982 skip = True
2983 if skip:
2984 continue
2985
Wez17c66962020-04-29 15:26:032986 for pattern in file_patterns:
2987 if input_api.fnmatch.fnmatch(
2988 input_api.os_path.basename(f.LocalPath()), pattern):
2989 AddPatternToCheck(f, pattern)
2990 break
2991
2992 return to_check
2993
2994
Saagar Sanghavifceeaae2020-08-12 16:40:362995def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292996 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2997 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032998 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292999
3000 if to_check:
3001 # If there are any OWNERS files to check, there are IPC-related changes in
3002 # this CL. Auto-CC the review list.
3003 output_api.AppendCC('[email protected]')
3004
3005 # Go through the OWNERS files to check, filtering out rules that are already
3006 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173007 for owners_file, patterns in to_check.iteritems():
3008 try:
3009 with file(owners_file) as f:
3010 lines = set(f.read().splitlines())
3011 for entry in patterns.itervalues():
3012 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3013 ]
3014 except IOError:
3015 # No OWNERS file, so all the rules are definitely missing.
3016 continue
3017
3018 # All the remaining lines weren't found in OWNERS files, so emit an error.
3019 errors = []
3020 for owners_file, patterns in to_check.iteritems():
3021 missing_lines = []
3022 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503023 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173024 missing_lines.extend(entry['rules'])
3025 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3026 if missing_lines:
3027 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053028 'Because of the presence of files:\n%s\n\n'
3029 '%s needs the following %d lines added:\n\n%s' %
3030 ('\n'.join(files), owners_file, len(missing_lines),
3031 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173032
3033 results = []
3034 if errors:
vabrf5ce3bf92016-07-11 14:52:413035 if input_api.is_committing:
3036 output = output_api.PresubmitError
3037 else:
3038 output = output_api.PresubmitPromptWarning
3039 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593040 'Found OWNERS files that need to be updated for IPC security ' +
3041 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173042 long_text='\n\n'.join(errors)))
3043
3044 return results
3045
3046
Robert Sesek2c905332020-05-06 23:17:133047def _GetFilesUsingSecurityCriticalFunctions(input_api):
3048 """Checks affected files for changes to security-critical calls. This
3049 function checks the full change diff, to catch both additions/changes
3050 and removals.
3051
3052 Returns a dict keyed by file name, and the value is a set of detected
3053 functions.
3054 """
3055 # Map of function pretty name (displayed in an error) to the pattern to
3056 # match it with.
3057 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373058 'content::GetServiceSandboxType<>()':
3059 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133060 }
3061 _PATTERNS_TO_CHECK = {
3062 k: input_api.re.compile(v)
3063 for k, v in _PATTERNS_TO_CHECK.items()
3064 }
3065
3066 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3067 files_to_functions = {}
3068 for f in input_api.AffectedFiles():
3069 diff = f.GenerateScmDiff()
3070 for line in diff.split('\n'):
3071 # Not using just RightHandSideLines() because removing a
3072 # call to a security-critical function can be just as important
3073 # as adding or changing the arguments.
3074 if line.startswith('-') or (line.startswith('+') and
3075 not line.startswith('++')):
3076 for name, pattern in _PATTERNS_TO_CHECK.items():
3077 if pattern.search(line):
3078 path = f.LocalPath()
3079 if not path in files_to_functions:
3080 files_to_functions[path] = set()
3081 files_to_functions[path].add(name)
3082 return files_to_functions
3083
3084
Saagar Sanghavifceeaae2020-08-12 16:40:363085def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133086 """Checks that changes involving security-critical functions are reviewed
3087 by the security team.
3088 """
3089 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3090 if len(files_to_functions):
3091 owners_db = input_api.owners_db
3092 owner_email, reviewers = (
3093 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3094 input_api,
3095 owners_db.email_regexp,
3096 approval_needed=input_api.is_committing))
3097
3098 # Load the OWNERS file for security changes.
3099 owners_file = 'ipc/SECURITY_OWNERS'
3100 security_owners = owners_db.owners_rooted_at_file(owners_file)
3101
3102 has_security_owner = any([owner in reviewers for owner in security_owners])
3103 if not has_security_owner:
3104 msg = 'The following files change calls to security-sensive functions\n' \
3105 'that need to be reviewed by {}.\n'.format(owners_file)
3106 for path, names in files_to_functions.items():
3107 msg += ' {}\n'.format(path)
3108 for name in names:
3109 msg += ' {}\n'.format(name)
3110 msg += '\n'
3111
3112 if input_api.is_committing:
3113 output = output_api.PresubmitError
3114 else:
3115 output = output_api.PresubmitNotifyResult
3116 return [output(msg)]
3117
3118 return []
3119
3120
Saagar Sanghavifceeaae2020-08-12 16:40:363121def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263122 """Checks that set noparent is only used together with an OWNERS file in
3123 //build/OWNERS.setnoparent (see also
3124 //docs/code_reviews.md#owners-files-details)
3125 """
3126 errors = []
3127
3128 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3129 allowed_owners_files = set()
3130 with open(allowed_owners_files_file, 'r') as f:
3131 for line in f:
3132 line = line.strip()
3133 if not line or line.startswith('#'):
3134 continue
3135 allowed_owners_files.add(line)
3136
3137 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3138
3139 for f in input_api.AffectedFiles(include_deletes=False):
3140 if not f.LocalPath().endswith('OWNERS'):
3141 continue
3142
3143 found_owners_files = set()
3144 found_set_noparent_lines = dict()
3145
3146 # Parse the OWNERS file.
3147 for lineno, line in enumerate(f.NewContents(), 1):
3148 line = line.strip()
3149 if line.startswith('set noparent'):
3150 found_set_noparent_lines[''] = lineno
3151 if line.startswith('file://'):
3152 if line in allowed_owners_files:
3153 found_owners_files.add('')
3154 if line.startswith('per-file'):
3155 match = per_file_pattern.match(line)
3156 if match:
3157 glob = match.group(1).strip()
3158 directive = match.group(2).strip()
3159 if directive == 'set noparent':
3160 found_set_noparent_lines[glob] = lineno
3161 if directive.startswith('file://'):
3162 if directive in allowed_owners_files:
3163 found_owners_files.add(glob)
3164
3165 # Check that every set noparent line has a corresponding file:// line
3166 # listed in build/OWNERS.setnoparent.
3167 for set_noparent_line in found_set_noparent_lines:
3168 if set_noparent_line in found_owners_files:
3169 continue
3170 errors.append(' %s:%d' % (f.LocalPath(),
3171 found_set_noparent_lines[set_noparent_line]))
3172
3173 results = []
3174 if errors:
3175 if input_api.is_committing:
3176 output = output_api.PresubmitError
3177 else:
3178 output = output_api.PresubmitPromptWarning
3179 results.append(output(
3180 'Found the following "set noparent" restrictions in OWNERS files that '
3181 'do not include owners from build/OWNERS.setnoparent:',
3182 long_text='\n\n'.join(errors)))
3183 return results
3184
3185
Saagar Sanghavifceeaae2020-08-12 16:40:363186def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313187 """Checks that added or removed lines in non third party affected
3188 header files do not lead to new useless class or struct forward
3189 declaration.
jbriance9e12f162016-11-25 07:57:503190 """
3191 results = []
3192 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3193 input_api.re.MULTILINE)
3194 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3195 input_api.re.MULTILINE)
3196 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313197 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193198 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493199 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313200 continue
3201
jbriance9e12f162016-11-25 07:57:503202 if not f.LocalPath().endswith('.h'):
3203 continue
3204
3205 contents = input_api.ReadFile(f)
3206 fwd_decls = input_api.re.findall(class_pattern, contents)
3207 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3208
3209 useless_fwd_decls = []
3210 for decl in fwd_decls:
3211 count = sum(1 for _ in input_api.re.finditer(
3212 r'\b%s\b' % input_api.re.escape(decl), contents))
3213 if count == 1:
3214 useless_fwd_decls.append(decl)
3215
3216 if not useless_fwd_decls:
3217 continue
3218
3219 for line in f.GenerateScmDiff().splitlines():
3220 if (line.startswith('-') and not line.startswith('--') or
3221 line.startswith('+') and not line.startswith('++')):
3222 for decl in useless_fwd_decls:
3223 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3224 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243225 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503226 (f.LocalPath(), decl)))
3227 useless_fwd_decls.remove(decl)
3228
3229 return results
3230
Jinsong Fan91ebbbd2019-04-16 14:57:173231def _CheckAndroidDebuggableBuild(input_api, output_api):
3232 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3233 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3234 this is a debuggable build of Android.
3235 """
3236 build_type_check_pattern = input_api.re.compile(
3237 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3238
3239 errors = []
3240
3241 sources = lambda affected_file: input_api.FilterSourceFile(
3242 affected_file,
James Cook24a504192020-07-23 00:08:443243 files_to_skip=(_EXCLUDED_PATHS +
3244 _TEST_CODE_EXCLUDED_PATHS +
3245 input_api.DEFAULT_FILES_TO_SKIP +
3246 (r"^android_webview[\\/]support_library[\\/]"
3247 "boundary_interfaces[\\/]",
3248 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3249 r'^third_party[\\/].*',
3250 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3251 r"webview[\\/]chromium[\\/]License.*",)),
3252 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173253
3254 for f in input_api.AffectedSourceFiles(sources):
3255 for line_num, line in f.ChangedContents():
3256 if build_type_check_pattern.search(line):
3257 errors.append("%s:%d" % (f.LocalPath(), line_num))
3258
3259 results = []
3260
3261 if errors:
3262 results.append(output_api.PresubmitPromptWarning(
3263 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3264 ' Please use BuildInfo.isDebugAndroid() instead.',
3265 errors))
3266
3267 return results
jbriance9e12f162016-11-25 07:57:503268
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493269# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293270def _CheckAndroidToastUsage(input_api, output_api):
3271 """Checks that code uses org.chromium.ui.widget.Toast instead of
3272 android.widget.Toast (Chromium Toast doesn't force hardware
3273 acceleration on low-end devices, saving memory).
3274 """
3275 toast_import_pattern = input_api.re.compile(
3276 r'^import android\.widget\.Toast;$')
3277
3278 errors = []
3279
3280 sources = lambda affected_file: input_api.FilterSourceFile(
3281 affected_file,
James Cook24a504192020-07-23 00:08:443282 files_to_skip=(_EXCLUDED_PATHS +
3283 _TEST_CODE_EXCLUDED_PATHS +
3284 input_api.DEFAULT_FILES_TO_SKIP +
3285 (r'^chromecast[\\/].*',
3286 r'^remoting[\\/].*')),
3287 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293288
3289 for f in input_api.AffectedSourceFiles(sources):
3290 for line_num, line in f.ChangedContents():
3291 if toast_import_pattern.search(line):
3292 errors.append("%s:%d" % (f.LocalPath(), line_num))
3293
3294 results = []
3295
3296 if errors:
3297 results.append(output_api.PresubmitError(
3298 'android.widget.Toast usage is detected. Android toasts use hardware'
3299 ' acceleration, and can be\ncostly on low-end devices. Please use'
3300 ' org.chromium.ui.widget.Toast instead.\n'
3301 'Contact [email protected] if you have any questions.',
3302 errors))
3303
3304 return results
3305
3306
dgnaa68d5e2015-06-10 10:08:223307def _CheckAndroidCrLogUsage(input_api, output_api):
3308 """Checks that new logs using org.chromium.base.Log:
3309 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513310 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223311 """
pkotwicza1dd0b002016-05-16 14:41:043312
torne89540622017-03-24 19:41:303313 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043314 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303315 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043316 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303317 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043318 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3319 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093320 # The customtabs_benchmark is a small app that does not depend on Chromium
3321 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043322 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043323 ]
3324
dgnaa68d5e2015-06-10 10:08:223325 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123326 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3327 class_in_base_pattern = input_api.re.compile(
3328 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3329 has_some_log_import_pattern = input_api.re.compile(
3330 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223331 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553332 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223333 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463334 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553335 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223336
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463337 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443338 sources = lambda x: input_api.FilterSourceFile(x,
3339 files_to_check=[r'.*\.java$'],
3340 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123341
dgnaa68d5e2015-06-10 10:08:223342 tag_decl_errors = []
3343 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123344 tag_errors = []
dgn38736db2015-09-18 19:20:513345 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123346 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223347
3348 for f in input_api.AffectedSourceFiles(sources):
3349 file_content = input_api.ReadFile(f)
3350 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223351 # Per line checks
dgn87d9fb62015-06-12 09:15:123352 if (cr_log_import_pattern.search(file_content) or
3353 (class_in_base_pattern.search(file_content) and
3354 not has_some_log_import_pattern.search(file_content))):
3355 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223356 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553357 if rough_log_decl_pattern.search(line):
3358 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223359
3360 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123361 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223362 if match:
3363 has_modified_logs = True
3364
3365 # Make sure it uses "TAG"
3366 if not match.group('tag') == 'TAG':
3367 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123368 else:
3369 # Report non cr Log function calls in changed lines
3370 for line_num, line in f.ChangedContents():
3371 if log_call_pattern.search(line):
3372 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223373
3374 # Per file checks
3375 if has_modified_logs:
3376 # Make sure the tag is using the "cr" prefix and is not too long
3377 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513378 tag_name = match.group('name') if match else None
3379 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223380 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513381 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223382 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513383 elif '.' in tag_name:
3384 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223385
3386 results = []
3387 if tag_decl_errors:
3388 results.append(output_api.PresubmitPromptWarning(
3389 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513390 '"private static final String TAG = "<package tag>".\n'
3391 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223392 tag_decl_errors))
3393
3394 if tag_length_errors:
3395 results.append(output_api.PresubmitError(
3396 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513397 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223398 tag_length_errors))
3399
3400 if tag_errors:
3401 results.append(output_api.PresubmitPromptWarning(
3402 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3403 tag_errors))
3404
dgn87d9fb62015-06-12 09:15:123405 if util_log_errors:
dgn4401aa52015-04-29 16:26:173406 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123407 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3408 util_log_errors))
3409
dgn38736db2015-09-18 19:20:513410 if tag_with_dot_errors:
3411 results.append(output_api.PresubmitPromptWarning(
3412 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3413 tag_with_dot_errors))
3414
dgn4401aa52015-04-29 16:26:173415 return results
3416
3417
Yoland Yanb92fa522017-08-28 17:37:063418def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3419 """Checks that junit.framework.* is no longer used."""
3420 deprecated_junit_framework_pattern = input_api.re.compile(
3421 r'^import junit\.framework\..*;',
3422 input_api.re.MULTILINE)
3423 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443424 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063425 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133426 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063427 for line_num, line in f.ChangedContents():
3428 if deprecated_junit_framework_pattern.search(line):
3429 errors.append("%s:%d" % (f.LocalPath(), line_num))
3430
3431 results = []
3432 if errors:
3433 results.append(output_api.PresubmitError(
3434 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3435 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3436 ' if you have any question.', errors))
3437 return results
3438
3439
3440def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3441 """Checks that if new Java test classes have inheritance.
3442 Either the new test class is JUnit3 test or it is a JUnit4 test class
3443 with a base class, either case is undesirable.
3444 """
3445 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3446
3447 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443448 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063449 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133450 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063451 if not f.OldContents():
3452 class_declaration_start_flag = False
3453 for line_num, line in f.ChangedContents():
3454 if class_declaration_pattern.search(line):
3455 class_declaration_start_flag = True
3456 if class_declaration_start_flag and ' extends ' in line:
3457 errors.append('%s:%d' % (f.LocalPath(), line_num))
3458 if '{' in line:
3459 class_declaration_start_flag = False
3460
3461 results = []
3462 if errors:
3463 results.append(output_api.PresubmitPromptWarning(
3464 'The newly created files include Test classes that inherits from base'
3465 ' class. Please do not use inheritance in JUnit4 tests or add new'
3466 ' JUnit3 tests. Contact [email protected] if you have any'
3467 ' questions.', errors))
3468 return results
3469
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203470
yolandyan45001472016-12-21 21:12:423471def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3472 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3473 deprecated_annotation_import_pattern = input_api.re.compile(
3474 r'^import android\.test\.suitebuilder\.annotation\..*;',
3475 input_api.re.MULTILINE)
3476 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443477 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423478 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133479 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423480 for line_num, line in f.ChangedContents():
3481 if deprecated_annotation_import_pattern.search(line):
3482 errors.append("%s:%d" % (f.LocalPath(), line_num))
3483
3484 results = []
3485 if errors:
3486 results.append(output_api.PresubmitError(
3487 'Annotations in android.test.suitebuilder.annotation have been'
3488 ' deprecated since API level 24. Please use android.support.test.filters'
3489 ' from //third_party/android_support_test_runner:runner_java instead.'
3490 ' Contact [email protected] if you have any questions.', errors))
3491 return results
3492
3493
agrieve7b6479d82015-10-07 14:24:223494def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3495 """Checks if MDPI assets are placed in a correct directory."""
3496 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3497 ('/res/drawable/' in f.LocalPath() or
3498 '/res/drawable-ldrtl/' in f.LocalPath()))
3499 errors = []
3500 for f in input_api.AffectedFiles(include_deletes=False,
3501 file_filter=file_filter):
3502 errors.append(' %s' % f.LocalPath())
3503
3504 results = []
3505 if errors:
3506 results.append(output_api.PresubmitError(
3507 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3508 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3509 '/res/drawable-ldrtl/.\n'
3510 'Contact [email protected] if you have questions.', errors))
3511 return results
3512
3513
Nate Fischer535972b2017-09-16 01:06:183514def _CheckAndroidWebkitImports(input_api, output_api):
3515 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353516 android.webview.ValueCallback except in the WebView glue layer
3517 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183518 """
3519 valuecallback_import_pattern = input_api.re.compile(
3520 r'^import android\.webkit\.ValueCallback;$')
3521
3522 errors = []
3523
3524 sources = lambda affected_file: input_api.FilterSourceFile(
3525 affected_file,
James Cook24a504192020-07-23 00:08:443526 files_to_skip=(_EXCLUDED_PATHS +
3527 _TEST_CODE_EXCLUDED_PATHS +
3528 input_api.DEFAULT_FILES_TO_SKIP +
3529 (r'^android_webview[\\/]glue[\\/].*',
3530 r'^weblayer[\\/].*',)),
3531 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183532
3533 for f in input_api.AffectedSourceFiles(sources):
3534 for line_num, line in f.ChangedContents():
3535 if valuecallback_import_pattern.search(line):
3536 errors.append("%s:%d" % (f.LocalPath(), line_num))
3537
3538 results = []
3539
3540 if errors:
3541 results.append(output_api.PresubmitError(
3542 'android.webkit.ValueCallback usage is detected outside of the glue'
3543 ' layer. To stay compatible with the support library, android.webkit.*'
3544 ' classes should only be used inside the glue layer and'
3545 ' org.chromium.base.Callback should be used instead.',
3546 errors))
3547
3548 return results
3549
3550
Becky Zhou7c69b50992018-12-10 19:37:573551def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3552 """Checks Android XML styles """
3553 import sys
3554 original_sys_path = sys.path
3555 try:
3556 sys.path = sys.path + [input_api.os_path.join(
3557 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3558 import checkxmlstyle
3559 finally:
3560 # Restore sys.path to what it was before.
3561 sys.path = original_sys_path
3562
3563 if is_check_on_upload:
3564 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3565 else:
3566 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3567
3568
agrievef32bcc72016-04-04 14:57:403569class PydepsChecker(object):
3570 def __init__(self, input_api, pydeps_files):
3571 self._file_cache = {}
3572 self._input_api = input_api
3573 self._pydeps_files = pydeps_files
3574
3575 def _LoadFile(self, path):
3576 """Returns the list of paths within a .pydeps file relative to //."""
3577 if path not in self._file_cache:
3578 with open(path) as f:
3579 self._file_cache[path] = f.read()
3580 return self._file_cache[path]
3581
3582 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3583 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393584 pydeps_data = self._LoadFile(pydeps_path)
3585 uses_gn_paths = '--gn-paths' in pydeps_data
3586 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3587 if uses_gn_paths:
3588 # Paths look like: //foo/bar/baz
3589 return (e[2:] for e in entries)
3590 else:
3591 # Paths look like: path/relative/to/file.pydeps
3592 os_path = self._input_api.os_path
3593 pydeps_dir = os_path.dirname(pydeps_path)
3594 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403595
3596 def _CreateFilesToPydepsMap(self):
3597 """Returns a map of local_path -> list_of_pydeps."""
3598 ret = {}
3599 for pydep_local_path in self._pydeps_files:
3600 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3601 ret.setdefault(path, []).append(pydep_local_path)
3602 return ret
3603
3604 def ComputeAffectedPydeps(self):
3605 """Returns an iterable of .pydeps files that might need regenerating."""
3606 affected_pydeps = set()
3607 file_to_pydeps_map = None
3608 for f in self._input_api.AffectedFiles(include_deletes=True):
3609 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463610 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3611 # subrepositories. We can't figure out which files change, so re-check
3612 # all files.
3613 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383614 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3615 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403616 return self._pydeps_files
3617 elif local_path.endswith('.pydeps'):
3618 if local_path in self._pydeps_files:
3619 affected_pydeps.add(local_path)
3620 elif local_path.endswith('.py'):
3621 if file_to_pydeps_map is None:
3622 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3623 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3624 return affected_pydeps
3625
3626 def DetermineIfStale(self, pydeps_path):
3627 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413628 import difflib
John Budorick47ca3fe2018-02-10 00:53:103629 import os
3630
agrievef32bcc72016-04-04 14:57:403631 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033632 if old_pydeps_data:
3633 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393634 if '--output' not in cmd:
3635 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033636 old_contents = old_pydeps_data[2:]
3637 else:
3638 # A default cmd that should work in most cases (as long as pydeps filename
3639 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3640 # file is empty/new.
3641 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3642 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3643 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103644 env = dict(os.environ)
3645 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403646 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103647 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413648 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033649 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413650 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403651
3652
Tibor Goldschwendt360793f72019-06-25 18:23:493653def _ParseGclientArgs():
3654 args = {}
3655 with open('build/config/gclient_args.gni', 'r') as f:
3656 for line in f:
3657 line = line.strip()
3658 if not line or line.startswith('#'):
3659 continue
3660 attribute, value = line.split('=')
3661 args[attribute.strip()] = value.strip()
3662 return args
3663
3664
Saagar Sanghavifceeaae2020-08-12 16:40:363665def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403666 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403667 # This check is for Python dependency lists (.pydeps files), and involves
3668 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3669 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283670 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003671 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493672 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403673 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403674 results = []
3675 # First, check for new / deleted .pydeps.
3676 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033677 # Check whether we are running the presubmit check for a file in src.
3678 # f.LocalPath is relative to repo (src, or internal repo).
3679 # os_path.exists is relative to src repo.
3680 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3681 # to src and we can conclude that the pydeps is in src.
3682 if input_api.os_path.exists(f.LocalPath()):
3683 if f.LocalPath().endswith('.pydeps'):
3684 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3685 results.append(output_api.PresubmitError(
3686 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3687 'remove %s' % f.LocalPath()))
3688 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3689 results.append(output_api.PresubmitError(
3690 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3691 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403692
3693 if results:
3694 return results
3695
Mohamed Heikal7cd4d8312020-06-16 16:49:403696 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3697 affected_pydeps = set(checker.ComputeAffectedPydeps())
3698 affected_android_pydeps = affected_pydeps.intersection(
3699 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3700 if affected_android_pydeps and not is_android:
3701 results.append(output_api.PresubmitPromptOrNotify(
3702 'You have changed python files that may affect pydeps for android\n'
3703 'specific scripts. However, the relevant presumbit check cannot be\n'
3704 'run because you are not using an Android checkout. To validate that\n'
3705 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3706 'use the android-internal-presubmit optional trybot.\n'
3707 'Possibly stale pydeps files:\n{}'.format(
3708 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403709
Mohamed Heikal7cd4d8312020-06-16 16:49:403710 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3711 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403712 try:
phajdan.jr0d9878552016-11-04 10:49:413713 result = checker.DetermineIfStale(pydep_path)
3714 if result:
3715 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403716 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413717 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3718 'To regenerate, run:\n\n %s' %
3719 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403720 except input_api.subprocess.CalledProcessError as error:
3721 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3722 long_text=error.output)]
3723
3724 return results
3725
3726
Saagar Sanghavifceeaae2020-08-12 16:40:363727def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433728 """Checks to make sure no header files have |Singleton<|."""
3729 def FileFilter(affected_file):
3730 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443731 files_to_skip = (_EXCLUDED_PATHS +
3732 input_api.DEFAULT_FILES_TO_SKIP +
3733 (r"^base[\\/]memory[\\/]singleton\.h$",
3734 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3735 r"quic_singleton_impl\.h$"))
3736 return input_api.FilterSourceFile(affected_file,
3737 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433738
sergeyu34d21222015-09-16 00:11:443739 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433740 files = []
3741 for f in input_api.AffectedSourceFiles(FileFilter):
3742 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3743 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3744 contents = input_api.ReadFile(f)
3745 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243746 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433747 pattern.search(line)):
3748 files.append(f)
3749 break
3750
3751 if files:
yolandyandaabc6d2016-04-18 18:29:393752 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443753 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433754 'Please move them to an appropriate source file so that the ' +
3755 'template gets instantiated in a single compilation unit.',
3756 files) ]
3757 return []
3758
3759
[email protected]fd20b902014-05-09 02:14:533760_DEPRECATED_CSS = [
3761 # Values
3762 ( "-webkit-box", "flex" ),
3763 ( "-webkit-inline-box", "inline-flex" ),
3764 ( "-webkit-flex", "flex" ),
3765 ( "-webkit-inline-flex", "inline-flex" ),
3766 ( "-webkit-min-content", "min-content" ),
3767 ( "-webkit-max-content", "max-content" ),
3768
3769 # Properties
3770 ( "-webkit-background-clip", "background-clip" ),
3771 ( "-webkit-background-origin", "background-origin" ),
3772 ( "-webkit-background-size", "background-size" ),
3773 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443774 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533775
3776 # Functions
3777 ( "-webkit-gradient", "gradient" ),
3778 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3779 ( "-webkit-linear-gradient", "linear-gradient" ),
3780 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3781 ( "-webkit-radial-gradient", "radial-gradient" ),
3782 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3783]
3784
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203785
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493786# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363787def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533788 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253789 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343790 documentation and iOS CSS for dom distiller
3791 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253792 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533793 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493794 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443795 files_to_skip = (_EXCLUDED_PATHS +
3796 _TEST_CODE_EXCLUDED_PATHS +
3797 input_api.DEFAULT_FILES_TO_SKIP +
3798 (r"^chrome/common/extensions/docs",
3799 r"^chrome/docs",
3800 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3801 r"^components/neterror/resources/neterror.css",
3802 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253803 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443804 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533805 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3806 for line_num, line in fpath.ChangedContents():
3807 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023808 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533809 results.append(output_api.PresubmitError(
3810 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3811 (fpath.LocalPath(), line_num, deprecated_value, value)))
3812 return results
3813
mohan.reddyf21db962014-10-16 12:26:473814
Saagar Sanghavifceeaae2020-08-12 16:40:363815def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363816 bad_files = {}
3817 for f in input_api.AffectedFiles(include_deletes=False):
3818 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493819 not f.LocalPath().startswith('third_party/blink') and
3820 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363821 continue
3822
Daniel Bratell65b033262019-04-23 08:17:063823 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363824 continue
3825
Vaclav Brozekd5de76a2018-03-17 07:57:503826 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363827 if "#include" in line and "../" in line]
3828 if not relative_includes:
3829 continue
3830 bad_files[f.LocalPath()] = relative_includes
3831
3832 if not bad_files:
3833 return []
3834
3835 error_descriptions = []
3836 for file_path, bad_lines in bad_files.iteritems():
3837 error_description = file_path
3838 for line in bad_lines:
3839 error_description += '\n ' + line
3840 error_descriptions.append(error_description)
3841
3842 results = []
3843 results.append(output_api.PresubmitError(
3844 'You added one or more relative #include paths (including "../").\n'
3845 'These shouldn\'t be used because they can be used to include headers\n'
3846 'from code that\'s not correctly specified as a dependency in the\n'
3847 'relevant BUILD.gn file(s).',
3848 error_descriptions))
3849
3850 return results
3851
Takeshi Yoshinoe387aa32017-08-02 13:16:133852
Saagar Sanghavifceeaae2020-08-12 16:40:363853def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063854 """Check that nobody tries to include a cc file. It's a relatively
3855 common error which results in duplicate symbols in object
3856 files. This may not always break the build until someone later gets
3857 very confusing linking errors."""
3858 results = []
3859 for f in input_api.AffectedFiles(include_deletes=False):
3860 # We let third_party code do whatever it wants
3861 if (f.LocalPath().startswith('third_party') and
3862 not f.LocalPath().startswith('third_party/blink') and
3863 not f.LocalPath().startswith('third_party\\blink')):
3864 continue
3865
3866 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3867 continue
3868
3869 for _, line in f.ChangedContents():
3870 if line.startswith('#include "'):
3871 included_file = line.split('"')[1]
3872 if _IsCPlusPlusFile(input_api, included_file):
3873 # The most common naming for external files with C++ code,
3874 # apart from standard headers, is to call them foo.inc, but
3875 # Chromium sometimes uses foo-inc.cc so allow that as well.
3876 if not included_file.endswith(('.h', '-inc.cc')):
3877 results.append(output_api.PresubmitError(
3878 'Only header files or .inc files should be included in other\n'
3879 'C++ files. Compiling the contents of a cc file more than once\n'
3880 'will cause duplicate information in the build which may later\n'
3881 'result in strange link_errors.\n' +
3882 f.LocalPath() + ':\n ' +
3883 line))
3884
3885 return results
3886
3887
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203888def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3889 if not isinstance(key, ast.Str):
3890 return 'Key at line %d must be a string literal' % key.lineno
3891 if not isinstance(value, ast.Dict):
3892 return 'Value at line %d must be a dict' % value.lineno
3893 if len(value.keys) != 1:
3894 return 'Dict at line %d must have single entry' % value.lineno
3895 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3896 return (
3897 'Entry at line %d must have a string literal \'filepath\' as key' %
3898 value.lineno)
3899 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133900
Takeshi Yoshinoe387aa32017-08-02 13:16:133901
Sergey Ulanov4af16052018-11-08 02:41:463902def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203903 if not isinstance(key, ast.Str):
3904 return 'Key at line %d must be a string literal' % key.lineno
3905 if not isinstance(value, ast.List):
3906 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463907 for element in value.elts:
3908 if not isinstance(element, ast.Str):
3909 return 'Watchlist elements on line %d is not a string' % key.lineno
3910 if not email_regex.match(element.s):
3911 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3912 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203913 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133914
Takeshi Yoshinoe387aa32017-08-02 13:16:133915
Sergey Ulanov4af16052018-11-08 02:41:463916def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203917 mismatch_template = (
3918 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3919 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133920
Sergey Ulanov4af16052018-11-08 02:41:463921 email_regex = input_api.re.compile(
3922 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3923
3924 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203925 i = 0
3926 last_key = ''
3927 while True:
3928 if i >= len(wd_dict.keys):
3929 if i >= len(w_dict.keys):
3930 return None
3931 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3932 elif i >= len(w_dict.keys):
3933 return (
3934 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133935
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203936 wd_key = wd_dict.keys[i]
3937 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133938
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203939 result = _CheckWatchlistDefinitionsEntrySyntax(
3940 wd_key, wd_dict.values[i], ast)
3941 if result is not None:
3942 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133943
Sergey Ulanov4af16052018-11-08 02:41:463944 result = _CheckWatchlistsEntrySyntax(
3945 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203946 if result is not None:
3947 return 'Bad entry in WATCHLISTS dict: %s' % result
3948
3949 if wd_key.s != w_key.s:
3950 return mismatch_template % (
3951 '%s at line %d' % (wd_key.s, wd_key.lineno),
3952 '%s at line %d' % (w_key.s, w_key.lineno))
3953
3954 if wd_key.s < last_key:
3955 return (
3956 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3957 (wd_key.lineno, w_key.lineno))
3958 last_key = wd_key.s
3959
3960 i = i + 1
3961
3962
Sergey Ulanov4af16052018-11-08 02:41:463963def _CheckWATCHLISTSSyntax(expression, input_api):
3964 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203965 if not isinstance(expression, ast.Expression):
3966 return 'WATCHLISTS file must contain a valid expression'
3967 dictionary = expression.body
3968 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3969 return 'WATCHLISTS file must have single dict with exactly two entries'
3970
3971 first_key = dictionary.keys[0]
3972 first_value = dictionary.values[0]
3973 second_key = dictionary.keys[1]
3974 second_value = dictionary.values[1]
3975
3976 if (not isinstance(first_key, ast.Str) or
3977 first_key.s != 'WATCHLIST_DEFINITIONS' or
3978 not isinstance(first_value, ast.Dict)):
3979 return (
3980 'The first entry of the dict in WATCHLISTS file must be '
3981 'WATCHLIST_DEFINITIONS dict')
3982
3983 if (not isinstance(second_key, ast.Str) or
3984 second_key.s != 'WATCHLISTS' or
3985 not isinstance(second_value, ast.Dict)):
3986 return (
3987 'The second entry of the dict in WATCHLISTS file must be '
3988 'WATCHLISTS dict')
3989
Sergey Ulanov4af16052018-11-08 02:41:463990 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133991
3992
Saagar Sanghavifceeaae2020-08-12 16:40:363993def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133994 for f in input_api.AffectedFiles(include_deletes=False):
3995 if f.LocalPath() == 'WATCHLISTS':
3996 contents = input_api.ReadFile(f, 'r')
3997
3998 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203999 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134000 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204001 # Get an AST tree for it and scan the tree for detailed style checking.
4002 expression = input_api.ast.parse(
4003 contents, filename='WATCHLISTS', mode='eval')
4004 except ValueError as e:
4005 return [output_api.PresubmitError(
4006 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4007 except SyntaxError as e:
4008 return [output_api.PresubmitError(
4009 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4010 except TypeError as e:
4011 return [output_api.PresubmitError(
4012 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134013
Sergey Ulanov4af16052018-11-08 02:41:464014 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204015 if result is not None:
4016 return [output_api.PresubmitError(result)]
4017 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134018
4019 return []
4020
4021
Andrew Grieve1b290e4a22020-11-24 20:07:014022def CheckGnGlobForward(input_api, output_api):
4023 """Checks that forward_variables_from(invoker, "*") follows best practices.
4024
4025 As documented at //build/docs/writing_gn_templates.md
4026 """
4027 def gn_files(f):
4028 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
4029
4030 problems = []
4031 for f in input_api.AffectedSourceFiles(gn_files):
4032 for line_num, line in f.ChangedContents():
4033 if 'forward_variables_from(invoker, "*")' in line:
4034 problems.append(
4035 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
4036 f.LocalPath(), line_num))
4037
4038 if problems:
4039 return [output_api.PresubmitPromptWarning(
4040 'forward_variables_from("*") without exclusions',
4041 items=sorted(problems),
4042 long_text=('The variables "visibilty" and "test_only" should be '
4043 'explicitly listed in forward_variables_from(). For more '
4044 'details, see:\n'
4045 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4046 'build/docs/writing_gn_templates.md'
4047 '#Using-forward_variables_from'))]
4048 return []
4049
4050
Saagar Sanghavifceeaae2020-08-12 16:40:364051def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194052 """Checks that newly added header files have corresponding GN changes.
4053 Note that this is only a heuristic. To be precise, run script:
4054 build/check_gn_headers.py.
4055 """
4056
4057 def headers(f):
4058 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444059 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194060
4061 new_headers = []
4062 for f in input_api.AffectedSourceFiles(headers):
4063 if f.Action() != 'A':
4064 continue
4065 new_headers.append(f.LocalPath())
4066
4067 def gn_files(f):
James Cook24a504192020-07-23 00:08:444068 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194069
4070 all_gn_changed_contents = ''
4071 for f in input_api.AffectedSourceFiles(gn_files):
4072 for _, line in f.ChangedContents():
4073 all_gn_changed_contents += line
4074
4075 problems = []
4076 for header in new_headers:
4077 basename = input_api.os_path.basename(header)
4078 if basename not in all_gn_changed_contents:
4079 problems.append(header)
4080
4081 if problems:
4082 return [output_api.PresubmitPromptWarning(
4083 'Missing GN changes for new header files', items=sorted(problems),
4084 long_text='Please double check whether newly added header files need '
4085 'corresponding changes in gn or gni files.\nThis checking is only a '
4086 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4087 'Read https://crbug.com/661774 for more info.')]
4088 return []
4089
4090
Saagar Sanghavifceeaae2020-08-12 16:40:364091def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024092 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4093
4094 This assumes we won't intentionally reference one product from the other
4095 product.
4096 """
4097 all_problems = []
4098 test_cases = [{
4099 "filename_postfix": "google_chrome_strings.grd",
4100 "correct_name": "Chrome",
4101 "incorrect_name": "Chromium",
4102 }, {
4103 "filename_postfix": "chromium_strings.grd",
4104 "correct_name": "Chromium",
4105 "incorrect_name": "Chrome",
4106 }]
4107
4108 for test_case in test_cases:
4109 problems = []
4110 filename_filter = lambda x: x.LocalPath().endswith(
4111 test_case["filename_postfix"])
4112
4113 # Check each new line. Can yield false positives in multiline comments, but
4114 # easier than trying to parse the XML because messages can have nested
4115 # children, and associating message elements with affected lines is hard.
4116 for f in input_api.AffectedSourceFiles(filename_filter):
4117 for line_num, line in f.ChangedContents():
4118 if "<message" in line or "<!--" in line or "-->" in line:
4119 continue
4120 if test_case["incorrect_name"] in line:
4121 problems.append(
4122 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4123
4124 if problems:
4125 message = (
4126 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4127 % (test_case["correct_name"], test_case["correct_name"],
4128 test_case["incorrect_name"]))
4129 all_problems.append(
4130 output_api.PresubmitPromptWarning(message, items=problems))
4131
4132 return all_problems
4133
4134
Saagar Sanghavifceeaae2020-08-12 16:40:364135def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514136 # TODO(crbug.com/941824): We need to make sure the entries in
4137 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4138 # so that users of //buildtools in other projects get the same tooling
4139 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4140 # support to gclient, we can eliminate the duplication and delete
4141 # this presubmit check.
4142
4143 # Update this regexp if new revisions are added to the files.
4144 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264145 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514146
4147 # If a user is changing one revision, they need to change the same
4148 # line in both files. This means that any given change should contain
4149 # exactly the same list of changed lines that match the regexps. The
4150 # replace(' ', '') call allows us to ignore whitespace changes to the
4151 # lines. The 'long_text' parameter to the error will contain the
4152 # list of changed lines in both files, which should make it easy enough
4153 # to spot the error without going overboard in this implementation.
4154 revs_changes = {
4155 'DEPS': {},
4156 'buildtools/DEPS': {},
4157 }
4158 long_text = ''
4159
4160 for f in input_api.AffectedFiles(
4161 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4162 for line_num, line in f.ChangedContents():
4163 if rev_regexp.search(line):
4164 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4165 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4166
4167 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4168 return [output_api.PresubmitError(
4169 'Change buildtools revisions in sync in both //DEPS and '
4170 '//buildtools/DEPS.', long_text=long_text + '\n')]
4171 else:
4172 return []
4173
4174
Saagar Sanghavifceeaae2020-08-12 16:40:364175def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364176 """Avoid large files, especially binary files, in the repository since
4177 git doesn't scale well for those. They will be in everyone's repo
4178 clones forever, forever making Chromium slower to clone and work
4179 with."""
4180
4181 # Uploading files to cloud storage is not trivial so we don't want
4182 # to set the limit too low, but the upper limit for "normal" large
4183 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4184 # anything over 20 MB is exceptional.
4185 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4186
4187 too_large_files = []
4188 for f in input_api.AffectedFiles():
4189 # Check both added and modified files (but not deleted files).
4190 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384191 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364192 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4193 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4194
4195 if too_large_files:
4196 message = (
4197 'Do not commit large files to git since git scales badly for those.\n' +
4198 'Instead put the large files in cloud storage and use DEPS to\n' +
4199 'fetch them.\n' + '\n'.join(too_large_files)
4200 )
4201 return [output_api.PresubmitError(
4202 'Too large files found in commit', long_text=message + '\n')]
4203 else:
4204 return []
4205
Max Morozb47503b2019-08-08 21:03:274206
Saagar Sanghavifceeaae2020-08-12 16:40:364207def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274208 """Checks specific for fuzz target sources."""
4209 EXPORTED_SYMBOLS = [
4210 'LLVMFuzzerInitialize',
4211 'LLVMFuzzerCustomMutator',
4212 'LLVMFuzzerCustomCrossOver',
4213 'LLVMFuzzerMutate',
4214 ]
4215
4216 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4217
4218 def FilterFile(affected_file):
4219 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444220 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4221 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274222
4223 return input_api.FilterSourceFile(
4224 affected_file,
James Cook24a504192020-07-23 00:08:444225 files_to_check=[files_to_check],
4226 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274227
4228 files_with_missing_header = []
4229 for f in input_api.AffectedSourceFiles(FilterFile):
4230 contents = input_api.ReadFile(f, 'r')
4231 if REQUIRED_HEADER in contents:
4232 continue
4233
4234 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4235 files_with_missing_header.append(f.LocalPath())
4236
4237 if not files_with_missing_header:
4238 return []
4239
4240 long_text = (
4241 'If you define any of the libFuzzer optional functions (%s), it is '
4242 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4243 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4244 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4245 'to access command line arguments passed to the fuzzer. Instead, prefer '
4246 'static initialization and shared resources as documented in '
4247 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4248 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4249 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4250 )
4251
4252 return [output_api.PresubmitPromptWarning(
4253 message="Missing '%s' in:" % REQUIRED_HEADER,
4254 items=files_with_missing_header,
4255 long_text=long_text)]
4256
4257
Mohamed Heikald048240a2019-11-12 16:57:374258def _CheckNewImagesWarning(input_api, output_api):
4259 """
4260 Warns authors who add images into the repo to make sure their images are
4261 optimized before committing.
4262 """
4263 images_added = False
4264 image_paths = []
4265 errors = []
4266 filter_lambda = lambda x: input_api.FilterSourceFile(
4267 x,
James Cook24a504192020-07-23 00:08:444268 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4269 + input_api.DEFAULT_FILES_TO_SKIP),
4270 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374271 )
4272 for f in input_api.AffectedFiles(
4273 include_deletes=False, file_filter=filter_lambda):
4274 local_path = f.LocalPath().lower()
4275 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4276 images_added = True
4277 image_paths.append(f)
4278 if images_added:
4279 errors.append(output_api.PresubmitPromptWarning(
4280 'It looks like you are trying to commit some images. If these are '
4281 'non-test-only images, please make sure to read and apply the tips in '
4282 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4283 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4284 'FYI only and will not block your CL on the CQ.', image_paths))
4285 return errors
4286
4287
Saagar Sanghavifceeaae2020-08-12 16:40:364288def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574289 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224290 results = []
dgnaa68d5e2015-06-10 10:08:224291 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174292 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224293 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294294 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064295 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4296 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424297 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184298 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574299 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374300 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154301 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574302 return results
4303
Saagar Sanghavifceeaae2020-08-12 16:40:364304def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574305 """Groups commit checks that target android code."""
4306 results = []
4307 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224308 return results
4309
Chris Hall59f8d0c72020-05-01 07:31:194310# TODO(chrishall): could we additionally match on any path owned by
4311# ui/accessibility/OWNERS ?
4312_ACCESSIBILITY_PATHS = (
4313 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4314 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4315 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4316 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4317 r"^content[\\/]browser[\\/]accessibility[\\/]",
4318 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4319 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4320 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4321 r"^ui[\\/]accessibility[\\/]",
4322 r"^ui[\\/]views[\\/]accessibility[\\/]",
4323)
4324
Saagar Sanghavifceeaae2020-08-12 16:40:364325def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194326 """Checks that commits to accessibility code contain an AX-Relnotes field in
4327 their commit message."""
4328 def FileFilter(affected_file):
4329 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444330 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194331
4332 # Only consider changes affecting accessibility paths.
4333 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4334 return []
4335
Akihiro Ota08108e542020-05-20 15:30:534336 # AX-Relnotes can appear in either the description or the footer.
4337 # When searching the description, require 'AX-Relnotes:' to appear at the
4338 # beginning of a line.
4339 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4340 description_has_relnotes = any(ax_regex.match(line)
4341 for line in input_api.change.DescriptionText().lower().splitlines())
4342
4343 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4344 'AX-Relnotes', [])
4345 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194346 return []
4347
4348 # TODO(chrishall): link to Relnotes documentation in message.
4349 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4350 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4351 "user-facing changes"
4352 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4353 "user-facing effects"
4354 "\n if this is confusing or annoying then please contact members "
4355 "of ui/accessibility/OWNERS.")
4356
4357 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224358
Saagar Sanghavifceeaae2020-08-12 16:40:364359def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394360 """Checks common to both upload and commit."""
4361 results = []
4362 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384363 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544364 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084365
4366 author = input_api.change.author_email
4367 if author and author not in _KNOWN_ROBOTS:
4368 results.extend(
4369 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4370
[email protected]9f919cc2013-07-31 03:04:044371 results.extend(
4372 input_api.canned_checks.CheckChangeHasNoTabs(
4373 input_api,
4374 output_api,
4375 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434376 results.extend(input_api.RunTests(
4377 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244378
Edward Lesmesce51df52020-08-04 22:10:174379 dirmd_bin = input_api.os_path.join(
4380 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4381 results.extend(input_api.RunTests(
4382 input_api.canned_checks.CheckDirMetadataFormat(
4383 input_api, output_api, dirmd_bin)))
4384 results.extend(
4385 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4386 input_api, output_api))
4387
Vaclav Brozekcdc7defb2018-03-20 09:54:354388 for f in input_api.AffectedFiles():
4389 path, name = input_api.os_path.split(f.LocalPath())
4390 if name == 'PRESUBMIT.py':
4391 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004392 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4393 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074394 # The PRESUBMIT.py file (and the directory containing it) might
4395 # have been affected by being moved or removed, so only try to
4396 # run the tests if they still exist.
4397 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4398 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444399 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394400 return results
[email protected]1f7b4172010-01-28 01:17:344401
[email protected]b337cb5b2011-01-23 21:24:054402
Saagar Sanghavifceeaae2020-08-12 16:40:364403def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494404 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4405 if f.LocalPath().endswith(('.orig', '.rej'))]
4406 if problems:
4407 return [output_api.PresubmitError(
4408 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034409 else:
4410 return []
[email protected]b8079ae4a2012-12-05 19:56:494411
4412
Saagar Sanghavifceeaae2020-08-12 16:40:364413def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214414 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4415 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4416 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074417 include_re = input_api.re.compile(
4418 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4419 extension_re = input_api.re.compile(r'\.[a-z]+$')
4420 errors = []
4421 for f in input_api.AffectedFiles():
4422 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4423 continue
4424 found_line_number = None
4425 found_macro = None
4426 for line_num, line in f.ChangedContents():
4427 match = macro_re.search(line)
4428 if match:
4429 found_line_number = line_num
4430 found_macro = match.group(2)
4431 break
4432 if not found_line_number:
4433 continue
4434
4435 found_include = False
4436 for line in f.NewContents():
4437 if include_re.search(line):
4438 found_include = True
4439 break
4440 if found_include:
4441 continue
4442
4443 if not f.LocalPath().endswith('.h'):
4444 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4445 try:
4446 content = input_api.ReadFile(primary_header_path, 'r')
4447 if include_re.search(content):
4448 continue
4449 except IOError:
4450 pass
4451 errors.append('%s:%d %s macro is used without including build/'
4452 'build_config.h.'
4453 % (f.LocalPath(), found_line_number, found_macro))
4454 if errors:
4455 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4456 return []
4457
4458
[email protected]b00342e7f2013-03-26 16:21:544459def _DidYouMeanOSMacro(bad_macro):
4460 try:
4461 return {'A': 'OS_ANDROID',
4462 'B': 'OS_BSD',
4463 'C': 'OS_CHROMEOS',
4464 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444465 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544466 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444467 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544468 'N': 'OS_NACL',
4469 'O': 'OS_OPENBSD',
4470 'P': 'OS_POSIX',
4471 'S': 'OS_SOLARIS',
4472 'W': 'OS_WIN'}[bad_macro[3].upper()]
4473 except KeyError:
4474 return ''
4475
4476
4477def _CheckForInvalidOSMacrosInFile(input_api, f):
4478 """Check for sensible looking, totally invalid OS macros."""
4479 preprocessor_statement = input_api.re.compile(r'^\s*#')
4480 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4481 results = []
4482 for lnum, line in f.ChangedContents():
4483 if preprocessor_statement.search(line):
4484 for match in os_macro.finditer(line):
4485 if not match.group(1) in _VALID_OS_MACROS:
4486 good = _DidYouMeanOSMacro(match.group(1))
4487 did_you_mean = ' (did you mean %s?)' % good if good else ''
4488 results.append(' %s:%d %s%s' % (f.LocalPath(),
4489 lnum,
4490 match.group(1),
4491 did_you_mean))
4492 return results
4493
4494
Saagar Sanghavifceeaae2020-08-12 16:40:364495def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544496 """Check all affected files for invalid OS macros."""
4497 bad_macros = []
tzik3f295992018-12-04 20:32:234498 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474499 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544500 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4501
4502 if not bad_macros:
4503 return []
4504
4505 return [output_api.PresubmitError(
4506 'Possibly invalid OS macro[s] found. Please fix your code\n'
4507 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4508
lliabraa35bab3932014-10-01 12:16:444509
4510def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4511 """Check all affected files for invalid "if defined" macros."""
4512 ALWAYS_DEFINED_MACROS = (
4513 "TARGET_CPU_PPC",
4514 "TARGET_CPU_PPC64",
4515 "TARGET_CPU_68K",
4516 "TARGET_CPU_X86",
4517 "TARGET_CPU_ARM",
4518 "TARGET_CPU_MIPS",
4519 "TARGET_CPU_SPARC",
4520 "TARGET_CPU_ALPHA",
4521 "TARGET_IPHONE_SIMULATOR",
4522 "TARGET_OS_EMBEDDED",
4523 "TARGET_OS_IPHONE",
4524 "TARGET_OS_MAC",
4525 "TARGET_OS_UNIX",
4526 "TARGET_OS_WIN32",
4527 )
4528 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4529 results = []
4530 for lnum, line in f.ChangedContents():
4531 for match in ifdef_macro.finditer(line):
4532 if match.group(1) in ALWAYS_DEFINED_MACROS:
4533 always_defined = ' %s is always defined. ' % match.group(1)
4534 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4535 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4536 lnum,
4537 always_defined,
4538 did_you_mean))
4539 return results
4540
4541
Saagar Sanghavifceeaae2020-08-12 16:40:364542def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444543 """Check all affected files for invalid "if defined" macros."""
4544 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054545 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444546 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054547 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214548 continue
lliabraa35bab3932014-10-01 12:16:444549 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4550 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4551
4552 if not bad_macros:
4553 return []
4554
4555 return [output_api.PresubmitError(
4556 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4557 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4558 bad_macros)]
4559
4560
Saagar Sanghavifceeaae2020-08-12 16:40:364561def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044562 """Check for same IPC rules described in
4563 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4564 """
4565 base_pattern = r'IPC_ENUM_TRAITS\('
4566 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4567 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4568
4569 problems = []
4570 for f in input_api.AffectedSourceFiles(None):
4571 local_path = f.LocalPath()
4572 if not local_path.endswith('.h'):
4573 continue
4574 for line_number, line in f.ChangedContents():
4575 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4576 problems.append(
4577 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4578
4579 if problems:
4580 return [output_api.PresubmitPromptWarning(
4581 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4582 else:
4583 return []
4584
[email protected]b00342e7f2013-03-26 16:21:544585
Saagar Sanghavifceeaae2020-08-12 16:40:364586def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054587 """Check to make sure no files being submitted have long paths.
4588 This causes issues on Windows.
4589 """
4590 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194591 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054592 local_path = f.LocalPath()
4593 # Windows has a path limit of 260 characters. Limit path length to 200 so
4594 # that we have some extra for the prefix on dev machines and the bots.
4595 if len(local_path) > 200:
4596 problems.append(local_path)
4597
4598 if problems:
4599 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4600 else:
4601 return []
4602
4603
Saagar Sanghavifceeaae2020-08-12 16:40:364604def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144605 """Check that header files have proper guards against multiple inclusion.
4606 If a file should not have such guards (and it probably should) then it
4607 should include the string "no-include-guard-because-multiply-included".
4608 """
Daniel Bratell6a75baef62018-06-04 10:04:454609 def is_chromium_header_file(f):
4610 # We only check header files under the control of the Chromium
4611 # project. That is, those outside third_party apart from
4612 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324613 # We also exclude *_message_generator.h headers as they use
4614 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454615 file_with_path = input_api.os_path.normpath(f.LocalPath())
4616 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324617 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454618 (not file_with_path.startswith('third_party') or
4619 file_with_path.startswith(
4620 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144621
4622 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344623 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144624
4625 errors = []
4626
Daniel Bratell6a75baef62018-06-04 10:04:454627 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144628 guard_name = None
4629 guard_line_number = None
4630 seen_guard_end = False
4631
4632 file_with_path = input_api.os_path.normpath(f.LocalPath())
4633 base_file_name = input_api.os_path.splitext(
4634 input_api.os_path.basename(file_with_path))[0]
4635 upper_base_file_name = base_file_name.upper()
4636
4637 expected_guard = replace_special_with_underscore(
4638 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144639
4640 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574641 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4642 # are too many (1000+) files with slight deviations from the
4643 # coding style. The most important part is that the include guard
4644 # is there, and that it's unique, not the name so this check is
4645 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144646 #
4647 # As code becomes more uniform, this could be made stricter.
4648
4649 guard_name_pattern_list = [
4650 # Anything with the right suffix (maybe with an extra _).
4651 r'\w+_H__?',
4652
Daniel Bratell39b5b062018-05-16 18:09:574653 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144654 r'\w+_h',
4655
4656 # Anything including the uppercase name of the file.
4657 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4658 upper_base_file_name)) + r'\w*',
4659 ]
4660 guard_name_pattern = '|'.join(guard_name_pattern_list)
4661 guard_pattern = input_api.re.compile(
4662 r'#ifndef\s+(' + guard_name_pattern + ')')
4663
4664 for line_number, line in enumerate(f.NewContents()):
4665 if 'no-include-guard-because-multiply-included' in line:
4666 guard_name = 'DUMMY' # To not trigger check outside the loop.
4667 break
4668
4669 if guard_name is None:
4670 match = guard_pattern.match(line)
4671 if match:
4672 guard_name = match.group(1)
4673 guard_line_number = line_number
4674
Daniel Bratell39b5b062018-05-16 18:09:574675 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454676 # don't match the chromium style guide, but new files should
4677 # get it right.
4678 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574679 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144680 errors.append(output_api.PresubmitPromptWarning(
4681 'Header using the wrong include guard name %s' % guard_name,
4682 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574683 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144684 else:
4685 # The line after #ifndef should have a #define of the same name.
4686 if line_number == guard_line_number + 1:
4687 expected_line = '#define %s' % guard_name
4688 if line != expected_line:
4689 errors.append(output_api.PresubmitPromptWarning(
4690 'Missing "%s" for include guard' % expected_line,
4691 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4692 'Expected: %r\nGot: %r' % (expected_line, line)))
4693
4694 if not seen_guard_end and line == '#endif // %s' % guard_name:
4695 seen_guard_end = True
4696 elif seen_guard_end:
4697 if line.strip() != '':
4698 errors.append(output_api.PresubmitPromptWarning(
4699 'Include guard %s not covering the whole file' % (
4700 guard_name), [f.LocalPath()]))
4701 break # Nothing else to check and enough to warn once.
4702
4703 if guard_name is None:
4704 errors.append(output_api.PresubmitPromptWarning(
4705 'Missing include guard %s' % expected_guard,
4706 [f.LocalPath()],
4707 'Missing include guard in %s\n'
4708 'Recommended name: %s\n'
4709 'This check can be disabled by having the string\n'
4710 'no-include-guard-because-multiply-included in the header.' %
4711 (f.LocalPath(), expected_guard)))
4712
4713 return errors
4714
4715
Saagar Sanghavifceeaae2020-08-12 16:40:364716def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234717 """Check source code and known ascii text files for Windows style line
4718 endings.
4719 """
earthdok1b5e0ee2015-03-10 15:19:104720 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234721
4722 file_inclusion_pattern = (
4723 known_text_files,
4724 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4725 )
4726
mostynbb639aca52015-01-07 20:31:234727 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534728 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444729 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534730 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504731 include_file = False
4732 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234733 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504734 include_file = True
4735 if include_file:
4736 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234737
4738 if problems:
4739 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4740 'these files to contain Windows style line endings?\n' +
4741 '\n'.join(problems))]
4742
4743 return []
4744
4745
Saagar Sanghavifceeaae2020-08-12 16:40:364746def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134747 """Checks that all source files use SYSLOG properly."""
4748 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364749 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564750 for line_number, line in f.ChangedContents():
4751 if 'SYSLOG' in line:
4752 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4753
pastarmovj89f7ee12016-09-20 14:58:134754 if syslog_files:
4755 return [output_api.PresubmitPromptWarning(
4756 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4757 ' calls.\nFiles to check:\n', items=syslog_files)]
4758 return []
4759
4760
[email protected]1f7b4172010-01-28 01:17:344761def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364762 if input_api.version < [2, 0, 0]:
4763 return [output_api.PresubmitError("Your depot_tools is out of date. "
4764 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4765 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344766 results = []
scottmg39b29952014-12-08 18:31:284767 results.extend(
jam93a6ee792017-02-08 23:59:224768 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544769 return results
[email protected]ca8d1982009-02-19 16:33:124770
4771
[email protected]1bfb8322014-04-23 01:02:414772def GetTryServerMasterForBot(bot):
4773 """Returns the Try Server master for the given bot.
4774
[email protected]0bb112362014-07-26 04:38:324775 It tries to guess the master from the bot name, but may still fail
4776 and return None. There is no longer a default master.
4777 """
4778 # Potentially ambiguous bot names are listed explicitly.
4779 master_map = {
tandriie5587792016-07-14 00:34:504780 'chromium_presubmit': 'master.tryserver.chromium.linux',
4781 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414782 }
[email protected]0bb112362014-07-26 04:38:324783 master = master_map.get(bot)
4784 if not master:
wnwen4fbaab82016-05-25 12:54:364785 if 'android' in bot:
tandriie5587792016-07-14 00:34:504786 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364787 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504788 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324789 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504790 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324791 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504792 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324793 return master
[email protected]1bfb8322014-04-23 01:02:414794
4795
[email protected]ca8d1982009-02-19 16:33:124796def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364797 if input_api.version < [2, 0, 0]:
4798 return [output_api.PresubmitError("Your depot_tools is out of date. "
4799 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4800 "but your version is %d.%d.%d" % tuple(input_api.version))]
4801
[email protected]fe5f57c52009-06-05 14:25:544802 results = []
[email protected]fe5f57c52009-06-05 14:25:544803 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274804 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344805 input_api,
4806 output_api,
[email protected]2fdd1f362013-01-16 03:56:034807 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274808
jam93a6ee792017-02-08 23:59:224809 results.extend(
4810 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544811 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4812 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384813 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4814 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414815 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4816 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544817 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144818
4819
Saagar Sanghavifceeaae2020-08-12 16:40:364820def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264821 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024822 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4823 # footer is set to true.
4824 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264825 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024826 footer.lower()
4827 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264828 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024829
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144830 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264831 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144832 import sys
4833 from io import StringIO
4834
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144835 new_or_added_paths = set(f.LocalPath()
4836 for f in input_api.AffectedFiles()
4837 if (f.Action() == 'A' or f.Action() == 'M'))
4838 removed_paths = set(f.LocalPath()
4839 for f in input_api.AffectedFiles(include_deletes=True)
4840 if f.Action() == 'D')
4841
Andrew Grieve0e8790c2020-09-03 17:27:324842 affected_grds = [
4843 f for f in input_api.AffectedFiles()
4844 if f.LocalPath().endswith(('.grd', '.grdp'))
4845 ]
4846 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164847 if not affected_grds:
4848 return []
4849
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144850 affected_png_paths = [f.AbsoluteLocalPath()
4851 for f in input_api.AffectedFiles()
4852 if (f.LocalPath().endswith('.png'))]
4853
4854 # Check for screenshots. Developers can upload screenshots using
4855 # tools/translation/upload_screenshots.py which finds and uploads
4856 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4857 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4858 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4859 #
4860 # The logic here is as follows:
4861 #
4862 # - If the CL has a .png file under the screenshots directory for a grd
4863 # file, warn the developer. Actual images should never be checked into the
4864 # Chrome repo.
4865 #
4866 # - If the CL contains modified or new messages in grd files and doesn't
4867 # contain the corresponding .sha1 files, warn the developer to add images
4868 # and upload them via tools/translation/upload_screenshots.py.
4869 #
4870 # - If the CL contains modified or new messages in grd files and the
4871 # corresponding .sha1 files, everything looks good.
4872 #
4873 # - If the CL contains removed messages in grd files but the corresponding
4874 # .sha1 files aren't removed, warn the developer to remove them.
4875 unnecessary_screenshots = []
4876 missing_sha1 = []
4877 unnecessary_sha1_files = []
4878
Rainhard Findlingfc31844c52020-05-15 09:58:264879 # This checks verifies that the ICU syntax of messages this CL touched is
4880 # valid, and reports any found syntax errors.
4881 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4882 # without developers being aware of them. Later on, such ICU syntax errors
4883 # break message extraction for translation, hence would block Chromium
4884 # translations until they are fixed.
4885 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144886
4887 def _CheckScreenshotAdded(screenshots_dir, message_id):
4888 sha1_path = input_api.os_path.join(
4889 screenshots_dir, message_id + '.png.sha1')
4890 if sha1_path not in new_or_added_paths:
4891 missing_sha1.append(sha1_path)
4892
4893
4894 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4895 sha1_path = input_api.os_path.join(
4896 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034897 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144898 unnecessary_sha1_files.append(sha1_path)
4899
Rainhard Findlingfc31844c52020-05-15 09:58:264900
4901 def _ValidateIcuSyntax(text, level, signatures):
4902 """Validates ICU syntax of a text string.
4903
4904 Check if text looks similar to ICU and checks for ICU syntax correctness
4905 in this case. Reports various issues with ICU syntax and values of
4906 variants. Supports checking of nested messages. Accumulate information of
4907 each ICU messages found in the text for further checking.
4908
4909 Args:
4910 text: a string to check.
4911 level: a number of current nesting level.
4912 signatures: an accumulator, a list of tuple of (level, variable,
4913 kind, variants).
4914
4915 Returns:
4916 None if a string is not ICU or no issue detected.
4917 A tuple of (message, start index, end index) if an issue detected.
4918 """
4919 valid_types = {
4920 'plural': (frozenset(
4921 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4922 frozenset(['=1', 'other'])),
4923 'selectordinal': (frozenset(
4924 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4925 frozenset(['one', 'other'])),
4926 'select': (frozenset(), frozenset(['other'])),
4927 }
4928
4929 # Check if the message looks like an attempt to use ICU
4930 # plural. If yes - check if its syntax strictly matches ICU format.
4931 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4932 if not like:
4933 signatures.append((level, None, None, None))
4934 return
4935
4936 # Check for valid prefix and suffix
4937 m = re.match(
4938 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4939 r'(plural|selectordinal|select),\s*'
4940 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4941 if not m:
4942 return (('This message looks like an ICU plural, '
4943 'but does not follow ICU syntax.'), like.start(), like.end())
4944 starting, variable, kind, variant_pairs = m.groups()
4945 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4946 if depth:
4947 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4948 len(text))
4949 first = text[0]
4950 ending = text[last_pos:]
4951 if not starting:
4952 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4953 last_pos)
4954 if not ending or '}' not in ending:
4955 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4956 last_pos)
4957 elif first != '{':
4958 return (
4959 ('Invalid ICU format. Extra characters at the start of a complex '
4960 'message (go/icu-message-migration): "%s"') %
4961 starting, 0, len(starting))
4962 elif ending != '}':
4963 return (('Invalid ICU format. Extra characters at the end of a complex '
4964 'message (go/icu-message-migration): "%s"')
4965 % ending, last_pos - 1, len(text) - 1)
4966 if kind not in valid_types:
4967 return (('Unknown ICU message type %s. '
4968 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4969 known, required = valid_types[kind]
4970 defined_variants = set()
4971 for variant, variant_range, value, value_range in variants:
4972 start, end = variant_range
4973 if variant in defined_variants:
4974 return ('Variant "%s" is defined more than once' % variant,
4975 start, end)
4976 elif known and variant not in known:
4977 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4978 start, end)
4979 defined_variants.add(variant)
4980 # Check for nested structure
4981 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4982 if res:
4983 return (res[0], res[1] + value_range[0] + 1,
4984 res[2] + value_range[0] + 1)
4985 missing = required - defined_variants
4986 if missing:
4987 return ('Required variants missing: %s' % ', '.join(missing), 0,
4988 len(text))
4989 signatures.append((level, variable, kind, defined_variants))
4990
4991
4992 def _ParseIcuVariants(text, offset=0):
4993 """Parse variants part of ICU complex message.
4994
4995 Builds a tuple of variant names and values, as well as
4996 their offsets in the input string.
4997
4998 Args:
4999 text: a string to parse
5000 offset: additional offset to add to positions in the text to get correct
5001 position in the complete ICU string.
5002
5003 Returns:
5004 List of tuples, each tuple consist of four fields: variant name,
5005 variant name span (tuple of two integers), variant value, value
5006 span (tuple of two integers).
5007 """
5008 depth, start, end = 0, -1, -1
5009 variants = []
5010 key = None
5011 for idx, char in enumerate(text):
5012 if char == '{':
5013 if not depth:
5014 start = idx
5015 chunk = text[end + 1:start]
5016 key = chunk.strip()
5017 pos = offset + end + 1 + chunk.find(key)
5018 span = (pos, pos + len(key))
5019 depth += 1
5020 elif char == '}':
5021 if not depth:
5022 return variants, depth, offset + idx
5023 depth -= 1
5024 if not depth:
5025 end = idx
5026 variants.append((key, span, text[start:end + 1], (offset + start,
5027 offset + end + 1)))
5028 return variants, depth, offset + end + 1
5029
meacer8c0d3832019-12-26 21:46:165030 try:
5031 old_sys_path = sys.path
5032 sys.path = sys.path + [input_api.os_path.join(
5033 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5034 from helper import grd_helper
5035 finally:
5036 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145037
5038 for f in affected_grds:
5039 file_path = f.LocalPath()
5040 old_id_to_msg_map = {}
5041 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385042 # Note that this code doesn't check if the file has been deleted. This is
5043 # OK because it only uses the old and new file contents and doesn't load
5044 # the file via its path.
5045 # It's also possible that a file's content refers to a renamed or deleted
5046 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5047 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5048 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145049 if file_path.endswith('.grdp'):
5050 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585051 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395052 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145053 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585054 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395055 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145056 else:
meacerff8a9b62019-12-10 19:43:585057 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145058 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585059 old_id_to_msg_map = grd_helper.GetGrdMessages(
5060 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145061 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585062 new_id_to_msg_map = grd_helper.GetGrdMessages(
5063 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145064
Rainhard Findlingd8d04372020-08-13 13:30:095065 grd_name, ext = input_api.os_path.splitext(
5066 input_api.os_path.basename(file_path))
5067 screenshots_dir = input_api.os_path.join(
5068 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5069
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145070 # Compute added, removed and modified message IDs.
5071 old_ids = set(old_id_to_msg_map)
5072 new_ids = set(new_id_to_msg_map)
5073 added_ids = new_ids - old_ids
5074 removed_ids = old_ids - new_ids
5075 modified_ids = set([])
5076 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355077 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095078 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5079 # The message content itself changed. Require an updated screenshot.
5080 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355081 elif old_id_to_msg_map[key].attrs['meaning'] != \
5082 new_id_to_msg_map[key].attrs['meaning']:
5083 # The message meaning changed. Ensure there is a screenshot for it.
5084 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5085 if sha1_path not in new_or_added_paths and not \
5086 input_api.os_path.exists(sha1_path):
5087 # There is neither a previous screenshot nor is a new one added now.
5088 # Require a screenshot.
5089 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145090
Rainhard Findlingfc31844c52020-05-15 09:58:265091 if run_screenshot_check:
5092 # Check the screenshot directory for .png files. Warn if there is any.
5093 for png_path in affected_png_paths:
5094 if png_path.startswith(screenshots_dir):
5095 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145096
Rainhard Findlingfc31844c52020-05-15 09:58:265097 for added_id in added_ids:
5098 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145099
Rainhard Findlingfc31844c52020-05-15 09:58:265100 for modified_id in modified_ids:
5101 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145102
Rainhard Findlingfc31844c52020-05-15 09:58:265103 for removed_id in removed_ids:
5104 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5105
5106 # Check new and changed strings for ICU syntax errors.
5107 for key in added_ids.union(modified_ids):
5108 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5109 err = _ValidateIcuSyntax(msg, 0, [])
5110 if err is not None:
5111 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145112
5113 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265114 if run_screenshot_check:
5115 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005116 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265117 'Do not include actual screenshots in the changelist. Run '
5118 'tools/translate/upload_screenshots.py to upload them instead:',
5119 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145120
Rainhard Findlingfc31844c52020-05-15 09:58:265121 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005122 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265123 'You are adding or modifying UI strings.\n'
5124 'To ensure the best translations, take screenshots of the relevant UI '
5125 '(https://g.co/chrome/translation) and add these files to your '
5126 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145127
Rainhard Findlingfc31844c52020-05-15 09:58:265128 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005129 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265130 'You removed strings associated with these files. Remove:',
5131 sorted(unnecessary_sha1_files)))
5132 else:
5133 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5134 'screenshots check.'))
5135
5136 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075137 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265138 'ICU syntax errors were found in the following strings (problems or '
5139 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145140
5141 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125142
5143
Saagar Sanghavifceeaae2020-08-12 16:40:365144def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125145 repo_root=None,
5146 translation_expectations_path=None,
5147 grd_files=None):
5148 import sys
5149 affected_grds = [f for f in input_api.AffectedFiles()
5150 if (f.LocalPath().endswith('.grd') or
5151 f.LocalPath().endswith('.grdp'))]
5152 if not affected_grds:
5153 return []
5154
5155 try:
5156 old_sys_path = sys.path
5157 sys.path = sys.path + [
5158 input_api.os_path.join(
5159 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5160 from helper import git_helper
5161 from helper import translation_helper
5162 finally:
5163 sys.path = old_sys_path
5164
5165 # Check that translation expectations can be parsed and we can get a list of
5166 # translatable grd files. |repo_root| and |translation_expectations_path| are
5167 # only passed by tests.
5168 if not repo_root:
5169 repo_root = input_api.PresubmitLocalPath()
5170 if not translation_expectations_path:
5171 translation_expectations_path = input_api.os_path.join(
5172 repo_root, 'tools', 'gritsettings',
5173 'translation_expectations.pyl')
5174 if not grd_files:
5175 grd_files = git_helper.list_grds_in_repository(repo_root)
5176
dpapad8e21b472020-10-23 17:15:035177 # Ignore bogus grd files used only for testing
5178 # ui/webui/resoucres/tools/generate_grd.py.
5179 ignore_path = input_api.os_path.join(
5180 'ui', 'webui', 'resources', 'tools', 'tests')
5181 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5182
Mustafa Emre Acer51f2f742020-03-09 19:41:125183 try:
5184 translation_helper.get_translatable_grds(repo_root, grd_files,
5185 translation_expectations_path)
5186 except Exception as e:
5187 return [output_api.PresubmitNotifyResult(
5188 'Failed to get a list of translatable grd files. This happens when:\n'
5189 ' - One of the modified grd or grdp files cannot be parsed or\n'
5190 ' - %s is not updated.\n'
5191 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5192 return []
Ken Rockotc31f4832020-05-29 18:58:515193
5194
Saagar Sanghavifceeaae2020-08-12 16:40:365195def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515196 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095197 changed_mojoms = input_api.AffectedFiles(
5198 include_deletes=True,
5199 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515200 delta = []
5201 for mojom in changed_mojoms:
5202 old_contents = ''.join(mojom.OldContents()) or None
5203 new_contents = ''.join(mojom.NewContents()) or None
5204 delta.append({
5205 'filename': mojom.LocalPath(),
5206 'old': '\n'.join(mojom.OldContents()) or None,
5207 'new': '\n'.join(mojom.NewContents()) or None,
5208 })
5209
5210 process = input_api.subprocess.Popen(
5211 [input_api.python_executable,
5212 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5213 'public', 'tools', 'mojom',
5214 'check_stable_mojom_compatibility.py'),
5215 '--src-root', input_api.PresubmitLocalPath()],
5216 stdin=input_api.subprocess.PIPE,
5217 stdout=input_api.subprocess.PIPE,
5218 stderr=input_api.subprocess.PIPE,
5219 universal_newlines=True)
5220 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5221 if process.returncode:
5222 return [output_api.PresubmitError(
5223 'One or more [Stable] mojom definitions appears to have been changed '
5224 'in a way that is not backward-compatible.',
5225 long_text=error)]
5226 return []
Dominic Battre645d42342020-12-04 16:14:105227
5228def CheckDeprecationOfPreferences(input_api, output_api):
5229 """Removing a preference should come with a deprecation."""
5230
5231 def FilterFile(affected_file):
5232 """Accept only .cc files and the like."""
5233 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5234 files_to_skip = (_EXCLUDED_PATHS +
5235 _TEST_CODE_EXCLUDED_PATHS +
5236 input_api.DEFAULT_FILES_TO_SKIP)
5237 return input_api.FilterSourceFile(
5238 affected_file,
5239 files_to_check=file_inclusion_pattern,
5240 files_to_skip=files_to_skip)
5241
5242 def ModifiedLines(affected_file):
5243 """Returns a list of tuples (line number, line text) of added and removed
5244 lines.
5245
5246 Deleted lines share the same line number as the previous line.
5247
5248 This relies on the scm diff output describing each changed code section
5249 with a line of the form
5250
5251 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5252 """
5253 line_num = 0
5254 modified_lines = []
5255 for line in affected_file.GenerateScmDiff().splitlines():
5256 # Extract <new line num> of the patch fragment (see format above).
5257 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5258 if m:
5259 line_num = int(m.groups(1)[0])
5260 continue
5261 if ((line.startswith('+') and not line.startswith('++')) or
5262 (line.startswith('-') and not line.startswith('--'))):
5263 modified_lines.append((line_num, line))
5264
5265 if not line.startswith('-'):
5266 line_num += 1
5267 return modified_lines
5268
5269 def FindLineWith(lines, needle):
5270 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5271
5272 If 0 or >1 lines contain `needle`, -1 is returned.
5273 """
5274 matching_line_numbers = [
5275 # + 1 for 1-based counting of line numbers.
5276 i + 1 for i, line
5277 in enumerate(lines)
5278 if needle in line]
5279 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5280
5281 def ModifiedPrefMigration(affected_file):
5282 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5283 # Determine first and last lines of MigrateObsolete.*Pref functions.
5284 new_contents = affected_file.NewContents();
5285 range_1 = (
5286 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5287 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5288 range_2 = (
5289 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5290 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5291 if (-1 in range_1 + range_2):
5292 raise Exception(
5293 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5294
5295 # Check whether any of the modified lines are part of the
5296 # MigrateObsolete.*Pref functions.
5297 for line_nr, line in ModifiedLines(affected_file):
5298 if (range_1[0] <= line_nr <= range_1[1] or
5299 range_2[0] <= line_nr <= range_2[1]):
5300 return True
5301 return False
5302
5303 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5304 browser_prefs_file_pattern = input_api.re.compile(
5305 r'chrome/browser/prefs/browser_prefs.cc')
5306
5307 changes = input_api.AffectedFiles(include_deletes=True,
5308 file_filter=FilterFile)
5309 potential_problems = []
5310 for f in changes:
5311 for line in f.GenerateScmDiff().splitlines():
5312 # Check deleted lines for pref registrations.
5313 if (line.startswith('-') and not line.startswith('--') and
5314 register_pref_pattern.search(line)):
5315 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5316
5317 if browser_prefs_file_pattern.search(f.LocalPath()):
5318 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5319 # assume that they knew that they have to deprecate preferences and don't
5320 # warn.
5321 try:
5322 if ModifiedPrefMigration(f):
5323 return []
5324 except Exception as e:
5325 return [output_api.PresubmitError(str(e))]
5326
5327 if potential_problems:
5328 return [output_api.PresubmitPromptWarning(
5329 'Discovered possible removal of preference registrations.\n\n'
5330 'Please make sure to properly deprecate preferences by clearing their\n'
5331 'value for a couple of milestones before finally removing the code.\n'
5332 'Otherwise data may stay in the preferences files forever. See\n'
5333 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5334 'This may be a false positive warning (e.g. if you move preference\n'
5335 'registrations to a different place).\n',
5336 potential_problems
5337 )]
5338 return []