blob: 11026618fb5e23e8dc22cf95fc68729eb5b6ea30 [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/thumbnail/cc/',
Alexander Cooper6b447b22020-07-22 00:47:18366 '^chrome/browser/translate/',
367 '^chrome/browser/ui/',
Alexander Cooper6b447b22020-07-22 00:47:18368 '^chrome/browser/web_applications/',
369 '^chrome/browser/win/',
Alex Turner1dc2e1022020-10-22 16:31:54370 '^chrome/test/chromedriver/server/http_handler.cc',
danakj7a2b7082019-05-21 21:13:51371 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51372 '^components/drive/',
danakj7a2b7082019-05-21 21:13:51373 '^components/search_engines/',
danakj7a2b7082019-05-21 21:13:51374 '^components/webcrypto/',
Alan Cutter04a00642020-03-02 01:45:20375 '^extensions/browser/',
376 '^extensions/renderer/',
David Bienvenu0cf6ec02020-12-04 21:03:21377 '^media/blink/',
Daniel Hosseinian41af1882020-10-29 23:10:10378 '^media/cdm/',
Steve Kobes334b6ed2020-07-09 07:26:31379 '^net/http/',
380 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51381 '^ppapi/proxy/',
danakj7a2b7082019-05-21 21:13:51382 '^services/',
danakj7a2b7082019-05-21 21:13:51383 '^tools/clang/base_bind_rewriters/', # Intentional.
384 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51385))
[email protected]127f18ec2012-06-16 05:05:59386
Daniel Bratell609102be2019-03-27 20:53:21387# Format: Sequence of tuples containing:
388# * String pattern or, if starting with a slash, a regular expression.
389# * Sequence of strings to show when the pattern matches.
390# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
391# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59392_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20393 (
Dave Tapuska98199b612019-07-10 13:30:44394 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53395 (
396 'New code should not use NULL. Use nullptr instead.',
397 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20398 False,
thomasandersone7caaa9b2017-03-29 19:22:53399 (),
400 ),
Peter Kasting94a56c42019-10-25 21:54:04401 (
402 r'/\busing namespace ',
403 (
404 'Using directives ("using namespace x") are banned by the Google Style',
405 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
406 'Explicitly qualify symbols or use using declarations ("using x::foo").',
407 ),
408 True,
409 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
410 ),
Antonio Gomes07300d02019-03-13 20:59:57411 # Make sure that gtest's FRIEND_TEST() macro is not used; the
412 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
413 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53414 (
[email protected]23e6cbc2012-06-16 18:51:20415 'FRIEND_TEST(',
416 (
[email protected]e3c945502012-06-26 20:01:49417 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20418 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
419 ),
420 False,
[email protected]7345da02012-11-27 14:31:49421 (),
[email protected]23e6cbc2012-06-16 18:51:20422 ),
423 (
tomhudsone2c14d552016-05-26 17:07:46424 'setMatrixClip',
425 (
426 'Overriding setMatrixClip() is prohibited; ',
427 'the base function is deprecated. ',
428 ),
429 True,
430 (),
431 ),
432 (
[email protected]52657f62013-05-20 05:30:31433 'SkRefPtr',
434 (
435 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22436 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31437 ),
438 True,
439 (),
440 ),
441 (
442 'SkAutoRef',
443 (
444 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22445 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31446 ),
447 True,
448 (),
449 ),
450 (
451 'SkAutoTUnref',
452 (
453 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22454 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31455 ),
456 True,
457 (),
458 ),
459 (
460 'SkAutoUnref',
461 (
462 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
463 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22464 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31465 ),
466 True,
467 (),
468 ),
[email protected]d89eec82013-12-03 14:10:59469 (
470 r'/HANDLE_EINTR\(.*close',
471 (
472 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
473 'descriptor will be closed, and it is incorrect to retry the close.',
474 'Either call close directly and ignore its return value, or wrap close',
475 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
476 ),
477 True,
478 (),
479 ),
480 (
481 r'/IGNORE_EINTR\((?!.*close)',
482 (
483 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
484 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
485 ),
486 True,
487 (
488 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04489 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
490 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59491 ),
492 ),
[email protected]ec5b3f02014-04-04 18:43:43493 (
494 r'/v8::Extension\(',
495 (
496 'Do not introduce new v8::Extensions into the code base, use',
497 'gin::Wrappable instead. See http://crbug.com/334679',
498 ),
499 True,
[email protected]f55c90ee62014-04-12 00:50:03500 (
Egor Paskoce145c42018-09-28 19:31:04501 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03502 ),
[email protected]ec5b3f02014-04-04 18:43:43503 ),
skyostilf9469f72015-04-20 10:38:52504 (
jame2d1a952016-04-02 00:27:10505 '#pragma comment(lib,',
506 (
507 'Specify libraries to link with in build files and not in the source.',
508 ),
509 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41510 (
tzik3f295992018-12-04 20:32:23511 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04512 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41513 ),
jame2d1a952016-04-02 00:27:10514 ),
fdorayc4ac18d2017-05-01 21:39:59515 (
Gabriel Charette7cc6c432018-04-25 20:52:02516 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59517 (
518 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
519 ),
520 False,
521 (),
522 ),
523 (
Gabriel Charette7cc6c432018-04-25 20:52:02524 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59525 (
526 'Consider using THREAD_CHECKER macros instead of the class directly.',
527 ),
528 False,
529 (),
530 ),
dbeamb6f4fde2017-06-15 04:03:06531 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06532 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
533 (
534 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
535 'deprecated (http://crbug.com/634507). Please avoid converting away',
536 'from the Time types in Chromium code, especially if any math is',
537 'being done on time values. For interfacing with platform/library',
538 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
539 'type converter methods instead. For faking TimeXXX values (for unit',
540 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
541 'other use cases, please contact base/time/OWNERS.',
542 ),
543 False,
544 (),
545 ),
546 (
dbeamb6f4fde2017-06-15 04:03:06547 'CallJavascriptFunctionUnsafe',
548 (
549 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
550 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
551 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
552 ),
553 False,
554 (
Egor Paskoce145c42018-09-28 19:31:04555 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
556 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
557 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06558 ),
559 ),
dskiba1474c2bfd62017-07-20 02:19:24560 (
561 'leveldb::DB::Open',
562 (
563 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
564 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
565 "Chrome's tracing, making their memory usage visible.",
566 ),
567 True,
568 (
569 r'^third_party/leveldatabase/.*\.(cc|h)$',
570 ),
Gabriel Charette0592c3a2017-07-26 12:02:04571 ),
572 (
Chris Mumfordc38afb62017-10-09 17:55:08573 'leveldb::NewMemEnv',
574 (
575 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58576 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
577 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08578 ),
579 True,
580 (
581 r'^third_party/leveldatabase/.*\.(cc|h)$',
582 ),
583 ),
584 (
Gabriel Charetted9839bc2017-07-29 14:17:47585 'RunLoop::QuitCurrent',
586 (
Robert Liao64b7ab22017-08-04 23:03:43587 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
588 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47589 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41590 False,
Gabriel Charetted9839bc2017-07-29 14:17:47591 (),
Gabriel Charettea44975052017-08-21 23:14:04592 ),
593 (
594 'base::ScopedMockTimeMessageLoopTaskRunner',
595 (
Gabriel Charette87cc1af2018-04-25 20:52:51596 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11597 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51598 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
599 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
600 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04601 ),
Gabriel Charette87cc1af2018-04-25 20:52:51602 False,
Gabriel Charettea44975052017-08-21 23:14:04603 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57604 ),
605 (
Dave Tapuska98199b612019-07-10 13:30:44606 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57607 (
608 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02609 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57610 ),
611 True,
612 (),
Francois Doray43670e32017-09-27 12:40:38613 ),
614 (
Peter Kasting991618a62019-06-17 22:00:09615 r'/\bstd::stoi\b',
616 (
617 'std::stoi uses exceptions to communicate results. ',
618 'Use base::StringToInt() instead.',
619 ),
620 True,
621 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
622 ),
623 (
624 r'/\bstd::stol\b',
625 (
626 'std::stol uses exceptions to communicate results. ',
627 'Use base::StringToInt() instead.',
628 ),
629 True,
630 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
631 ),
632 (
633 r'/\bstd::stoul\b',
634 (
635 'std::stoul uses exceptions to communicate results. ',
636 'Use base::StringToUint() instead.',
637 ),
638 True,
639 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
640 ),
641 (
642 r'/\bstd::stoll\b',
643 (
644 'std::stoll uses exceptions to communicate results. ',
645 'Use base::StringToInt64() instead.',
646 ),
647 True,
648 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
649 ),
650 (
651 r'/\bstd::stoull\b',
652 (
653 'std::stoull uses exceptions to communicate results. ',
654 'Use base::StringToUint64() instead.',
655 ),
656 True,
657 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
658 ),
659 (
660 r'/\bstd::stof\b',
661 (
662 'std::stof uses exceptions to communicate results. ',
663 'For locale-independent values, e.g. reading numbers from disk',
664 'profiles, use base::StringToDouble().',
665 'For user-visible values, parse using ICU.',
666 ),
667 True,
668 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
669 ),
670 (
671 r'/\bstd::stod\b',
672 (
673 'std::stod uses exceptions to communicate results. ',
674 'For locale-independent values, e.g. reading numbers from disk',
675 'profiles, use base::StringToDouble().',
676 'For user-visible values, parse using ICU.',
677 ),
678 True,
679 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
680 ),
681 (
682 r'/\bstd::stold\b',
683 (
684 'std::stold uses exceptions to communicate results. ',
685 'For locale-independent values, e.g. reading numbers from disk',
686 'profiles, use base::StringToDouble().',
687 'For user-visible values, parse using ICU.',
688 ),
689 True,
690 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
691 ),
692 (
Daniel Bratell69334cc2019-03-26 11:07:45693 r'/\bstd::to_string\b',
694 (
695 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09696 'For locale-independent strings, e.g. writing numbers to disk',
697 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45698 'For user-visible strings, use base::FormatNumber() and',
699 'the related functions in base/i18n/number_formatting.h.',
700 ),
Peter Kasting991618a62019-06-17 22:00:09701 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21702 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45703 ),
704 (
705 r'/\bstd::shared_ptr\b',
706 (
707 'std::shared_ptr should not be used. Use scoped_refptr instead.',
708 ),
709 True,
Alex Chau9eb03cdd52020-07-13 21:04:57710 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
711 'array_buffer_contents\.(cc|h)',
712 # Needed for interop with third-party library
713 'chrome/services/sharing/nearby/',
714 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21715 ),
716 (
Peter Kasting991618a62019-06-17 22:00:09717 r'/\bstd::weak_ptr\b',
718 (
719 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
720 ),
721 True,
722 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
723 ),
724 (
Daniel Bratell609102be2019-03-27 20:53:21725 r'/\blong long\b',
726 (
727 'long long is banned. Use stdint.h if you need a 64 bit number.',
728 ),
729 False, # Only a warning since it is already used.
730 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
731 ),
732 (
733 r'/\bstd::bind\b',
734 (
735 'std::bind is banned because of lifetime risks.',
736 'Use base::BindOnce or base::BindRepeating instead.',
737 ),
738 True,
739 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
740 ),
741 (
742 r'/\b#include <chrono>\b',
743 (
744 '<chrono> overlaps with Time APIs in base. Keep using',
745 'base classes.',
746 ),
747 True,
748 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
749 ),
750 (
751 r'/\b#include <exception>\b',
752 (
753 'Exceptions are banned and disabled in Chromium.',
754 ),
755 True,
756 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
757 ),
758 (
759 r'/\bstd::function\b',
760 (
761 'std::function is banned. Instead use base::Callback which directly',
762 'supports Chromium\'s weak pointers, ref counting and more.',
763 ),
Peter Kasting991618a62019-06-17 22:00:09764 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21765 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
766 ),
767 (
768 r'/\b#include <random>\b',
769 (
770 'Do not use any random number engines from <random>. Instead',
771 'use base::RandomBitGenerator.',
772 ),
773 True,
774 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
775 ),
776 (
Tom Andersona95e12042020-09-09 23:08:00777 r'/\b#include <X11/',
778 (
779 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
780 ),
781 True,
782 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
783 ),
784 (
Daniel Bratell609102be2019-03-27 20:53:21785 r'/\bstd::ratio\b',
786 (
787 'std::ratio is banned by the Google Style Guide.',
788 ),
789 True,
790 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45791 ),
792 (
Francois Doray43670e32017-09-27 12:40:38793 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
794 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
795 (
796 'Use the new API in base/threading/thread_restrictions.h.',
797 ),
Gabriel Charette04b138f2018-08-06 00:03:22798 False,
Francois Doray43670e32017-09-27 12:40:38799 (),
800 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38801 (
danakj7a2b7082019-05-21 21:13:51802 r'/\bbase::Bind\(',
803 (
804 'Please use base::Bind{Once,Repeating} instead',
805 'of base::Bind. (crbug.com/714018)',
806 ),
807 False,
Erik Staaba737d7602019-11-25 18:41:07808 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51809 ),
810 (
811 r'/\bbase::Callback[<:]',
812 (
813 'Please use base::{Once,Repeating}Callback instead',
814 'of base::Callback. (crbug.com/714018)',
815 ),
816 False,
Erik Staaba737d7602019-11-25 18:41:07817 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51818 ),
819 (
820 r'/\bbase::Closure\b',
821 (
822 'Please use base::{Once,Repeating}Closure instead',
823 'of base::Closure. (crbug.com/714018)',
824 ),
825 False,
Erik Staaba737d7602019-11-25 18:41:07826 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51827 ),
828 (
Alex Turnerb3ea38c2020-11-25 18:03:07829 r'/\bbase::CancelableCallback[<:]',
830 (
831 'Please use base::Cancelable{Once,Repeating}Callback instead',
832 'of base::CancelableCallback. (crbug.com/714018)',
833 ),
834 False,
835 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
836 ),
837 (
838 r'/\bbase::CancelableClosure\b',
839 (
840 'Please use base::Cancelable{Once,Repeating}Closure instead',
841 'of base::CancelableClosure. (crbug.com/714018)',
842 ),
843 False,
844 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
845 ),
846 (
Michael Giuffrida7f93d6922019-04-19 14:39:58847 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19848 (
849 'RunMessageLoop is deprecated, use RunLoop instead.',
850 ),
851 False,
852 (),
853 ),
854 (
Dave Tapuska98199b612019-07-10 13:30:44855 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19856 (
857 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
858 ),
859 False,
860 (),
861 ),
862 (
Dave Tapuska98199b612019-07-10 13:30:44863 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19864 (
865 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
866 "if you're convinced you need this.",
867 ),
868 False,
869 (),
870 ),
871 (
Dave Tapuska98199b612019-07-10 13:30:44872 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19873 (
874 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04875 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19876 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
877 'async events instead of flushing threads.',
878 ),
879 False,
880 (),
881 ),
882 (
883 r'MessageLoopRunner',
884 (
885 'MessageLoopRunner is deprecated, use RunLoop instead.',
886 ),
887 False,
888 (),
889 ),
890 (
Dave Tapuska98199b612019-07-10 13:30:44891 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19892 (
893 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
894 "gab@ if you found a use case where this is the only solution.",
895 ),
896 False,
897 (),
898 ),
899 (
Victor Costane48a2e82019-03-15 22:02:34900 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16901 (
Victor Costane48a2e82019-03-15 22:02:34902 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16903 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
904 ),
905 True,
906 (
907 r'^sql/initialization\.(cc|h)$',
908 r'^third_party/sqlite/.*\.(c|cc|h)$',
909 ),
910 ),
Matt Menke7f520a82018-03-28 21:38:37911 (
Dave Tapuska98199b612019-07-10 13:30:44912 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47913 (
914 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
915 'base::RandomShuffle instead.'
916 ),
917 True,
918 (),
919 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24920 (
921 'ios/web/public/test/http_server',
922 (
923 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
924 ),
925 False,
926 (),
927 ),
Robert Liao764c9492019-01-24 18:46:28928 (
929 'GetAddressOf',
930 (
931 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53932 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11933 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53934 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28935 ),
936 True,
937 (),
938 ),
Antonio Gomes07300d02019-03-13 20:59:57939 (
940 'DEFINE_TYPE_CASTS',
941 (
942 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
943 '//third_party/blink/renderer/platform/casting.h.'
944 ),
945 True,
946 (
947 r'^third_party/blink/renderer/.*\.(cc|h)$',
948 ),
949 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38950 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45951 r'/\bIsHTML.+Element\(\b',
952 (
953 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
954 ' helpers IsA<HTMLXXXXElement> from ',
955 '//third_party/blink/renderer/platform/casting.h.'
956 ),
957 False,
958 (
959 r'^third_party/blink/renderer/.*\.(cc|h)$',
960 ),
961 ),
962 (
963 r'/\bToHTML.+Element(|OrNull)\(\b',
964 (
965 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
966 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
967 'and DynamicTo<HTMLXXXXElement> from ',
968 '//third_party/blink/renderer/platform/casting.h.'
969 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
970 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
971 ),
972 False,
973 (
974 r'^third_party/blink/renderer/.*\.(cc|h)$',
975 ),
976 ),
977 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37978 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38979 (
980 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
981 ),
982 True,
983 (),
984 ),
Ben Lewisa9514602019-04-29 17:53:05985 (
986 'SHFileOperation',
987 (
988 'SHFileOperation was deprecated in Windows Vista, and there are less ',
989 'complex functions to achieve the same goals. Use IFileOperation for ',
990 'any esoteric actions instead.'
991 ),
992 True,
993 (),
994 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18995 (
Cliff Smolinsky81951642019-04-30 21:39:51996 'StringFromGUID2',
997 (
998 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24999 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511000 ),
1001 True,
1002 (
1003 r'/base/win/win_util_unittest.cc'
1004 ),
1005 ),
1006 (
1007 'StringFromCLSID',
1008 (
1009 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241010 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511011 ),
1012 True,
1013 (
1014 r'/base/win/win_util_unittest.cc'
1015 ),
1016 ),
1017 (
Avi Drissman7382afa02019-04-29 23:27:131018 'kCFAllocatorNull',
1019 (
1020 'The use of kCFAllocatorNull with the NoCopy creation of ',
1021 'CoreFoundation types is prohibited.',
1022 ),
1023 True,
1024 (),
1025 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291026 (
1027 'mojo::ConvertTo',
1028 (
1029 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1030 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1031 'StringTraits if you would like to convert between custom types and',
1032 'the wire format of mojom types.'
1033 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221034 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291035 (
Wezf89dec092019-09-11 19:38:331036 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1037 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291038 r'^third_party/blink/.*\.(cc|h)$',
1039 r'^content/renderer/.*\.(cc|h)$',
1040 ),
1041 ),
Robert Liao1d78df52019-11-11 20:02:011042 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161043 'GetInterfaceProvider',
1044 (
1045 'InterfaceProvider is deprecated.',
1046 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1047 'or Platform::GetBrowserInterfaceBroker.'
1048 ),
1049 False,
1050 (),
1051 ),
1052 (
Robert Liao1d78df52019-11-11 20:02:011053 'CComPtr',
1054 (
1055 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1056 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1057 'details.'
1058 ),
1059 False,
1060 (),
1061 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201062 (
1063 r'/\b(IFACE|STD)METHOD_?\(',
1064 (
1065 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1066 'Instead, always use IFACEMETHODIMP in the declaration.'
1067 ),
1068 False,
1069 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1070 ),
Allen Bauer53b43fb12020-03-12 17:21:471071 (
1072 'set_owned_by_client',
1073 (
1074 'set_owned_by_client is deprecated.',
1075 'views::View already owns the child views by default. This introduces ',
1076 'a competing ownership model which makes the code difficult to reason ',
1077 'about. See http://crbug.com/1044687 for more details.'
1078 ),
1079 False,
1080 (),
1081 ),
Eric Secklerbe6f48d2020-05-06 18:09:121082 (
1083 r'/\bTRACE_EVENT_ASYNC_',
1084 (
1085 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1086 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1087 ),
1088 False,
1089 (
1090 r'^base/trace_event/.*',
1091 r'^base/tracing/.*',
1092 ),
1093 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:261094 (
1095 r'/\bScopedObserver',
1096 (
1097 'ScopedObserver is deprecated.',
1098 'Please use base::ScopedObservation for observing a single source,',
1099 'or base::ScopedMultiSourceObservation for observing multple sources',
1100 ),
1101 False,
1102 (),
1103 ),
[email protected]127f18ec2012-06-16 05:05:591104)
1105
Mario Sanchez Prada2472cab2019-09-18 10:58:311106# Format: Sequence of tuples containing:
1107# * String pattern or, if starting with a slash, a regular expression.
1108# * Sequence of strings to show when the pattern matches.
1109_DEPRECATED_MOJO_TYPES = (
1110 (
1111 r'/\bmojo::AssociatedBinding\b',
1112 (
1113 'mojo::AssociatedBinding<Interface> is deprecated.',
1114 'Use mojo::AssociatedReceiver<Interface> instead.',
1115 ),
1116 ),
1117 (
1118 r'/\bmojo::AssociatedBindingSet\b',
1119 (
1120 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1121 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1122 ),
1123 ),
1124 (
1125 r'/\bmojo::AssociatedInterfacePtr\b',
1126 (
1127 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1128 'Use mojo::AssociatedRemote<Interface> instead.',
1129 ),
1130 ),
1131 (
1132 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1133 (
1134 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1135 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1136 ),
1137 ),
1138 (
1139 r'/\bmojo::AssociatedInterfaceRequest\b',
1140 (
1141 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1142 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1143 ),
1144 ),
1145 (
1146 r'/\bmojo::Binding\b',
1147 (
1148 'mojo::Binding<Interface> is deprecated.',
1149 'Use mojo::Receiver<Interface> instead.',
1150 ),
1151 ),
1152 (
1153 r'/\bmojo::BindingSet\b',
1154 (
1155 'mojo::BindingSet<Interface> is deprecated.',
1156 'Use mojo::ReceiverSet<Interface> instead.',
1157 ),
1158 ),
1159 (
1160 r'/\bmojo::InterfacePtr\b',
1161 (
1162 'mojo::InterfacePtr<Interface> is deprecated.',
1163 'Use mojo::Remote<Interface> instead.',
1164 ),
1165 ),
1166 (
1167 r'/\bmojo::InterfacePtrInfo\b',
1168 (
1169 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1170 'Use mojo::PendingRemote<Interface> instead.',
1171 ),
1172 ),
1173 (
1174 r'/\bmojo::InterfaceRequest\b',
1175 (
1176 'mojo::InterfaceRequest<Interface> is deprecated.',
1177 'Use mojo::PendingReceiver<Interface> instead.',
1178 ),
1179 ),
1180 (
1181 r'/\bmojo::MakeRequest\b',
1182 (
1183 'mojo::MakeRequest is deprecated.',
1184 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1185 ),
1186 ),
1187 (
1188 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1189 (
1190 'mojo::MakeRequest is deprecated.',
1191 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181192 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311193 ),
1194 ),
1195 (
1196 r'/\bmojo::MakeStrongBinding\b',
1197 (
1198 'mojo::MakeStrongBinding is deprecated.',
1199 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1200 'mojo::MakeSelfOwnedReceiver() instead.',
1201 ),
1202 ),
1203 (
1204 r'/\bmojo::MakeStrongAssociatedBinding\b',
1205 (
1206 'mojo::MakeStrongAssociatedBinding is deprecated.',
1207 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1208 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1209 ),
1210 ),
1211 (
Gyuyoung Kim4952ba62020-07-07 07:33:441212 r'/\bmojo::StrongAssociatedBinding\b',
1213 (
1214 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1215 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1216 ),
1217 ),
1218 (
1219 r'/\bmojo::StrongBinding\b',
1220 (
1221 'mojo::StrongBinding<Interface> is deprecated.',
1222 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1223 ),
1224 ),
1225 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311226 r'/\bmojo::StrongAssociatedBindingSet\b',
1227 (
1228 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1229 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1230 ),
1231 ),
1232 (
1233 r'/\bmojo::StrongBindingSet\b',
1234 (
1235 'mojo::StrongBindingSet<Interface> is deprecated.',
1236 'Use mojo::UniqueReceiverSet<Interface> instead.',
1237 ),
1238 ),
1239)
wnwenbdc444e2016-05-25 13:44:151240
mlamouria82272622014-09-16 18:45:041241_IPC_ENUM_TRAITS_DEPRECATED = (
1242 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501243 'See http://www.chromium.org/Home/chromium-security/education/'
1244 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041245
Stephen Martinis97a394142018-06-07 23:06:051246_LONG_PATH_ERROR = (
1247 'Some files included in this CL have file names that are too long (> 200'
1248 ' characters). If committed, these files will cause issues on Windows. See'
1249 ' https://crbug.com/612667 for more details.'
1250)
1251
Shenghua Zhangbfaa38b82017-11-16 21:58:021252_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041253 r".*[\\/]BuildHooksAndroidImpl\.java",
1254 r".*[\\/]LicenseContentProvider\.java",
1255 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281256 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021257]
[email protected]127f18ec2012-06-16 05:05:591258
Mohamed Heikald048240a2019-11-12 16:57:371259# List of image extensions that are used as resources in chromium.
1260_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1261
Sean Kau46e29bc2017-08-28 16:31:161262# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401263_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041264 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401265 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041266 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1267 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041268 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431269 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161270]
1271
1272
[email protected]b00342e7f2013-03-26 16:21:541273_VALID_OS_MACROS = (
1274 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081275 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541276 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441277 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121278 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541279 'OS_BSD',
1280 'OS_CAT', # For testing.
1281 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041282 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541283 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371284 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541285 'OS_IOS',
1286 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441287 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541288 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211289 'OS_NACL_NONSFI',
1290 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121291 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541292 'OS_OPENBSD',
1293 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371294 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541295 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541296 'OS_WIN',
1297)
1298
1299
Andrew Grieveb773bad2020-06-05 18:00:381300# These are not checked on the public chromium-presubmit trybot.
1301# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041302# checkouts.
agrievef32bcc72016-04-04 14:57:401303_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381304 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381305]
1306
1307
1308_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041309 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361310 'base/android/jni_generator/jni_generator.pydeps',
1311 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361312 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041313 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361314 'build/android/gyp/aar.pydeps',
1315 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271316 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361317 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381318 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361319 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021320 'build/android/gyp/bytecode_rewriter.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111321 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361322 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361323 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111325 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041326 'build/android/gyp/create_app_bundle_apks.pydeps',
1327 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361328 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121329 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221330 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001331 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361332 'build/android/gyp/desugar.pydeps',
1333 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421334 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041335 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361336 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361337 'build/android/gyp/filter_zip.pydeps',
1338 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361339 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361340 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581341 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361342 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141343 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261344 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011345 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041346 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361347 'build/android/gyp/lint.pydeps',
1348 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361349 'build/android/gyp/merge_manifest.pydeps',
1350 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221351 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361352 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461353 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241354 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361355 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461356 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561357 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361358 'build/android/incremental_install/generate_android_manifest.pydeps',
1359 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041360 'build/android/resource_sizes.pydeps',
1361 'build/android/test_runner.pydeps',
1362 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361363 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361364 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321365 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271366 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1367 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001368 'components/cronet/tools/generate_javadoc.pydeps',
1369 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381370 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001371 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381372 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041373 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181374 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041375 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421376 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1377 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131378 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061379 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221380 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401381]
1382
wnwenbdc444e2016-05-25 13:44:151383
agrievef32bcc72016-04-04 14:57:401384_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1385
1386
Eric Boren6fd2b932018-01-25 15:05:081387# Bypass the AUTHORS check for these accounts.
1388_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591389 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451390 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591391 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521392 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071393 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041394 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271395 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041396 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301397 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081398
1399
Daniel Bratell65b033262019-04-23 08:17:061400def _IsCPlusPlusFile(input_api, file_path):
1401 """Returns True if this file contains C++-like code (and not Python,
1402 Go, Java, MarkDown, ...)"""
1403
1404 ext = input_api.os_path.splitext(file_path)[1]
1405 # This list is compatible with CppChecker.IsCppFile but we should
1406 # consider adding ".c" to it. If we do that we can use this function
1407 # at more places in the code.
1408 return ext in (
1409 '.h',
1410 '.cc',
1411 '.cpp',
1412 '.m',
1413 '.mm',
1414 )
1415
1416def _IsCPlusPlusHeaderFile(input_api, file_path):
1417 return input_api.os_path.splitext(file_path)[1] == ".h"
1418
1419
1420def _IsJavaFile(input_api, file_path):
1421 return input_api.os_path.splitext(file_path)[1] == ".java"
1422
1423
1424def _IsProtoFile(input_api, file_path):
1425 return input_api.os_path.splitext(file_path)[1] == ".proto"
1426
Mohamed Heikal5e5b7922020-10-29 18:57:591427
1428def CheckNoUpstreamDepsOnClank(input_api, output_api):
1429 """Prevent additions of dependencies from the upstream repo on //clank."""
1430 # clank can depend on clank
1431 if input_api.change.RepositoryRoot().endswith('clank'):
1432 return []
1433 build_file_patterns = [
1434 r'(.+/)?BUILD\.gn',
1435 r'.+\.gni',
1436 ]
1437 excluded_files = [
1438 r'build[/\\]config[/\\]android[/\\]config\.gni'
1439 ]
1440 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1441
1442 error_message = 'Disallowed import on //clank in an upstream build file:'
1443
1444 def FilterFile(affected_file):
1445 return input_api.FilterSourceFile(
1446 affected_file,
1447 files_to_check=build_file_patterns,
1448 files_to_skip=excluded_files)
1449
1450 problems = []
1451 for f in input_api.AffectedSourceFiles(FilterFile):
1452 local_path = f.LocalPath()
1453 for line_number, line in f.ChangedContents():
1454 if (bad_pattern.search(line)):
1455 problems.append(
1456 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1457 if problems:
1458 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1459 else:
1460 return []
1461
1462
Saagar Sanghavifceeaae2020-08-12 16:40:361463def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191464 """Attempts to prevent use of functions intended only for testing in
1465 non-testing code. For now this is just a best-effort implementation
1466 that ignores header files and may have some false positives. A
1467 better implementation would probably need a proper C++ parser.
1468 """
1469 # We only scan .cc files and the like, as the declaration of
1470 # for-testing functions in header files are hard to distinguish from
1471 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491472 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191473
jochenc0d4808c2015-07-27 09:25:421474 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191475 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091476 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131477 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191478 exclusion_pattern = input_api.re.compile(
1479 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1480 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131481 # Avoid a false positive in this case, where the method name, the ::, and
1482 # the closing { are all on different lines due to line wrapping.
1483 # HelperClassForTesting::
1484 # HelperClassForTesting(
1485 # args)
1486 # : member(0) {}
1487 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191488
1489 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441490 files_to_skip = (_EXCLUDED_PATHS +
1491 _TEST_CODE_EXCLUDED_PATHS +
1492 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191493 return input_api.FilterSourceFile(
1494 affected_file,
James Cook24a504192020-07-23 00:08:441495 files_to_check=file_inclusion_pattern,
1496 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191497
1498 problems = []
1499 for f in input_api.AffectedSourceFiles(FilterFile):
1500 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131501 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241502 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031503 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461504 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131505 not exclusion_pattern.search(line) and
1506 not allowlist_pattern.search(line) and
1507 not in_method_defn):
[email protected]55459852011-08-10 15:17:191508 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031509 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131510 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191511
1512 if problems:
[email protected]f7051d52013-04-02 18:31:421513 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031514 else:
1515 return []
[email protected]55459852011-08-10 15:17:191516
1517
Saagar Sanghavifceeaae2020-08-12 16:40:361518def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231519 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591520 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231521 """
1522 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1523 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1524 name_pattern = r'ForTest(s|ing)?'
1525 # Describes an occurrence of "ForTest*" inside a // comment.
1526 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501527 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551528 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231529 # Catch calls.
1530 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1531 # Ignore definitions. (Comments are ignored separately.)
1532 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1533
1534 problems = []
1535 sources = lambda x: input_api.FilterSourceFile(
1536 x,
James Cook24a504192020-07-23 00:08:441537 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1538 + input_api.DEFAULT_FILES_TO_SKIP),
1539 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231540 )
1541 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1542 local_path = f.LocalPath()
1543 is_inside_javadoc = False
1544 for line_number, line in f.ChangedContents():
1545 if is_inside_javadoc and javadoc_end_re.search(line):
1546 is_inside_javadoc = False
1547 if not is_inside_javadoc and javadoc_start_re.search(line):
1548 is_inside_javadoc = True
1549 if is_inside_javadoc:
1550 continue
1551 if (inclusion_re.search(line) and
1552 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501553 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231554 not exclusion_re.search(line)):
1555 problems.append(
1556 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1557
1558 if problems:
1559 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1560 else:
1561 return []
1562
1563
Saagar Sanghavifceeaae2020-08-12 16:40:361564def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541565 """Checks to make sure no .h files include <iostream>."""
1566 files = []
1567 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1568 input_api.re.MULTILINE)
1569 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1570 if not f.LocalPath().endswith('.h'):
1571 continue
1572 contents = input_api.ReadFile(f)
1573 if pattern.search(contents):
1574 files.append(f)
1575
1576 if len(files):
yolandyandaabc6d2016-04-18 18:29:391577 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061578 'Do not #include <iostream> in header files, since it inserts static '
1579 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541580 '#include <ostream>. See http://crbug.com/94794',
1581 files) ]
1582 return []
1583
Danil Chapovalov3518f362018-08-11 16:13:431584def _CheckNoStrCatRedefines(input_api, output_api):
1585 """Checks no windows headers with StrCat redefined are included directly."""
1586 files = []
1587 pattern_deny = input_api.re.compile(
1588 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1589 input_api.re.MULTILINE)
1590 pattern_allow = input_api.re.compile(
1591 r'^#include\s"base/win/windows_defines.inc"',
1592 input_api.re.MULTILINE)
1593 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1594 contents = input_api.ReadFile(f)
1595 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1596 files.append(f.LocalPath())
1597
1598 if len(files):
1599 return [output_api.PresubmitError(
1600 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1601 'directly since they pollute code with StrCat macro. Instead, '
1602 'include matching header from base/win. See http://crbug.com/856536',
1603 files) ]
1604 return []
1605
[email protected]10689ca2011-09-02 02:31:541606
Saagar Sanghavifceeaae2020-08-12 16:40:361607def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521608 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181609 problems = []
1610 for f in input_api.AffectedFiles():
1611 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1612 continue
1613
1614 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041615 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181616 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1617
1618 if not problems:
1619 return []
1620 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1621 '\n'.join(problems))]
1622
Saagar Sanghavifceeaae2020-08-12 16:40:361623def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341624 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1625
1626 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1627 instead of DISABLED_. To filter false positives, reports are only generated
1628 if a corresponding MAYBE_ line exists.
1629 """
1630 problems = []
1631
1632 # The following two patterns are looked for in tandem - is a test labeled
1633 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1634 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1635 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1636
1637 # This is for the case that a test is disabled on all platforms.
1638 full_disable_pattern = input_api.re.compile(
1639 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1640 input_api.re.MULTILINE)
1641
Katie Df13948e2018-09-25 07:33:441642 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341643 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1644 continue
1645
1646 # Search for MABYE_, DISABLE_ pairs.
1647 disable_lines = {} # Maps of test name to line number.
1648 maybe_lines = {}
1649 for line_num, line in f.ChangedContents():
1650 disable_match = disable_pattern.search(line)
1651 if disable_match:
1652 disable_lines[disable_match.group(1)] = line_num
1653 maybe_match = maybe_pattern.search(line)
1654 if maybe_match:
1655 maybe_lines[maybe_match.group(1)] = line_num
1656
1657 # Search for DISABLE_ occurrences within a TEST() macro.
1658 disable_tests = set(disable_lines.keys())
1659 maybe_tests = set(maybe_lines.keys())
1660 for test in disable_tests.intersection(maybe_tests):
1661 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1662
1663 contents = input_api.ReadFile(f)
1664 full_disable_match = full_disable_pattern.search(contents)
1665 if full_disable_match:
1666 problems.append(' %s' % f.LocalPath())
1667
1668 if not problems:
1669 return []
1670 return [
1671 output_api.PresubmitPromptWarning(
1672 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1673 '\n'.join(problems))
1674 ]
1675
[email protected]72df4e782012-06-21 16:28:181676
Saagar Sanghavifceeaae2020-08-12 16:40:361677def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571678 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521679 errors = []
Hans Wennborg944479f2020-06-25 21:39:251680 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521681 input_api.re.MULTILINE)
1682 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1683 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1684 continue
1685 for lnum, line in f.ChangedContents():
1686 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171687 errors.append(output_api.PresubmitError(
1688 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571689 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171690 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521691 return errors
1692
1693
Weilun Shia487fad2020-10-28 00:10:341694# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1695# more reliable way. See
1696# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191697
wnwenbdc444e2016-05-25 13:44:151698
Saagar Sanghavifceeaae2020-08-12 16:40:361699def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391700 """Check that FlakyTest annotation is our own instead of the android one"""
1701 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1702 files = []
1703 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1704 if f.LocalPath().endswith('Test.java'):
1705 if pattern.search(input_api.ReadFile(f)):
1706 files.append(f)
1707 if len(files):
1708 return [output_api.PresubmitError(
1709 'Use org.chromium.base.test.util.FlakyTest instead of '
1710 'android.test.FlakyTest',
1711 files)]
1712 return []
mcasasb7440c282015-02-04 14:52:191713
wnwenbdc444e2016-05-25 13:44:151714
Saagar Sanghavifceeaae2020-08-12 16:40:361715def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221716 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271717 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221718 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201719 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571720 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341721 '/win/' in f.LocalPath() or
1722 'chrome_elf' in f.LocalPath() or
1723 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201724 continue
[email protected]8ea5d4b2011-09-13 21:49:221725
[email protected]a11dbe9b2012-08-07 01:32:581726 allowWString = False
[email protected]b5c24292011-11-28 14:38:201727 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581728 if 'presubmit: allow wstring' in line:
1729 allowWString = True
1730 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271731 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581732 allowWString = False
1733 else:
1734 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221735
[email protected]55463aa62011-10-12 00:48:271736 if not problems:
1737 return []
1738 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581739 ' If you are calling a cross-platform API that accepts a wstring, '
1740 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271741 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221742
1743
Saagar Sanghavifceeaae2020-08-12 16:40:361744def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441745 """Make sure .DEPS.git is never modified manually."""
1746 if any(f.LocalPath().endswith('.DEPS.git') for f in
1747 input_api.AffectedFiles()):
1748 return [output_api.PresubmitError(
1749 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1750 'automated system based on what\'s in DEPS and your changes will be\n'
1751 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501752 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1753 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441754 'for more information')]
1755 return []
1756
1757
Saagar Sanghavifceeaae2020-08-12 16:40:361758def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471759 """Checks that DEPS file deps are from allowed_hosts."""
1760 # Run only if DEPS file has been modified to annoy fewer bystanders.
1761 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1762 return []
1763 # Outsource work to gclient verify
1764 try:
John Budorickf20c0042019-04-25 23:23:401765 gclient_path = input_api.os_path.join(
1766 input_api.PresubmitLocalPath(),
1767 'third_party', 'depot_tools', 'gclient.py')
1768 input_api.subprocess.check_output(
1769 [input_api.python_executable, gclient_path, 'verify'],
1770 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471771 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201772 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471773 return [output_api.PresubmitError(
1774 'DEPS file must have only git dependencies.',
1775 long_text=error.output)]
1776
1777
Mario Sanchez Prada2472cab2019-09-18 10:58:311778def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1779 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591780 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311781
1782 Returns an string composed of the name of the file, the line number where the
1783 match has been found and the additional text passed as |message| in case the
1784 target type name matches the text inside the line passed as parameter.
1785 """
Peng Huang9c5949a02020-06-11 19:20:541786 result = []
1787
1788 if line.endswith(" nocheck"):
1789 return result
1790
Mario Sanchez Prada2472cab2019-09-18 10:58:311791 matched = False
1792 if type_name[0:1] == '/':
1793 regex = type_name[1:]
1794 if input_api.re.search(regex, line):
1795 matched = True
1796 elif type_name in line:
1797 matched = True
1798
Mario Sanchez Prada2472cab2019-09-18 10:58:311799 if matched:
1800 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1801 for message_line in message:
1802 result.append(' %s' % message_line)
1803
1804 return result
1805
1806
Saagar Sanghavifceeaae2020-08-12 16:40:361807def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591808 """Make sure that banned functions are not used."""
1809 warnings = []
1810 errors = []
1811
James Cook24a504192020-07-23 00:08:441812 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151813 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441814 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151815 if input_api.re.match(item, local_path):
1816 return True
1817 return False
1818
Peter K. Lee6c03ccff2019-07-15 14:40:051819 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541820 local_path = affected_file.LocalPath()
1821 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1822 return False
1823 basename = input_api.os_path.basename(local_path)
1824 if 'ios' in basename.split('_'):
1825 return True
1826 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1827 if sep and 'ios' in local_path.split(sep):
1828 return True
1829 return False
1830
wnwenbdc444e2016-05-25 13:44:151831 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311832 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1833 func_name, message)
1834 if problems:
wnwenbdc444e2016-05-25 13:44:151835 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311836 errors.extend(problems)
1837 else:
1838 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151839
Eric Stevensona9a980972017-09-23 00:04:411840 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1841 for f in input_api.AffectedFiles(file_filter=file_filter):
1842 for line_num, line in f.ChangedContents():
1843 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1844 CheckForMatch(f, line_num, line, func_name, message, error)
1845
[email protected]127f18ec2012-06-16 05:05:591846 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1847 for f in input_api.AffectedFiles(file_filter=file_filter):
1848 for line_num, line in f.ChangedContents():
1849 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151850 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591851
Peter K. Lee6c03ccff2019-07-15 14:40:051852 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541853 for line_num, line in f.ChangedContents():
1854 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1855 CheckForMatch(f, line_num, line, func_name, message, error)
1856
Peter K. Lee6c03ccff2019-07-15 14:40:051857 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1858 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1859 for line_num, line in f.ChangedContents():
1860 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1861 CheckForMatch(f, line_num, line, func_name, message, error)
1862
[email protected]127f18ec2012-06-16 05:05:591863 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1864 for f in input_api.AffectedFiles(file_filter=file_filter):
1865 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491866 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441867 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491868 continue
wnwenbdc444e2016-05-25 13:44:151869 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591870
1871 result = []
1872 if (warnings):
1873 result.append(output_api.PresubmitPromptWarning(
1874 'Banned functions were used.\n' + '\n'.join(warnings)))
1875 if (errors):
1876 result.append(output_api.PresubmitError(
1877 'Banned functions were used.\n' + '\n'.join(errors)))
1878 return result
1879
1880
Michael Thiessen44457642020-02-06 00:24:151881def _CheckAndroidNoBannedImports(input_api, output_api):
1882 """Make sure that banned java imports are not used."""
1883 errors = []
1884
1885 def IsException(path, exceptions):
1886 for exception in exceptions:
1887 if (path.startswith(exception)):
1888 return True
1889 return False
1890
1891 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1892 for f in input_api.AffectedFiles(file_filter=file_filter):
1893 for line_num, line in f.ChangedContents():
1894 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1895 if IsException(f.LocalPath(), exceptions):
1896 continue;
1897 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1898 'import ' + import_name, message)
1899 if problems:
1900 errors.extend(problems)
1901 result = []
1902 if (errors):
1903 result.append(output_api.PresubmitError(
1904 'Banned imports were used.\n' + '\n'.join(errors)))
1905 return result
1906
1907
Saagar Sanghavifceeaae2020-08-12 16:40:361908def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311909 """Make sure that old Mojo types are not used."""
1910 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571911 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311912
Mario Sanchez Pradaaab91382019-12-19 08:57:091913 # For any path that is not an "ok" or an "error" path, a warning will be
1914 # raised if deprecated mojo types are found.
1915 ok_paths = ['components/arc']
1916 error_paths = ['third_party/blink', 'content']
1917
Mario Sanchez Prada2472cab2019-09-18 10:58:311918 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1919 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571920 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091921 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311922 continue
1923
1924 for line_num, line in f.ChangedContents():
1925 for func_name, message in _DEPRECATED_MOJO_TYPES:
1926 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1927 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571928
Mario Sanchez Prada2472cab2019-09-18 10:58:311929 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091930 # Raise errors inside |error_paths| and warnings everywhere else.
1931 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571932 errors.extend(problems)
1933 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311934 warnings.extend(problems)
1935
1936 result = []
1937 if (warnings):
1938 result.append(output_api.PresubmitPromptWarning(
1939 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571940 if (errors):
1941 result.append(output_api.PresubmitError(
1942 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311943 return result
1944
1945
Saagar Sanghavifceeaae2020-08-12 16:40:361946def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061947 """Make sure that banned functions are not used."""
1948 files = []
1949 pattern = input_api.re.compile(r'^#pragma\s+once',
1950 input_api.re.MULTILINE)
1951 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1952 if not f.LocalPath().endswith('.h'):
1953 continue
1954 contents = input_api.ReadFile(f)
1955 if pattern.search(contents):
1956 files.append(f)
1957
1958 if files:
1959 return [output_api.PresubmitError(
1960 'Do not use #pragma once in header files.\n'
1961 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1962 files)]
1963 return []
1964
[email protected]127f18ec2012-06-16 05:05:591965
Saagar Sanghavifceeaae2020-08-12 16:40:361966def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121967 """Checks to make sure we don't introduce use of foo ? true : false."""
1968 problems = []
1969 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1970 for f in input_api.AffectedFiles():
1971 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1972 continue
1973
1974 for line_num, line in f.ChangedContents():
1975 if pattern.match(line):
1976 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1977
1978 if not problems:
1979 return []
1980 return [output_api.PresubmitPromptWarning(
1981 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1982 '\n'.join(problems))]
1983
1984
Saagar Sanghavifceeaae2020-08-12 16:40:361985def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281986 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181987 change. Breaking - rules is an error, breaking ! rules is a
1988 warning.
1989 """
mohan.reddyf21db962014-10-16 12:26:471990 import sys
[email protected]55f9f382012-07-31 11:02:181991 # We need to wait until we have an input_api object and use this
1992 # roundabout construct to import checkdeps because this file is
1993 # eval-ed and thus doesn't have __file__.
1994 original_sys_path = sys.path
1995 try:
1996 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471997 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181998 import checkdeps
[email protected]55f9f382012-07-31 11:02:181999 from rules import Rule
2000 finally:
2001 # Restore sys.path to what it was before.
2002 sys.path = original_sys_path
2003
2004 added_includes = []
rhalavati08acd232017-04-03 07:23:282005 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242006 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182007 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062008 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502009 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082010 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062011 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502012 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082013 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062014 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502015 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082016 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182017
[email protected]26385172013-05-09 23:11:352018 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182019
2020 error_descriptions = []
2021 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282022 error_subjects = set()
2023 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362024
[email protected]55f9f382012-07-31 11:02:182025 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2026 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082027 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182028 description_with_path = '%s\n %s' % (path, rule_description)
2029 if rule_type == Rule.DISALLOW:
2030 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282031 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182032 else:
2033 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282034 warning_subjects.add("#includes")
2035
2036 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2037 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082038 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282039 description_with_path = '%s\n %s' % (path, rule_description)
2040 if rule_type == Rule.DISALLOW:
2041 error_descriptions.append(description_with_path)
2042 error_subjects.add("imports")
2043 else:
2044 warning_descriptions.append(description_with_path)
2045 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182046
Jinsuk Kim5a092672017-10-24 22:42:242047 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022048 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082049 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242050 description_with_path = '%s\n %s' % (path, rule_description)
2051 if rule_type == Rule.DISALLOW:
2052 error_descriptions.append(description_with_path)
2053 error_subjects.add("imports")
2054 else:
2055 warning_descriptions.append(description_with_path)
2056 warning_subjects.add("imports")
2057
[email protected]55f9f382012-07-31 11:02:182058 results = []
2059 if error_descriptions:
2060 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282061 'You added one or more %s that violate checkdeps rules.'
2062 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182063 error_descriptions))
2064 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422065 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282066 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182067 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282068 '%s? See relevant DEPS file(s) for details and contacts.' %
2069 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182070 warning_descriptions))
2071 return results
2072
2073
Saagar Sanghavifceeaae2020-08-12 16:40:362074def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222075 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152076 if input_api.platform == 'win32':
2077 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292078 checkperms_tool = input_api.os_path.join(
2079 input_api.PresubmitLocalPath(),
2080 'tools', 'checkperms', 'checkperms.py')
2081 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472082 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392083 with input_api.CreateTemporaryFile() as file_list:
2084 for f in input_api.AffectedFiles():
2085 # checkperms.py file/directory arguments must be relative to the
2086 # repository.
2087 file_list.write(f.LocalPath() + '\n')
2088 file_list.close()
2089 args += ['--file-list', file_list.name]
2090 try:
2091 input_api.subprocess.check_output(args)
2092 return []
2093 except input_api.subprocess.CalledProcessError as error:
2094 return [output_api.PresubmitError(
2095 'checkperms.py failed:',
2096 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222097
2098
Saagar Sanghavifceeaae2020-08-12 16:40:362099def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492100 """Makes sure we don't include ui/aura/window_property.h
2101 in header files.
2102 """
2103 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2104 errors = []
2105 for f in input_api.AffectedFiles():
2106 if not f.LocalPath().endswith('.h'):
2107 continue
2108 for line_num, line in f.ChangedContents():
2109 if pattern.match(line):
2110 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2111
2112 results = []
2113 if errors:
2114 results.append(output_api.PresubmitError(
2115 'Header files should not include ui/aura/window_property.h', errors))
2116 return results
2117
2118
[email protected]70ca77752012-11-20 03:45:032119def _CheckForVersionControlConflictsInFile(input_api, f):
2120 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2121 errors = []
2122 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162123 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232124 # First-level headers in markdown look a lot like version control
2125 # conflict markers. http://daringfireball.net/projects/markdown/basics
2126 continue
[email protected]70ca77752012-11-20 03:45:032127 if pattern.match(line):
2128 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2129 return errors
2130
2131
Saagar Sanghavifceeaae2020-08-12 16:40:362132def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032133 """Usually this is not intentional and will cause a compile failure."""
2134 errors = []
2135 for f in input_api.AffectedFiles():
2136 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2137
2138 results = []
2139 if errors:
2140 results.append(output_api.PresubmitError(
2141 'Version control conflict markers found, please resolve.', errors))
2142 return results
2143
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202144
Saagar Sanghavifceeaae2020-08-12 16:40:362145def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162146 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2147 errors = []
2148 for f in input_api.AffectedFiles():
2149 for line_num, line in f.ChangedContents():
2150 if pattern.search(line):
2151 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2152
2153 results = []
2154 if errors:
2155 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502156 'Found Google support URL addressed by answer number. Please replace '
2157 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162158 return results
2159
[email protected]70ca77752012-11-20 03:45:032160
Saagar Sanghavifceeaae2020-08-12 16:40:362161def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442162 def FilterFile(affected_file):
2163 """Filter function for use with input_api.AffectedSourceFiles,
2164 below. This filters out everything except non-test files from
2165 top-level directories that generally speaking should not hard-code
2166 service URLs (e.g. src/android_webview/, src/content/ and others).
2167 """
2168 return input_api.FilterSourceFile(
2169 affected_file,
James Cook24a504192020-07-23 00:08:442170 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2171 files_to_skip=(_EXCLUDED_PATHS +
2172 _TEST_CODE_EXCLUDED_PATHS +
2173 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442174
reillyi38965732015-11-16 18:27:332175 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2176 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462177 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2178 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442179 problems = [] # items are (filename, line_number, line)
2180 for f in input_api.AffectedSourceFiles(FilterFile):
2181 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462182 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442183 problems.append((f.LocalPath(), line_num, line))
2184
2185 if problems:
[email protected]f7051d52013-04-02 18:31:422186 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442187 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582188 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442189 [' %s:%d: %s' % (
2190 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032191 else:
2192 return []
[email protected]06e6d0ff2012-12-11 01:36:442193
2194
Saagar Sanghavifceeaae2020-08-12 16:40:362195def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292196 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2197 def FileFilter(affected_file):
2198 """Includes directories known to be Chrome OS only."""
2199 return input_api.FilterSourceFile(
2200 affected_file,
James Cook24a504192020-07-23 00:08:442201 files_to_check=('^ash/',
2202 '^chromeos/', # Top-level src/chromeos.
2203 '/chromeos/', # Any path component.
2204 '^components/arc',
2205 '^components/exo'),
2206 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292207
2208 prefs = []
2209 priority_prefs = []
2210 for f in input_api.AffectedFiles(file_filter=FileFilter):
2211 for line_num, line in f.ChangedContents():
2212 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2213 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2214 prefs.append(' %s' % line)
2215 if input_api.re.search(
2216 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2217 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2218 priority_prefs.append(' %s' % line)
2219
2220 results = []
2221 if (prefs):
2222 results.append(output_api.PresubmitPromptWarning(
2223 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2224 'by browser sync settings. If these prefs should be controlled by OS '
2225 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2226 if (priority_prefs):
2227 results.append(output_api.PresubmitPromptWarning(
2228 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2229 'controlled by browser sync settings. If these prefs should be '
2230 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2231 'instead.\n' + '\n'.join(prefs)))
2232 return results
2233
2234
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492235# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362236def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272237 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312238 The native_client_sdk directory is excluded because it has auto-generated PNG
2239 files for documentation.
[email protected]d2530012013-01-25 16:39:272240 """
[email protected]d2530012013-01-25 16:39:272241 errors = []
James Cook24a504192020-07-23 00:08:442242 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2243 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312244 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442245 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312246 for f in input_api.AffectedFiles(include_deletes=False,
2247 file_filter=file_filter):
2248 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272249
2250 results = []
2251 if errors:
2252 results.append(output_api.PresubmitError(
2253 'The name of PNG files should not have abbreviations. \n'
2254 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2255 'Contact [email protected] if you have questions.', errors))
2256 return results
2257
2258
Daniel Cheng4dcdb6b2017-04-13 08:30:172259def _ExtractAddRulesFromParsedDeps(parsed_deps):
2260 """Extract the rules that add dependencies from a parsed DEPS file.
2261
2262 Args:
2263 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2264 add_rules = set()
2265 add_rules.update([
2266 rule[1:] for rule in parsed_deps.get('include_rules', [])
2267 if rule.startswith('+') or rule.startswith('!')
2268 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502269 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172270 {}).iteritems():
2271 add_rules.update([
2272 rule[1:] for rule in rules
2273 if rule.startswith('+') or rule.startswith('!')
2274 ])
2275 return add_rules
2276
2277
2278def _ParseDeps(contents):
2279 """Simple helper for parsing DEPS files."""
2280 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172281 class _VarImpl:
2282
2283 def __init__(self, local_scope):
2284 self._local_scope = local_scope
2285
2286 def Lookup(self, var_name):
2287 """Implements the Var syntax."""
2288 try:
2289 return self._local_scope['vars'][var_name]
2290 except KeyError:
2291 raise Exception('Var is not defined: %s' % var_name)
2292
2293 local_scope = {}
2294 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172295 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592296 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172297 }
2298 exec contents in global_scope, local_scope
2299 return local_scope
2300
2301
2302def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592303 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412304 a set of DEPS entries that we should look up.
2305
2306 For a directory (rather than a specific filename) we fake a path to
2307 a specific filename by adding /DEPS. This is chosen as a file that
2308 will seldom or never be subject to per-file include_rules.
2309 """
[email protected]2b438d62013-11-14 17:54:142310 # We ignore deps entries on auto-generated directories.
2311 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082312
Daniel Cheng4dcdb6b2017-04-13 08:30:172313 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2314 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2315
2316 added_deps = new_deps.difference(old_deps)
2317
[email protected]2b438d62013-11-14 17:54:142318 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172319 for added_dep in added_deps:
2320 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2321 continue
2322 # Assume that a rule that ends in .h is a rule for a specific file.
2323 if added_dep.endswith('.h'):
2324 results.add(added_dep)
2325 else:
2326 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082327 return results
2328
2329
Saagar Sanghavifceeaae2020-08-12 16:40:362330def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552331 """When a dependency prefixed with + is added to a DEPS file, we
2332 want to make sure that the change is reviewed by an OWNER of the
2333 target file or directory, to avoid layering violations from being
2334 introduced. This check verifies that this happens.
2335 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172336 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242337
2338 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492339 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242340 for f in input_api.AffectedFiles(include_deletes=False,
2341 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552342 filename = input_api.os_path.basename(f.LocalPath())
2343 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172344 virtual_depended_on_files.update(_CalculateAddedDeps(
2345 input_api.os_path,
2346 '\n'.join(f.OldContents()),
2347 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552348
[email protected]e871964c2013-05-13 14:14:552349 if not virtual_depended_on_files:
2350 return []
2351
2352 if input_api.is_committing:
2353 if input_api.tbr:
2354 return [output_api.PresubmitNotifyResult(
2355 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272356 if input_api.dry_run:
2357 return [output_api.PresubmitNotifyResult(
2358 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552359 if not input_api.change.issue:
2360 return [output_api.PresubmitError(
2361 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402362 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552363 output = output_api.PresubmitError
2364 else:
2365 output = output_api.PresubmitNotifyResult
2366
2367 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502368 owner_email, reviewers = (
2369 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2370 input_api,
2371 owners_db.email_regexp,
2372 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552373
2374 owner_email = owner_email or input_api.change.author_email
2375
[email protected]de4f7d22013-05-23 14:27:462376 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512377 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462378 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552379 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2380 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412381
2382 # We strip the /DEPS part that was added by
2383 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2384 # directory.
2385 def StripDeps(path):
2386 start_deps = path.rfind('/DEPS')
2387 if start_deps != -1:
2388 return path[:start_deps]
2389 else:
2390 return path
2391 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552392 for path in missing_files]
2393
2394 if unapproved_dependencies:
2395 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152396 output('You need LGTM from owners of depends-on paths in DEPS that were '
2397 'modified in this CL:\n %s' %
2398 '\n '.join(sorted(unapproved_dependencies)))]
2399 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2400 output_list.append(output(
2401 'Suggested missing target path OWNERS:\n %s' %
2402 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552403 return output_list
2404
2405 return []
2406
2407
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492408# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362409def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492410 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442411 files_to_skip = (_EXCLUDED_PATHS +
2412 _TEST_CODE_EXCLUDED_PATHS +
2413 input_api.DEFAULT_FILES_TO_SKIP +
2414 (r"^base[\\/]logging\.h$",
2415 r"^base[\\/]logging\.cc$",
2416 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2417 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2418 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2419 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2420 r"startup_browser_creator\.cc$",
2421 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2422 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2423 r"diagnostics_writer\.cc$",
2424 r"^chrome[\\/]chrome_cleaner[\\/].*",
2425 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2426 r"dll_hash_main\.cc$",
2427 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2428 r"^chromecast[\\/]",
2429 r"^cloud_print[\\/]",
2430 r"^components[\\/]browser_watcher[\\/]"
2431 r"dump_stability_report_main_win.cc$",
2432 r"^components[\\/]media_control[\\/]renderer[\\/]"
2433 r"media_playback_options\.cc$",
2434 r"^components[\\/]zucchini[\\/].*",
2435 # TODO(peter): Remove exception. https://crbug.com/534537
2436 r"^content[\\/]browser[\\/]notifications[\\/]"
2437 r"notification_event_dispatcher_impl\.cc$",
2438 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2439 r"gl_helper_benchmark\.cc$",
2440 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2441 r"^courgette[\\/]courgette_tool\.cc$",
2442 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2443 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2444 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2445 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2446 r"^ipc[\\/]ipc_logging\.cc$",
2447 r"^native_client_sdk[\\/]",
2448 r"^remoting[\\/]base[\\/]logging\.h$",
2449 r"^remoting[\\/]host[\\/].*",
2450 r"^sandbox[\\/]linux[\\/].*",
2451 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2452 r"dump_file_system.cc$",
2453 r"^tools[\\/]",
2454 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2455 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2456 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2457 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2458 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402459 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442460 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402461
thomasanderson625d3932017-03-29 07:16:582462 log_info = set([])
2463 printf = set([])
[email protected]85218562013-11-22 07:41:402464
2465 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582466 for _, line in f.ChangedContents():
2467 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2468 log_info.add(f.LocalPath())
2469 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2470 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372471
thomasanderson625d3932017-03-29 07:16:582472 if input_api.re.search(r"\bprintf\(", line):
2473 printf.add(f.LocalPath())
2474 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2475 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402476
2477 if log_info:
2478 return [output_api.PresubmitError(
2479 'These files spam the console log with LOG(INFO):',
2480 items=log_info)]
2481 if printf:
2482 return [output_api.PresubmitError(
2483 'These files spam the console log with printf/fprintf:',
2484 items=printf)]
2485 return []
2486
2487
Saagar Sanghavifceeaae2020-08-12 16:40:362488def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162489 """These types are all expected to hold locks while in scope and
2490 so should never be anonymous (which causes them to be immediately
2491 destroyed)."""
2492 they_who_must_be_named = [
2493 'base::AutoLock',
2494 'base::AutoReset',
2495 'base::AutoUnlock',
2496 'SkAutoAlphaRestore',
2497 'SkAutoBitmapShaderInstall',
2498 'SkAutoBlitterChoose',
2499 'SkAutoBounderCommit',
2500 'SkAutoCallProc',
2501 'SkAutoCanvasRestore',
2502 'SkAutoCommentBlock',
2503 'SkAutoDescriptor',
2504 'SkAutoDisableDirectionCheck',
2505 'SkAutoDisableOvalCheck',
2506 'SkAutoFree',
2507 'SkAutoGlyphCache',
2508 'SkAutoHDC',
2509 'SkAutoLockColors',
2510 'SkAutoLockPixels',
2511 'SkAutoMalloc',
2512 'SkAutoMaskFreeImage',
2513 'SkAutoMutexAcquire',
2514 'SkAutoPathBoundsUpdate',
2515 'SkAutoPDFRelease',
2516 'SkAutoRasterClipValidate',
2517 'SkAutoRef',
2518 'SkAutoTime',
2519 'SkAutoTrace',
2520 'SkAutoUnref',
2521 ]
2522 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2523 # bad: base::AutoLock(lock.get());
2524 # not bad: base::AutoLock lock(lock.get());
2525 bad_pattern = input_api.re.compile(anonymous)
2526 # good: new base::AutoLock(lock.get())
2527 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2528 errors = []
2529
2530 for f in input_api.AffectedFiles():
2531 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2532 continue
2533 for linenum, line in f.ChangedContents():
2534 if bad_pattern.search(line) and not good_pattern.search(line):
2535 errors.append('%s:%d' % (f.LocalPath(), linenum))
2536
2537 if errors:
2538 return [output_api.PresubmitError(
2539 'These lines create anonymous variables that need to be named:',
2540 items=errors)]
2541 return []
2542
2543
Saagar Sanghavifceeaae2020-08-12 16:40:362544def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532545 # Returns whether |template_str| is of the form <T, U...> for some types T
2546 # and U. Assumes that |template_str| is already in the form <...>.
2547 def HasMoreThanOneArg(template_str):
2548 # Level of <...> nesting.
2549 nesting = 0
2550 for c in template_str:
2551 if c == '<':
2552 nesting += 1
2553 elif c == '>':
2554 nesting -= 1
2555 elif c == ',' and nesting == 1:
2556 return True
2557 return False
2558
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492559 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102560 sources = lambda affected_file: input_api.FilterSourceFile(
2561 affected_file,
James Cook24a504192020-07-23 00:08:442562 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2563 input_api.DEFAULT_FILES_TO_SKIP),
2564 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552565
2566 # Pattern to capture a single "<...>" block of template arguments. It can
2567 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2568 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2569 # latter would likely require counting that < and > match, which is not
2570 # expressible in regular languages. Should the need arise, one can introduce
2571 # limited counting (matching up to a total number of nesting depth), which
2572 # should cover all practical cases for already a low nesting limit.
2573 template_arg_pattern = (
2574 r'<[^>]*' # Opening block of <.
2575 r'>([^<]*>)?') # Closing block of >.
2576 # Prefix expressing that whatever follows is not already inside a <...>
2577 # block.
2578 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102579 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552580 not_inside_template_arg_pattern
2581 + r'\bstd::unique_ptr'
2582 + template_arg_pattern
2583 + r'\(\)')
2584
2585 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2586 template_arg_no_array_pattern = (
2587 r'<[^>]*[^]]' # Opening block of <.
2588 r'>([^(<]*[^]]>)?') # Closing block of >.
2589 # Prefix saying that what follows is the start of an expression.
2590 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2591 # Suffix saying that what follows are call parentheses with a non-empty list
2592 # of arguments.
2593 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532594 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552595 return_construct_pattern = input_api.re.compile(
2596 start_of_expr_pattern
2597 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532598 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552599 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532600 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552601 + nonempty_arg_list_pattern)
2602
Vaclav Brozek851d9602018-04-04 16:13:052603 problems_constructor = []
2604 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102605 for f in input_api.AffectedSourceFiles(sources):
2606 for line_number, line in f.ChangedContents():
2607 # Disallow:
2608 # return std::unique_ptr<T>(foo);
2609 # bar = std::unique_ptr<T>(foo);
2610 # But allow:
2611 # return std::unique_ptr<T[]>(foo);
2612 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532613 # And also allow cases when the second template argument is present. Those
2614 # cases cannot be handled by std::make_unique:
2615 # return std::unique_ptr<T, U>(foo);
2616 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052617 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532618 return_construct_result = return_construct_pattern.search(line)
2619 if return_construct_result and not HasMoreThanOneArg(
2620 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052621 problems_constructor.append(
2622 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102623 # Disallow:
2624 # std::unique_ptr<T>()
2625 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052626 problems_nullptr.append(
2627 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2628
2629 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162630 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052631 errors.append(output_api.PresubmitError(
2632 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162633 problems_nullptr))
2634 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052635 errors.append(output_api.PresubmitError(
2636 'The following files use explicit std::unique_ptr constructor.'
2637 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162638 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102639 return errors
2640
2641
Saagar Sanghavifceeaae2020-08-12 16:40:362642def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082643 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522644 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082645 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522646 # If actions.xml is already included in the changelist, the PRESUBMIT
2647 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082648 return []
2649
[email protected]999261d2014-03-03 20:08:082650 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2651 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522652 current_actions = None
[email protected]999261d2014-03-03 20:08:082653 for f in input_api.AffectedFiles(file_filter=file_filter):
2654 for line_num, line in f.ChangedContents():
2655 match = input_api.re.search(action_re, line)
2656 if match:
[email protected]2f92dec2014-03-07 19:21:522657 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2658 # loaded only once.
2659 if not current_actions:
2660 with open('tools/metrics/actions/actions.xml') as actions_f:
2661 current_actions = actions_f.read()
2662 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082663 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522664 action = 'name="{0}"'.format(action_name)
2665 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082666 return [output_api.PresubmitPromptWarning(
2667 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522668 'tools/metrics/actions/actions.xml. Please run '
2669 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082670 % (f.LocalPath(), line_num, action_name))]
2671 return []
2672
2673
Daniel Cheng13ca61a882017-08-25 15:11:252674def _ImportJSONCommentEater(input_api):
2675 import sys
2676 sys.path = sys.path + [input_api.os_path.join(
2677 input_api.PresubmitLocalPath(),
2678 'tools', 'json_comment_eater')]
2679 import json_comment_eater
2680 return json_comment_eater
2681
2682
[email protected]99171a92014-06-03 08:44:472683def _GetJSONParseError(input_api, filename, eat_comments=True):
2684 try:
2685 contents = input_api.ReadFile(filename)
2686 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252687 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132688 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472689
2690 input_api.json.loads(contents)
2691 except ValueError as e:
2692 return e
2693 return None
2694
2695
2696def _GetIDLParseError(input_api, filename):
2697 try:
2698 contents = input_api.ReadFile(filename)
2699 idl_schema = input_api.os_path.join(
2700 input_api.PresubmitLocalPath(),
2701 'tools', 'json_schema_compiler', 'idl_schema.py')
2702 process = input_api.subprocess.Popen(
2703 [input_api.python_executable, idl_schema],
2704 stdin=input_api.subprocess.PIPE,
2705 stdout=input_api.subprocess.PIPE,
2706 stderr=input_api.subprocess.PIPE,
2707 universal_newlines=True)
2708 (_, error) = process.communicate(input=contents)
2709 return error or None
2710 except ValueError as e:
2711 return e
2712
2713
Saagar Sanghavifceeaae2020-08-12 16:40:362714def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472715 """Check that IDL and JSON files do not contain syntax errors."""
2716 actions = {
2717 '.idl': _GetIDLParseError,
2718 '.json': _GetJSONParseError,
2719 }
[email protected]99171a92014-06-03 08:44:472720 # Most JSON files are preprocessed and support comments, but these do not.
2721 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042722 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472723 ]
2724 # Only run IDL checker on files in these directories.
2725 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042726 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2727 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472728 ]
2729
2730 def get_action(affected_file):
2731 filename = affected_file.LocalPath()
2732 return actions.get(input_api.os_path.splitext(filename)[1])
2733
[email protected]99171a92014-06-03 08:44:472734 def FilterFile(affected_file):
2735 action = get_action(affected_file)
2736 if not action:
2737 return False
2738 path = affected_file.LocalPath()
2739
Erik Staab2dd72b12020-04-16 15:03:402740 if _MatchesFile(input_api,
2741 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2742 path):
[email protected]99171a92014-06-03 08:44:472743 return False
2744
2745 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162746 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472747 return False
2748 return True
2749
2750 results = []
2751 for affected_file in input_api.AffectedFiles(
2752 file_filter=FilterFile, include_deletes=False):
2753 action = get_action(affected_file)
2754 kwargs = {}
2755 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162756 _MatchesFile(input_api, json_no_comments_patterns,
2757 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472758 kwargs['eat_comments'] = False
2759 parse_error = action(input_api,
2760 affected_file.AbsoluteLocalPath(),
2761 **kwargs)
2762 if parse_error:
2763 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2764 (affected_file.LocalPath(), parse_error)))
2765 return results
2766
2767
Saagar Sanghavifceeaae2020-08-12 16:40:362768def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492769 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472770 import sys
[email protected]760deea2013-12-10 19:33:492771 original_sys_path = sys.path
2772 try:
2773 sys.path = sys.path + [input_api.os_path.join(
2774 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2775 import checkstyle
2776 finally:
2777 # Restore sys.path to what it was before.
2778 sys.path = original_sys_path
2779
2780 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092781 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442782 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492783
2784
Saagar Sanghavifceeaae2020-08-12 16:40:362785def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002786 """Checks to make sure devil is initialized correctly in python scripts."""
2787 script_common_initialize_pattern = input_api.re.compile(
2788 r'script_common\.InitializeEnvironment\(')
2789 devil_env_config_initialize = input_api.re.compile(
2790 r'devil_env\.config\.Initialize\(')
2791
2792 errors = []
2793
2794 sources = lambda affected_file: input_api.FilterSourceFile(
2795 affected_file,
James Cook24a504192020-07-23 00:08:442796 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2797 (r'^build[\\/]android[\\/]devil_chromium\.py',
2798 r'^third_party[\\/].*',)),
2799 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002800
2801 for f in input_api.AffectedSourceFiles(sources):
2802 for line_num, line in f.ChangedContents():
2803 if (script_common_initialize_pattern.search(line) or
2804 devil_env_config_initialize.search(line)):
2805 errors.append("%s:%d" % (f.LocalPath(), line_num))
2806
2807 results = []
2808
2809 if errors:
2810 results.append(output_api.PresubmitError(
2811 'Devil initialization should always be done using '
2812 'devil_chromium.Initialize() in the chromium project, to use better '
2813 'defaults for dependencies (ex. up-to-date version of adb).',
2814 errors))
2815
2816 return results
2817
2818
Sean Kau46e29bc2017-08-28 16:31:162819def _MatchesFile(input_api, patterns, path):
2820 for pattern in patterns:
2821 if input_api.re.search(pattern, path):
2822 return True
2823 return False
2824
2825
Daniel Cheng7052cdf2017-11-21 19:23:292826def _GetOwnersFilesToCheckForIpcOwners(input_api):
2827 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172828
Daniel Cheng7052cdf2017-11-21 19:23:292829 Returns:
2830 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2831 contain to cover IPC-related files with noparent reviewer rules.
2832 """
2833 # Whether or not a file affects IPC is (mostly) determined by a simple list
2834 # of filename patterns.
dchenge07de812016-06-20 19:27:172835 file_patterns = [
palmerb19a0932017-01-24 04:00:312836 # Legacy IPC:
dchenge07de812016-06-20 19:27:172837 '*_messages.cc',
2838 '*_messages*.h',
2839 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312840 # Mojo IPC:
dchenge07de812016-06-20 19:27:172841 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472842 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172843 '*_struct_traits*.*',
2844 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312845 '*.typemap',
2846 # Android native IPC:
2847 '*.aidl',
2848 # Blink uses a different file naming convention:
2849 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472850 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172851 '*StructTraits*.*',
2852 '*TypeConverter*.*',
2853 ]
2854
scottmg7a6ed5ba2016-11-04 18:22:042855 # These third_party directories do not contain IPCs, but contain files
2856 # matching the above patterns, which trigger false positives.
2857 exclude_paths = [
2858 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162859 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232860 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292861 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542862 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162863 # These files are just used to communicate between class loaders running
2864 # in the same process.
2865 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572866 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2867
scottmg7a6ed5ba2016-11-04 18:22:042868 ]
2869
dchenge07de812016-06-20 19:27:172870 # Dictionary mapping an OWNERS file path to Patterns.
2871 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2872 # rules ) to a PatternEntry.
2873 # PatternEntry is a dictionary with two keys:
2874 # - 'files': the files that are matched by this pattern
2875 # - 'rules': the per-file rules needed for this pattern
2876 # For example, if we expect OWNERS file to contain rules for *.mojom and
2877 # *_struct_traits*.*, Patterns might look like this:
2878 # {
2879 # '*.mojom': {
2880 # 'files': ...,
2881 # 'rules': [
2882 # 'per-file *.mojom=set noparent',
2883 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2884 # ],
2885 # },
2886 # '*_struct_traits*.*': {
2887 # 'files': ...,
2888 # 'rules': [
2889 # 'per-file *_struct_traits*.*=set noparent',
2890 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2891 # ],
2892 # },
2893 # }
2894 to_check = {}
2895
Daniel Cheng13ca61a882017-08-25 15:11:252896 def AddPatternToCheck(input_file, pattern):
2897 owners_file = input_api.os_path.join(
2898 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2899 if owners_file not in to_check:
2900 to_check[owners_file] = {}
2901 if pattern not in to_check[owners_file]:
2902 to_check[owners_file][pattern] = {
2903 'files': [],
2904 'rules': [
2905 'per-file %s=set noparent' % pattern,
2906 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2907 ]
2908 }
Vaclav Brozekd5de76a2018-03-17 07:57:502909 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252910
dchenge07de812016-06-20 19:27:172911 # Iterate through the affected files to see what we actually need to check
2912 # for. We should only nag patch authors about per-file rules if a file in that
2913 # directory would match that pattern. If a directory only contains *.mojom
2914 # files and no *_messages*.h files, we should only nag about rules for
2915 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252916 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262917 # Manifest files don't have a strong naming convention. Instead, try to find
2918 # affected .cc and .h files which look like they contain a manifest
2919 # definition.
2920 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2921 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2922 if (manifest_pattern.search(f.LocalPath()) and not
2923 test_manifest_pattern.search(f.LocalPath())):
2924 # We expect all actual service manifest files to contain at least one
2925 # qualified reference to service_manager::Manifest.
2926 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252927 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172928 for pattern in file_patterns:
2929 if input_api.fnmatch.fnmatch(
2930 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042931 skip = False
2932 for exclude in exclude_paths:
2933 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2934 skip = True
2935 break
2936 if skip:
2937 continue
Daniel Cheng13ca61a882017-08-25 15:11:252938 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172939 break
2940
Daniel Cheng7052cdf2017-11-21 19:23:292941 return to_check
2942
2943
Wez17c66962020-04-29 15:26:032944def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2945 """Adds OWNERS files to check for correct Fuchsia security owners."""
2946
2947 file_patterns = [
2948 # Component specifications.
2949 '*.cml', # Component Framework v2.
2950 '*.cmx', # Component Framework v1.
2951
2952 # Fuchsia IDL protocol specifications.
2953 '*.fidl',
2954 ]
2955
2956 def AddPatternToCheck(input_file, pattern):
2957 owners_file = input_api.os_path.join(
2958 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2959 if owners_file not in to_check:
2960 to_check[owners_file] = {}
2961 if pattern not in to_check[owners_file]:
2962 to_check[owners_file][pattern] = {
2963 'files': [],
2964 'rules': [
2965 'per-file %s=set noparent' % pattern,
2966 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2967 ]
2968 }
2969 to_check[owners_file][pattern]['files'].append(input_file)
2970
2971 # Iterate through the affected files to see what we actually need to check
2972 # for. We should only nag patch authors about per-file rules if a file in that
2973 # directory would match that pattern.
2974 for f in input_api.AffectedFiles(include_deletes=False):
2975 for pattern in file_patterns:
2976 if input_api.fnmatch.fnmatch(
2977 input_api.os_path.basename(f.LocalPath()), pattern):
2978 AddPatternToCheck(f, pattern)
2979 break
2980
2981 return to_check
2982
2983
Saagar Sanghavifceeaae2020-08-12 16:40:362984def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292985 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2986 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032987 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292988
2989 if to_check:
2990 # If there are any OWNERS files to check, there are IPC-related changes in
2991 # this CL. Auto-CC the review list.
2992 output_api.AppendCC('[email protected]')
2993
2994 # Go through the OWNERS files to check, filtering out rules that are already
2995 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172996 for owners_file, patterns in to_check.iteritems():
2997 try:
2998 with file(owners_file) as f:
2999 lines = set(f.read().splitlines())
3000 for entry in patterns.itervalues():
3001 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3002 ]
3003 except IOError:
3004 # No OWNERS file, so all the rules are definitely missing.
3005 continue
3006
3007 # All the remaining lines weren't found in OWNERS files, so emit an error.
3008 errors = []
3009 for owners_file, patterns in to_check.iteritems():
3010 missing_lines = []
3011 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503012 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173013 missing_lines.extend(entry['rules'])
3014 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3015 if missing_lines:
3016 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053017 'Because of the presence of files:\n%s\n\n'
3018 '%s needs the following %d lines added:\n\n%s' %
3019 ('\n'.join(files), owners_file, len(missing_lines),
3020 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173021
3022 results = []
3023 if errors:
vabrf5ce3bf92016-07-11 14:52:413024 if input_api.is_committing:
3025 output = output_api.PresubmitError
3026 else:
3027 output = output_api.PresubmitPromptWarning
3028 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593029 'Found OWNERS files that need to be updated for IPC security ' +
3030 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173031 long_text='\n\n'.join(errors)))
3032
3033 return results
3034
3035
Robert Sesek2c905332020-05-06 23:17:133036def _GetFilesUsingSecurityCriticalFunctions(input_api):
3037 """Checks affected files for changes to security-critical calls. This
3038 function checks the full change diff, to catch both additions/changes
3039 and removals.
3040
3041 Returns a dict keyed by file name, and the value is a set of detected
3042 functions.
3043 """
3044 # Map of function pretty name (displayed in an error) to the pattern to
3045 # match it with.
3046 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373047 'content::GetServiceSandboxType<>()':
3048 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133049 }
3050 _PATTERNS_TO_CHECK = {
3051 k: input_api.re.compile(v)
3052 for k, v in _PATTERNS_TO_CHECK.items()
3053 }
3054
3055 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3056 files_to_functions = {}
3057 for f in input_api.AffectedFiles():
3058 diff = f.GenerateScmDiff()
3059 for line in diff.split('\n'):
3060 # Not using just RightHandSideLines() because removing a
3061 # call to a security-critical function can be just as important
3062 # as adding or changing the arguments.
3063 if line.startswith('-') or (line.startswith('+') and
3064 not line.startswith('++')):
3065 for name, pattern in _PATTERNS_TO_CHECK.items():
3066 if pattern.search(line):
3067 path = f.LocalPath()
3068 if not path in files_to_functions:
3069 files_to_functions[path] = set()
3070 files_to_functions[path].add(name)
3071 return files_to_functions
3072
3073
Saagar Sanghavifceeaae2020-08-12 16:40:363074def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133075 """Checks that changes involving security-critical functions are reviewed
3076 by the security team.
3077 """
3078 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3079 if len(files_to_functions):
3080 owners_db = input_api.owners_db
3081 owner_email, reviewers = (
3082 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3083 input_api,
3084 owners_db.email_regexp,
3085 approval_needed=input_api.is_committing))
3086
3087 # Load the OWNERS file for security changes.
3088 owners_file = 'ipc/SECURITY_OWNERS'
3089 security_owners = owners_db.owners_rooted_at_file(owners_file)
3090
3091 has_security_owner = any([owner in reviewers for owner in security_owners])
3092 if not has_security_owner:
3093 msg = 'The following files change calls to security-sensive functions\n' \
3094 'that need to be reviewed by {}.\n'.format(owners_file)
3095 for path, names in files_to_functions.items():
3096 msg += ' {}\n'.format(path)
3097 for name in names:
3098 msg += ' {}\n'.format(name)
3099 msg += '\n'
3100
3101 if input_api.is_committing:
3102 output = output_api.PresubmitError
3103 else:
3104 output = output_api.PresubmitNotifyResult
3105 return [output(msg)]
3106
3107 return []
3108
3109
Saagar Sanghavifceeaae2020-08-12 16:40:363110def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263111 """Checks that set noparent is only used together with an OWNERS file in
3112 //build/OWNERS.setnoparent (see also
3113 //docs/code_reviews.md#owners-files-details)
3114 """
3115 errors = []
3116
3117 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3118 allowed_owners_files = set()
3119 with open(allowed_owners_files_file, 'r') as f:
3120 for line in f:
3121 line = line.strip()
3122 if not line or line.startswith('#'):
3123 continue
3124 allowed_owners_files.add(line)
3125
3126 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3127
3128 for f in input_api.AffectedFiles(include_deletes=False):
3129 if not f.LocalPath().endswith('OWNERS'):
3130 continue
3131
3132 found_owners_files = set()
3133 found_set_noparent_lines = dict()
3134
3135 # Parse the OWNERS file.
3136 for lineno, line in enumerate(f.NewContents(), 1):
3137 line = line.strip()
3138 if line.startswith('set noparent'):
3139 found_set_noparent_lines[''] = lineno
3140 if line.startswith('file://'):
3141 if line in allowed_owners_files:
3142 found_owners_files.add('')
3143 if line.startswith('per-file'):
3144 match = per_file_pattern.match(line)
3145 if match:
3146 glob = match.group(1).strip()
3147 directive = match.group(2).strip()
3148 if directive == 'set noparent':
3149 found_set_noparent_lines[glob] = lineno
3150 if directive.startswith('file://'):
3151 if directive in allowed_owners_files:
3152 found_owners_files.add(glob)
3153
3154 # Check that every set noparent line has a corresponding file:// line
3155 # listed in build/OWNERS.setnoparent.
3156 for set_noparent_line in found_set_noparent_lines:
3157 if set_noparent_line in found_owners_files:
3158 continue
3159 errors.append(' %s:%d' % (f.LocalPath(),
3160 found_set_noparent_lines[set_noparent_line]))
3161
3162 results = []
3163 if errors:
3164 if input_api.is_committing:
3165 output = output_api.PresubmitError
3166 else:
3167 output = output_api.PresubmitPromptWarning
3168 results.append(output(
3169 'Found the following "set noparent" restrictions in OWNERS files that '
3170 'do not include owners from build/OWNERS.setnoparent:',
3171 long_text='\n\n'.join(errors)))
3172 return results
3173
3174
Saagar Sanghavifceeaae2020-08-12 16:40:363175def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313176 """Checks that added or removed lines in non third party affected
3177 header files do not lead to new useless class or struct forward
3178 declaration.
jbriance9e12f162016-11-25 07:57:503179 """
3180 results = []
3181 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3182 input_api.re.MULTILINE)
3183 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3184 input_api.re.MULTILINE)
3185 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313186 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193187 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493188 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313189 continue
3190
jbriance9e12f162016-11-25 07:57:503191 if not f.LocalPath().endswith('.h'):
3192 continue
3193
3194 contents = input_api.ReadFile(f)
3195 fwd_decls = input_api.re.findall(class_pattern, contents)
3196 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3197
3198 useless_fwd_decls = []
3199 for decl in fwd_decls:
3200 count = sum(1 for _ in input_api.re.finditer(
3201 r'\b%s\b' % input_api.re.escape(decl), contents))
3202 if count == 1:
3203 useless_fwd_decls.append(decl)
3204
3205 if not useless_fwd_decls:
3206 continue
3207
3208 for line in f.GenerateScmDiff().splitlines():
3209 if (line.startswith('-') and not line.startswith('--') or
3210 line.startswith('+') and not line.startswith('++')):
3211 for decl in useless_fwd_decls:
3212 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3213 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243214 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503215 (f.LocalPath(), decl)))
3216 useless_fwd_decls.remove(decl)
3217
3218 return results
3219
Jinsong Fan91ebbbd2019-04-16 14:57:173220def _CheckAndroidDebuggableBuild(input_api, output_api):
3221 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3222 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3223 this is a debuggable build of Android.
3224 """
3225 build_type_check_pattern = input_api.re.compile(
3226 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3227
3228 errors = []
3229
3230 sources = lambda affected_file: input_api.FilterSourceFile(
3231 affected_file,
James Cook24a504192020-07-23 00:08:443232 files_to_skip=(_EXCLUDED_PATHS +
3233 _TEST_CODE_EXCLUDED_PATHS +
3234 input_api.DEFAULT_FILES_TO_SKIP +
3235 (r"^android_webview[\\/]support_library[\\/]"
3236 "boundary_interfaces[\\/]",
3237 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3238 r'^third_party[\\/].*',
3239 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3240 r"webview[\\/]chromium[\\/]License.*",)),
3241 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173242
3243 for f in input_api.AffectedSourceFiles(sources):
3244 for line_num, line in f.ChangedContents():
3245 if build_type_check_pattern.search(line):
3246 errors.append("%s:%d" % (f.LocalPath(), line_num))
3247
3248 results = []
3249
3250 if errors:
3251 results.append(output_api.PresubmitPromptWarning(
3252 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3253 ' Please use BuildInfo.isDebugAndroid() instead.',
3254 errors))
3255
3256 return results
jbriance9e12f162016-11-25 07:57:503257
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493258# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293259def _CheckAndroidToastUsage(input_api, output_api):
3260 """Checks that code uses org.chromium.ui.widget.Toast instead of
3261 android.widget.Toast (Chromium Toast doesn't force hardware
3262 acceleration on low-end devices, saving memory).
3263 """
3264 toast_import_pattern = input_api.re.compile(
3265 r'^import android\.widget\.Toast;$')
3266
3267 errors = []
3268
3269 sources = lambda affected_file: input_api.FilterSourceFile(
3270 affected_file,
James Cook24a504192020-07-23 00:08:443271 files_to_skip=(_EXCLUDED_PATHS +
3272 _TEST_CODE_EXCLUDED_PATHS +
3273 input_api.DEFAULT_FILES_TO_SKIP +
3274 (r'^chromecast[\\/].*',
3275 r'^remoting[\\/].*')),
3276 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293277
3278 for f in input_api.AffectedSourceFiles(sources):
3279 for line_num, line in f.ChangedContents():
3280 if toast_import_pattern.search(line):
3281 errors.append("%s:%d" % (f.LocalPath(), line_num))
3282
3283 results = []
3284
3285 if errors:
3286 results.append(output_api.PresubmitError(
3287 'android.widget.Toast usage is detected. Android toasts use hardware'
3288 ' acceleration, and can be\ncostly on low-end devices. Please use'
3289 ' org.chromium.ui.widget.Toast instead.\n'
3290 'Contact [email protected] if you have any questions.',
3291 errors))
3292
3293 return results
3294
3295
dgnaa68d5e2015-06-10 10:08:223296def _CheckAndroidCrLogUsage(input_api, output_api):
3297 """Checks that new logs using org.chromium.base.Log:
3298 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513299 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223300 """
pkotwicza1dd0b002016-05-16 14:41:043301
torne89540622017-03-24 19:41:303302 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043303 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303304 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043305 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303306 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043307 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3308 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093309 # The customtabs_benchmark is a small app that does not depend on Chromium
3310 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043311 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043312 ]
3313
dgnaa68d5e2015-06-10 10:08:223314 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123315 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3316 class_in_base_pattern = input_api.re.compile(
3317 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3318 has_some_log_import_pattern = input_api.re.compile(
3319 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223320 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553321 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223322 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463323 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553324 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223325
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463326 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443327 sources = lambda x: input_api.FilterSourceFile(x,
3328 files_to_check=[r'.*\.java$'],
3329 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123330
dgnaa68d5e2015-06-10 10:08:223331 tag_decl_errors = []
3332 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123333 tag_errors = []
dgn38736db2015-09-18 19:20:513334 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123335 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223336
3337 for f in input_api.AffectedSourceFiles(sources):
3338 file_content = input_api.ReadFile(f)
3339 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223340 # Per line checks
dgn87d9fb62015-06-12 09:15:123341 if (cr_log_import_pattern.search(file_content) or
3342 (class_in_base_pattern.search(file_content) and
3343 not has_some_log_import_pattern.search(file_content))):
3344 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223345 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553346 if rough_log_decl_pattern.search(line):
3347 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223348
3349 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123350 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223351 if match:
3352 has_modified_logs = True
3353
3354 # Make sure it uses "TAG"
3355 if not match.group('tag') == 'TAG':
3356 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123357 else:
3358 # Report non cr Log function calls in changed lines
3359 for line_num, line in f.ChangedContents():
3360 if log_call_pattern.search(line):
3361 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223362
3363 # Per file checks
3364 if has_modified_logs:
3365 # Make sure the tag is using the "cr" prefix and is not too long
3366 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513367 tag_name = match.group('name') if match else None
3368 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223369 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513370 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223371 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513372 elif '.' in tag_name:
3373 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223374
3375 results = []
3376 if tag_decl_errors:
3377 results.append(output_api.PresubmitPromptWarning(
3378 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513379 '"private static final String TAG = "<package tag>".\n'
3380 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223381 tag_decl_errors))
3382
3383 if tag_length_errors:
3384 results.append(output_api.PresubmitError(
3385 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513386 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223387 tag_length_errors))
3388
3389 if tag_errors:
3390 results.append(output_api.PresubmitPromptWarning(
3391 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3392 tag_errors))
3393
dgn87d9fb62015-06-12 09:15:123394 if util_log_errors:
dgn4401aa52015-04-29 16:26:173395 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123396 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3397 util_log_errors))
3398
dgn38736db2015-09-18 19:20:513399 if tag_with_dot_errors:
3400 results.append(output_api.PresubmitPromptWarning(
3401 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3402 tag_with_dot_errors))
3403
dgn4401aa52015-04-29 16:26:173404 return results
3405
3406
Yoland Yanb92fa522017-08-28 17:37:063407def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3408 """Checks that junit.framework.* is no longer used."""
3409 deprecated_junit_framework_pattern = input_api.re.compile(
3410 r'^import junit\.framework\..*;',
3411 input_api.re.MULTILINE)
3412 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443413 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063414 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133415 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063416 for line_num, line in f.ChangedContents():
3417 if deprecated_junit_framework_pattern.search(line):
3418 errors.append("%s:%d" % (f.LocalPath(), line_num))
3419
3420 results = []
3421 if errors:
3422 results.append(output_api.PresubmitError(
3423 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3424 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3425 ' if you have any question.', errors))
3426 return results
3427
3428
3429def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3430 """Checks that if new Java test classes have inheritance.
3431 Either the new test class is JUnit3 test or it is a JUnit4 test class
3432 with a base class, either case is undesirable.
3433 """
3434 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3435
3436 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443437 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063438 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133439 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063440 if not f.OldContents():
3441 class_declaration_start_flag = False
3442 for line_num, line in f.ChangedContents():
3443 if class_declaration_pattern.search(line):
3444 class_declaration_start_flag = True
3445 if class_declaration_start_flag and ' extends ' in line:
3446 errors.append('%s:%d' % (f.LocalPath(), line_num))
3447 if '{' in line:
3448 class_declaration_start_flag = False
3449
3450 results = []
3451 if errors:
3452 results.append(output_api.PresubmitPromptWarning(
3453 'The newly created files include Test classes that inherits from base'
3454 ' class. Please do not use inheritance in JUnit4 tests or add new'
3455 ' JUnit3 tests. Contact [email protected] if you have any'
3456 ' questions.', errors))
3457 return results
3458
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203459
yolandyan45001472016-12-21 21:12:423460def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3461 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3462 deprecated_annotation_import_pattern = input_api.re.compile(
3463 r'^import android\.test\.suitebuilder\.annotation\..*;',
3464 input_api.re.MULTILINE)
3465 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443466 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423467 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133468 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423469 for line_num, line in f.ChangedContents():
3470 if deprecated_annotation_import_pattern.search(line):
3471 errors.append("%s:%d" % (f.LocalPath(), line_num))
3472
3473 results = []
3474 if errors:
3475 results.append(output_api.PresubmitError(
3476 'Annotations in android.test.suitebuilder.annotation have been'
3477 ' deprecated since API level 24. Please use android.support.test.filters'
3478 ' from //third_party/android_support_test_runner:runner_java instead.'
3479 ' Contact [email protected] if you have any questions.', errors))
3480 return results
3481
3482
agrieve7b6479d82015-10-07 14:24:223483def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3484 """Checks if MDPI assets are placed in a correct directory."""
3485 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3486 ('/res/drawable/' in f.LocalPath() or
3487 '/res/drawable-ldrtl/' in f.LocalPath()))
3488 errors = []
3489 for f in input_api.AffectedFiles(include_deletes=False,
3490 file_filter=file_filter):
3491 errors.append(' %s' % f.LocalPath())
3492
3493 results = []
3494 if errors:
3495 results.append(output_api.PresubmitError(
3496 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3497 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3498 '/res/drawable-ldrtl/.\n'
3499 'Contact [email protected] if you have questions.', errors))
3500 return results
3501
3502
Nate Fischer535972b2017-09-16 01:06:183503def _CheckAndroidWebkitImports(input_api, output_api):
3504 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353505 android.webview.ValueCallback except in the WebView glue layer
3506 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183507 """
3508 valuecallback_import_pattern = input_api.re.compile(
3509 r'^import android\.webkit\.ValueCallback;$')
3510
3511 errors = []
3512
3513 sources = lambda affected_file: input_api.FilterSourceFile(
3514 affected_file,
James Cook24a504192020-07-23 00:08:443515 files_to_skip=(_EXCLUDED_PATHS +
3516 _TEST_CODE_EXCLUDED_PATHS +
3517 input_api.DEFAULT_FILES_TO_SKIP +
3518 (r'^android_webview[\\/]glue[\\/].*',
3519 r'^weblayer[\\/].*',)),
3520 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183521
3522 for f in input_api.AffectedSourceFiles(sources):
3523 for line_num, line in f.ChangedContents():
3524 if valuecallback_import_pattern.search(line):
3525 errors.append("%s:%d" % (f.LocalPath(), line_num))
3526
3527 results = []
3528
3529 if errors:
3530 results.append(output_api.PresubmitError(
3531 'android.webkit.ValueCallback usage is detected outside of the glue'
3532 ' layer. To stay compatible with the support library, android.webkit.*'
3533 ' classes should only be used inside the glue layer and'
3534 ' org.chromium.base.Callback should be used instead.',
3535 errors))
3536
3537 return results
3538
3539
Becky Zhou7c69b50992018-12-10 19:37:573540def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3541 """Checks Android XML styles """
3542 import sys
3543 original_sys_path = sys.path
3544 try:
3545 sys.path = sys.path + [input_api.os_path.join(
3546 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3547 import checkxmlstyle
3548 finally:
3549 # Restore sys.path to what it was before.
3550 sys.path = original_sys_path
3551
3552 if is_check_on_upload:
3553 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3554 else:
3555 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3556
3557
agrievef32bcc72016-04-04 14:57:403558class PydepsChecker(object):
3559 def __init__(self, input_api, pydeps_files):
3560 self._file_cache = {}
3561 self._input_api = input_api
3562 self._pydeps_files = pydeps_files
3563
3564 def _LoadFile(self, path):
3565 """Returns the list of paths within a .pydeps file relative to //."""
3566 if path not in self._file_cache:
3567 with open(path) as f:
3568 self._file_cache[path] = f.read()
3569 return self._file_cache[path]
3570
3571 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3572 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393573 pydeps_data = self._LoadFile(pydeps_path)
3574 uses_gn_paths = '--gn-paths' in pydeps_data
3575 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3576 if uses_gn_paths:
3577 # Paths look like: //foo/bar/baz
3578 return (e[2:] for e in entries)
3579 else:
3580 # Paths look like: path/relative/to/file.pydeps
3581 os_path = self._input_api.os_path
3582 pydeps_dir = os_path.dirname(pydeps_path)
3583 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403584
3585 def _CreateFilesToPydepsMap(self):
3586 """Returns a map of local_path -> list_of_pydeps."""
3587 ret = {}
3588 for pydep_local_path in self._pydeps_files:
3589 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3590 ret.setdefault(path, []).append(pydep_local_path)
3591 return ret
3592
3593 def ComputeAffectedPydeps(self):
3594 """Returns an iterable of .pydeps files that might need regenerating."""
3595 affected_pydeps = set()
3596 file_to_pydeps_map = None
3597 for f in self._input_api.AffectedFiles(include_deletes=True):
3598 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463599 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3600 # subrepositories. We can't figure out which files change, so re-check
3601 # all files.
3602 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383603 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3604 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403605 return self._pydeps_files
3606 elif local_path.endswith('.pydeps'):
3607 if local_path in self._pydeps_files:
3608 affected_pydeps.add(local_path)
3609 elif local_path.endswith('.py'):
3610 if file_to_pydeps_map is None:
3611 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3612 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3613 return affected_pydeps
3614
3615 def DetermineIfStale(self, pydeps_path):
3616 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413617 import difflib
John Budorick47ca3fe2018-02-10 00:53:103618 import os
3619
agrievef32bcc72016-04-04 14:57:403620 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033621 if old_pydeps_data:
3622 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393623 if '--output' not in cmd:
3624 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033625 old_contents = old_pydeps_data[2:]
3626 else:
3627 # A default cmd that should work in most cases (as long as pydeps filename
3628 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3629 # file is empty/new.
3630 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3631 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3632 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103633 env = dict(os.environ)
3634 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403635 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103636 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413637 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033638 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413639 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403640
3641
Tibor Goldschwendt360793f72019-06-25 18:23:493642def _ParseGclientArgs():
3643 args = {}
3644 with open('build/config/gclient_args.gni', 'r') as f:
3645 for line in f:
3646 line = line.strip()
3647 if not line or line.startswith('#'):
3648 continue
3649 attribute, value = line.split('=')
3650 args[attribute.strip()] = value.strip()
3651 return args
3652
3653
Saagar Sanghavifceeaae2020-08-12 16:40:363654def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403655 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403656 # This check is for Python dependency lists (.pydeps files), and involves
3657 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3658 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283659 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003660 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493661 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403662 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403663 results = []
3664 # First, check for new / deleted .pydeps.
3665 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033666 # Check whether we are running the presubmit check for a file in src.
3667 # f.LocalPath is relative to repo (src, or internal repo).
3668 # os_path.exists is relative to src repo.
3669 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3670 # to src and we can conclude that the pydeps is in src.
3671 if input_api.os_path.exists(f.LocalPath()):
3672 if f.LocalPath().endswith('.pydeps'):
3673 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3674 results.append(output_api.PresubmitError(
3675 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3676 'remove %s' % f.LocalPath()))
3677 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3678 results.append(output_api.PresubmitError(
3679 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3680 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403681
3682 if results:
3683 return results
3684
Mohamed Heikal7cd4d8312020-06-16 16:49:403685 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3686 affected_pydeps = set(checker.ComputeAffectedPydeps())
3687 affected_android_pydeps = affected_pydeps.intersection(
3688 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3689 if affected_android_pydeps and not is_android:
3690 results.append(output_api.PresubmitPromptOrNotify(
3691 'You have changed python files that may affect pydeps for android\n'
3692 'specific scripts. However, the relevant presumbit check cannot be\n'
3693 'run because you are not using an Android checkout. To validate that\n'
3694 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3695 'use the android-internal-presubmit optional trybot.\n'
3696 'Possibly stale pydeps files:\n{}'.format(
3697 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403698
Mohamed Heikal7cd4d8312020-06-16 16:49:403699 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3700 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403701 try:
phajdan.jr0d9878552016-11-04 10:49:413702 result = checker.DetermineIfStale(pydep_path)
3703 if result:
3704 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403705 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413706 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3707 'To regenerate, run:\n\n %s' %
3708 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403709 except input_api.subprocess.CalledProcessError as error:
3710 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3711 long_text=error.output)]
3712
3713 return results
3714
3715
Saagar Sanghavifceeaae2020-08-12 16:40:363716def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433717 """Checks to make sure no header files have |Singleton<|."""
3718 def FileFilter(affected_file):
3719 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443720 files_to_skip = (_EXCLUDED_PATHS +
3721 input_api.DEFAULT_FILES_TO_SKIP +
3722 (r"^base[\\/]memory[\\/]singleton\.h$",
3723 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3724 r"quic_singleton_impl\.h$"))
3725 return input_api.FilterSourceFile(affected_file,
3726 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433727
sergeyu34d21222015-09-16 00:11:443728 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433729 files = []
3730 for f in input_api.AffectedSourceFiles(FileFilter):
3731 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3732 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3733 contents = input_api.ReadFile(f)
3734 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243735 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433736 pattern.search(line)):
3737 files.append(f)
3738 break
3739
3740 if files:
yolandyandaabc6d2016-04-18 18:29:393741 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443742 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433743 'Please move them to an appropriate source file so that the ' +
3744 'template gets instantiated in a single compilation unit.',
3745 files) ]
3746 return []
3747
3748
[email protected]fd20b902014-05-09 02:14:533749_DEPRECATED_CSS = [
3750 # Values
3751 ( "-webkit-box", "flex" ),
3752 ( "-webkit-inline-box", "inline-flex" ),
3753 ( "-webkit-flex", "flex" ),
3754 ( "-webkit-inline-flex", "inline-flex" ),
3755 ( "-webkit-min-content", "min-content" ),
3756 ( "-webkit-max-content", "max-content" ),
3757
3758 # Properties
3759 ( "-webkit-background-clip", "background-clip" ),
3760 ( "-webkit-background-origin", "background-origin" ),
3761 ( "-webkit-background-size", "background-size" ),
3762 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443763 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533764
3765 # Functions
3766 ( "-webkit-gradient", "gradient" ),
3767 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3768 ( "-webkit-linear-gradient", "linear-gradient" ),
3769 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3770 ( "-webkit-radial-gradient", "radial-gradient" ),
3771 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3772]
3773
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203774
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493775# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363776def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533777 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253778 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343779 documentation and iOS CSS for dom distiller
3780 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253781 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533782 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493783 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443784 files_to_skip = (_EXCLUDED_PATHS +
3785 _TEST_CODE_EXCLUDED_PATHS +
3786 input_api.DEFAULT_FILES_TO_SKIP +
3787 (r"^chrome/common/extensions/docs",
3788 r"^chrome/docs",
3789 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3790 r"^components/neterror/resources/neterror.css",
3791 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253792 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443793 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533794 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3795 for line_num, line in fpath.ChangedContents():
3796 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023797 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533798 results.append(output_api.PresubmitError(
3799 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3800 (fpath.LocalPath(), line_num, deprecated_value, value)))
3801 return results
3802
mohan.reddyf21db962014-10-16 12:26:473803
Saagar Sanghavifceeaae2020-08-12 16:40:363804def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363805 bad_files = {}
3806 for f in input_api.AffectedFiles(include_deletes=False):
3807 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493808 not f.LocalPath().startswith('third_party/blink') and
3809 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363810 continue
3811
Daniel Bratell65b033262019-04-23 08:17:063812 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363813 continue
3814
Vaclav Brozekd5de76a2018-03-17 07:57:503815 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363816 if "#include" in line and "../" in line]
3817 if not relative_includes:
3818 continue
3819 bad_files[f.LocalPath()] = relative_includes
3820
3821 if not bad_files:
3822 return []
3823
3824 error_descriptions = []
3825 for file_path, bad_lines in bad_files.iteritems():
3826 error_description = file_path
3827 for line in bad_lines:
3828 error_description += '\n ' + line
3829 error_descriptions.append(error_description)
3830
3831 results = []
3832 results.append(output_api.PresubmitError(
3833 'You added one or more relative #include paths (including "../").\n'
3834 'These shouldn\'t be used because they can be used to include headers\n'
3835 'from code that\'s not correctly specified as a dependency in the\n'
3836 'relevant BUILD.gn file(s).',
3837 error_descriptions))
3838
3839 return results
3840
Takeshi Yoshinoe387aa32017-08-02 13:16:133841
Saagar Sanghavifceeaae2020-08-12 16:40:363842def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063843 """Check that nobody tries to include a cc file. It's a relatively
3844 common error which results in duplicate symbols in object
3845 files. This may not always break the build until someone later gets
3846 very confusing linking errors."""
3847 results = []
3848 for f in input_api.AffectedFiles(include_deletes=False):
3849 # We let third_party code do whatever it wants
3850 if (f.LocalPath().startswith('third_party') and
3851 not f.LocalPath().startswith('third_party/blink') and
3852 not f.LocalPath().startswith('third_party\\blink')):
3853 continue
3854
3855 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3856 continue
3857
3858 for _, line in f.ChangedContents():
3859 if line.startswith('#include "'):
3860 included_file = line.split('"')[1]
3861 if _IsCPlusPlusFile(input_api, included_file):
3862 # The most common naming for external files with C++ code,
3863 # apart from standard headers, is to call them foo.inc, but
3864 # Chromium sometimes uses foo-inc.cc so allow that as well.
3865 if not included_file.endswith(('.h', '-inc.cc')):
3866 results.append(output_api.PresubmitError(
3867 'Only header files or .inc files should be included in other\n'
3868 'C++ files. Compiling the contents of a cc file more than once\n'
3869 'will cause duplicate information in the build which may later\n'
3870 'result in strange link_errors.\n' +
3871 f.LocalPath() + ':\n ' +
3872 line))
3873
3874 return results
3875
3876
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203877def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3878 if not isinstance(key, ast.Str):
3879 return 'Key at line %d must be a string literal' % key.lineno
3880 if not isinstance(value, ast.Dict):
3881 return 'Value at line %d must be a dict' % value.lineno
3882 if len(value.keys) != 1:
3883 return 'Dict at line %d must have single entry' % value.lineno
3884 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3885 return (
3886 'Entry at line %d must have a string literal \'filepath\' as key' %
3887 value.lineno)
3888 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133889
Takeshi Yoshinoe387aa32017-08-02 13:16:133890
Sergey Ulanov4af16052018-11-08 02:41:463891def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203892 if not isinstance(key, ast.Str):
3893 return 'Key at line %d must be a string literal' % key.lineno
3894 if not isinstance(value, ast.List):
3895 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463896 for element in value.elts:
3897 if not isinstance(element, ast.Str):
3898 return 'Watchlist elements on line %d is not a string' % key.lineno
3899 if not email_regex.match(element.s):
3900 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3901 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203902 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133903
Takeshi Yoshinoe387aa32017-08-02 13:16:133904
Sergey Ulanov4af16052018-11-08 02:41:463905def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203906 mismatch_template = (
3907 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3908 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133909
Sergey Ulanov4af16052018-11-08 02:41:463910 email_regex = input_api.re.compile(
3911 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3912
3913 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203914 i = 0
3915 last_key = ''
3916 while True:
3917 if i >= len(wd_dict.keys):
3918 if i >= len(w_dict.keys):
3919 return None
3920 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3921 elif i >= len(w_dict.keys):
3922 return (
3923 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133924
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203925 wd_key = wd_dict.keys[i]
3926 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133927
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203928 result = _CheckWatchlistDefinitionsEntrySyntax(
3929 wd_key, wd_dict.values[i], ast)
3930 if result is not None:
3931 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133932
Sergey Ulanov4af16052018-11-08 02:41:463933 result = _CheckWatchlistsEntrySyntax(
3934 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203935 if result is not None:
3936 return 'Bad entry in WATCHLISTS dict: %s' % result
3937
3938 if wd_key.s != w_key.s:
3939 return mismatch_template % (
3940 '%s at line %d' % (wd_key.s, wd_key.lineno),
3941 '%s at line %d' % (w_key.s, w_key.lineno))
3942
3943 if wd_key.s < last_key:
3944 return (
3945 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3946 (wd_key.lineno, w_key.lineno))
3947 last_key = wd_key.s
3948
3949 i = i + 1
3950
3951
Sergey Ulanov4af16052018-11-08 02:41:463952def _CheckWATCHLISTSSyntax(expression, input_api):
3953 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203954 if not isinstance(expression, ast.Expression):
3955 return 'WATCHLISTS file must contain a valid expression'
3956 dictionary = expression.body
3957 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3958 return 'WATCHLISTS file must have single dict with exactly two entries'
3959
3960 first_key = dictionary.keys[0]
3961 first_value = dictionary.values[0]
3962 second_key = dictionary.keys[1]
3963 second_value = dictionary.values[1]
3964
3965 if (not isinstance(first_key, ast.Str) or
3966 first_key.s != 'WATCHLIST_DEFINITIONS' or
3967 not isinstance(first_value, ast.Dict)):
3968 return (
3969 'The first entry of the dict in WATCHLISTS file must be '
3970 'WATCHLIST_DEFINITIONS dict')
3971
3972 if (not isinstance(second_key, ast.Str) or
3973 second_key.s != 'WATCHLISTS' or
3974 not isinstance(second_value, ast.Dict)):
3975 return (
3976 'The second entry of the dict in WATCHLISTS file must be '
3977 'WATCHLISTS dict')
3978
Sergey Ulanov4af16052018-11-08 02:41:463979 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133980
3981
Saagar Sanghavifceeaae2020-08-12 16:40:363982def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133983 for f in input_api.AffectedFiles(include_deletes=False):
3984 if f.LocalPath() == 'WATCHLISTS':
3985 contents = input_api.ReadFile(f, 'r')
3986
3987 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203988 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133989 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203990 # Get an AST tree for it and scan the tree for detailed style checking.
3991 expression = input_api.ast.parse(
3992 contents, filename='WATCHLISTS', mode='eval')
3993 except ValueError as e:
3994 return [output_api.PresubmitError(
3995 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3996 except SyntaxError as e:
3997 return [output_api.PresubmitError(
3998 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3999 except TypeError as e:
4000 return [output_api.PresubmitError(
4001 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134002
Sergey Ulanov4af16052018-11-08 02:41:464003 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204004 if result is not None:
4005 return [output_api.PresubmitError(result)]
4006 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134007
4008 return []
4009
4010
Andrew Grieve1b290e4a22020-11-24 20:07:014011def CheckGnGlobForward(input_api, output_api):
4012 """Checks that forward_variables_from(invoker, "*") follows best practices.
4013
4014 As documented at //build/docs/writing_gn_templates.md
4015 """
4016 def gn_files(f):
4017 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
4018
4019 problems = []
4020 for f in input_api.AffectedSourceFiles(gn_files):
4021 for line_num, line in f.ChangedContents():
4022 if 'forward_variables_from(invoker, "*")' in line:
4023 problems.append(
4024 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
4025 f.LocalPath(), line_num))
4026
4027 if problems:
4028 return [output_api.PresubmitPromptWarning(
4029 'forward_variables_from("*") without exclusions',
4030 items=sorted(problems),
4031 long_text=('The variables "visibilty" and "test_only" should be '
4032 'explicitly listed in forward_variables_from(). For more '
4033 'details, see:\n'
4034 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4035 'build/docs/writing_gn_templates.md'
4036 '#Using-forward_variables_from'))]
4037 return []
4038
4039
Saagar Sanghavifceeaae2020-08-12 16:40:364040def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194041 """Checks that newly added header files have corresponding GN changes.
4042 Note that this is only a heuristic. To be precise, run script:
4043 build/check_gn_headers.py.
4044 """
4045
4046 def headers(f):
4047 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444048 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194049
4050 new_headers = []
4051 for f in input_api.AffectedSourceFiles(headers):
4052 if f.Action() != 'A':
4053 continue
4054 new_headers.append(f.LocalPath())
4055
4056 def gn_files(f):
James Cook24a504192020-07-23 00:08:444057 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194058
4059 all_gn_changed_contents = ''
4060 for f in input_api.AffectedSourceFiles(gn_files):
4061 for _, line in f.ChangedContents():
4062 all_gn_changed_contents += line
4063
4064 problems = []
4065 for header in new_headers:
4066 basename = input_api.os_path.basename(header)
4067 if basename not in all_gn_changed_contents:
4068 problems.append(header)
4069
4070 if problems:
4071 return [output_api.PresubmitPromptWarning(
4072 'Missing GN changes for new header files', items=sorted(problems),
4073 long_text='Please double check whether newly added header files need '
4074 'corresponding changes in gn or gni files.\nThis checking is only a '
4075 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4076 'Read https://crbug.com/661774 for more info.')]
4077 return []
4078
4079
Saagar Sanghavifceeaae2020-08-12 16:40:364080def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024081 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4082
4083 This assumes we won't intentionally reference one product from the other
4084 product.
4085 """
4086 all_problems = []
4087 test_cases = [{
4088 "filename_postfix": "google_chrome_strings.grd",
4089 "correct_name": "Chrome",
4090 "incorrect_name": "Chromium",
4091 }, {
4092 "filename_postfix": "chromium_strings.grd",
4093 "correct_name": "Chromium",
4094 "incorrect_name": "Chrome",
4095 }]
4096
4097 for test_case in test_cases:
4098 problems = []
4099 filename_filter = lambda x: x.LocalPath().endswith(
4100 test_case["filename_postfix"])
4101
4102 # Check each new line. Can yield false positives in multiline comments, but
4103 # easier than trying to parse the XML because messages can have nested
4104 # children, and associating message elements with affected lines is hard.
4105 for f in input_api.AffectedSourceFiles(filename_filter):
4106 for line_num, line in f.ChangedContents():
4107 if "<message" in line or "<!--" in line or "-->" in line:
4108 continue
4109 if test_case["incorrect_name"] in line:
4110 problems.append(
4111 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4112
4113 if problems:
4114 message = (
4115 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4116 % (test_case["correct_name"], test_case["correct_name"],
4117 test_case["incorrect_name"]))
4118 all_problems.append(
4119 output_api.PresubmitPromptWarning(message, items=problems))
4120
4121 return all_problems
4122
4123
Saagar Sanghavifceeaae2020-08-12 16:40:364124def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514125 # TODO(crbug.com/941824): We need to make sure the entries in
4126 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4127 # so that users of //buildtools in other projects get the same tooling
4128 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4129 # support to gclient, we can eliminate the duplication and delete
4130 # this presubmit check.
4131
4132 # Update this regexp if new revisions are added to the files.
4133 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264134 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514135
4136 # If a user is changing one revision, they need to change the same
4137 # line in both files. This means that any given change should contain
4138 # exactly the same list of changed lines that match the regexps. The
4139 # replace(' ', '') call allows us to ignore whitespace changes to the
4140 # lines. The 'long_text' parameter to the error will contain the
4141 # list of changed lines in both files, which should make it easy enough
4142 # to spot the error without going overboard in this implementation.
4143 revs_changes = {
4144 'DEPS': {},
4145 'buildtools/DEPS': {},
4146 }
4147 long_text = ''
4148
4149 for f in input_api.AffectedFiles(
4150 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4151 for line_num, line in f.ChangedContents():
4152 if rev_regexp.search(line):
4153 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4154 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4155
4156 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4157 return [output_api.PresubmitError(
4158 'Change buildtools revisions in sync in both //DEPS and '
4159 '//buildtools/DEPS.', long_text=long_text + '\n')]
4160 else:
4161 return []
4162
4163
Saagar Sanghavifceeaae2020-08-12 16:40:364164def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364165 """Avoid large files, especially binary files, in the repository since
4166 git doesn't scale well for those. They will be in everyone's repo
4167 clones forever, forever making Chromium slower to clone and work
4168 with."""
4169
4170 # Uploading files to cloud storage is not trivial so we don't want
4171 # to set the limit too low, but the upper limit for "normal" large
4172 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4173 # anything over 20 MB is exceptional.
4174 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4175
4176 too_large_files = []
4177 for f in input_api.AffectedFiles():
4178 # Check both added and modified files (but not deleted files).
4179 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384180 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364181 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4182 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4183
4184 if too_large_files:
4185 message = (
4186 'Do not commit large files to git since git scales badly for those.\n' +
4187 'Instead put the large files in cloud storage and use DEPS to\n' +
4188 'fetch them.\n' + '\n'.join(too_large_files)
4189 )
4190 return [output_api.PresubmitError(
4191 'Too large files found in commit', long_text=message + '\n')]
4192 else:
4193 return []
4194
Max Morozb47503b2019-08-08 21:03:274195
Saagar Sanghavifceeaae2020-08-12 16:40:364196def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274197 """Checks specific for fuzz target sources."""
4198 EXPORTED_SYMBOLS = [
4199 'LLVMFuzzerInitialize',
4200 'LLVMFuzzerCustomMutator',
4201 'LLVMFuzzerCustomCrossOver',
4202 'LLVMFuzzerMutate',
4203 ]
4204
4205 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4206
4207 def FilterFile(affected_file):
4208 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444209 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4210 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274211
4212 return input_api.FilterSourceFile(
4213 affected_file,
James Cook24a504192020-07-23 00:08:444214 files_to_check=[files_to_check],
4215 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274216
4217 files_with_missing_header = []
4218 for f in input_api.AffectedSourceFiles(FilterFile):
4219 contents = input_api.ReadFile(f, 'r')
4220 if REQUIRED_HEADER in contents:
4221 continue
4222
4223 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4224 files_with_missing_header.append(f.LocalPath())
4225
4226 if not files_with_missing_header:
4227 return []
4228
4229 long_text = (
4230 'If you define any of the libFuzzer optional functions (%s), it is '
4231 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4232 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4233 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4234 'to access command line arguments passed to the fuzzer. Instead, prefer '
4235 'static initialization and shared resources as documented in '
4236 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4237 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4238 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4239 )
4240
4241 return [output_api.PresubmitPromptWarning(
4242 message="Missing '%s' in:" % REQUIRED_HEADER,
4243 items=files_with_missing_header,
4244 long_text=long_text)]
4245
4246
Mohamed Heikald048240a2019-11-12 16:57:374247def _CheckNewImagesWarning(input_api, output_api):
4248 """
4249 Warns authors who add images into the repo to make sure their images are
4250 optimized before committing.
4251 """
4252 images_added = False
4253 image_paths = []
4254 errors = []
4255 filter_lambda = lambda x: input_api.FilterSourceFile(
4256 x,
James Cook24a504192020-07-23 00:08:444257 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4258 + input_api.DEFAULT_FILES_TO_SKIP),
4259 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374260 )
4261 for f in input_api.AffectedFiles(
4262 include_deletes=False, file_filter=filter_lambda):
4263 local_path = f.LocalPath().lower()
4264 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4265 images_added = True
4266 image_paths.append(f)
4267 if images_added:
4268 errors.append(output_api.PresubmitPromptWarning(
4269 'It looks like you are trying to commit some images. If these are '
4270 'non-test-only images, please make sure to read and apply the tips in '
4271 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4272 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4273 'FYI only and will not block your CL on the CQ.', image_paths))
4274 return errors
4275
4276
Saagar Sanghavifceeaae2020-08-12 16:40:364277def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574278 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224279 results = []
dgnaa68d5e2015-06-10 10:08:224280 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174281 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224282 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294283 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064284 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4285 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424286 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184287 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574288 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374289 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154290 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574291 return results
4292
Saagar Sanghavifceeaae2020-08-12 16:40:364293def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574294 """Groups commit checks that target android code."""
4295 results = []
4296 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224297 return results
4298
Chris Hall59f8d0c72020-05-01 07:31:194299# TODO(chrishall): could we additionally match on any path owned by
4300# ui/accessibility/OWNERS ?
4301_ACCESSIBILITY_PATHS = (
4302 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4303 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4304 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4305 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4306 r"^content[\\/]browser[\\/]accessibility[\\/]",
4307 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4308 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4309 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4310 r"^ui[\\/]accessibility[\\/]",
4311 r"^ui[\\/]views[\\/]accessibility[\\/]",
4312)
4313
Saagar Sanghavifceeaae2020-08-12 16:40:364314def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194315 """Checks that commits to accessibility code contain an AX-Relnotes field in
4316 their commit message."""
4317 def FileFilter(affected_file):
4318 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444319 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194320
4321 # Only consider changes affecting accessibility paths.
4322 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4323 return []
4324
Akihiro Ota08108e542020-05-20 15:30:534325 # AX-Relnotes can appear in either the description or the footer.
4326 # When searching the description, require 'AX-Relnotes:' to appear at the
4327 # beginning of a line.
4328 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4329 description_has_relnotes = any(ax_regex.match(line)
4330 for line in input_api.change.DescriptionText().lower().splitlines())
4331
4332 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4333 'AX-Relnotes', [])
4334 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194335 return []
4336
4337 # TODO(chrishall): link to Relnotes documentation in message.
4338 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4339 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4340 "user-facing changes"
4341 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4342 "user-facing effects"
4343 "\n if this is confusing or annoying then please contact members "
4344 "of ui/accessibility/OWNERS.")
4345
4346 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224347
Saagar Sanghavifceeaae2020-08-12 16:40:364348def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394349 """Checks common to both upload and commit."""
4350 results = []
4351 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384352 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544353 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084354
4355 author = input_api.change.author_email
4356 if author and author not in _KNOWN_ROBOTS:
4357 results.extend(
4358 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4359
[email protected]9f919cc2013-07-31 03:04:044360 results.extend(
4361 input_api.canned_checks.CheckChangeHasNoTabs(
4362 input_api,
4363 output_api,
4364 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434365 results.extend(input_api.RunTests(
4366 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244367
Edward Lesmesce51df52020-08-04 22:10:174368 dirmd_bin = input_api.os_path.join(
4369 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4370 results.extend(input_api.RunTests(
4371 input_api.canned_checks.CheckDirMetadataFormat(
4372 input_api, output_api, dirmd_bin)))
4373 results.extend(
4374 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4375 input_api, output_api))
4376
Vaclav Brozekcdc7defb2018-03-20 09:54:354377 for f in input_api.AffectedFiles():
4378 path, name = input_api.os_path.split(f.LocalPath())
4379 if name == 'PRESUBMIT.py':
4380 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004381 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4382 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074383 # The PRESUBMIT.py file (and the directory containing it) might
4384 # have been affected by being moved or removed, so only try to
4385 # run the tests if they still exist.
4386 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4387 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444388 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394389 return results
[email protected]1f7b4172010-01-28 01:17:344390
[email protected]b337cb5b2011-01-23 21:24:054391
Saagar Sanghavifceeaae2020-08-12 16:40:364392def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494393 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4394 if f.LocalPath().endswith(('.orig', '.rej'))]
4395 if problems:
4396 return [output_api.PresubmitError(
4397 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034398 else:
4399 return []
[email protected]b8079ae4a2012-12-05 19:56:494400
4401
Saagar Sanghavifceeaae2020-08-12 16:40:364402def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214403 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4404 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4405 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074406 include_re = input_api.re.compile(
4407 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4408 extension_re = input_api.re.compile(r'\.[a-z]+$')
4409 errors = []
4410 for f in input_api.AffectedFiles():
4411 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4412 continue
4413 found_line_number = None
4414 found_macro = None
4415 for line_num, line in f.ChangedContents():
4416 match = macro_re.search(line)
4417 if match:
4418 found_line_number = line_num
4419 found_macro = match.group(2)
4420 break
4421 if not found_line_number:
4422 continue
4423
4424 found_include = False
4425 for line in f.NewContents():
4426 if include_re.search(line):
4427 found_include = True
4428 break
4429 if found_include:
4430 continue
4431
4432 if not f.LocalPath().endswith('.h'):
4433 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4434 try:
4435 content = input_api.ReadFile(primary_header_path, 'r')
4436 if include_re.search(content):
4437 continue
4438 except IOError:
4439 pass
4440 errors.append('%s:%d %s macro is used without including build/'
4441 'build_config.h.'
4442 % (f.LocalPath(), found_line_number, found_macro))
4443 if errors:
4444 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4445 return []
4446
4447
[email protected]b00342e7f2013-03-26 16:21:544448def _DidYouMeanOSMacro(bad_macro):
4449 try:
4450 return {'A': 'OS_ANDROID',
4451 'B': 'OS_BSD',
4452 'C': 'OS_CHROMEOS',
4453 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444454 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544455 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444456 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544457 'N': 'OS_NACL',
4458 'O': 'OS_OPENBSD',
4459 'P': 'OS_POSIX',
4460 'S': 'OS_SOLARIS',
4461 'W': 'OS_WIN'}[bad_macro[3].upper()]
4462 except KeyError:
4463 return ''
4464
4465
4466def _CheckForInvalidOSMacrosInFile(input_api, f):
4467 """Check for sensible looking, totally invalid OS macros."""
4468 preprocessor_statement = input_api.re.compile(r'^\s*#')
4469 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4470 results = []
4471 for lnum, line in f.ChangedContents():
4472 if preprocessor_statement.search(line):
4473 for match in os_macro.finditer(line):
4474 if not match.group(1) in _VALID_OS_MACROS:
4475 good = _DidYouMeanOSMacro(match.group(1))
4476 did_you_mean = ' (did you mean %s?)' % good if good else ''
4477 results.append(' %s:%d %s%s' % (f.LocalPath(),
4478 lnum,
4479 match.group(1),
4480 did_you_mean))
4481 return results
4482
4483
Saagar Sanghavifceeaae2020-08-12 16:40:364484def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544485 """Check all affected files for invalid OS macros."""
4486 bad_macros = []
tzik3f295992018-12-04 20:32:234487 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474488 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544489 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4490
4491 if not bad_macros:
4492 return []
4493
4494 return [output_api.PresubmitError(
4495 'Possibly invalid OS macro[s] found. Please fix your code\n'
4496 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4497
lliabraa35bab3932014-10-01 12:16:444498
4499def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4500 """Check all affected files for invalid "if defined" macros."""
4501 ALWAYS_DEFINED_MACROS = (
4502 "TARGET_CPU_PPC",
4503 "TARGET_CPU_PPC64",
4504 "TARGET_CPU_68K",
4505 "TARGET_CPU_X86",
4506 "TARGET_CPU_ARM",
4507 "TARGET_CPU_MIPS",
4508 "TARGET_CPU_SPARC",
4509 "TARGET_CPU_ALPHA",
4510 "TARGET_IPHONE_SIMULATOR",
4511 "TARGET_OS_EMBEDDED",
4512 "TARGET_OS_IPHONE",
4513 "TARGET_OS_MAC",
4514 "TARGET_OS_UNIX",
4515 "TARGET_OS_WIN32",
4516 )
4517 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4518 results = []
4519 for lnum, line in f.ChangedContents():
4520 for match in ifdef_macro.finditer(line):
4521 if match.group(1) in ALWAYS_DEFINED_MACROS:
4522 always_defined = ' %s is always defined. ' % match.group(1)
4523 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4524 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4525 lnum,
4526 always_defined,
4527 did_you_mean))
4528 return results
4529
4530
Saagar Sanghavifceeaae2020-08-12 16:40:364531def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444532 """Check all affected files for invalid "if defined" macros."""
4533 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054534 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444535 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054536 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214537 continue
lliabraa35bab3932014-10-01 12:16:444538 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4539 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4540
4541 if not bad_macros:
4542 return []
4543
4544 return [output_api.PresubmitError(
4545 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4546 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4547 bad_macros)]
4548
4549
Saagar Sanghavifceeaae2020-08-12 16:40:364550def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044551 """Check for same IPC rules described in
4552 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4553 """
4554 base_pattern = r'IPC_ENUM_TRAITS\('
4555 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4556 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4557
4558 problems = []
4559 for f in input_api.AffectedSourceFiles(None):
4560 local_path = f.LocalPath()
4561 if not local_path.endswith('.h'):
4562 continue
4563 for line_number, line in f.ChangedContents():
4564 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4565 problems.append(
4566 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4567
4568 if problems:
4569 return [output_api.PresubmitPromptWarning(
4570 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4571 else:
4572 return []
4573
[email protected]b00342e7f2013-03-26 16:21:544574
Saagar Sanghavifceeaae2020-08-12 16:40:364575def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054576 """Check to make sure no files being submitted have long paths.
4577 This causes issues on Windows.
4578 """
4579 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194580 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054581 local_path = f.LocalPath()
4582 # Windows has a path limit of 260 characters. Limit path length to 200 so
4583 # that we have some extra for the prefix on dev machines and the bots.
4584 if len(local_path) > 200:
4585 problems.append(local_path)
4586
4587 if problems:
4588 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4589 else:
4590 return []
4591
4592
Saagar Sanghavifceeaae2020-08-12 16:40:364593def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144594 """Check that header files have proper guards against multiple inclusion.
4595 If a file should not have such guards (and it probably should) then it
4596 should include the string "no-include-guard-because-multiply-included".
4597 """
Daniel Bratell6a75baef62018-06-04 10:04:454598 def is_chromium_header_file(f):
4599 # We only check header files under the control of the Chromium
4600 # project. That is, those outside third_party apart from
4601 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324602 # We also exclude *_message_generator.h headers as they use
4603 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454604 file_with_path = input_api.os_path.normpath(f.LocalPath())
4605 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324606 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454607 (not file_with_path.startswith('third_party') or
4608 file_with_path.startswith(
4609 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144610
4611 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344612 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144613
4614 errors = []
4615
Daniel Bratell6a75baef62018-06-04 10:04:454616 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144617 guard_name = None
4618 guard_line_number = None
4619 seen_guard_end = False
4620
4621 file_with_path = input_api.os_path.normpath(f.LocalPath())
4622 base_file_name = input_api.os_path.splitext(
4623 input_api.os_path.basename(file_with_path))[0]
4624 upper_base_file_name = base_file_name.upper()
4625
4626 expected_guard = replace_special_with_underscore(
4627 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144628
4629 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574630 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4631 # are too many (1000+) files with slight deviations from the
4632 # coding style. The most important part is that the include guard
4633 # is there, and that it's unique, not the name so this check is
4634 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144635 #
4636 # As code becomes more uniform, this could be made stricter.
4637
4638 guard_name_pattern_list = [
4639 # Anything with the right suffix (maybe with an extra _).
4640 r'\w+_H__?',
4641
Daniel Bratell39b5b062018-05-16 18:09:574642 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144643 r'\w+_h',
4644
4645 # Anything including the uppercase name of the file.
4646 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4647 upper_base_file_name)) + r'\w*',
4648 ]
4649 guard_name_pattern = '|'.join(guard_name_pattern_list)
4650 guard_pattern = input_api.re.compile(
4651 r'#ifndef\s+(' + guard_name_pattern + ')')
4652
4653 for line_number, line in enumerate(f.NewContents()):
4654 if 'no-include-guard-because-multiply-included' in line:
4655 guard_name = 'DUMMY' # To not trigger check outside the loop.
4656 break
4657
4658 if guard_name is None:
4659 match = guard_pattern.match(line)
4660 if match:
4661 guard_name = match.group(1)
4662 guard_line_number = line_number
4663
Daniel Bratell39b5b062018-05-16 18:09:574664 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454665 # don't match the chromium style guide, but new files should
4666 # get it right.
4667 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574668 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144669 errors.append(output_api.PresubmitPromptWarning(
4670 'Header using the wrong include guard name %s' % guard_name,
4671 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574672 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144673 else:
4674 # The line after #ifndef should have a #define of the same name.
4675 if line_number == guard_line_number + 1:
4676 expected_line = '#define %s' % guard_name
4677 if line != expected_line:
4678 errors.append(output_api.PresubmitPromptWarning(
4679 'Missing "%s" for include guard' % expected_line,
4680 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4681 'Expected: %r\nGot: %r' % (expected_line, line)))
4682
4683 if not seen_guard_end and line == '#endif // %s' % guard_name:
4684 seen_guard_end = True
4685 elif seen_guard_end:
4686 if line.strip() != '':
4687 errors.append(output_api.PresubmitPromptWarning(
4688 'Include guard %s not covering the whole file' % (
4689 guard_name), [f.LocalPath()]))
4690 break # Nothing else to check and enough to warn once.
4691
4692 if guard_name is None:
4693 errors.append(output_api.PresubmitPromptWarning(
4694 'Missing include guard %s' % expected_guard,
4695 [f.LocalPath()],
4696 'Missing include guard in %s\n'
4697 'Recommended name: %s\n'
4698 'This check can be disabled by having the string\n'
4699 'no-include-guard-because-multiply-included in the header.' %
4700 (f.LocalPath(), expected_guard)))
4701
4702 return errors
4703
4704
Saagar Sanghavifceeaae2020-08-12 16:40:364705def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234706 """Check source code and known ascii text files for Windows style line
4707 endings.
4708 """
earthdok1b5e0ee2015-03-10 15:19:104709 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234710
4711 file_inclusion_pattern = (
4712 known_text_files,
4713 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4714 )
4715
mostynbb639aca52015-01-07 20:31:234716 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534717 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444718 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534719 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504720 include_file = False
4721 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234722 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504723 include_file = True
4724 if include_file:
4725 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234726
4727 if problems:
4728 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4729 'these files to contain Windows style line endings?\n' +
4730 '\n'.join(problems))]
4731
4732 return []
4733
4734
Saagar Sanghavifceeaae2020-08-12 16:40:364735def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134736 """Checks that all source files use SYSLOG properly."""
4737 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364738 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564739 for line_number, line in f.ChangedContents():
4740 if 'SYSLOG' in line:
4741 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4742
pastarmovj89f7ee12016-09-20 14:58:134743 if syslog_files:
4744 return [output_api.PresubmitPromptWarning(
4745 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4746 ' calls.\nFiles to check:\n', items=syslog_files)]
4747 return []
4748
4749
[email protected]1f7b4172010-01-28 01:17:344750def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364751 if input_api.version < [2, 0, 0]:
4752 return [output_api.PresubmitError("Your depot_tools is out of date. "
4753 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4754 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344755 results = []
scottmg39b29952014-12-08 18:31:284756 results.extend(
jam93a6ee792017-02-08 23:59:224757 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544758 return results
[email protected]ca8d1982009-02-19 16:33:124759
4760
[email protected]1bfb8322014-04-23 01:02:414761def GetTryServerMasterForBot(bot):
4762 """Returns the Try Server master for the given bot.
4763
[email protected]0bb112362014-07-26 04:38:324764 It tries to guess the master from the bot name, but may still fail
4765 and return None. There is no longer a default master.
4766 """
4767 # Potentially ambiguous bot names are listed explicitly.
4768 master_map = {
tandriie5587792016-07-14 00:34:504769 'chromium_presubmit': 'master.tryserver.chromium.linux',
4770 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414771 }
[email protected]0bb112362014-07-26 04:38:324772 master = master_map.get(bot)
4773 if not master:
wnwen4fbaab82016-05-25 12:54:364774 if 'android' in bot:
tandriie5587792016-07-14 00:34:504775 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364776 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504777 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324778 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504779 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324780 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504781 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324782 return master
[email protected]1bfb8322014-04-23 01:02:414783
4784
[email protected]ca8d1982009-02-19 16:33:124785def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364786 if input_api.version < [2, 0, 0]:
4787 return [output_api.PresubmitError("Your depot_tools is out of date. "
4788 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4789 "but your version is %d.%d.%d" % tuple(input_api.version))]
4790
[email protected]fe5f57c52009-06-05 14:25:544791 results = []
[email protected]fe5f57c52009-06-05 14:25:544792 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274793 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344794 input_api,
4795 output_api,
[email protected]2fdd1f362013-01-16 03:56:034796 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274797
jam93a6ee792017-02-08 23:59:224798 results.extend(
4799 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544800 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4801 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384802 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4803 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414804 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4805 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544806 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144807
4808
Saagar Sanghavifceeaae2020-08-12 16:40:364809def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264810 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024811 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4812 # footer is set to true.
4813 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264814 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024815 footer.lower()
4816 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264817 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024818
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144819 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264820 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144821 import sys
4822 from io import StringIO
4823
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144824 new_or_added_paths = set(f.LocalPath()
4825 for f in input_api.AffectedFiles()
4826 if (f.Action() == 'A' or f.Action() == 'M'))
4827 removed_paths = set(f.LocalPath()
4828 for f in input_api.AffectedFiles(include_deletes=True)
4829 if f.Action() == 'D')
4830
Andrew Grieve0e8790c2020-09-03 17:27:324831 affected_grds = [
4832 f for f in input_api.AffectedFiles()
4833 if f.LocalPath().endswith(('.grd', '.grdp'))
4834 ]
4835 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164836 if not affected_grds:
4837 return []
4838
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144839 affected_png_paths = [f.AbsoluteLocalPath()
4840 for f in input_api.AffectedFiles()
4841 if (f.LocalPath().endswith('.png'))]
4842
4843 # Check for screenshots. Developers can upload screenshots using
4844 # tools/translation/upload_screenshots.py which finds and uploads
4845 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4846 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4847 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4848 #
4849 # The logic here is as follows:
4850 #
4851 # - If the CL has a .png file under the screenshots directory for a grd
4852 # file, warn the developer. Actual images should never be checked into the
4853 # Chrome repo.
4854 #
4855 # - If the CL contains modified or new messages in grd files and doesn't
4856 # contain the corresponding .sha1 files, warn the developer to add images
4857 # and upload them via tools/translation/upload_screenshots.py.
4858 #
4859 # - If the CL contains modified or new messages in grd files and the
4860 # corresponding .sha1 files, everything looks good.
4861 #
4862 # - If the CL contains removed messages in grd files but the corresponding
4863 # .sha1 files aren't removed, warn the developer to remove them.
4864 unnecessary_screenshots = []
4865 missing_sha1 = []
4866 unnecessary_sha1_files = []
4867
Rainhard Findlingfc31844c52020-05-15 09:58:264868 # This checks verifies that the ICU syntax of messages this CL touched is
4869 # valid, and reports any found syntax errors.
4870 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4871 # without developers being aware of them. Later on, such ICU syntax errors
4872 # break message extraction for translation, hence would block Chromium
4873 # translations until they are fixed.
4874 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144875
4876 def _CheckScreenshotAdded(screenshots_dir, message_id):
4877 sha1_path = input_api.os_path.join(
4878 screenshots_dir, message_id + '.png.sha1')
4879 if sha1_path not in new_or_added_paths:
4880 missing_sha1.append(sha1_path)
4881
4882
4883 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4884 sha1_path = input_api.os_path.join(
4885 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034886 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144887 unnecessary_sha1_files.append(sha1_path)
4888
Rainhard Findlingfc31844c52020-05-15 09:58:264889
4890 def _ValidateIcuSyntax(text, level, signatures):
4891 """Validates ICU syntax of a text string.
4892
4893 Check if text looks similar to ICU and checks for ICU syntax correctness
4894 in this case. Reports various issues with ICU syntax and values of
4895 variants. Supports checking of nested messages. Accumulate information of
4896 each ICU messages found in the text for further checking.
4897
4898 Args:
4899 text: a string to check.
4900 level: a number of current nesting level.
4901 signatures: an accumulator, a list of tuple of (level, variable,
4902 kind, variants).
4903
4904 Returns:
4905 None if a string is not ICU or no issue detected.
4906 A tuple of (message, start index, end index) if an issue detected.
4907 """
4908 valid_types = {
4909 'plural': (frozenset(
4910 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4911 frozenset(['=1', 'other'])),
4912 'selectordinal': (frozenset(
4913 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4914 frozenset(['one', 'other'])),
4915 'select': (frozenset(), frozenset(['other'])),
4916 }
4917
4918 # Check if the message looks like an attempt to use ICU
4919 # plural. If yes - check if its syntax strictly matches ICU format.
4920 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4921 if not like:
4922 signatures.append((level, None, None, None))
4923 return
4924
4925 # Check for valid prefix and suffix
4926 m = re.match(
4927 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4928 r'(plural|selectordinal|select),\s*'
4929 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4930 if not m:
4931 return (('This message looks like an ICU plural, '
4932 'but does not follow ICU syntax.'), like.start(), like.end())
4933 starting, variable, kind, variant_pairs = m.groups()
4934 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4935 if depth:
4936 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4937 len(text))
4938 first = text[0]
4939 ending = text[last_pos:]
4940 if not starting:
4941 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4942 last_pos)
4943 if not ending or '}' not in ending:
4944 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4945 last_pos)
4946 elif first != '{':
4947 return (
4948 ('Invalid ICU format. Extra characters at the start of a complex '
4949 'message (go/icu-message-migration): "%s"') %
4950 starting, 0, len(starting))
4951 elif ending != '}':
4952 return (('Invalid ICU format. Extra characters at the end of a complex '
4953 'message (go/icu-message-migration): "%s"')
4954 % ending, last_pos - 1, len(text) - 1)
4955 if kind not in valid_types:
4956 return (('Unknown ICU message type %s. '
4957 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4958 known, required = valid_types[kind]
4959 defined_variants = set()
4960 for variant, variant_range, value, value_range in variants:
4961 start, end = variant_range
4962 if variant in defined_variants:
4963 return ('Variant "%s" is defined more than once' % variant,
4964 start, end)
4965 elif known and variant not in known:
4966 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4967 start, end)
4968 defined_variants.add(variant)
4969 # Check for nested structure
4970 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4971 if res:
4972 return (res[0], res[1] + value_range[0] + 1,
4973 res[2] + value_range[0] + 1)
4974 missing = required - defined_variants
4975 if missing:
4976 return ('Required variants missing: %s' % ', '.join(missing), 0,
4977 len(text))
4978 signatures.append((level, variable, kind, defined_variants))
4979
4980
4981 def _ParseIcuVariants(text, offset=0):
4982 """Parse variants part of ICU complex message.
4983
4984 Builds a tuple of variant names and values, as well as
4985 their offsets in the input string.
4986
4987 Args:
4988 text: a string to parse
4989 offset: additional offset to add to positions in the text to get correct
4990 position in the complete ICU string.
4991
4992 Returns:
4993 List of tuples, each tuple consist of four fields: variant name,
4994 variant name span (tuple of two integers), variant value, value
4995 span (tuple of two integers).
4996 """
4997 depth, start, end = 0, -1, -1
4998 variants = []
4999 key = None
5000 for idx, char in enumerate(text):
5001 if char == '{':
5002 if not depth:
5003 start = idx
5004 chunk = text[end + 1:start]
5005 key = chunk.strip()
5006 pos = offset + end + 1 + chunk.find(key)
5007 span = (pos, pos + len(key))
5008 depth += 1
5009 elif char == '}':
5010 if not depth:
5011 return variants, depth, offset + idx
5012 depth -= 1
5013 if not depth:
5014 end = idx
5015 variants.append((key, span, text[start:end + 1], (offset + start,
5016 offset + end + 1)))
5017 return variants, depth, offset + end + 1
5018
meacer8c0d3832019-12-26 21:46:165019 try:
5020 old_sys_path = sys.path
5021 sys.path = sys.path + [input_api.os_path.join(
5022 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5023 from helper import grd_helper
5024 finally:
5025 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145026
5027 for f in affected_grds:
5028 file_path = f.LocalPath()
5029 old_id_to_msg_map = {}
5030 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385031 # Note that this code doesn't check if the file has been deleted. This is
5032 # OK because it only uses the old and new file contents and doesn't load
5033 # the file via its path.
5034 # It's also possible that a file's content refers to a renamed or deleted
5035 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5036 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5037 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145038 if file_path.endswith('.grdp'):
5039 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585040 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395041 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145042 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585043 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395044 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145045 else:
meacerff8a9b62019-12-10 19:43:585046 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145047 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585048 old_id_to_msg_map = grd_helper.GetGrdMessages(
5049 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145050 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585051 new_id_to_msg_map = grd_helper.GetGrdMessages(
5052 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145053
Rainhard Findlingd8d04372020-08-13 13:30:095054 grd_name, ext = input_api.os_path.splitext(
5055 input_api.os_path.basename(file_path))
5056 screenshots_dir = input_api.os_path.join(
5057 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5058
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145059 # Compute added, removed and modified message IDs.
5060 old_ids = set(old_id_to_msg_map)
5061 new_ids = set(new_id_to_msg_map)
5062 added_ids = new_ids - old_ids
5063 removed_ids = old_ids - new_ids
5064 modified_ids = set([])
5065 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355066 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095067 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5068 # The message content itself changed. Require an updated screenshot.
5069 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355070 elif old_id_to_msg_map[key].attrs['meaning'] != \
5071 new_id_to_msg_map[key].attrs['meaning']:
5072 # The message meaning changed. Ensure there is a screenshot for it.
5073 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5074 if sha1_path not in new_or_added_paths and not \
5075 input_api.os_path.exists(sha1_path):
5076 # There is neither a previous screenshot nor is a new one added now.
5077 # Require a screenshot.
5078 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145079
Rainhard Findlingfc31844c52020-05-15 09:58:265080 if run_screenshot_check:
5081 # Check the screenshot directory for .png files. Warn if there is any.
5082 for png_path in affected_png_paths:
5083 if png_path.startswith(screenshots_dir):
5084 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145085
Rainhard Findlingfc31844c52020-05-15 09:58:265086 for added_id in added_ids:
5087 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145088
Rainhard Findlingfc31844c52020-05-15 09:58:265089 for modified_id in modified_ids:
5090 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145091
Rainhard Findlingfc31844c52020-05-15 09:58:265092 for removed_id in removed_ids:
5093 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5094
5095 # Check new and changed strings for ICU syntax errors.
5096 for key in added_ids.union(modified_ids):
5097 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5098 err = _ValidateIcuSyntax(msg, 0, [])
5099 if err is not None:
5100 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145101
5102 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265103 if run_screenshot_check:
5104 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005105 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265106 'Do not include actual screenshots in the changelist. Run '
5107 'tools/translate/upload_screenshots.py to upload them instead:',
5108 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145109
Rainhard Findlingfc31844c52020-05-15 09:58:265110 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005111 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265112 'You are adding or modifying UI strings.\n'
5113 'To ensure the best translations, take screenshots of the relevant UI '
5114 '(https://g.co/chrome/translation) and add these files to your '
5115 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145116
Rainhard Findlingfc31844c52020-05-15 09:58:265117 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005118 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265119 'You removed strings associated with these files. Remove:',
5120 sorted(unnecessary_sha1_files)))
5121 else:
5122 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5123 'screenshots check.'))
5124
5125 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075126 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265127 'ICU syntax errors were found in the following strings (problems or '
5128 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145129
5130 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125131
5132
Saagar Sanghavifceeaae2020-08-12 16:40:365133def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125134 repo_root=None,
5135 translation_expectations_path=None,
5136 grd_files=None):
5137 import sys
5138 affected_grds = [f for f in input_api.AffectedFiles()
5139 if (f.LocalPath().endswith('.grd') or
5140 f.LocalPath().endswith('.grdp'))]
5141 if not affected_grds:
5142 return []
5143
5144 try:
5145 old_sys_path = sys.path
5146 sys.path = sys.path + [
5147 input_api.os_path.join(
5148 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5149 from helper import git_helper
5150 from helper import translation_helper
5151 finally:
5152 sys.path = old_sys_path
5153
5154 # Check that translation expectations can be parsed and we can get a list of
5155 # translatable grd files. |repo_root| and |translation_expectations_path| are
5156 # only passed by tests.
5157 if not repo_root:
5158 repo_root = input_api.PresubmitLocalPath()
5159 if not translation_expectations_path:
5160 translation_expectations_path = input_api.os_path.join(
5161 repo_root, 'tools', 'gritsettings',
5162 'translation_expectations.pyl')
5163 if not grd_files:
5164 grd_files = git_helper.list_grds_in_repository(repo_root)
5165
dpapad8e21b472020-10-23 17:15:035166 # Ignore bogus grd files used only for testing
5167 # ui/webui/resoucres/tools/generate_grd.py.
5168 ignore_path = input_api.os_path.join(
5169 'ui', 'webui', 'resources', 'tools', 'tests')
5170 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5171
Mustafa Emre Acer51f2f742020-03-09 19:41:125172 try:
5173 translation_helper.get_translatable_grds(repo_root, grd_files,
5174 translation_expectations_path)
5175 except Exception as e:
5176 return [output_api.PresubmitNotifyResult(
5177 'Failed to get a list of translatable grd files. This happens when:\n'
5178 ' - One of the modified grd or grdp files cannot be parsed or\n'
5179 ' - %s is not updated.\n'
5180 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5181 return []
Ken Rockotc31f4832020-05-29 18:58:515182
5183
Saagar Sanghavifceeaae2020-08-12 16:40:365184def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515185 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095186 changed_mojoms = input_api.AffectedFiles(
5187 include_deletes=True,
5188 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515189 delta = []
5190 for mojom in changed_mojoms:
5191 old_contents = ''.join(mojom.OldContents()) or None
5192 new_contents = ''.join(mojom.NewContents()) or None
5193 delta.append({
5194 'filename': mojom.LocalPath(),
5195 'old': '\n'.join(mojom.OldContents()) or None,
5196 'new': '\n'.join(mojom.NewContents()) or None,
5197 })
5198
5199 process = input_api.subprocess.Popen(
5200 [input_api.python_executable,
5201 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5202 'public', 'tools', 'mojom',
5203 'check_stable_mojom_compatibility.py'),
5204 '--src-root', input_api.PresubmitLocalPath()],
5205 stdin=input_api.subprocess.PIPE,
5206 stdout=input_api.subprocess.PIPE,
5207 stderr=input_api.subprocess.PIPE,
5208 universal_newlines=True)
5209 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5210 if process.returncode:
5211 return [output_api.PresubmitError(
5212 'One or more [Stable] mojom definitions appears to have been changed '
5213 'in a way that is not backward-compatible.',
5214 long_text=error)]
5215 return []
Dominic Battre645d42342020-12-04 16:14:105216
5217def CheckDeprecationOfPreferences(input_api, output_api):
5218 """Removing a preference should come with a deprecation."""
5219
5220 def FilterFile(affected_file):
5221 """Accept only .cc files and the like."""
5222 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5223 files_to_skip = (_EXCLUDED_PATHS +
5224 _TEST_CODE_EXCLUDED_PATHS +
5225 input_api.DEFAULT_FILES_TO_SKIP)
5226 return input_api.FilterSourceFile(
5227 affected_file,
5228 files_to_check=file_inclusion_pattern,
5229 files_to_skip=files_to_skip)
5230
5231 def ModifiedLines(affected_file):
5232 """Returns a list of tuples (line number, line text) of added and removed
5233 lines.
5234
5235 Deleted lines share the same line number as the previous line.
5236
5237 This relies on the scm diff output describing each changed code section
5238 with a line of the form
5239
5240 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5241 """
5242 line_num = 0
5243 modified_lines = []
5244 for line in affected_file.GenerateScmDiff().splitlines():
5245 # Extract <new line num> of the patch fragment (see format above).
5246 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5247 if m:
5248 line_num = int(m.groups(1)[0])
5249 continue
5250 if ((line.startswith('+') and not line.startswith('++')) or
5251 (line.startswith('-') and not line.startswith('--'))):
5252 modified_lines.append((line_num, line))
5253
5254 if not line.startswith('-'):
5255 line_num += 1
5256 return modified_lines
5257
5258 def FindLineWith(lines, needle):
5259 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5260
5261 If 0 or >1 lines contain `needle`, -1 is returned.
5262 """
5263 matching_line_numbers = [
5264 # + 1 for 1-based counting of line numbers.
5265 i + 1 for i, line
5266 in enumerate(lines)
5267 if needle in line]
5268 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5269
5270 def ModifiedPrefMigration(affected_file):
5271 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5272 # Determine first and last lines of MigrateObsolete.*Pref functions.
5273 new_contents = affected_file.NewContents();
5274 range_1 = (
5275 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5276 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5277 range_2 = (
5278 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5279 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5280 if (-1 in range_1 + range_2):
5281 raise Exception(
5282 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5283
5284 # Check whether any of the modified lines are part of the
5285 # MigrateObsolete.*Pref functions.
5286 for line_nr, line in ModifiedLines(affected_file):
5287 if (range_1[0] <= line_nr <= range_1[1] or
5288 range_2[0] <= line_nr <= range_2[1]):
5289 return True
5290 return False
5291
5292 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5293 browser_prefs_file_pattern = input_api.re.compile(
5294 r'chrome/browser/prefs/browser_prefs.cc')
5295
5296 changes = input_api.AffectedFiles(include_deletes=True,
5297 file_filter=FilterFile)
5298 potential_problems = []
5299 for f in changes:
5300 for line in f.GenerateScmDiff().splitlines():
5301 # Check deleted lines for pref registrations.
5302 if (line.startswith('-') and not line.startswith('--') and
5303 register_pref_pattern.search(line)):
5304 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5305
5306 if browser_prefs_file_pattern.search(f.LocalPath()):
5307 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5308 # assume that they knew that they have to deprecate preferences and don't
5309 # warn.
5310 try:
5311 if ModifiedPrefMigration(f):
5312 return []
5313 except Exception as e:
5314 return [output_api.PresubmitError(str(e))]
5315
5316 if potential_problems:
5317 return [output_api.PresubmitPromptWarning(
5318 'Discovered possible removal of preference registrations.\n\n'
5319 'Please make sure to properly deprecate preferences by clearing their\n'
5320 'value for a couple of milestones before finally removing the code.\n'
5321 'Otherwise data may stay in the preferences files forever. See\n'
5322 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5323 'This may be a false positive warning (e.g. if you move preference\n'
5324 'registrations to a different place).\n',
5325 potential_problems
5326 )]
5327 return []