blob: 4f3456ca000116d44b5cb7ce8fbdebde5a883b26 [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/',
Alexander Cooper922f2112020-07-22 16:27:43377 '^google_apis/drive/',
Daniel Hosseinian41af1882020-10-29 23:10:10378 '^media/blink/',
Daniel Hosseinian41af1882020-10-29 23:10:10379 '^media/cdm/',
Steve Kobes334b6ed2020-07-09 07:26:31380 '^net/http/',
381 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51382 '^ppapi/proxy/',
danakj7a2b7082019-05-21 21:13:51383 '^services/',
danakj7a2b7082019-05-21 21:13:51384 '^tools/clang/base_bind_rewriters/', # Intentional.
385 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51386))
[email protected]127f18ec2012-06-16 05:05:59387
Daniel Bratell609102be2019-03-27 20:53:21388# Format: Sequence of tuples containing:
389# * String pattern or, if starting with a slash, a regular expression.
390# * Sequence of strings to show when the pattern matches.
391# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
392# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59393_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20394 (
Dave Tapuska98199b612019-07-10 13:30:44395 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53396 (
397 'New code should not use NULL. Use nullptr instead.',
398 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20399 False,
thomasandersone7caaa9b2017-03-29 19:22:53400 (),
401 ),
Peter Kasting94a56c42019-10-25 21:54:04402 (
403 r'/\busing namespace ',
404 (
405 'Using directives ("using namespace x") are banned by the Google Style',
406 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
407 'Explicitly qualify symbols or use using declarations ("using x::foo").',
408 ),
409 True,
410 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
411 ),
Antonio Gomes07300d02019-03-13 20:59:57412 # Make sure that gtest's FRIEND_TEST() macro is not used; the
413 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
414 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53415 (
[email protected]23e6cbc2012-06-16 18:51:20416 'FRIEND_TEST(',
417 (
[email protected]e3c945502012-06-26 20:01:49418 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20419 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
420 ),
421 False,
[email protected]7345da02012-11-27 14:31:49422 (),
[email protected]23e6cbc2012-06-16 18:51:20423 ),
424 (
tomhudsone2c14d552016-05-26 17:07:46425 'setMatrixClip',
426 (
427 'Overriding setMatrixClip() is prohibited; ',
428 'the base function is deprecated. ',
429 ),
430 True,
431 (),
432 ),
433 (
[email protected]52657f62013-05-20 05:30:31434 'SkRefPtr',
435 (
436 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22437 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31438 ),
439 True,
440 (),
441 ),
442 (
443 'SkAutoRef',
444 (
445 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22446 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31447 ),
448 True,
449 (),
450 ),
451 (
452 'SkAutoTUnref',
453 (
454 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22455 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31456 ),
457 True,
458 (),
459 ),
460 (
461 'SkAutoUnref',
462 (
463 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
464 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22465 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31466 ),
467 True,
468 (),
469 ),
[email protected]d89eec82013-12-03 14:10:59470 (
471 r'/HANDLE_EINTR\(.*close',
472 (
473 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
474 'descriptor will be closed, and it is incorrect to retry the close.',
475 'Either call close directly and ignore its return value, or wrap close',
476 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
477 ),
478 True,
479 (),
480 ),
481 (
482 r'/IGNORE_EINTR\((?!.*close)',
483 (
484 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
485 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
486 ),
487 True,
488 (
489 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04490 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
491 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59492 ),
493 ),
[email protected]ec5b3f02014-04-04 18:43:43494 (
495 r'/v8::Extension\(',
496 (
497 'Do not introduce new v8::Extensions into the code base, use',
498 'gin::Wrappable instead. See http://crbug.com/334679',
499 ),
500 True,
[email protected]f55c90ee62014-04-12 00:50:03501 (
Egor Paskoce145c42018-09-28 19:31:04502 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03503 ),
[email protected]ec5b3f02014-04-04 18:43:43504 ),
skyostilf9469f72015-04-20 10:38:52505 (
jame2d1a952016-04-02 00:27:10506 '#pragma comment(lib,',
507 (
508 'Specify libraries to link with in build files and not in the source.',
509 ),
510 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41511 (
tzik3f295992018-12-04 20:32:23512 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04513 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41514 ),
jame2d1a952016-04-02 00:27:10515 ),
fdorayc4ac18d2017-05-01 21:39:59516 (
Gabriel Charette7cc6c432018-04-25 20:52:02517 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59518 (
519 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
520 ),
521 False,
522 (),
523 ),
524 (
Gabriel Charette7cc6c432018-04-25 20:52:02525 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59526 (
527 'Consider using THREAD_CHECKER macros instead of the class directly.',
528 ),
529 False,
530 (),
531 ),
dbeamb6f4fde2017-06-15 04:03:06532 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06533 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
534 (
535 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
536 'deprecated (http://crbug.com/634507). Please avoid converting away',
537 'from the Time types in Chromium code, especially if any math is',
538 'being done on time values. For interfacing with platform/library',
539 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
540 'type converter methods instead. For faking TimeXXX values (for unit',
541 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
542 'other use cases, please contact base/time/OWNERS.',
543 ),
544 False,
545 (),
546 ),
547 (
dbeamb6f4fde2017-06-15 04:03:06548 'CallJavascriptFunctionUnsafe',
549 (
550 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
551 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
552 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
553 ),
554 False,
555 (
Egor Paskoce145c42018-09-28 19:31:04556 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
557 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
558 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06559 ),
560 ),
dskiba1474c2bfd62017-07-20 02:19:24561 (
562 'leveldb::DB::Open',
563 (
564 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
565 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
566 "Chrome's tracing, making their memory usage visible.",
567 ),
568 True,
569 (
570 r'^third_party/leveldatabase/.*\.(cc|h)$',
571 ),
Gabriel Charette0592c3a2017-07-26 12:02:04572 ),
573 (
Chris Mumfordc38afb62017-10-09 17:55:08574 'leveldb::NewMemEnv',
575 (
576 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58577 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
578 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08579 ),
580 True,
581 (
582 r'^third_party/leveldatabase/.*\.(cc|h)$',
583 ),
584 ),
585 (
Gabriel Charetted9839bc2017-07-29 14:17:47586 'RunLoop::QuitCurrent',
587 (
Robert Liao64b7ab22017-08-04 23:03:43588 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
589 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47590 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41591 False,
Gabriel Charetted9839bc2017-07-29 14:17:47592 (),
Gabriel Charettea44975052017-08-21 23:14:04593 ),
594 (
595 'base::ScopedMockTimeMessageLoopTaskRunner',
596 (
Gabriel Charette87cc1af2018-04-25 20:52:51597 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11598 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51599 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
600 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
601 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04602 ),
Gabriel Charette87cc1af2018-04-25 20:52:51603 False,
Gabriel Charettea44975052017-08-21 23:14:04604 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57605 ),
606 (
Dave Tapuska98199b612019-07-10 13:30:44607 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57608 (
609 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02610 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57611 ),
612 True,
613 (),
Francois Doray43670e32017-09-27 12:40:38614 ),
615 (
Peter Kasting991618a62019-06-17 22:00:09616 r'/\bstd::stoi\b',
617 (
618 'std::stoi uses exceptions to communicate results. ',
619 'Use base::StringToInt() instead.',
620 ),
621 True,
622 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
623 ),
624 (
625 r'/\bstd::stol\b',
626 (
627 'std::stol uses exceptions to communicate results. ',
628 'Use base::StringToInt() instead.',
629 ),
630 True,
631 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
632 ),
633 (
634 r'/\bstd::stoul\b',
635 (
636 'std::stoul uses exceptions to communicate results. ',
637 'Use base::StringToUint() instead.',
638 ),
639 True,
640 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
641 ),
642 (
643 r'/\bstd::stoll\b',
644 (
645 'std::stoll uses exceptions to communicate results. ',
646 'Use base::StringToInt64() instead.',
647 ),
648 True,
649 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
650 ),
651 (
652 r'/\bstd::stoull\b',
653 (
654 'std::stoull uses exceptions to communicate results. ',
655 'Use base::StringToUint64() instead.',
656 ),
657 True,
658 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
659 ),
660 (
661 r'/\bstd::stof\b',
662 (
663 'std::stof uses exceptions to communicate results. ',
664 'For locale-independent values, e.g. reading numbers from disk',
665 'profiles, use base::StringToDouble().',
666 'For user-visible values, parse using ICU.',
667 ),
668 True,
669 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
670 ),
671 (
672 r'/\bstd::stod\b',
673 (
674 'std::stod uses exceptions to communicate results. ',
675 'For locale-independent values, e.g. reading numbers from disk',
676 'profiles, use base::StringToDouble().',
677 'For user-visible values, parse using ICU.',
678 ),
679 True,
680 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
681 ),
682 (
683 r'/\bstd::stold\b',
684 (
685 'std::stold uses exceptions to communicate results. ',
686 'For locale-independent values, e.g. reading numbers from disk',
687 'profiles, use base::StringToDouble().',
688 'For user-visible values, parse using ICU.',
689 ),
690 True,
691 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
692 ),
693 (
Daniel Bratell69334cc2019-03-26 11:07:45694 r'/\bstd::to_string\b',
695 (
696 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09697 'For locale-independent strings, e.g. writing numbers to disk',
698 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45699 'For user-visible strings, use base::FormatNumber() and',
700 'the related functions in base/i18n/number_formatting.h.',
701 ),
Peter Kasting991618a62019-06-17 22:00:09702 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21703 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45704 ),
705 (
706 r'/\bstd::shared_ptr\b',
707 (
708 'std::shared_ptr should not be used. Use scoped_refptr instead.',
709 ),
710 True,
Alex Chau9eb03cdd52020-07-13 21:04:57711 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
712 'array_buffer_contents\.(cc|h)',
713 # Needed for interop with third-party library
714 'chrome/services/sharing/nearby/',
715 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21716 ),
717 (
Peter Kasting991618a62019-06-17 22:00:09718 r'/\bstd::weak_ptr\b',
719 (
720 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
721 ),
722 True,
723 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
724 ),
725 (
Daniel Bratell609102be2019-03-27 20:53:21726 r'/\blong long\b',
727 (
728 'long long is banned. Use stdint.h if you need a 64 bit number.',
729 ),
730 False, # Only a warning since it is already used.
731 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
732 ),
733 (
734 r'/\bstd::bind\b',
735 (
736 'std::bind is banned because of lifetime risks.',
737 'Use base::BindOnce or base::BindRepeating instead.',
738 ),
739 True,
740 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
741 ),
742 (
743 r'/\b#include <chrono>\b',
744 (
745 '<chrono> overlaps with Time APIs in base. Keep using',
746 'base classes.',
747 ),
748 True,
749 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
750 ),
751 (
752 r'/\b#include <exception>\b',
753 (
754 'Exceptions are banned and disabled in Chromium.',
755 ),
756 True,
757 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
758 ),
759 (
760 r'/\bstd::function\b',
761 (
762 'std::function is banned. Instead use base::Callback which directly',
763 'supports Chromium\'s weak pointers, ref counting and more.',
764 ),
Peter Kasting991618a62019-06-17 22:00:09765 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21766 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
767 ),
768 (
769 r'/\b#include <random>\b',
770 (
771 'Do not use any random number engines from <random>. Instead',
772 'use base::RandomBitGenerator.',
773 ),
774 True,
775 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
776 ),
777 (
Tom Andersona95e12042020-09-09 23:08:00778 r'/\b#include <X11/',
779 (
780 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
781 ),
782 True,
783 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
784 ),
785 (
Daniel Bratell609102be2019-03-27 20:53:21786 r'/\bstd::ratio\b',
787 (
788 'std::ratio is banned by the Google Style Guide.',
789 ),
790 True,
791 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45792 ),
793 (
Francois Doray43670e32017-09-27 12:40:38794 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
795 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
796 (
797 'Use the new API in base/threading/thread_restrictions.h.',
798 ),
Gabriel Charette04b138f2018-08-06 00:03:22799 False,
Francois Doray43670e32017-09-27 12:40:38800 (),
801 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38802 (
danakj7a2b7082019-05-21 21:13:51803 r'/\bbase::Bind\(',
804 (
805 'Please use base::Bind{Once,Repeating} instead',
806 'of base::Bind. (crbug.com/714018)',
807 ),
808 False,
Erik Staaba737d7602019-11-25 18:41:07809 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51810 ),
811 (
812 r'/\bbase::Callback[<:]',
813 (
814 'Please use base::{Once,Repeating}Callback instead',
815 'of base::Callback. (crbug.com/714018)',
816 ),
817 False,
Erik Staaba737d7602019-11-25 18:41:07818 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51819 ),
820 (
821 r'/\bbase::Closure\b',
822 (
823 'Please use base::{Once,Repeating}Closure instead',
824 'of base::Closure. (crbug.com/714018)',
825 ),
826 False,
Erik Staaba737d7602019-11-25 18:41:07827 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51828 ),
829 (
Alex Turnerb3ea38c2020-11-25 18:03:07830 r'/\bbase::CancelableCallback[<:]',
831 (
832 'Please use base::Cancelable{Once,Repeating}Callback instead',
833 'of base::CancelableCallback. (crbug.com/714018)',
834 ),
835 False,
836 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
837 ),
838 (
839 r'/\bbase::CancelableClosure\b',
840 (
841 'Please use base::Cancelable{Once,Repeating}Closure instead',
842 'of base::CancelableClosure. (crbug.com/714018)',
843 ),
844 False,
845 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
846 ),
847 (
Michael Giuffrida7f93d6922019-04-19 14:39:58848 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19849 (
850 'RunMessageLoop is deprecated, use RunLoop instead.',
851 ),
852 False,
853 (),
854 ),
855 (
Dave Tapuska98199b612019-07-10 13:30:44856 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19857 (
858 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
859 ),
860 False,
861 (),
862 ),
863 (
Dave Tapuska98199b612019-07-10 13:30:44864 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19865 (
866 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
867 "if you're convinced you need this.",
868 ),
869 False,
870 (),
871 ),
872 (
Dave Tapuska98199b612019-07-10 13:30:44873 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19874 (
875 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04876 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19877 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
878 'async events instead of flushing threads.',
879 ),
880 False,
881 (),
882 ),
883 (
884 r'MessageLoopRunner',
885 (
886 'MessageLoopRunner is deprecated, use RunLoop instead.',
887 ),
888 False,
889 (),
890 ),
891 (
Dave Tapuska98199b612019-07-10 13:30:44892 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19893 (
894 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
895 "gab@ if you found a use case where this is the only solution.",
896 ),
897 False,
898 (),
899 ),
900 (
Victor Costane48a2e82019-03-15 22:02:34901 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16902 (
Victor Costane48a2e82019-03-15 22:02:34903 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16904 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
905 ),
906 True,
907 (
908 r'^sql/initialization\.(cc|h)$',
909 r'^third_party/sqlite/.*\.(c|cc|h)$',
910 ),
911 ),
Matt Menke7f520a82018-03-28 21:38:37912 (
Dave Tapuska98199b612019-07-10 13:30:44913 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47914 (
915 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
916 'base::RandomShuffle instead.'
917 ),
918 True,
919 (),
920 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24921 (
922 'ios/web/public/test/http_server',
923 (
924 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
925 ),
926 False,
927 (),
928 ),
Robert Liao764c9492019-01-24 18:46:28929 (
930 'GetAddressOf',
931 (
932 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53933 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11934 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53935 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28936 ),
937 True,
938 (),
939 ),
Antonio Gomes07300d02019-03-13 20:59:57940 (
941 'DEFINE_TYPE_CASTS',
942 (
943 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
944 '//third_party/blink/renderer/platform/casting.h.'
945 ),
946 True,
947 (
948 r'^third_party/blink/renderer/.*\.(cc|h)$',
949 ),
950 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38951 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45952 r'/\bIsHTML.+Element\(\b',
953 (
954 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
955 ' helpers IsA<HTMLXXXXElement> from ',
956 '//third_party/blink/renderer/platform/casting.h.'
957 ),
958 False,
959 (
960 r'^third_party/blink/renderer/.*\.(cc|h)$',
961 ),
962 ),
963 (
964 r'/\bToHTML.+Element(|OrNull)\(\b',
965 (
966 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
967 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
968 'and DynamicTo<HTMLXXXXElement> from ',
969 '//third_party/blink/renderer/platform/casting.h.'
970 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
971 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
972 ),
973 False,
974 (
975 r'^third_party/blink/renderer/.*\.(cc|h)$',
976 ),
977 ),
978 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37979 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38980 (
981 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
982 ),
983 True,
984 (),
985 ),
Ben Lewisa9514602019-04-29 17:53:05986 (
987 'SHFileOperation',
988 (
989 'SHFileOperation was deprecated in Windows Vista, and there are less ',
990 'complex functions to achieve the same goals. Use IFileOperation for ',
991 'any esoteric actions instead.'
992 ),
993 True,
994 (),
995 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18996 (
Cliff Smolinsky81951642019-04-30 21:39:51997 'StringFromGUID2',
998 (
999 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241000 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511001 ),
1002 True,
1003 (
1004 r'/base/win/win_util_unittest.cc'
1005 ),
1006 ),
1007 (
1008 'StringFromCLSID',
1009 (
1010 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241011 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511012 ),
1013 True,
1014 (
1015 r'/base/win/win_util_unittest.cc'
1016 ),
1017 ),
1018 (
Avi Drissman7382afa02019-04-29 23:27:131019 'kCFAllocatorNull',
1020 (
1021 'The use of kCFAllocatorNull with the NoCopy creation of ',
1022 'CoreFoundation types is prohibited.',
1023 ),
1024 True,
1025 (),
1026 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291027 (
1028 'mojo::ConvertTo',
1029 (
1030 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1031 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1032 'StringTraits if you would like to convert between custom types and',
1033 'the wire format of mojom types.'
1034 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221035 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291036 (
Wezf89dec092019-09-11 19:38:331037 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1038 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291039 r'^third_party/blink/.*\.(cc|h)$',
1040 r'^content/renderer/.*\.(cc|h)$',
1041 ),
1042 ),
Robert Liao1d78df52019-11-11 20:02:011043 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161044 'GetInterfaceProvider',
1045 (
1046 'InterfaceProvider is deprecated.',
1047 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1048 'or Platform::GetBrowserInterfaceBroker.'
1049 ),
1050 False,
1051 (),
1052 ),
1053 (
Robert Liao1d78df52019-11-11 20:02:011054 'CComPtr',
1055 (
1056 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1057 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1058 'details.'
1059 ),
1060 False,
1061 (),
1062 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201063 (
1064 r'/\b(IFACE|STD)METHOD_?\(',
1065 (
1066 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1067 'Instead, always use IFACEMETHODIMP in the declaration.'
1068 ),
1069 False,
1070 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1071 ),
Allen Bauer53b43fb12020-03-12 17:21:471072 (
1073 'set_owned_by_client',
1074 (
1075 'set_owned_by_client is deprecated.',
1076 'views::View already owns the child views by default. This introduces ',
1077 'a competing ownership model which makes the code difficult to reason ',
1078 'about. See http://crbug.com/1044687 for more details.'
1079 ),
1080 False,
1081 (),
1082 ),
Eric Secklerbe6f48d2020-05-06 18:09:121083 (
1084 r'/\bTRACE_EVENT_ASYNC_',
1085 (
1086 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1087 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1088 ),
1089 False,
1090 (
1091 r'^base/trace_event/.*',
1092 r'^base/tracing/.*',
1093 ),
1094 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:261095 (
1096 r'/\bScopedObserver',
1097 (
1098 'ScopedObserver is deprecated.',
1099 'Please use base::ScopedObservation for observing a single source,',
1100 'or base::ScopedMultiSourceObservation for observing multple sources',
1101 ),
1102 False,
1103 (),
1104 ),
[email protected]127f18ec2012-06-16 05:05:591105)
1106
Mario Sanchez Prada2472cab2019-09-18 10:58:311107# Format: Sequence of tuples containing:
1108# * String pattern or, if starting with a slash, a regular expression.
1109# * Sequence of strings to show when the pattern matches.
1110_DEPRECATED_MOJO_TYPES = (
1111 (
1112 r'/\bmojo::AssociatedBinding\b',
1113 (
1114 'mojo::AssociatedBinding<Interface> is deprecated.',
1115 'Use mojo::AssociatedReceiver<Interface> instead.',
1116 ),
1117 ),
1118 (
1119 r'/\bmojo::AssociatedBindingSet\b',
1120 (
1121 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1122 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1123 ),
1124 ),
1125 (
1126 r'/\bmojo::AssociatedInterfacePtr\b',
1127 (
1128 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1129 'Use mojo::AssociatedRemote<Interface> instead.',
1130 ),
1131 ),
1132 (
1133 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1134 (
1135 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1136 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1137 ),
1138 ),
1139 (
1140 r'/\bmojo::AssociatedInterfaceRequest\b',
1141 (
1142 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1143 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1144 ),
1145 ),
1146 (
1147 r'/\bmojo::Binding\b',
1148 (
1149 'mojo::Binding<Interface> is deprecated.',
1150 'Use mojo::Receiver<Interface> instead.',
1151 ),
1152 ),
1153 (
1154 r'/\bmojo::BindingSet\b',
1155 (
1156 'mojo::BindingSet<Interface> is deprecated.',
1157 'Use mojo::ReceiverSet<Interface> instead.',
1158 ),
1159 ),
1160 (
1161 r'/\bmojo::InterfacePtr\b',
1162 (
1163 'mojo::InterfacePtr<Interface> is deprecated.',
1164 'Use mojo::Remote<Interface> instead.',
1165 ),
1166 ),
1167 (
1168 r'/\bmojo::InterfacePtrInfo\b',
1169 (
1170 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1171 'Use mojo::PendingRemote<Interface> instead.',
1172 ),
1173 ),
1174 (
1175 r'/\bmojo::InterfaceRequest\b',
1176 (
1177 'mojo::InterfaceRequest<Interface> is deprecated.',
1178 'Use mojo::PendingReceiver<Interface> instead.',
1179 ),
1180 ),
1181 (
1182 r'/\bmojo::MakeRequest\b',
1183 (
1184 'mojo::MakeRequest is deprecated.',
1185 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1186 ),
1187 ),
1188 (
1189 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1190 (
1191 'mojo::MakeRequest is deprecated.',
1192 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181193 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311194 ),
1195 ),
1196 (
1197 r'/\bmojo::MakeStrongBinding\b',
1198 (
1199 'mojo::MakeStrongBinding is deprecated.',
1200 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1201 'mojo::MakeSelfOwnedReceiver() instead.',
1202 ),
1203 ),
1204 (
1205 r'/\bmojo::MakeStrongAssociatedBinding\b',
1206 (
1207 'mojo::MakeStrongAssociatedBinding is deprecated.',
1208 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1209 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1210 ),
1211 ),
1212 (
Gyuyoung Kim4952ba62020-07-07 07:33:441213 r'/\bmojo::StrongAssociatedBinding\b',
1214 (
1215 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1216 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1217 ),
1218 ),
1219 (
1220 r'/\bmojo::StrongBinding\b',
1221 (
1222 'mojo::StrongBinding<Interface> is deprecated.',
1223 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1224 ),
1225 ),
1226 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311227 r'/\bmojo::StrongAssociatedBindingSet\b',
1228 (
1229 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1230 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1231 ),
1232 ),
1233 (
1234 r'/\bmojo::StrongBindingSet\b',
1235 (
1236 'mojo::StrongBindingSet<Interface> is deprecated.',
1237 'Use mojo::UniqueReceiverSet<Interface> instead.',
1238 ),
1239 ),
1240)
wnwenbdc444e2016-05-25 13:44:151241
mlamouria82272622014-09-16 18:45:041242_IPC_ENUM_TRAITS_DEPRECATED = (
1243 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501244 'See http://www.chromium.org/Home/chromium-security/education/'
1245 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041246
Stephen Martinis97a394142018-06-07 23:06:051247_LONG_PATH_ERROR = (
1248 'Some files included in this CL have file names that are too long (> 200'
1249 ' characters). If committed, these files will cause issues on Windows. See'
1250 ' https://crbug.com/612667 for more details.'
1251)
1252
Shenghua Zhangbfaa38b82017-11-16 21:58:021253_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041254 r".*[\\/]BuildHooksAndroidImpl\.java",
1255 r".*[\\/]LicenseContentProvider\.java",
1256 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281257 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021258]
[email protected]127f18ec2012-06-16 05:05:591259
Mohamed Heikald048240a2019-11-12 16:57:371260# List of image extensions that are used as resources in chromium.
1261_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1262
Sean Kau46e29bc2017-08-28 16:31:161263# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401264_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041265 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401266 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041267 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1268 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041269 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431270 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161271]
1272
1273
[email protected]b00342e7f2013-03-26 16:21:541274_VALID_OS_MACROS = (
1275 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081276 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541277 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441278 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121279 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541280 'OS_BSD',
1281 'OS_CAT', # For testing.
1282 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041283 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541284 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371285 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541286 'OS_IOS',
1287 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441288 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541289 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211290 'OS_NACL_NONSFI',
1291 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121292 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541293 'OS_OPENBSD',
1294 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371295 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541296 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541297 'OS_WIN',
1298)
1299
1300
Andrew Grieveb773bad2020-06-05 18:00:381301# These are not checked on the public chromium-presubmit trybot.
1302# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041303# checkouts.
agrievef32bcc72016-04-04 14:57:401304_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381305 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381306]
1307
1308
1309_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041310 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361311 'base/android/jni_generator/jni_generator.pydeps',
1312 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361313 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041314 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361315 'build/android/gyp/aar.pydeps',
1316 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271317 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361318 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381319 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361320 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021321 'build/android/gyp/bytecode_rewriter.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111322 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361323 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361325 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111326 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041327 'build/android/gyp/create_app_bundle_apks.pydeps',
1328 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361329 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121330 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221331 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001332 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361333 'build/android/gyp/desugar.pydeps',
1334 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421335 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041336 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361337 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361338 'build/android/gyp/filter_zip.pydeps',
1339 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361340 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361341 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581342 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361343 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141344 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261345 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011346 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041347 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361348 'build/android/gyp/lint.pydeps',
1349 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361350 'build/android/gyp/merge_manifest.pydeps',
1351 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221352 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461354 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241355 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361356 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461357 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561358 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361359 'build/android/incremental_install/generate_android_manifest.pydeps',
1360 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041361 'build/android/resource_sizes.pydeps',
1362 'build/android/test_runner.pydeps',
1363 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361364 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361365 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321366 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271367 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1368 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001369 'components/cronet/tools/generate_javadoc.pydeps',
1370 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381371 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001372 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381373 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041374 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181375 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041376 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421377 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1378 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131379 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061380 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221381 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401382]
1383
wnwenbdc444e2016-05-25 13:44:151384
agrievef32bcc72016-04-04 14:57:401385_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1386
1387
Eric Boren6fd2b932018-01-25 15:05:081388# Bypass the AUTHORS check for these accounts.
1389_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591390 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451391 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591392 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521393 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071394 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041395 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271396 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041397 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301398 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081399
1400
Daniel Bratell65b033262019-04-23 08:17:061401def _IsCPlusPlusFile(input_api, file_path):
1402 """Returns True if this file contains C++-like code (and not Python,
1403 Go, Java, MarkDown, ...)"""
1404
1405 ext = input_api.os_path.splitext(file_path)[1]
1406 # This list is compatible with CppChecker.IsCppFile but we should
1407 # consider adding ".c" to it. If we do that we can use this function
1408 # at more places in the code.
1409 return ext in (
1410 '.h',
1411 '.cc',
1412 '.cpp',
1413 '.m',
1414 '.mm',
1415 )
1416
1417def _IsCPlusPlusHeaderFile(input_api, file_path):
1418 return input_api.os_path.splitext(file_path)[1] == ".h"
1419
1420
1421def _IsJavaFile(input_api, file_path):
1422 return input_api.os_path.splitext(file_path)[1] == ".java"
1423
1424
1425def _IsProtoFile(input_api, file_path):
1426 return input_api.os_path.splitext(file_path)[1] == ".proto"
1427
Mohamed Heikal5e5b7922020-10-29 18:57:591428
1429def CheckNoUpstreamDepsOnClank(input_api, output_api):
1430 """Prevent additions of dependencies from the upstream repo on //clank."""
1431 # clank can depend on clank
1432 if input_api.change.RepositoryRoot().endswith('clank'):
1433 return []
1434 build_file_patterns = [
1435 r'(.+/)?BUILD\.gn',
1436 r'.+\.gni',
1437 ]
1438 excluded_files = [
1439 r'build[/\\]config[/\\]android[/\\]config\.gni'
1440 ]
1441 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1442
1443 error_message = 'Disallowed import on //clank in an upstream build file:'
1444
1445 def FilterFile(affected_file):
1446 return input_api.FilterSourceFile(
1447 affected_file,
1448 files_to_check=build_file_patterns,
1449 files_to_skip=excluded_files)
1450
1451 problems = []
1452 for f in input_api.AffectedSourceFiles(FilterFile):
1453 local_path = f.LocalPath()
1454 for line_number, line in f.ChangedContents():
1455 if (bad_pattern.search(line)):
1456 problems.append(
1457 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1458 if problems:
1459 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1460 else:
1461 return []
1462
1463
Saagar Sanghavifceeaae2020-08-12 16:40:361464def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191465 """Attempts to prevent use of functions intended only for testing in
1466 non-testing code. For now this is just a best-effort implementation
1467 that ignores header files and may have some false positives. A
1468 better implementation would probably need a proper C++ parser.
1469 """
1470 # We only scan .cc files and the like, as the declaration of
1471 # for-testing functions in header files are hard to distinguish from
1472 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491473 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191474
jochenc0d4808c2015-07-27 09:25:421475 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191476 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091477 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131478 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191479 exclusion_pattern = input_api.re.compile(
1480 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1481 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131482 # Avoid a false positive in this case, where the method name, the ::, and
1483 # the closing { are all on different lines due to line wrapping.
1484 # HelperClassForTesting::
1485 # HelperClassForTesting(
1486 # args)
1487 # : member(0) {}
1488 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191489
1490 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441491 files_to_skip = (_EXCLUDED_PATHS +
1492 _TEST_CODE_EXCLUDED_PATHS +
1493 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191494 return input_api.FilterSourceFile(
1495 affected_file,
James Cook24a504192020-07-23 00:08:441496 files_to_check=file_inclusion_pattern,
1497 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191498
1499 problems = []
1500 for f in input_api.AffectedSourceFiles(FilterFile):
1501 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131502 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241503 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031504 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461505 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131506 not exclusion_pattern.search(line) and
1507 not allowlist_pattern.search(line) and
1508 not in_method_defn):
[email protected]55459852011-08-10 15:17:191509 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031510 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131511 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191512
1513 if problems:
[email protected]f7051d52013-04-02 18:31:421514 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031515 else:
1516 return []
[email protected]55459852011-08-10 15:17:191517
1518
Saagar Sanghavifceeaae2020-08-12 16:40:361519def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231520 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591521 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231522 """
1523 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1524 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1525 name_pattern = r'ForTest(s|ing)?'
1526 # Describes an occurrence of "ForTest*" inside a // comment.
1527 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501528 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551529 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231530 # Catch calls.
1531 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1532 # Ignore definitions. (Comments are ignored separately.)
1533 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1534
1535 problems = []
1536 sources = lambda x: input_api.FilterSourceFile(
1537 x,
James Cook24a504192020-07-23 00:08:441538 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1539 + input_api.DEFAULT_FILES_TO_SKIP),
1540 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231541 )
1542 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1543 local_path = f.LocalPath()
1544 is_inside_javadoc = False
1545 for line_number, line in f.ChangedContents():
1546 if is_inside_javadoc and javadoc_end_re.search(line):
1547 is_inside_javadoc = False
1548 if not is_inside_javadoc and javadoc_start_re.search(line):
1549 is_inside_javadoc = True
1550 if is_inside_javadoc:
1551 continue
1552 if (inclusion_re.search(line) and
1553 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501554 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231555 not exclusion_re.search(line)):
1556 problems.append(
1557 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1558
1559 if problems:
1560 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1561 else:
1562 return []
1563
1564
Saagar Sanghavifceeaae2020-08-12 16:40:361565def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541566 """Checks to make sure no .h files include <iostream>."""
1567 files = []
1568 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1569 input_api.re.MULTILINE)
1570 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1571 if not f.LocalPath().endswith('.h'):
1572 continue
1573 contents = input_api.ReadFile(f)
1574 if pattern.search(contents):
1575 files.append(f)
1576
1577 if len(files):
yolandyandaabc6d2016-04-18 18:29:391578 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061579 'Do not #include <iostream> in header files, since it inserts static '
1580 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541581 '#include <ostream>. See http://crbug.com/94794',
1582 files) ]
1583 return []
1584
Danil Chapovalov3518f362018-08-11 16:13:431585def _CheckNoStrCatRedefines(input_api, output_api):
1586 """Checks no windows headers with StrCat redefined are included directly."""
1587 files = []
1588 pattern_deny = input_api.re.compile(
1589 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1590 input_api.re.MULTILINE)
1591 pattern_allow = input_api.re.compile(
1592 r'^#include\s"base/win/windows_defines.inc"',
1593 input_api.re.MULTILINE)
1594 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1595 contents = input_api.ReadFile(f)
1596 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1597 files.append(f.LocalPath())
1598
1599 if len(files):
1600 return [output_api.PresubmitError(
1601 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1602 'directly since they pollute code with StrCat macro. Instead, '
1603 'include matching header from base/win. See http://crbug.com/856536',
1604 files) ]
1605 return []
1606
[email protected]10689ca2011-09-02 02:31:541607
Saagar Sanghavifceeaae2020-08-12 16:40:361608def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521609 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181610 problems = []
1611 for f in input_api.AffectedFiles():
1612 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1613 continue
1614
1615 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041616 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181617 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1618
1619 if not problems:
1620 return []
1621 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1622 '\n'.join(problems))]
1623
Saagar Sanghavifceeaae2020-08-12 16:40:361624def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341625 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1626
1627 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1628 instead of DISABLED_. To filter false positives, reports are only generated
1629 if a corresponding MAYBE_ line exists.
1630 """
1631 problems = []
1632
1633 # The following two patterns are looked for in tandem - is a test labeled
1634 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1635 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1636 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1637
1638 # This is for the case that a test is disabled on all platforms.
1639 full_disable_pattern = input_api.re.compile(
1640 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1641 input_api.re.MULTILINE)
1642
Katie Df13948e2018-09-25 07:33:441643 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341644 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1645 continue
1646
1647 # Search for MABYE_, DISABLE_ pairs.
1648 disable_lines = {} # Maps of test name to line number.
1649 maybe_lines = {}
1650 for line_num, line in f.ChangedContents():
1651 disable_match = disable_pattern.search(line)
1652 if disable_match:
1653 disable_lines[disable_match.group(1)] = line_num
1654 maybe_match = maybe_pattern.search(line)
1655 if maybe_match:
1656 maybe_lines[maybe_match.group(1)] = line_num
1657
1658 # Search for DISABLE_ occurrences within a TEST() macro.
1659 disable_tests = set(disable_lines.keys())
1660 maybe_tests = set(maybe_lines.keys())
1661 for test in disable_tests.intersection(maybe_tests):
1662 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1663
1664 contents = input_api.ReadFile(f)
1665 full_disable_match = full_disable_pattern.search(contents)
1666 if full_disable_match:
1667 problems.append(' %s' % f.LocalPath())
1668
1669 if not problems:
1670 return []
1671 return [
1672 output_api.PresubmitPromptWarning(
1673 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1674 '\n'.join(problems))
1675 ]
1676
[email protected]72df4e782012-06-21 16:28:181677
Saagar Sanghavifceeaae2020-08-12 16:40:361678def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571679 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521680 errors = []
Hans Wennborg944479f2020-06-25 21:39:251681 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521682 input_api.re.MULTILINE)
1683 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1684 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1685 continue
1686 for lnum, line in f.ChangedContents():
1687 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171688 errors.append(output_api.PresubmitError(
1689 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571690 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171691 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521692 return errors
1693
1694
Weilun Shia487fad2020-10-28 00:10:341695# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1696# more reliable way. See
1697# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191698
wnwenbdc444e2016-05-25 13:44:151699
Saagar Sanghavifceeaae2020-08-12 16:40:361700def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391701 """Check that FlakyTest annotation is our own instead of the android one"""
1702 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1703 files = []
1704 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1705 if f.LocalPath().endswith('Test.java'):
1706 if pattern.search(input_api.ReadFile(f)):
1707 files.append(f)
1708 if len(files):
1709 return [output_api.PresubmitError(
1710 'Use org.chromium.base.test.util.FlakyTest instead of '
1711 'android.test.FlakyTest',
1712 files)]
1713 return []
mcasasb7440c282015-02-04 14:52:191714
wnwenbdc444e2016-05-25 13:44:151715
Saagar Sanghavifceeaae2020-08-12 16:40:361716def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221717 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271718 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221719 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201720 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571721 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341722 '/win/' in f.LocalPath() or
1723 'chrome_elf' in f.LocalPath() or
1724 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201725 continue
[email protected]8ea5d4b2011-09-13 21:49:221726
[email protected]a11dbe9b2012-08-07 01:32:581727 allowWString = False
[email protected]b5c24292011-11-28 14:38:201728 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581729 if 'presubmit: allow wstring' in line:
1730 allowWString = True
1731 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271732 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581733 allowWString = False
1734 else:
1735 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221736
[email protected]55463aa62011-10-12 00:48:271737 if not problems:
1738 return []
1739 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581740 ' If you are calling a cross-platform API that accepts a wstring, '
1741 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271742 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221743
1744
Saagar Sanghavifceeaae2020-08-12 16:40:361745def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441746 """Make sure .DEPS.git is never modified manually."""
1747 if any(f.LocalPath().endswith('.DEPS.git') for f in
1748 input_api.AffectedFiles()):
1749 return [output_api.PresubmitError(
1750 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1751 'automated system based on what\'s in DEPS and your changes will be\n'
1752 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501753 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1754 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441755 'for more information')]
1756 return []
1757
1758
Saagar Sanghavifceeaae2020-08-12 16:40:361759def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471760 """Checks that DEPS file deps are from allowed_hosts."""
1761 # Run only if DEPS file has been modified to annoy fewer bystanders.
1762 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1763 return []
1764 # Outsource work to gclient verify
1765 try:
John Budorickf20c0042019-04-25 23:23:401766 gclient_path = input_api.os_path.join(
1767 input_api.PresubmitLocalPath(),
1768 'third_party', 'depot_tools', 'gclient.py')
1769 input_api.subprocess.check_output(
1770 [input_api.python_executable, gclient_path, 'verify'],
1771 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471772 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201773 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471774 return [output_api.PresubmitError(
1775 'DEPS file must have only git dependencies.',
1776 long_text=error.output)]
1777
1778
Mario Sanchez Prada2472cab2019-09-18 10:58:311779def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1780 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591781 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311782
1783 Returns an string composed of the name of the file, the line number where the
1784 match has been found and the additional text passed as |message| in case the
1785 target type name matches the text inside the line passed as parameter.
1786 """
Peng Huang9c5949a02020-06-11 19:20:541787 result = []
1788
1789 if line.endswith(" nocheck"):
1790 return result
1791
Mario Sanchez Prada2472cab2019-09-18 10:58:311792 matched = False
1793 if type_name[0:1] == '/':
1794 regex = type_name[1:]
1795 if input_api.re.search(regex, line):
1796 matched = True
1797 elif type_name in line:
1798 matched = True
1799
Mario Sanchez Prada2472cab2019-09-18 10:58:311800 if matched:
1801 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1802 for message_line in message:
1803 result.append(' %s' % message_line)
1804
1805 return result
1806
1807
Saagar Sanghavifceeaae2020-08-12 16:40:361808def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591809 """Make sure that banned functions are not used."""
1810 warnings = []
1811 errors = []
1812
James Cook24a504192020-07-23 00:08:441813 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151814 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441815 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151816 if input_api.re.match(item, local_path):
1817 return True
1818 return False
1819
Peter K. Lee6c03ccff2019-07-15 14:40:051820 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541821 local_path = affected_file.LocalPath()
1822 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1823 return False
1824 basename = input_api.os_path.basename(local_path)
1825 if 'ios' in basename.split('_'):
1826 return True
1827 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1828 if sep and 'ios' in local_path.split(sep):
1829 return True
1830 return False
1831
wnwenbdc444e2016-05-25 13:44:151832 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311833 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1834 func_name, message)
1835 if problems:
wnwenbdc444e2016-05-25 13:44:151836 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311837 errors.extend(problems)
1838 else:
1839 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151840
Eric Stevensona9a980972017-09-23 00:04:411841 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1842 for f in input_api.AffectedFiles(file_filter=file_filter):
1843 for line_num, line in f.ChangedContents():
1844 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1845 CheckForMatch(f, line_num, line, func_name, message, error)
1846
[email protected]127f18ec2012-06-16 05:05:591847 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1848 for f in input_api.AffectedFiles(file_filter=file_filter):
1849 for line_num, line in f.ChangedContents():
1850 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151851 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591852
Peter K. Lee6c03ccff2019-07-15 14:40:051853 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541854 for line_num, line in f.ChangedContents():
1855 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1856 CheckForMatch(f, line_num, line, func_name, message, error)
1857
Peter K. Lee6c03ccff2019-07-15 14:40:051858 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1859 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1860 for line_num, line in f.ChangedContents():
1861 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1862 CheckForMatch(f, line_num, line, func_name, message, error)
1863
[email protected]127f18ec2012-06-16 05:05:591864 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1865 for f in input_api.AffectedFiles(file_filter=file_filter):
1866 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491867 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441868 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491869 continue
wnwenbdc444e2016-05-25 13:44:151870 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591871
1872 result = []
1873 if (warnings):
1874 result.append(output_api.PresubmitPromptWarning(
1875 'Banned functions were used.\n' + '\n'.join(warnings)))
1876 if (errors):
1877 result.append(output_api.PresubmitError(
1878 'Banned functions were used.\n' + '\n'.join(errors)))
1879 return result
1880
1881
Michael Thiessen44457642020-02-06 00:24:151882def _CheckAndroidNoBannedImports(input_api, output_api):
1883 """Make sure that banned java imports are not used."""
1884 errors = []
1885
1886 def IsException(path, exceptions):
1887 for exception in exceptions:
1888 if (path.startswith(exception)):
1889 return True
1890 return False
1891
1892 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1893 for f in input_api.AffectedFiles(file_filter=file_filter):
1894 for line_num, line in f.ChangedContents():
1895 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1896 if IsException(f.LocalPath(), exceptions):
1897 continue;
1898 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1899 'import ' + import_name, message)
1900 if problems:
1901 errors.extend(problems)
1902 result = []
1903 if (errors):
1904 result.append(output_api.PresubmitError(
1905 'Banned imports were used.\n' + '\n'.join(errors)))
1906 return result
1907
1908
Saagar Sanghavifceeaae2020-08-12 16:40:361909def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311910 """Make sure that old Mojo types are not used."""
1911 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571912 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311913
Mario Sanchez Pradaaab91382019-12-19 08:57:091914 # For any path that is not an "ok" or an "error" path, a warning will be
1915 # raised if deprecated mojo types are found.
1916 ok_paths = ['components/arc']
1917 error_paths = ['third_party/blink', 'content']
1918
Mario Sanchez Prada2472cab2019-09-18 10:58:311919 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1920 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571921 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091922 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311923 continue
1924
1925 for line_num, line in f.ChangedContents():
1926 for func_name, message in _DEPRECATED_MOJO_TYPES:
1927 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1928 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571929
Mario Sanchez Prada2472cab2019-09-18 10:58:311930 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091931 # Raise errors inside |error_paths| and warnings everywhere else.
1932 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571933 errors.extend(problems)
1934 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311935 warnings.extend(problems)
1936
1937 result = []
1938 if (warnings):
1939 result.append(output_api.PresubmitPromptWarning(
1940 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571941 if (errors):
1942 result.append(output_api.PresubmitError(
1943 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311944 return result
1945
1946
Saagar Sanghavifceeaae2020-08-12 16:40:361947def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061948 """Make sure that banned functions are not used."""
1949 files = []
1950 pattern = input_api.re.compile(r'^#pragma\s+once',
1951 input_api.re.MULTILINE)
1952 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1953 if not f.LocalPath().endswith('.h'):
1954 continue
1955 contents = input_api.ReadFile(f)
1956 if pattern.search(contents):
1957 files.append(f)
1958
1959 if files:
1960 return [output_api.PresubmitError(
1961 'Do not use #pragma once in header files.\n'
1962 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1963 files)]
1964 return []
1965
[email protected]127f18ec2012-06-16 05:05:591966
Saagar Sanghavifceeaae2020-08-12 16:40:361967def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121968 """Checks to make sure we don't introduce use of foo ? true : false."""
1969 problems = []
1970 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1971 for f in input_api.AffectedFiles():
1972 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1973 continue
1974
1975 for line_num, line in f.ChangedContents():
1976 if pattern.match(line):
1977 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1978
1979 if not problems:
1980 return []
1981 return [output_api.PresubmitPromptWarning(
1982 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1983 '\n'.join(problems))]
1984
1985
Saagar Sanghavifceeaae2020-08-12 16:40:361986def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281987 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181988 change. Breaking - rules is an error, breaking ! rules is a
1989 warning.
1990 """
mohan.reddyf21db962014-10-16 12:26:471991 import sys
[email protected]55f9f382012-07-31 11:02:181992 # We need to wait until we have an input_api object and use this
1993 # roundabout construct to import checkdeps because this file is
1994 # eval-ed and thus doesn't have __file__.
1995 original_sys_path = sys.path
1996 try:
1997 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471998 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181999 import checkdeps
[email protected]55f9f382012-07-31 11:02:182000 from rules import Rule
2001 finally:
2002 # Restore sys.path to what it was before.
2003 sys.path = original_sys_path
2004
2005 added_includes = []
rhalavati08acd232017-04-03 07:23:282006 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242007 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182008 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062009 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502010 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082011 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062012 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502013 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082014 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062015 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502016 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082017 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182018
[email protected]26385172013-05-09 23:11:352019 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182020
2021 error_descriptions = []
2022 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282023 error_subjects = set()
2024 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362025
[email protected]55f9f382012-07-31 11:02:182026 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2027 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082028 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182029 description_with_path = '%s\n %s' % (path, rule_description)
2030 if rule_type == Rule.DISALLOW:
2031 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282032 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182033 else:
2034 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282035 warning_subjects.add("#includes")
2036
2037 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2038 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082039 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282040 description_with_path = '%s\n %s' % (path, rule_description)
2041 if rule_type == Rule.DISALLOW:
2042 error_descriptions.append(description_with_path)
2043 error_subjects.add("imports")
2044 else:
2045 warning_descriptions.append(description_with_path)
2046 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182047
Jinsuk Kim5a092672017-10-24 22:42:242048 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022049 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082050 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242051 description_with_path = '%s\n %s' % (path, rule_description)
2052 if rule_type == Rule.DISALLOW:
2053 error_descriptions.append(description_with_path)
2054 error_subjects.add("imports")
2055 else:
2056 warning_descriptions.append(description_with_path)
2057 warning_subjects.add("imports")
2058
[email protected]55f9f382012-07-31 11:02:182059 results = []
2060 if error_descriptions:
2061 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282062 'You added one or more %s that violate checkdeps rules.'
2063 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182064 error_descriptions))
2065 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422066 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282067 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182068 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282069 '%s? See relevant DEPS file(s) for details and contacts.' %
2070 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182071 warning_descriptions))
2072 return results
2073
2074
Saagar Sanghavifceeaae2020-08-12 16:40:362075def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222076 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152077 if input_api.platform == 'win32':
2078 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292079 checkperms_tool = input_api.os_path.join(
2080 input_api.PresubmitLocalPath(),
2081 'tools', 'checkperms', 'checkperms.py')
2082 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472083 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392084 with input_api.CreateTemporaryFile() as file_list:
2085 for f in input_api.AffectedFiles():
2086 # checkperms.py file/directory arguments must be relative to the
2087 # repository.
2088 file_list.write(f.LocalPath() + '\n')
2089 file_list.close()
2090 args += ['--file-list', file_list.name]
2091 try:
2092 input_api.subprocess.check_output(args)
2093 return []
2094 except input_api.subprocess.CalledProcessError as error:
2095 return [output_api.PresubmitError(
2096 'checkperms.py failed:',
2097 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222098
2099
Saagar Sanghavifceeaae2020-08-12 16:40:362100def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492101 """Makes sure we don't include ui/aura/window_property.h
2102 in header files.
2103 """
2104 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2105 errors = []
2106 for f in input_api.AffectedFiles():
2107 if not f.LocalPath().endswith('.h'):
2108 continue
2109 for line_num, line in f.ChangedContents():
2110 if pattern.match(line):
2111 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2112
2113 results = []
2114 if errors:
2115 results.append(output_api.PresubmitError(
2116 'Header files should not include ui/aura/window_property.h', errors))
2117 return results
2118
2119
[email protected]70ca77752012-11-20 03:45:032120def _CheckForVersionControlConflictsInFile(input_api, f):
2121 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2122 errors = []
2123 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162124 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232125 # First-level headers in markdown look a lot like version control
2126 # conflict markers. http://daringfireball.net/projects/markdown/basics
2127 continue
[email protected]70ca77752012-11-20 03:45:032128 if pattern.match(line):
2129 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2130 return errors
2131
2132
Saagar Sanghavifceeaae2020-08-12 16:40:362133def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032134 """Usually this is not intentional and will cause a compile failure."""
2135 errors = []
2136 for f in input_api.AffectedFiles():
2137 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2138
2139 results = []
2140 if errors:
2141 results.append(output_api.PresubmitError(
2142 'Version control conflict markers found, please resolve.', errors))
2143 return results
2144
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202145
Saagar Sanghavifceeaae2020-08-12 16:40:362146def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162147 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2148 errors = []
2149 for f in input_api.AffectedFiles():
2150 for line_num, line in f.ChangedContents():
2151 if pattern.search(line):
2152 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2153
2154 results = []
2155 if errors:
2156 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502157 'Found Google support URL addressed by answer number. Please replace '
2158 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162159 return results
2160
[email protected]70ca77752012-11-20 03:45:032161
Saagar Sanghavifceeaae2020-08-12 16:40:362162def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442163 def FilterFile(affected_file):
2164 """Filter function for use with input_api.AffectedSourceFiles,
2165 below. This filters out everything except non-test files from
2166 top-level directories that generally speaking should not hard-code
2167 service URLs (e.g. src/android_webview/, src/content/ and others).
2168 """
2169 return input_api.FilterSourceFile(
2170 affected_file,
James Cook24a504192020-07-23 00:08:442171 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2172 files_to_skip=(_EXCLUDED_PATHS +
2173 _TEST_CODE_EXCLUDED_PATHS +
2174 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442175
reillyi38965732015-11-16 18:27:332176 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2177 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462178 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2179 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442180 problems = [] # items are (filename, line_number, line)
2181 for f in input_api.AffectedSourceFiles(FilterFile):
2182 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462183 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442184 problems.append((f.LocalPath(), line_num, line))
2185
2186 if problems:
[email protected]f7051d52013-04-02 18:31:422187 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442188 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582189 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442190 [' %s:%d: %s' % (
2191 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032192 else:
2193 return []
[email protected]06e6d0ff2012-12-11 01:36:442194
2195
Saagar Sanghavifceeaae2020-08-12 16:40:362196def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292197 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2198 def FileFilter(affected_file):
2199 """Includes directories known to be Chrome OS only."""
2200 return input_api.FilterSourceFile(
2201 affected_file,
James Cook24a504192020-07-23 00:08:442202 files_to_check=('^ash/',
2203 '^chromeos/', # Top-level src/chromeos.
2204 '/chromeos/', # Any path component.
2205 '^components/arc',
2206 '^components/exo'),
2207 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292208
2209 prefs = []
2210 priority_prefs = []
2211 for f in input_api.AffectedFiles(file_filter=FileFilter):
2212 for line_num, line in f.ChangedContents():
2213 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2214 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2215 prefs.append(' %s' % line)
2216 if input_api.re.search(
2217 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2218 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2219 priority_prefs.append(' %s' % line)
2220
2221 results = []
2222 if (prefs):
2223 results.append(output_api.PresubmitPromptWarning(
2224 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2225 'by browser sync settings. If these prefs should be controlled by OS '
2226 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2227 if (priority_prefs):
2228 results.append(output_api.PresubmitPromptWarning(
2229 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2230 'controlled by browser sync settings. If these prefs should be '
2231 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2232 'instead.\n' + '\n'.join(prefs)))
2233 return results
2234
2235
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492236# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362237def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272238 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312239 The native_client_sdk directory is excluded because it has auto-generated PNG
2240 files for documentation.
[email protected]d2530012013-01-25 16:39:272241 """
[email protected]d2530012013-01-25 16:39:272242 errors = []
James Cook24a504192020-07-23 00:08:442243 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2244 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312245 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442246 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312247 for f in input_api.AffectedFiles(include_deletes=False,
2248 file_filter=file_filter):
2249 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272250
2251 results = []
2252 if errors:
2253 results.append(output_api.PresubmitError(
2254 'The name of PNG files should not have abbreviations. \n'
2255 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2256 'Contact [email protected] if you have questions.', errors))
2257 return results
2258
2259
Daniel Cheng4dcdb6b2017-04-13 08:30:172260def _ExtractAddRulesFromParsedDeps(parsed_deps):
2261 """Extract the rules that add dependencies from a parsed DEPS file.
2262
2263 Args:
2264 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2265 add_rules = set()
2266 add_rules.update([
2267 rule[1:] for rule in parsed_deps.get('include_rules', [])
2268 if rule.startswith('+') or rule.startswith('!')
2269 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502270 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172271 {}).iteritems():
2272 add_rules.update([
2273 rule[1:] for rule in rules
2274 if rule.startswith('+') or rule.startswith('!')
2275 ])
2276 return add_rules
2277
2278
2279def _ParseDeps(contents):
2280 """Simple helper for parsing DEPS files."""
2281 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172282 class _VarImpl:
2283
2284 def __init__(self, local_scope):
2285 self._local_scope = local_scope
2286
2287 def Lookup(self, var_name):
2288 """Implements the Var syntax."""
2289 try:
2290 return self._local_scope['vars'][var_name]
2291 except KeyError:
2292 raise Exception('Var is not defined: %s' % var_name)
2293
2294 local_scope = {}
2295 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172296 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592297 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172298 }
2299 exec contents in global_scope, local_scope
2300 return local_scope
2301
2302
2303def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592304 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412305 a set of DEPS entries that we should look up.
2306
2307 For a directory (rather than a specific filename) we fake a path to
2308 a specific filename by adding /DEPS. This is chosen as a file that
2309 will seldom or never be subject to per-file include_rules.
2310 """
[email protected]2b438d62013-11-14 17:54:142311 # We ignore deps entries on auto-generated directories.
2312 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082313
Daniel Cheng4dcdb6b2017-04-13 08:30:172314 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2315 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2316
2317 added_deps = new_deps.difference(old_deps)
2318
[email protected]2b438d62013-11-14 17:54:142319 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172320 for added_dep in added_deps:
2321 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2322 continue
2323 # Assume that a rule that ends in .h is a rule for a specific file.
2324 if added_dep.endswith('.h'):
2325 results.add(added_dep)
2326 else:
2327 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082328 return results
2329
2330
Saagar Sanghavifceeaae2020-08-12 16:40:362331def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552332 """When a dependency prefixed with + is added to a DEPS file, we
2333 want to make sure that the change is reviewed by an OWNER of the
2334 target file or directory, to avoid layering violations from being
2335 introduced. This check verifies that this happens.
2336 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172337 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242338
2339 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492340 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242341 for f in input_api.AffectedFiles(include_deletes=False,
2342 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552343 filename = input_api.os_path.basename(f.LocalPath())
2344 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172345 virtual_depended_on_files.update(_CalculateAddedDeps(
2346 input_api.os_path,
2347 '\n'.join(f.OldContents()),
2348 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552349
[email protected]e871964c2013-05-13 14:14:552350 if not virtual_depended_on_files:
2351 return []
2352
2353 if input_api.is_committing:
2354 if input_api.tbr:
2355 return [output_api.PresubmitNotifyResult(
2356 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272357 if input_api.dry_run:
2358 return [output_api.PresubmitNotifyResult(
2359 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552360 if not input_api.change.issue:
2361 return [output_api.PresubmitError(
2362 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402363 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552364 output = output_api.PresubmitError
2365 else:
2366 output = output_api.PresubmitNotifyResult
2367
2368 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502369 owner_email, reviewers = (
2370 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2371 input_api,
2372 owners_db.email_regexp,
2373 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552374
2375 owner_email = owner_email or input_api.change.author_email
2376
[email protected]de4f7d22013-05-23 14:27:462377 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512378 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462379 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552380 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2381 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412382
2383 # We strip the /DEPS part that was added by
2384 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2385 # directory.
2386 def StripDeps(path):
2387 start_deps = path.rfind('/DEPS')
2388 if start_deps != -1:
2389 return path[:start_deps]
2390 else:
2391 return path
2392 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552393 for path in missing_files]
2394
2395 if unapproved_dependencies:
2396 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152397 output('You need LGTM from owners of depends-on paths in DEPS that were '
2398 'modified in this CL:\n %s' %
2399 '\n '.join(sorted(unapproved_dependencies)))]
2400 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2401 output_list.append(output(
2402 'Suggested missing target path OWNERS:\n %s' %
2403 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552404 return output_list
2405
2406 return []
2407
2408
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492409# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362410def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492411 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442412 files_to_skip = (_EXCLUDED_PATHS +
2413 _TEST_CODE_EXCLUDED_PATHS +
2414 input_api.DEFAULT_FILES_TO_SKIP +
2415 (r"^base[\\/]logging\.h$",
2416 r"^base[\\/]logging\.cc$",
2417 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2418 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2419 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2420 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2421 r"startup_browser_creator\.cc$",
2422 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2423 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2424 r"diagnostics_writer\.cc$",
2425 r"^chrome[\\/]chrome_cleaner[\\/].*",
2426 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2427 r"dll_hash_main\.cc$",
2428 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2429 r"^chromecast[\\/]",
2430 r"^cloud_print[\\/]",
2431 r"^components[\\/]browser_watcher[\\/]"
2432 r"dump_stability_report_main_win.cc$",
2433 r"^components[\\/]media_control[\\/]renderer[\\/]"
2434 r"media_playback_options\.cc$",
2435 r"^components[\\/]zucchini[\\/].*",
2436 # TODO(peter): Remove exception. https://crbug.com/534537
2437 r"^content[\\/]browser[\\/]notifications[\\/]"
2438 r"notification_event_dispatcher_impl\.cc$",
2439 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2440 r"gl_helper_benchmark\.cc$",
2441 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2442 r"^courgette[\\/]courgette_tool\.cc$",
2443 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2444 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2445 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2446 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2447 r"^ipc[\\/]ipc_logging\.cc$",
2448 r"^native_client_sdk[\\/]",
2449 r"^remoting[\\/]base[\\/]logging\.h$",
2450 r"^remoting[\\/]host[\\/].*",
2451 r"^sandbox[\\/]linux[\\/].*",
2452 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2453 r"dump_file_system.cc$",
2454 r"^tools[\\/]",
2455 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2456 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2457 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2458 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2459 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402460 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442461 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402462
thomasanderson625d3932017-03-29 07:16:582463 log_info = set([])
2464 printf = set([])
[email protected]85218562013-11-22 07:41:402465
2466 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582467 for _, line in f.ChangedContents():
2468 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2469 log_info.add(f.LocalPath())
2470 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2471 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372472
thomasanderson625d3932017-03-29 07:16:582473 if input_api.re.search(r"\bprintf\(", line):
2474 printf.add(f.LocalPath())
2475 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2476 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402477
2478 if log_info:
2479 return [output_api.PresubmitError(
2480 'These files spam the console log with LOG(INFO):',
2481 items=log_info)]
2482 if printf:
2483 return [output_api.PresubmitError(
2484 'These files spam the console log with printf/fprintf:',
2485 items=printf)]
2486 return []
2487
2488
Saagar Sanghavifceeaae2020-08-12 16:40:362489def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162490 """These types are all expected to hold locks while in scope and
2491 so should never be anonymous (which causes them to be immediately
2492 destroyed)."""
2493 they_who_must_be_named = [
2494 'base::AutoLock',
2495 'base::AutoReset',
2496 'base::AutoUnlock',
2497 'SkAutoAlphaRestore',
2498 'SkAutoBitmapShaderInstall',
2499 'SkAutoBlitterChoose',
2500 'SkAutoBounderCommit',
2501 'SkAutoCallProc',
2502 'SkAutoCanvasRestore',
2503 'SkAutoCommentBlock',
2504 'SkAutoDescriptor',
2505 'SkAutoDisableDirectionCheck',
2506 'SkAutoDisableOvalCheck',
2507 'SkAutoFree',
2508 'SkAutoGlyphCache',
2509 'SkAutoHDC',
2510 'SkAutoLockColors',
2511 'SkAutoLockPixels',
2512 'SkAutoMalloc',
2513 'SkAutoMaskFreeImage',
2514 'SkAutoMutexAcquire',
2515 'SkAutoPathBoundsUpdate',
2516 'SkAutoPDFRelease',
2517 'SkAutoRasterClipValidate',
2518 'SkAutoRef',
2519 'SkAutoTime',
2520 'SkAutoTrace',
2521 'SkAutoUnref',
2522 ]
2523 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2524 # bad: base::AutoLock(lock.get());
2525 # not bad: base::AutoLock lock(lock.get());
2526 bad_pattern = input_api.re.compile(anonymous)
2527 # good: new base::AutoLock(lock.get())
2528 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2529 errors = []
2530
2531 for f in input_api.AffectedFiles():
2532 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2533 continue
2534 for linenum, line in f.ChangedContents():
2535 if bad_pattern.search(line) and not good_pattern.search(line):
2536 errors.append('%s:%d' % (f.LocalPath(), linenum))
2537
2538 if errors:
2539 return [output_api.PresubmitError(
2540 'These lines create anonymous variables that need to be named:',
2541 items=errors)]
2542 return []
2543
2544
Saagar Sanghavifceeaae2020-08-12 16:40:362545def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532546 # Returns whether |template_str| is of the form <T, U...> for some types T
2547 # and U. Assumes that |template_str| is already in the form <...>.
2548 def HasMoreThanOneArg(template_str):
2549 # Level of <...> nesting.
2550 nesting = 0
2551 for c in template_str:
2552 if c == '<':
2553 nesting += 1
2554 elif c == '>':
2555 nesting -= 1
2556 elif c == ',' and nesting == 1:
2557 return True
2558 return False
2559
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492560 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102561 sources = lambda affected_file: input_api.FilterSourceFile(
2562 affected_file,
James Cook24a504192020-07-23 00:08:442563 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2564 input_api.DEFAULT_FILES_TO_SKIP),
2565 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552566
2567 # Pattern to capture a single "<...>" block of template arguments. It can
2568 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2569 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2570 # latter would likely require counting that < and > match, which is not
2571 # expressible in regular languages. Should the need arise, one can introduce
2572 # limited counting (matching up to a total number of nesting depth), which
2573 # should cover all practical cases for already a low nesting limit.
2574 template_arg_pattern = (
2575 r'<[^>]*' # Opening block of <.
2576 r'>([^<]*>)?') # Closing block of >.
2577 # Prefix expressing that whatever follows is not already inside a <...>
2578 # block.
2579 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102580 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552581 not_inside_template_arg_pattern
2582 + r'\bstd::unique_ptr'
2583 + template_arg_pattern
2584 + r'\(\)')
2585
2586 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2587 template_arg_no_array_pattern = (
2588 r'<[^>]*[^]]' # Opening block of <.
2589 r'>([^(<]*[^]]>)?') # Closing block of >.
2590 # Prefix saying that what follows is the start of an expression.
2591 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2592 # Suffix saying that what follows are call parentheses with a non-empty list
2593 # of arguments.
2594 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532595 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552596 return_construct_pattern = input_api.re.compile(
2597 start_of_expr_pattern
2598 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532599 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552600 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532601 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552602 + nonempty_arg_list_pattern)
2603
Vaclav Brozek851d9602018-04-04 16:13:052604 problems_constructor = []
2605 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102606 for f in input_api.AffectedSourceFiles(sources):
2607 for line_number, line in f.ChangedContents():
2608 # Disallow:
2609 # return std::unique_ptr<T>(foo);
2610 # bar = std::unique_ptr<T>(foo);
2611 # But allow:
2612 # return std::unique_ptr<T[]>(foo);
2613 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532614 # And also allow cases when the second template argument is present. Those
2615 # cases cannot be handled by std::make_unique:
2616 # return std::unique_ptr<T, U>(foo);
2617 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052618 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532619 return_construct_result = return_construct_pattern.search(line)
2620 if return_construct_result and not HasMoreThanOneArg(
2621 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052622 problems_constructor.append(
2623 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102624 # Disallow:
2625 # std::unique_ptr<T>()
2626 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052627 problems_nullptr.append(
2628 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2629
2630 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162631 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052632 errors.append(output_api.PresubmitError(
2633 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162634 problems_nullptr))
2635 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052636 errors.append(output_api.PresubmitError(
2637 'The following files use explicit std::unique_ptr constructor.'
2638 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162639 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102640 return errors
2641
2642
Saagar Sanghavifceeaae2020-08-12 16:40:362643def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082644 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522645 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082646 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522647 # If actions.xml is already included in the changelist, the PRESUBMIT
2648 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082649 return []
2650
[email protected]999261d2014-03-03 20:08:082651 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2652 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522653 current_actions = None
[email protected]999261d2014-03-03 20:08:082654 for f in input_api.AffectedFiles(file_filter=file_filter):
2655 for line_num, line in f.ChangedContents():
2656 match = input_api.re.search(action_re, line)
2657 if match:
[email protected]2f92dec2014-03-07 19:21:522658 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2659 # loaded only once.
2660 if not current_actions:
2661 with open('tools/metrics/actions/actions.xml') as actions_f:
2662 current_actions = actions_f.read()
2663 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082664 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522665 action = 'name="{0}"'.format(action_name)
2666 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082667 return [output_api.PresubmitPromptWarning(
2668 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522669 'tools/metrics/actions/actions.xml. Please run '
2670 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082671 % (f.LocalPath(), line_num, action_name))]
2672 return []
2673
2674
Daniel Cheng13ca61a882017-08-25 15:11:252675def _ImportJSONCommentEater(input_api):
2676 import sys
2677 sys.path = sys.path + [input_api.os_path.join(
2678 input_api.PresubmitLocalPath(),
2679 'tools', 'json_comment_eater')]
2680 import json_comment_eater
2681 return json_comment_eater
2682
2683
[email protected]99171a92014-06-03 08:44:472684def _GetJSONParseError(input_api, filename, eat_comments=True):
2685 try:
2686 contents = input_api.ReadFile(filename)
2687 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252688 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132689 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472690
2691 input_api.json.loads(contents)
2692 except ValueError as e:
2693 return e
2694 return None
2695
2696
2697def _GetIDLParseError(input_api, filename):
2698 try:
2699 contents = input_api.ReadFile(filename)
2700 idl_schema = input_api.os_path.join(
2701 input_api.PresubmitLocalPath(),
2702 'tools', 'json_schema_compiler', 'idl_schema.py')
2703 process = input_api.subprocess.Popen(
2704 [input_api.python_executable, idl_schema],
2705 stdin=input_api.subprocess.PIPE,
2706 stdout=input_api.subprocess.PIPE,
2707 stderr=input_api.subprocess.PIPE,
2708 universal_newlines=True)
2709 (_, error) = process.communicate(input=contents)
2710 return error or None
2711 except ValueError as e:
2712 return e
2713
2714
Saagar Sanghavifceeaae2020-08-12 16:40:362715def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472716 """Check that IDL and JSON files do not contain syntax errors."""
2717 actions = {
2718 '.idl': _GetIDLParseError,
2719 '.json': _GetJSONParseError,
2720 }
[email protected]99171a92014-06-03 08:44:472721 # Most JSON files are preprocessed and support comments, but these do not.
2722 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042723 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472724 ]
2725 # Only run IDL checker on files in these directories.
2726 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042727 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2728 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472729 ]
2730
2731 def get_action(affected_file):
2732 filename = affected_file.LocalPath()
2733 return actions.get(input_api.os_path.splitext(filename)[1])
2734
[email protected]99171a92014-06-03 08:44:472735 def FilterFile(affected_file):
2736 action = get_action(affected_file)
2737 if not action:
2738 return False
2739 path = affected_file.LocalPath()
2740
Erik Staab2dd72b12020-04-16 15:03:402741 if _MatchesFile(input_api,
2742 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2743 path):
[email protected]99171a92014-06-03 08:44:472744 return False
2745
2746 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162747 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472748 return False
2749 return True
2750
2751 results = []
2752 for affected_file in input_api.AffectedFiles(
2753 file_filter=FilterFile, include_deletes=False):
2754 action = get_action(affected_file)
2755 kwargs = {}
2756 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162757 _MatchesFile(input_api, json_no_comments_patterns,
2758 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472759 kwargs['eat_comments'] = False
2760 parse_error = action(input_api,
2761 affected_file.AbsoluteLocalPath(),
2762 **kwargs)
2763 if parse_error:
2764 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2765 (affected_file.LocalPath(), parse_error)))
2766 return results
2767
2768
Saagar Sanghavifceeaae2020-08-12 16:40:362769def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492770 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472771 import sys
[email protected]760deea2013-12-10 19:33:492772 original_sys_path = sys.path
2773 try:
2774 sys.path = sys.path + [input_api.os_path.join(
2775 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2776 import checkstyle
2777 finally:
2778 # Restore sys.path to what it was before.
2779 sys.path = original_sys_path
2780
2781 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092782 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442783 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492784
2785
Saagar Sanghavifceeaae2020-08-12 16:40:362786def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002787 """Checks to make sure devil is initialized correctly in python scripts."""
2788 script_common_initialize_pattern = input_api.re.compile(
2789 r'script_common\.InitializeEnvironment\(')
2790 devil_env_config_initialize = input_api.re.compile(
2791 r'devil_env\.config\.Initialize\(')
2792
2793 errors = []
2794
2795 sources = lambda affected_file: input_api.FilterSourceFile(
2796 affected_file,
James Cook24a504192020-07-23 00:08:442797 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2798 (r'^build[\\/]android[\\/]devil_chromium\.py',
2799 r'^third_party[\\/].*',)),
2800 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002801
2802 for f in input_api.AffectedSourceFiles(sources):
2803 for line_num, line in f.ChangedContents():
2804 if (script_common_initialize_pattern.search(line) or
2805 devil_env_config_initialize.search(line)):
2806 errors.append("%s:%d" % (f.LocalPath(), line_num))
2807
2808 results = []
2809
2810 if errors:
2811 results.append(output_api.PresubmitError(
2812 'Devil initialization should always be done using '
2813 'devil_chromium.Initialize() in the chromium project, to use better '
2814 'defaults for dependencies (ex. up-to-date version of adb).',
2815 errors))
2816
2817 return results
2818
2819
Sean Kau46e29bc2017-08-28 16:31:162820def _MatchesFile(input_api, patterns, path):
2821 for pattern in patterns:
2822 if input_api.re.search(pattern, path):
2823 return True
2824 return False
2825
2826
Daniel Cheng7052cdf2017-11-21 19:23:292827def _GetOwnersFilesToCheckForIpcOwners(input_api):
2828 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172829
Daniel Cheng7052cdf2017-11-21 19:23:292830 Returns:
2831 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2832 contain to cover IPC-related files with noparent reviewer rules.
2833 """
2834 # Whether or not a file affects IPC is (mostly) determined by a simple list
2835 # of filename patterns.
dchenge07de812016-06-20 19:27:172836 file_patterns = [
palmerb19a0932017-01-24 04:00:312837 # Legacy IPC:
dchenge07de812016-06-20 19:27:172838 '*_messages.cc',
2839 '*_messages*.h',
2840 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312841 # Mojo IPC:
dchenge07de812016-06-20 19:27:172842 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472843 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172844 '*_struct_traits*.*',
2845 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312846 '*.typemap',
2847 # Android native IPC:
2848 '*.aidl',
2849 # Blink uses a different file naming convention:
2850 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472851 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172852 '*StructTraits*.*',
2853 '*TypeConverter*.*',
2854 ]
2855
scottmg7a6ed5ba2016-11-04 18:22:042856 # These third_party directories do not contain IPCs, but contain files
2857 # matching the above patterns, which trigger false positives.
2858 exclude_paths = [
2859 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162860 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232861 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292862 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542863 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162864 # These files are just used to communicate between class loaders running
2865 # in the same process.
2866 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572867 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2868
scottmg7a6ed5ba2016-11-04 18:22:042869 ]
2870
dchenge07de812016-06-20 19:27:172871 # Dictionary mapping an OWNERS file path to Patterns.
2872 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2873 # rules ) to a PatternEntry.
2874 # PatternEntry is a dictionary with two keys:
2875 # - 'files': the files that are matched by this pattern
2876 # - 'rules': the per-file rules needed for this pattern
2877 # For example, if we expect OWNERS file to contain rules for *.mojom and
2878 # *_struct_traits*.*, Patterns might look like this:
2879 # {
2880 # '*.mojom': {
2881 # 'files': ...,
2882 # 'rules': [
2883 # 'per-file *.mojom=set noparent',
2884 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2885 # ],
2886 # },
2887 # '*_struct_traits*.*': {
2888 # 'files': ...,
2889 # 'rules': [
2890 # 'per-file *_struct_traits*.*=set noparent',
2891 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2892 # ],
2893 # },
2894 # }
2895 to_check = {}
2896
Daniel Cheng13ca61a882017-08-25 15:11:252897 def AddPatternToCheck(input_file, pattern):
2898 owners_file = input_api.os_path.join(
2899 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2900 if owners_file not in to_check:
2901 to_check[owners_file] = {}
2902 if pattern not in to_check[owners_file]:
2903 to_check[owners_file][pattern] = {
2904 'files': [],
2905 'rules': [
2906 'per-file %s=set noparent' % pattern,
2907 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2908 ]
2909 }
Vaclav Brozekd5de76a2018-03-17 07:57:502910 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252911
dchenge07de812016-06-20 19:27:172912 # Iterate through the affected files to see what we actually need to check
2913 # for. We should only nag patch authors about per-file rules if a file in that
2914 # directory would match that pattern. If a directory only contains *.mojom
2915 # files and no *_messages*.h files, we should only nag about rules for
2916 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252917 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262918 # Manifest files don't have a strong naming convention. Instead, try to find
2919 # affected .cc and .h files which look like they contain a manifest
2920 # definition.
2921 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2922 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2923 if (manifest_pattern.search(f.LocalPath()) and not
2924 test_manifest_pattern.search(f.LocalPath())):
2925 # We expect all actual service manifest files to contain at least one
2926 # qualified reference to service_manager::Manifest.
2927 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252928 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172929 for pattern in file_patterns:
2930 if input_api.fnmatch.fnmatch(
2931 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042932 skip = False
2933 for exclude in exclude_paths:
2934 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2935 skip = True
2936 break
2937 if skip:
2938 continue
Daniel Cheng13ca61a882017-08-25 15:11:252939 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172940 break
2941
Daniel Cheng7052cdf2017-11-21 19:23:292942 return to_check
2943
2944
Wez17c66962020-04-29 15:26:032945def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2946 """Adds OWNERS files to check for correct Fuchsia security owners."""
2947
2948 file_patterns = [
2949 # Component specifications.
2950 '*.cml', # Component Framework v2.
2951 '*.cmx', # Component Framework v1.
2952
2953 # Fuchsia IDL protocol specifications.
2954 '*.fidl',
2955 ]
2956
2957 def AddPatternToCheck(input_file, pattern):
2958 owners_file = input_api.os_path.join(
2959 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2960 if owners_file not in to_check:
2961 to_check[owners_file] = {}
2962 if pattern not in to_check[owners_file]:
2963 to_check[owners_file][pattern] = {
2964 'files': [],
2965 'rules': [
2966 'per-file %s=set noparent' % pattern,
2967 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2968 ]
2969 }
2970 to_check[owners_file][pattern]['files'].append(input_file)
2971
2972 # Iterate through the affected files to see what we actually need to check
2973 # for. We should only nag patch authors about per-file rules if a file in that
2974 # directory would match that pattern.
2975 for f in input_api.AffectedFiles(include_deletes=False):
2976 for pattern in file_patterns:
2977 if input_api.fnmatch.fnmatch(
2978 input_api.os_path.basename(f.LocalPath()), pattern):
2979 AddPatternToCheck(f, pattern)
2980 break
2981
2982 return to_check
2983
2984
Saagar Sanghavifceeaae2020-08-12 16:40:362985def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292986 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2987 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032988 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292989
2990 if to_check:
2991 # If there are any OWNERS files to check, there are IPC-related changes in
2992 # this CL. Auto-CC the review list.
2993 output_api.AppendCC('[email protected]')
2994
2995 # Go through the OWNERS files to check, filtering out rules that are already
2996 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172997 for owners_file, patterns in to_check.iteritems():
2998 try:
2999 with file(owners_file) as f:
3000 lines = set(f.read().splitlines())
3001 for entry in patterns.itervalues():
3002 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3003 ]
3004 except IOError:
3005 # No OWNERS file, so all the rules are definitely missing.
3006 continue
3007
3008 # All the remaining lines weren't found in OWNERS files, so emit an error.
3009 errors = []
3010 for owners_file, patterns in to_check.iteritems():
3011 missing_lines = []
3012 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503013 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173014 missing_lines.extend(entry['rules'])
3015 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3016 if missing_lines:
3017 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053018 'Because of the presence of files:\n%s\n\n'
3019 '%s needs the following %d lines added:\n\n%s' %
3020 ('\n'.join(files), owners_file, len(missing_lines),
3021 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173022
3023 results = []
3024 if errors:
vabrf5ce3bf92016-07-11 14:52:413025 if input_api.is_committing:
3026 output = output_api.PresubmitError
3027 else:
3028 output = output_api.PresubmitPromptWarning
3029 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593030 'Found OWNERS files that need to be updated for IPC security ' +
3031 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173032 long_text='\n\n'.join(errors)))
3033
3034 return results
3035
3036
Robert Sesek2c905332020-05-06 23:17:133037def _GetFilesUsingSecurityCriticalFunctions(input_api):
3038 """Checks affected files for changes to security-critical calls. This
3039 function checks the full change diff, to catch both additions/changes
3040 and removals.
3041
3042 Returns a dict keyed by file name, and the value is a set of detected
3043 functions.
3044 """
3045 # Map of function pretty name (displayed in an error) to the pattern to
3046 # match it with.
3047 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373048 'content::GetServiceSandboxType<>()':
3049 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133050 }
3051 _PATTERNS_TO_CHECK = {
3052 k: input_api.re.compile(v)
3053 for k, v in _PATTERNS_TO_CHECK.items()
3054 }
3055
3056 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3057 files_to_functions = {}
3058 for f in input_api.AffectedFiles():
3059 diff = f.GenerateScmDiff()
3060 for line in diff.split('\n'):
3061 # Not using just RightHandSideLines() because removing a
3062 # call to a security-critical function can be just as important
3063 # as adding or changing the arguments.
3064 if line.startswith('-') or (line.startswith('+') and
3065 not line.startswith('++')):
3066 for name, pattern in _PATTERNS_TO_CHECK.items():
3067 if pattern.search(line):
3068 path = f.LocalPath()
3069 if not path in files_to_functions:
3070 files_to_functions[path] = set()
3071 files_to_functions[path].add(name)
3072 return files_to_functions
3073
3074
Saagar Sanghavifceeaae2020-08-12 16:40:363075def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133076 """Checks that changes involving security-critical functions are reviewed
3077 by the security team.
3078 """
3079 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3080 if len(files_to_functions):
3081 owners_db = input_api.owners_db
3082 owner_email, reviewers = (
3083 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3084 input_api,
3085 owners_db.email_regexp,
3086 approval_needed=input_api.is_committing))
3087
3088 # Load the OWNERS file for security changes.
3089 owners_file = 'ipc/SECURITY_OWNERS'
3090 security_owners = owners_db.owners_rooted_at_file(owners_file)
3091
3092 has_security_owner = any([owner in reviewers for owner in security_owners])
3093 if not has_security_owner:
3094 msg = 'The following files change calls to security-sensive functions\n' \
3095 'that need to be reviewed by {}.\n'.format(owners_file)
3096 for path, names in files_to_functions.items():
3097 msg += ' {}\n'.format(path)
3098 for name in names:
3099 msg += ' {}\n'.format(name)
3100 msg += '\n'
3101
3102 if input_api.is_committing:
3103 output = output_api.PresubmitError
3104 else:
3105 output = output_api.PresubmitNotifyResult
3106 return [output(msg)]
3107
3108 return []
3109
3110
Saagar Sanghavifceeaae2020-08-12 16:40:363111def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263112 """Checks that set noparent is only used together with an OWNERS file in
3113 //build/OWNERS.setnoparent (see also
3114 //docs/code_reviews.md#owners-files-details)
3115 """
3116 errors = []
3117
3118 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3119 allowed_owners_files = set()
3120 with open(allowed_owners_files_file, 'r') as f:
3121 for line in f:
3122 line = line.strip()
3123 if not line or line.startswith('#'):
3124 continue
3125 allowed_owners_files.add(line)
3126
3127 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3128
3129 for f in input_api.AffectedFiles(include_deletes=False):
3130 if not f.LocalPath().endswith('OWNERS'):
3131 continue
3132
3133 found_owners_files = set()
3134 found_set_noparent_lines = dict()
3135
3136 # Parse the OWNERS file.
3137 for lineno, line in enumerate(f.NewContents(), 1):
3138 line = line.strip()
3139 if line.startswith('set noparent'):
3140 found_set_noparent_lines[''] = lineno
3141 if line.startswith('file://'):
3142 if line in allowed_owners_files:
3143 found_owners_files.add('')
3144 if line.startswith('per-file'):
3145 match = per_file_pattern.match(line)
3146 if match:
3147 glob = match.group(1).strip()
3148 directive = match.group(2).strip()
3149 if directive == 'set noparent':
3150 found_set_noparent_lines[glob] = lineno
3151 if directive.startswith('file://'):
3152 if directive in allowed_owners_files:
3153 found_owners_files.add(glob)
3154
3155 # Check that every set noparent line has a corresponding file:// line
3156 # listed in build/OWNERS.setnoparent.
3157 for set_noparent_line in found_set_noparent_lines:
3158 if set_noparent_line in found_owners_files:
3159 continue
3160 errors.append(' %s:%d' % (f.LocalPath(),
3161 found_set_noparent_lines[set_noparent_line]))
3162
3163 results = []
3164 if errors:
3165 if input_api.is_committing:
3166 output = output_api.PresubmitError
3167 else:
3168 output = output_api.PresubmitPromptWarning
3169 results.append(output(
3170 'Found the following "set noparent" restrictions in OWNERS files that '
3171 'do not include owners from build/OWNERS.setnoparent:',
3172 long_text='\n\n'.join(errors)))
3173 return results
3174
3175
Saagar Sanghavifceeaae2020-08-12 16:40:363176def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313177 """Checks that added or removed lines in non third party affected
3178 header files do not lead to new useless class or struct forward
3179 declaration.
jbriance9e12f162016-11-25 07:57:503180 """
3181 results = []
3182 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3183 input_api.re.MULTILINE)
3184 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3185 input_api.re.MULTILINE)
3186 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313187 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193188 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493189 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313190 continue
3191
jbriance9e12f162016-11-25 07:57:503192 if not f.LocalPath().endswith('.h'):
3193 continue
3194
3195 contents = input_api.ReadFile(f)
3196 fwd_decls = input_api.re.findall(class_pattern, contents)
3197 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3198
3199 useless_fwd_decls = []
3200 for decl in fwd_decls:
3201 count = sum(1 for _ in input_api.re.finditer(
3202 r'\b%s\b' % input_api.re.escape(decl), contents))
3203 if count == 1:
3204 useless_fwd_decls.append(decl)
3205
3206 if not useless_fwd_decls:
3207 continue
3208
3209 for line in f.GenerateScmDiff().splitlines():
3210 if (line.startswith('-') and not line.startswith('--') or
3211 line.startswith('+') and not line.startswith('++')):
3212 for decl in useless_fwd_decls:
3213 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3214 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243215 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503216 (f.LocalPath(), decl)))
3217 useless_fwd_decls.remove(decl)
3218
3219 return results
3220
Jinsong Fan91ebbbd2019-04-16 14:57:173221def _CheckAndroidDebuggableBuild(input_api, output_api):
3222 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3223 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3224 this is a debuggable build of Android.
3225 """
3226 build_type_check_pattern = input_api.re.compile(
3227 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3228
3229 errors = []
3230
3231 sources = lambda affected_file: input_api.FilterSourceFile(
3232 affected_file,
James Cook24a504192020-07-23 00:08:443233 files_to_skip=(_EXCLUDED_PATHS +
3234 _TEST_CODE_EXCLUDED_PATHS +
3235 input_api.DEFAULT_FILES_TO_SKIP +
3236 (r"^android_webview[\\/]support_library[\\/]"
3237 "boundary_interfaces[\\/]",
3238 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3239 r'^third_party[\\/].*',
3240 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3241 r"webview[\\/]chromium[\\/]License.*",)),
3242 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173243
3244 for f in input_api.AffectedSourceFiles(sources):
3245 for line_num, line in f.ChangedContents():
3246 if build_type_check_pattern.search(line):
3247 errors.append("%s:%d" % (f.LocalPath(), line_num))
3248
3249 results = []
3250
3251 if errors:
3252 results.append(output_api.PresubmitPromptWarning(
3253 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3254 ' Please use BuildInfo.isDebugAndroid() instead.',
3255 errors))
3256
3257 return results
jbriance9e12f162016-11-25 07:57:503258
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493259# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293260def _CheckAndroidToastUsage(input_api, output_api):
3261 """Checks that code uses org.chromium.ui.widget.Toast instead of
3262 android.widget.Toast (Chromium Toast doesn't force hardware
3263 acceleration on low-end devices, saving memory).
3264 """
3265 toast_import_pattern = input_api.re.compile(
3266 r'^import android\.widget\.Toast;$')
3267
3268 errors = []
3269
3270 sources = lambda affected_file: input_api.FilterSourceFile(
3271 affected_file,
James Cook24a504192020-07-23 00:08:443272 files_to_skip=(_EXCLUDED_PATHS +
3273 _TEST_CODE_EXCLUDED_PATHS +
3274 input_api.DEFAULT_FILES_TO_SKIP +
3275 (r'^chromecast[\\/].*',
3276 r'^remoting[\\/].*')),
3277 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293278
3279 for f in input_api.AffectedSourceFiles(sources):
3280 for line_num, line in f.ChangedContents():
3281 if toast_import_pattern.search(line):
3282 errors.append("%s:%d" % (f.LocalPath(), line_num))
3283
3284 results = []
3285
3286 if errors:
3287 results.append(output_api.PresubmitError(
3288 'android.widget.Toast usage is detected. Android toasts use hardware'
3289 ' acceleration, and can be\ncostly on low-end devices. Please use'
3290 ' org.chromium.ui.widget.Toast instead.\n'
3291 'Contact [email protected] if you have any questions.',
3292 errors))
3293
3294 return results
3295
3296
dgnaa68d5e2015-06-10 10:08:223297def _CheckAndroidCrLogUsage(input_api, output_api):
3298 """Checks that new logs using org.chromium.base.Log:
3299 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513300 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223301 """
pkotwicza1dd0b002016-05-16 14:41:043302
torne89540622017-03-24 19:41:303303 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043304 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303305 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043306 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303307 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043308 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3309 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093310 # The customtabs_benchmark is a small app that does not depend on Chromium
3311 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043312 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043313 ]
3314
dgnaa68d5e2015-06-10 10:08:223315 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123316 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3317 class_in_base_pattern = input_api.re.compile(
3318 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3319 has_some_log_import_pattern = input_api.re.compile(
3320 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223321 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553322 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223323 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463324 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553325 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223326
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463327 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443328 sources = lambda x: input_api.FilterSourceFile(x,
3329 files_to_check=[r'.*\.java$'],
3330 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123331
dgnaa68d5e2015-06-10 10:08:223332 tag_decl_errors = []
3333 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123334 tag_errors = []
dgn38736db2015-09-18 19:20:513335 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123336 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223337
3338 for f in input_api.AffectedSourceFiles(sources):
3339 file_content = input_api.ReadFile(f)
3340 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223341 # Per line checks
dgn87d9fb62015-06-12 09:15:123342 if (cr_log_import_pattern.search(file_content) or
3343 (class_in_base_pattern.search(file_content) and
3344 not has_some_log_import_pattern.search(file_content))):
3345 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223346 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553347 if rough_log_decl_pattern.search(line):
3348 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223349
3350 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123351 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223352 if match:
3353 has_modified_logs = True
3354
3355 # Make sure it uses "TAG"
3356 if not match.group('tag') == 'TAG':
3357 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123358 else:
3359 # Report non cr Log function calls in changed lines
3360 for line_num, line in f.ChangedContents():
3361 if log_call_pattern.search(line):
3362 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223363
3364 # Per file checks
3365 if has_modified_logs:
3366 # Make sure the tag is using the "cr" prefix and is not too long
3367 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513368 tag_name = match.group('name') if match else None
3369 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223370 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513371 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223372 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513373 elif '.' in tag_name:
3374 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223375
3376 results = []
3377 if tag_decl_errors:
3378 results.append(output_api.PresubmitPromptWarning(
3379 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513380 '"private static final String TAG = "<package tag>".\n'
3381 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223382 tag_decl_errors))
3383
3384 if tag_length_errors:
3385 results.append(output_api.PresubmitError(
3386 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513387 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223388 tag_length_errors))
3389
3390 if tag_errors:
3391 results.append(output_api.PresubmitPromptWarning(
3392 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3393 tag_errors))
3394
dgn87d9fb62015-06-12 09:15:123395 if util_log_errors:
dgn4401aa52015-04-29 16:26:173396 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123397 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3398 util_log_errors))
3399
dgn38736db2015-09-18 19:20:513400 if tag_with_dot_errors:
3401 results.append(output_api.PresubmitPromptWarning(
3402 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3403 tag_with_dot_errors))
3404
dgn4401aa52015-04-29 16:26:173405 return results
3406
3407
Yoland Yanb92fa522017-08-28 17:37:063408def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3409 """Checks that junit.framework.* is no longer used."""
3410 deprecated_junit_framework_pattern = input_api.re.compile(
3411 r'^import junit\.framework\..*;',
3412 input_api.re.MULTILINE)
3413 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443414 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063415 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133416 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063417 for line_num, line in f.ChangedContents():
3418 if deprecated_junit_framework_pattern.search(line):
3419 errors.append("%s:%d" % (f.LocalPath(), line_num))
3420
3421 results = []
3422 if errors:
3423 results.append(output_api.PresubmitError(
3424 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3425 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3426 ' if you have any question.', errors))
3427 return results
3428
3429
3430def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3431 """Checks that if new Java test classes have inheritance.
3432 Either the new test class is JUnit3 test or it is a JUnit4 test class
3433 with a base class, either case is undesirable.
3434 """
3435 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3436
3437 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443438 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063439 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133440 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063441 if not f.OldContents():
3442 class_declaration_start_flag = False
3443 for line_num, line in f.ChangedContents():
3444 if class_declaration_pattern.search(line):
3445 class_declaration_start_flag = True
3446 if class_declaration_start_flag and ' extends ' in line:
3447 errors.append('%s:%d' % (f.LocalPath(), line_num))
3448 if '{' in line:
3449 class_declaration_start_flag = False
3450
3451 results = []
3452 if errors:
3453 results.append(output_api.PresubmitPromptWarning(
3454 'The newly created files include Test classes that inherits from base'
3455 ' class. Please do not use inheritance in JUnit4 tests or add new'
3456 ' JUnit3 tests. Contact [email protected] if you have any'
3457 ' questions.', errors))
3458 return results
3459
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203460
yolandyan45001472016-12-21 21:12:423461def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3462 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3463 deprecated_annotation_import_pattern = input_api.re.compile(
3464 r'^import android\.test\.suitebuilder\.annotation\..*;',
3465 input_api.re.MULTILINE)
3466 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443467 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423468 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133469 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423470 for line_num, line in f.ChangedContents():
3471 if deprecated_annotation_import_pattern.search(line):
3472 errors.append("%s:%d" % (f.LocalPath(), line_num))
3473
3474 results = []
3475 if errors:
3476 results.append(output_api.PresubmitError(
3477 'Annotations in android.test.suitebuilder.annotation have been'
3478 ' deprecated since API level 24. Please use android.support.test.filters'
3479 ' from //third_party/android_support_test_runner:runner_java instead.'
3480 ' Contact [email protected] if you have any questions.', errors))
3481 return results
3482
3483
agrieve7b6479d82015-10-07 14:24:223484def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3485 """Checks if MDPI assets are placed in a correct directory."""
3486 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3487 ('/res/drawable/' in f.LocalPath() or
3488 '/res/drawable-ldrtl/' in f.LocalPath()))
3489 errors = []
3490 for f in input_api.AffectedFiles(include_deletes=False,
3491 file_filter=file_filter):
3492 errors.append(' %s' % f.LocalPath())
3493
3494 results = []
3495 if errors:
3496 results.append(output_api.PresubmitError(
3497 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3498 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3499 '/res/drawable-ldrtl/.\n'
3500 'Contact [email protected] if you have questions.', errors))
3501 return results
3502
3503
Nate Fischer535972b2017-09-16 01:06:183504def _CheckAndroidWebkitImports(input_api, output_api):
3505 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353506 android.webview.ValueCallback except in the WebView glue layer
3507 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183508 """
3509 valuecallback_import_pattern = input_api.re.compile(
3510 r'^import android\.webkit\.ValueCallback;$')
3511
3512 errors = []
3513
3514 sources = lambda affected_file: input_api.FilterSourceFile(
3515 affected_file,
James Cook24a504192020-07-23 00:08:443516 files_to_skip=(_EXCLUDED_PATHS +
3517 _TEST_CODE_EXCLUDED_PATHS +
3518 input_api.DEFAULT_FILES_TO_SKIP +
3519 (r'^android_webview[\\/]glue[\\/].*',
3520 r'^weblayer[\\/].*',)),
3521 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183522
3523 for f in input_api.AffectedSourceFiles(sources):
3524 for line_num, line in f.ChangedContents():
3525 if valuecallback_import_pattern.search(line):
3526 errors.append("%s:%d" % (f.LocalPath(), line_num))
3527
3528 results = []
3529
3530 if errors:
3531 results.append(output_api.PresubmitError(
3532 'android.webkit.ValueCallback usage is detected outside of the glue'
3533 ' layer. To stay compatible with the support library, android.webkit.*'
3534 ' classes should only be used inside the glue layer and'
3535 ' org.chromium.base.Callback should be used instead.',
3536 errors))
3537
3538 return results
3539
3540
Becky Zhou7c69b50992018-12-10 19:37:573541def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3542 """Checks Android XML styles """
3543 import sys
3544 original_sys_path = sys.path
3545 try:
3546 sys.path = sys.path + [input_api.os_path.join(
3547 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3548 import checkxmlstyle
3549 finally:
3550 # Restore sys.path to what it was before.
3551 sys.path = original_sys_path
3552
3553 if is_check_on_upload:
3554 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3555 else:
3556 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3557
3558
agrievef32bcc72016-04-04 14:57:403559class PydepsChecker(object):
3560 def __init__(self, input_api, pydeps_files):
3561 self._file_cache = {}
3562 self._input_api = input_api
3563 self._pydeps_files = pydeps_files
3564
3565 def _LoadFile(self, path):
3566 """Returns the list of paths within a .pydeps file relative to //."""
3567 if path not in self._file_cache:
3568 with open(path) as f:
3569 self._file_cache[path] = f.read()
3570 return self._file_cache[path]
3571
3572 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3573 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393574 pydeps_data = self._LoadFile(pydeps_path)
3575 uses_gn_paths = '--gn-paths' in pydeps_data
3576 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3577 if uses_gn_paths:
3578 # Paths look like: //foo/bar/baz
3579 return (e[2:] for e in entries)
3580 else:
3581 # Paths look like: path/relative/to/file.pydeps
3582 os_path = self._input_api.os_path
3583 pydeps_dir = os_path.dirname(pydeps_path)
3584 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403585
3586 def _CreateFilesToPydepsMap(self):
3587 """Returns a map of local_path -> list_of_pydeps."""
3588 ret = {}
3589 for pydep_local_path in self._pydeps_files:
3590 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3591 ret.setdefault(path, []).append(pydep_local_path)
3592 return ret
3593
3594 def ComputeAffectedPydeps(self):
3595 """Returns an iterable of .pydeps files that might need regenerating."""
3596 affected_pydeps = set()
3597 file_to_pydeps_map = None
3598 for f in self._input_api.AffectedFiles(include_deletes=True):
3599 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463600 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3601 # subrepositories. We can't figure out which files change, so re-check
3602 # all files.
3603 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383604 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3605 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403606 return self._pydeps_files
3607 elif local_path.endswith('.pydeps'):
3608 if local_path in self._pydeps_files:
3609 affected_pydeps.add(local_path)
3610 elif local_path.endswith('.py'):
3611 if file_to_pydeps_map is None:
3612 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3613 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3614 return affected_pydeps
3615
3616 def DetermineIfStale(self, pydeps_path):
3617 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413618 import difflib
John Budorick47ca3fe2018-02-10 00:53:103619 import os
3620
agrievef32bcc72016-04-04 14:57:403621 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033622 if old_pydeps_data:
3623 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393624 if '--output' not in cmd:
3625 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033626 old_contents = old_pydeps_data[2:]
3627 else:
3628 # A default cmd that should work in most cases (as long as pydeps filename
3629 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3630 # file is empty/new.
3631 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3632 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3633 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103634 env = dict(os.environ)
3635 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403636 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103637 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413638 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033639 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413640 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403641
3642
Tibor Goldschwendt360793f72019-06-25 18:23:493643def _ParseGclientArgs():
3644 args = {}
3645 with open('build/config/gclient_args.gni', 'r') as f:
3646 for line in f:
3647 line = line.strip()
3648 if not line or line.startswith('#'):
3649 continue
3650 attribute, value = line.split('=')
3651 args[attribute.strip()] = value.strip()
3652 return args
3653
3654
Saagar Sanghavifceeaae2020-08-12 16:40:363655def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403656 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403657 # This check is for Python dependency lists (.pydeps files), and involves
3658 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3659 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283660 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003661 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493662 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403663 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403664 results = []
3665 # First, check for new / deleted .pydeps.
3666 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033667 # Check whether we are running the presubmit check for a file in src.
3668 # f.LocalPath is relative to repo (src, or internal repo).
3669 # os_path.exists is relative to src repo.
3670 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3671 # to src and we can conclude that the pydeps is in src.
3672 if input_api.os_path.exists(f.LocalPath()):
3673 if f.LocalPath().endswith('.pydeps'):
3674 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3675 results.append(output_api.PresubmitError(
3676 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3677 'remove %s' % f.LocalPath()))
3678 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3679 results.append(output_api.PresubmitError(
3680 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3681 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403682
3683 if results:
3684 return results
3685
Mohamed Heikal7cd4d8312020-06-16 16:49:403686 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3687 affected_pydeps = set(checker.ComputeAffectedPydeps())
3688 affected_android_pydeps = affected_pydeps.intersection(
3689 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3690 if affected_android_pydeps and not is_android:
3691 results.append(output_api.PresubmitPromptOrNotify(
3692 'You have changed python files that may affect pydeps for android\n'
3693 'specific scripts. However, the relevant presumbit check cannot be\n'
3694 'run because you are not using an Android checkout. To validate that\n'
3695 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3696 'use the android-internal-presubmit optional trybot.\n'
3697 'Possibly stale pydeps files:\n{}'.format(
3698 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403699
Mohamed Heikal7cd4d8312020-06-16 16:49:403700 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3701 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403702 try:
phajdan.jr0d9878552016-11-04 10:49:413703 result = checker.DetermineIfStale(pydep_path)
3704 if result:
3705 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403706 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413707 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3708 'To regenerate, run:\n\n %s' %
3709 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403710 except input_api.subprocess.CalledProcessError as error:
3711 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3712 long_text=error.output)]
3713
3714 return results
3715
3716
Saagar Sanghavifceeaae2020-08-12 16:40:363717def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433718 """Checks to make sure no header files have |Singleton<|."""
3719 def FileFilter(affected_file):
3720 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443721 files_to_skip = (_EXCLUDED_PATHS +
3722 input_api.DEFAULT_FILES_TO_SKIP +
3723 (r"^base[\\/]memory[\\/]singleton\.h$",
3724 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3725 r"quic_singleton_impl\.h$"))
3726 return input_api.FilterSourceFile(affected_file,
3727 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433728
sergeyu34d21222015-09-16 00:11:443729 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433730 files = []
3731 for f in input_api.AffectedSourceFiles(FileFilter):
3732 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3733 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3734 contents = input_api.ReadFile(f)
3735 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243736 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433737 pattern.search(line)):
3738 files.append(f)
3739 break
3740
3741 if files:
yolandyandaabc6d2016-04-18 18:29:393742 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443743 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433744 'Please move them to an appropriate source file so that the ' +
3745 'template gets instantiated in a single compilation unit.',
3746 files) ]
3747 return []
3748
3749
[email protected]fd20b902014-05-09 02:14:533750_DEPRECATED_CSS = [
3751 # Values
3752 ( "-webkit-box", "flex" ),
3753 ( "-webkit-inline-box", "inline-flex" ),
3754 ( "-webkit-flex", "flex" ),
3755 ( "-webkit-inline-flex", "inline-flex" ),
3756 ( "-webkit-min-content", "min-content" ),
3757 ( "-webkit-max-content", "max-content" ),
3758
3759 # Properties
3760 ( "-webkit-background-clip", "background-clip" ),
3761 ( "-webkit-background-origin", "background-origin" ),
3762 ( "-webkit-background-size", "background-size" ),
3763 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443764 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533765
3766 # Functions
3767 ( "-webkit-gradient", "gradient" ),
3768 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3769 ( "-webkit-linear-gradient", "linear-gradient" ),
3770 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3771 ( "-webkit-radial-gradient", "radial-gradient" ),
3772 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3773]
3774
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203775
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493776# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363777def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533778 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253779 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343780 documentation and iOS CSS for dom distiller
3781 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253782 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533783 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493784 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443785 files_to_skip = (_EXCLUDED_PATHS +
3786 _TEST_CODE_EXCLUDED_PATHS +
3787 input_api.DEFAULT_FILES_TO_SKIP +
3788 (r"^chrome/common/extensions/docs",
3789 r"^chrome/docs",
3790 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3791 r"^components/neterror/resources/neterror.css",
3792 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253793 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443794 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533795 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3796 for line_num, line in fpath.ChangedContents():
3797 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023798 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533799 results.append(output_api.PresubmitError(
3800 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3801 (fpath.LocalPath(), line_num, deprecated_value, value)))
3802 return results
3803
mohan.reddyf21db962014-10-16 12:26:473804
Saagar Sanghavifceeaae2020-08-12 16:40:363805def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363806 bad_files = {}
3807 for f in input_api.AffectedFiles(include_deletes=False):
3808 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493809 not f.LocalPath().startswith('third_party/blink') and
3810 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363811 continue
3812
Daniel Bratell65b033262019-04-23 08:17:063813 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363814 continue
3815
Vaclav Brozekd5de76a2018-03-17 07:57:503816 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363817 if "#include" in line and "../" in line]
3818 if not relative_includes:
3819 continue
3820 bad_files[f.LocalPath()] = relative_includes
3821
3822 if not bad_files:
3823 return []
3824
3825 error_descriptions = []
3826 for file_path, bad_lines in bad_files.iteritems():
3827 error_description = file_path
3828 for line in bad_lines:
3829 error_description += '\n ' + line
3830 error_descriptions.append(error_description)
3831
3832 results = []
3833 results.append(output_api.PresubmitError(
3834 'You added one or more relative #include paths (including "../").\n'
3835 'These shouldn\'t be used because they can be used to include headers\n'
3836 'from code that\'s not correctly specified as a dependency in the\n'
3837 'relevant BUILD.gn file(s).',
3838 error_descriptions))
3839
3840 return results
3841
Takeshi Yoshinoe387aa32017-08-02 13:16:133842
Saagar Sanghavifceeaae2020-08-12 16:40:363843def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063844 """Check that nobody tries to include a cc file. It's a relatively
3845 common error which results in duplicate symbols in object
3846 files. This may not always break the build until someone later gets
3847 very confusing linking errors."""
3848 results = []
3849 for f in input_api.AffectedFiles(include_deletes=False):
3850 # We let third_party code do whatever it wants
3851 if (f.LocalPath().startswith('third_party') and
3852 not f.LocalPath().startswith('third_party/blink') and
3853 not f.LocalPath().startswith('third_party\\blink')):
3854 continue
3855
3856 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3857 continue
3858
3859 for _, line in f.ChangedContents():
3860 if line.startswith('#include "'):
3861 included_file = line.split('"')[1]
3862 if _IsCPlusPlusFile(input_api, included_file):
3863 # The most common naming for external files with C++ code,
3864 # apart from standard headers, is to call them foo.inc, but
3865 # Chromium sometimes uses foo-inc.cc so allow that as well.
3866 if not included_file.endswith(('.h', '-inc.cc')):
3867 results.append(output_api.PresubmitError(
3868 'Only header files or .inc files should be included in other\n'
3869 'C++ files. Compiling the contents of a cc file more than once\n'
3870 'will cause duplicate information in the build which may later\n'
3871 'result in strange link_errors.\n' +
3872 f.LocalPath() + ':\n ' +
3873 line))
3874
3875 return results
3876
3877
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203878def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3879 if not isinstance(key, ast.Str):
3880 return 'Key at line %d must be a string literal' % key.lineno
3881 if not isinstance(value, ast.Dict):
3882 return 'Value at line %d must be a dict' % value.lineno
3883 if len(value.keys) != 1:
3884 return 'Dict at line %d must have single entry' % value.lineno
3885 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3886 return (
3887 'Entry at line %d must have a string literal \'filepath\' as key' %
3888 value.lineno)
3889 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133890
Takeshi Yoshinoe387aa32017-08-02 13:16:133891
Sergey Ulanov4af16052018-11-08 02:41:463892def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203893 if not isinstance(key, ast.Str):
3894 return 'Key at line %d must be a string literal' % key.lineno
3895 if not isinstance(value, ast.List):
3896 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463897 for element in value.elts:
3898 if not isinstance(element, ast.Str):
3899 return 'Watchlist elements on line %d is not a string' % key.lineno
3900 if not email_regex.match(element.s):
3901 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3902 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203903 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133904
Takeshi Yoshinoe387aa32017-08-02 13:16:133905
Sergey Ulanov4af16052018-11-08 02:41:463906def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203907 mismatch_template = (
3908 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3909 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133910
Sergey Ulanov4af16052018-11-08 02:41:463911 email_regex = input_api.re.compile(
3912 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3913
3914 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203915 i = 0
3916 last_key = ''
3917 while True:
3918 if i >= len(wd_dict.keys):
3919 if i >= len(w_dict.keys):
3920 return None
3921 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3922 elif i >= len(w_dict.keys):
3923 return (
3924 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133925
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203926 wd_key = wd_dict.keys[i]
3927 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133928
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203929 result = _CheckWatchlistDefinitionsEntrySyntax(
3930 wd_key, wd_dict.values[i], ast)
3931 if result is not None:
3932 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133933
Sergey Ulanov4af16052018-11-08 02:41:463934 result = _CheckWatchlistsEntrySyntax(
3935 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203936 if result is not None:
3937 return 'Bad entry in WATCHLISTS dict: %s' % result
3938
3939 if wd_key.s != w_key.s:
3940 return mismatch_template % (
3941 '%s at line %d' % (wd_key.s, wd_key.lineno),
3942 '%s at line %d' % (w_key.s, w_key.lineno))
3943
3944 if wd_key.s < last_key:
3945 return (
3946 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3947 (wd_key.lineno, w_key.lineno))
3948 last_key = wd_key.s
3949
3950 i = i + 1
3951
3952
Sergey Ulanov4af16052018-11-08 02:41:463953def _CheckWATCHLISTSSyntax(expression, input_api):
3954 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203955 if not isinstance(expression, ast.Expression):
3956 return 'WATCHLISTS file must contain a valid expression'
3957 dictionary = expression.body
3958 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3959 return 'WATCHLISTS file must have single dict with exactly two entries'
3960
3961 first_key = dictionary.keys[0]
3962 first_value = dictionary.values[0]
3963 second_key = dictionary.keys[1]
3964 second_value = dictionary.values[1]
3965
3966 if (not isinstance(first_key, ast.Str) or
3967 first_key.s != 'WATCHLIST_DEFINITIONS' or
3968 not isinstance(first_value, ast.Dict)):
3969 return (
3970 'The first entry of the dict in WATCHLISTS file must be '
3971 'WATCHLIST_DEFINITIONS dict')
3972
3973 if (not isinstance(second_key, ast.Str) or
3974 second_key.s != 'WATCHLISTS' or
3975 not isinstance(second_value, ast.Dict)):
3976 return (
3977 'The second entry of the dict in WATCHLISTS file must be '
3978 'WATCHLISTS dict')
3979
Sergey Ulanov4af16052018-11-08 02:41:463980 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133981
3982
Saagar Sanghavifceeaae2020-08-12 16:40:363983def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133984 for f in input_api.AffectedFiles(include_deletes=False):
3985 if f.LocalPath() == 'WATCHLISTS':
3986 contents = input_api.ReadFile(f, 'r')
3987
3988 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203989 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133990 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203991 # Get an AST tree for it and scan the tree for detailed style checking.
3992 expression = input_api.ast.parse(
3993 contents, filename='WATCHLISTS', mode='eval')
3994 except ValueError as e:
3995 return [output_api.PresubmitError(
3996 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3997 except SyntaxError as e:
3998 return [output_api.PresubmitError(
3999 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4000 except TypeError as e:
4001 return [output_api.PresubmitError(
4002 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134003
Sergey Ulanov4af16052018-11-08 02:41:464004 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204005 if result is not None:
4006 return [output_api.PresubmitError(result)]
4007 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134008
4009 return []
4010
4011
Andrew Grieve1b290e4a22020-11-24 20:07:014012def CheckGnGlobForward(input_api, output_api):
4013 """Checks that forward_variables_from(invoker, "*") follows best practices.
4014
4015 As documented at //build/docs/writing_gn_templates.md
4016 """
4017 def gn_files(f):
4018 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
4019
4020 problems = []
4021 for f in input_api.AffectedSourceFiles(gn_files):
4022 for line_num, line in f.ChangedContents():
4023 if 'forward_variables_from(invoker, "*")' in line:
4024 problems.append(
4025 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
4026 f.LocalPath(), line_num))
4027
4028 if problems:
4029 return [output_api.PresubmitPromptWarning(
4030 'forward_variables_from("*") without exclusions',
4031 items=sorted(problems),
4032 long_text=('The variables "visibilty" and "test_only" should be '
4033 'explicitly listed in forward_variables_from(). For more '
4034 'details, see:\n'
4035 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4036 'build/docs/writing_gn_templates.md'
4037 '#Using-forward_variables_from'))]
4038 return []
4039
4040
Saagar Sanghavifceeaae2020-08-12 16:40:364041def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194042 """Checks that newly added header files have corresponding GN changes.
4043 Note that this is only a heuristic. To be precise, run script:
4044 build/check_gn_headers.py.
4045 """
4046
4047 def headers(f):
4048 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444049 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194050
4051 new_headers = []
4052 for f in input_api.AffectedSourceFiles(headers):
4053 if f.Action() != 'A':
4054 continue
4055 new_headers.append(f.LocalPath())
4056
4057 def gn_files(f):
James Cook24a504192020-07-23 00:08:444058 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194059
4060 all_gn_changed_contents = ''
4061 for f in input_api.AffectedSourceFiles(gn_files):
4062 for _, line in f.ChangedContents():
4063 all_gn_changed_contents += line
4064
4065 problems = []
4066 for header in new_headers:
4067 basename = input_api.os_path.basename(header)
4068 if basename not in all_gn_changed_contents:
4069 problems.append(header)
4070
4071 if problems:
4072 return [output_api.PresubmitPromptWarning(
4073 'Missing GN changes for new header files', items=sorted(problems),
4074 long_text='Please double check whether newly added header files need '
4075 'corresponding changes in gn or gni files.\nThis checking is only a '
4076 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4077 'Read https://crbug.com/661774 for more info.')]
4078 return []
4079
4080
Saagar Sanghavifceeaae2020-08-12 16:40:364081def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024082 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4083
4084 This assumes we won't intentionally reference one product from the other
4085 product.
4086 """
4087 all_problems = []
4088 test_cases = [{
4089 "filename_postfix": "google_chrome_strings.grd",
4090 "correct_name": "Chrome",
4091 "incorrect_name": "Chromium",
4092 }, {
4093 "filename_postfix": "chromium_strings.grd",
4094 "correct_name": "Chromium",
4095 "incorrect_name": "Chrome",
4096 }]
4097
4098 for test_case in test_cases:
4099 problems = []
4100 filename_filter = lambda x: x.LocalPath().endswith(
4101 test_case["filename_postfix"])
4102
4103 # Check each new line. Can yield false positives in multiline comments, but
4104 # easier than trying to parse the XML because messages can have nested
4105 # children, and associating message elements with affected lines is hard.
4106 for f in input_api.AffectedSourceFiles(filename_filter):
4107 for line_num, line in f.ChangedContents():
4108 if "<message" in line or "<!--" in line or "-->" in line:
4109 continue
4110 if test_case["incorrect_name"] in line:
4111 problems.append(
4112 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4113
4114 if problems:
4115 message = (
4116 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4117 % (test_case["correct_name"], test_case["correct_name"],
4118 test_case["incorrect_name"]))
4119 all_problems.append(
4120 output_api.PresubmitPromptWarning(message, items=problems))
4121
4122 return all_problems
4123
4124
Saagar Sanghavifceeaae2020-08-12 16:40:364125def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514126 # TODO(crbug.com/941824): We need to make sure the entries in
4127 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4128 # so that users of //buildtools in other projects get the same tooling
4129 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4130 # support to gclient, we can eliminate the duplication and delete
4131 # this presubmit check.
4132
4133 # Update this regexp if new revisions are added to the files.
4134 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264135 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514136
4137 # If a user is changing one revision, they need to change the same
4138 # line in both files. This means that any given change should contain
4139 # exactly the same list of changed lines that match the regexps. The
4140 # replace(' ', '') call allows us to ignore whitespace changes to the
4141 # lines. The 'long_text' parameter to the error will contain the
4142 # list of changed lines in both files, which should make it easy enough
4143 # to spot the error without going overboard in this implementation.
4144 revs_changes = {
4145 'DEPS': {},
4146 'buildtools/DEPS': {},
4147 }
4148 long_text = ''
4149
4150 for f in input_api.AffectedFiles(
4151 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4152 for line_num, line in f.ChangedContents():
4153 if rev_regexp.search(line):
4154 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4155 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4156
4157 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4158 return [output_api.PresubmitError(
4159 'Change buildtools revisions in sync in both //DEPS and '
4160 '//buildtools/DEPS.', long_text=long_text + '\n')]
4161 else:
4162 return []
4163
4164
Saagar Sanghavifceeaae2020-08-12 16:40:364165def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364166 """Avoid large files, especially binary files, in the repository since
4167 git doesn't scale well for those. They will be in everyone's repo
4168 clones forever, forever making Chromium slower to clone and work
4169 with."""
4170
4171 # Uploading files to cloud storage is not trivial so we don't want
4172 # to set the limit too low, but the upper limit for "normal" large
4173 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4174 # anything over 20 MB is exceptional.
4175 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4176
4177 too_large_files = []
4178 for f in input_api.AffectedFiles():
4179 # Check both added and modified files (but not deleted files).
4180 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384181 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364182 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4183 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4184
4185 if too_large_files:
4186 message = (
4187 'Do not commit large files to git since git scales badly for those.\n' +
4188 'Instead put the large files in cloud storage and use DEPS to\n' +
4189 'fetch them.\n' + '\n'.join(too_large_files)
4190 )
4191 return [output_api.PresubmitError(
4192 'Too large files found in commit', long_text=message + '\n')]
4193 else:
4194 return []
4195
Max Morozb47503b2019-08-08 21:03:274196
Saagar Sanghavifceeaae2020-08-12 16:40:364197def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274198 """Checks specific for fuzz target sources."""
4199 EXPORTED_SYMBOLS = [
4200 'LLVMFuzzerInitialize',
4201 'LLVMFuzzerCustomMutator',
4202 'LLVMFuzzerCustomCrossOver',
4203 'LLVMFuzzerMutate',
4204 ]
4205
4206 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4207
4208 def FilterFile(affected_file):
4209 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444210 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4211 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274212
4213 return input_api.FilterSourceFile(
4214 affected_file,
James Cook24a504192020-07-23 00:08:444215 files_to_check=[files_to_check],
4216 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274217
4218 files_with_missing_header = []
4219 for f in input_api.AffectedSourceFiles(FilterFile):
4220 contents = input_api.ReadFile(f, 'r')
4221 if REQUIRED_HEADER in contents:
4222 continue
4223
4224 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4225 files_with_missing_header.append(f.LocalPath())
4226
4227 if not files_with_missing_header:
4228 return []
4229
4230 long_text = (
4231 'If you define any of the libFuzzer optional functions (%s), it is '
4232 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4233 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4234 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4235 'to access command line arguments passed to the fuzzer. Instead, prefer '
4236 'static initialization and shared resources as documented in '
4237 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4238 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4239 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4240 )
4241
4242 return [output_api.PresubmitPromptWarning(
4243 message="Missing '%s' in:" % REQUIRED_HEADER,
4244 items=files_with_missing_header,
4245 long_text=long_text)]
4246
4247
Mohamed Heikald048240a2019-11-12 16:57:374248def _CheckNewImagesWarning(input_api, output_api):
4249 """
4250 Warns authors who add images into the repo to make sure their images are
4251 optimized before committing.
4252 """
4253 images_added = False
4254 image_paths = []
4255 errors = []
4256 filter_lambda = lambda x: input_api.FilterSourceFile(
4257 x,
James Cook24a504192020-07-23 00:08:444258 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4259 + input_api.DEFAULT_FILES_TO_SKIP),
4260 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374261 )
4262 for f in input_api.AffectedFiles(
4263 include_deletes=False, file_filter=filter_lambda):
4264 local_path = f.LocalPath().lower()
4265 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4266 images_added = True
4267 image_paths.append(f)
4268 if images_added:
4269 errors.append(output_api.PresubmitPromptWarning(
4270 'It looks like you are trying to commit some images. If these are '
4271 'non-test-only images, please make sure to read and apply the tips in '
4272 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4273 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4274 'FYI only and will not block your CL on the CQ.', image_paths))
4275 return errors
4276
4277
Saagar Sanghavifceeaae2020-08-12 16:40:364278def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574279 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224280 results = []
dgnaa68d5e2015-06-10 10:08:224281 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174282 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224283 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294284 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064285 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4286 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424287 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184288 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574289 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374290 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154291 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574292 return results
4293
Saagar Sanghavifceeaae2020-08-12 16:40:364294def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574295 """Groups commit checks that target android code."""
4296 results = []
4297 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224298 return results
4299
Chris Hall59f8d0c72020-05-01 07:31:194300# TODO(chrishall): could we additionally match on any path owned by
4301# ui/accessibility/OWNERS ?
4302_ACCESSIBILITY_PATHS = (
4303 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4304 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4305 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4306 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4307 r"^content[\\/]browser[\\/]accessibility[\\/]",
4308 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4309 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4310 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4311 r"^ui[\\/]accessibility[\\/]",
4312 r"^ui[\\/]views[\\/]accessibility[\\/]",
4313)
4314
Saagar Sanghavifceeaae2020-08-12 16:40:364315def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194316 """Checks that commits to accessibility code contain an AX-Relnotes field in
4317 their commit message."""
4318 def FileFilter(affected_file):
4319 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444320 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194321
4322 # Only consider changes affecting accessibility paths.
4323 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4324 return []
4325
Akihiro Ota08108e542020-05-20 15:30:534326 # AX-Relnotes can appear in either the description or the footer.
4327 # When searching the description, require 'AX-Relnotes:' to appear at the
4328 # beginning of a line.
4329 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4330 description_has_relnotes = any(ax_regex.match(line)
4331 for line in input_api.change.DescriptionText().lower().splitlines())
4332
4333 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4334 'AX-Relnotes', [])
4335 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194336 return []
4337
4338 # TODO(chrishall): link to Relnotes documentation in message.
4339 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4340 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4341 "user-facing changes"
4342 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4343 "user-facing effects"
4344 "\n if this is confusing or annoying then please contact members "
4345 "of ui/accessibility/OWNERS.")
4346
4347 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224348
Saagar Sanghavifceeaae2020-08-12 16:40:364349def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394350 """Checks common to both upload and commit."""
4351 results = []
4352 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384353 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544354 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084355
4356 author = input_api.change.author_email
4357 if author and author not in _KNOWN_ROBOTS:
4358 results.extend(
4359 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4360
[email protected]9f919cc2013-07-31 03:04:044361 results.extend(
4362 input_api.canned_checks.CheckChangeHasNoTabs(
4363 input_api,
4364 output_api,
4365 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434366 results.extend(input_api.RunTests(
4367 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244368
Edward Lesmesce51df52020-08-04 22:10:174369 dirmd_bin = input_api.os_path.join(
4370 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4371 results.extend(input_api.RunTests(
4372 input_api.canned_checks.CheckDirMetadataFormat(
4373 input_api, output_api, dirmd_bin)))
4374 results.extend(
4375 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4376 input_api, output_api))
4377
Vaclav Brozekcdc7defb2018-03-20 09:54:354378 for f in input_api.AffectedFiles():
4379 path, name = input_api.os_path.split(f.LocalPath())
4380 if name == 'PRESUBMIT.py':
4381 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004382 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4383 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074384 # The PRESUBMIT.py file (and the directory containing it) might
4385 # have been affected by being moved or removed, so only try to
4386 # run the tests if they still exist.
4387 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4388 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444389 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394390 return results
[email protected]1f7b4172010-01-28 01:17:344391
[email protected]b337cb5b2011-01-23 21:24:054392
Saagar Sanghavifceeaae2020-08-12 16:40:364393def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494394 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4395 if f.LocalPath().endswith(('.orig', '.rej'))]
4396 if problems:
4397 return [output_api.PresubmitError(
4398 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034399 else:
4400 return []
[email protected]b8079ae4a2012-12-05 19:56:494401
4402
Saagar Sanghavifceeaae2020-08-12 16:40:364403def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214404 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4405 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4406 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074407 include_re = input_api.re.compile(
4408 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4409 extension_re = input_api.re.compile(r'\.[a-z]+$')
4410 errors = []
4411 for f in input_api.AffectedFiles():
4412 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4413 continue
4414 found_line_number = None
4415 found_macro = None
4416 for line_num, line in f.ChangedContents():
4417 match = macro_re.search(line)
4418 if match:
4419 found_line_number = line_num
4420 found_macro = match.group(2)
4421 break
4422 if not found_line_number:
4423 continue
4424
4425 found_include = False
4426 for line in f.NewContents():
4427 if include_re.search(line):
4428 found_include = True
4429 break
4430 if found_include:
4431 continue
4432
4433 if not f.LocalPath().endswith('.h'):
4434 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4435 try:
4436 content = input_api.ReadFile(primary_header_path, 'r')
4437 if include_re.search(content):
4438 continue
4439 except IOError:
4440 pass
4441 errors.append('%s:%d %s macro is used without including build/'
4442 'build_config.h.'
4443 % (f.LocalPath(), found_line_number, found_macro))
4444 if errors:
4445 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4446 return []
4447
4448
[email protected]b00342e7f2013-03-26 16:21:544449def _DidYouMeanOSMacro(bad_macro):
4450 try:
4451 return {'A': 'OS_ANDROID',
4452 'B': 'OS_BSD',
4453 'C': 'OS_CHROMEOS',
4454 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444455 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544456 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444457 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544458 'N': 'OS_NACL',
4459 'O': 'OS_OPENBSD',
4460 'P': 'OS_POSIX',
4461 'S': 'OS_SOLARIS',
4462 'W': 'OS_WIN'}[bad_macro[3].upper()]
4463 except KeyError:
4464 return ''
4465
4466
4467def _CheckForInvalidOSMacrosInFile(input_api, f):
4468 """Check for sensible looking, totally invalid OS macros."""
4469 preprocessor_statement = input_api.re.compile(r'^\s*#')
4470 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4471 results = []
4472 for lnum, line in f.ChangedContents():
4473 if preprocessor_statement.search(line):
4474 for match in os_macro.finditer(line):
4475 if not match.group(1) in _VALID_OS_MACROS:
4476 good = _DidYouMeanOSMacro(match.group(1))
4477 did_you_mean = ' (did you mean %s?)' % good if good else ''
4478 results.append(' %s:%d %s%s' % (f.LocalPath(),
4479 lnum,
4480 match.group(1),
4481 did_you_mean))
4482 return results
4483
4484
Saagar Sanghavifceeaae2020-08-12 16:40:364485def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544486 """Check all affected files for invalid OS macros."""
4487 bad_macros = []
tzik3f295992018-12-04 20:32:234488 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474489 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544490 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4491
4492 if not bad_macros:
4493 return []
4494
4495 return [output_api.PresubmitError(
4496 'Possibly invalid OS macro[s] found. Please fix your code\n'
4497 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4498
lliabraa35bab3932014-10-01 12:16:444499
4500def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4501 """Check all affected files for invalid "if defined" macros."""
4502 ALWAYS_DEFINED_MACROS = (
4503 "TARGET_CPU_PPC",
4504 "TARGET_CPU_PPC64",
4505 "TARGET_CPU_68K",
4506 "TARGET_CPU_X86",
4507 "TARGET_CPU_ARM",
4508 "TARGET_CPU_MIPS",
4509 "TARGET_CPU_SPARC",
4510 "TARGET_CPU_ALPHA",
4511 "TARGET_IPHONE_SIMULATOR",
4512 "TARGET_OS_EMBEDDED",
4513 "TARGET_OS_IPHONE",
4514 "TARGET_OS_MAC",
4515 "TARGET_OS_UNIX",
4516 "TARGET_OS_WIN32",
4517 )
4518 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4519 results = []
4520 for lnum, line in f.ChangedContents():
4521 for match in ifdef_macro.finditer(line):
4522 if match.group(1) in ALWAYS_DEFINED_MACROS:
4523 always_defined = ' %s is always defined. ' % match.group(1)
4524 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4525 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4526 lnum,
4527 always_defined,
4528 did_you_mean))
4529 return results
4530
4531
Saagar Sanghavifceeaae2020-08-12 16:40:364532def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444533 """Check all affected files for invalid "if defined" macros."""
4534 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054535 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444536 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054537 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214538 continue
lliabraa35bab3932014-10-01 12:16:444539 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4540 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4541
4542 if not bad_macros:
4543 return []
4544
4545 return [output_api.PresubmitError(
4546 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4547 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4548 bad_macros)]
4549
4550
Saagar Sanghavifceeaae2020-08-12 16:40:364551def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044552 """Check for same IPC rules described in
4553 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4554 """
4555 base_pattern = r'IPC_ENUM_TRAITS\('
4556 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4557 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4558
4559 problems = []
4560 for f in input_api.AffectedSourceFiles(None):
4561 local_path = f.LocalPath()
4562 if not local_path.endswith('.h'):
4563 continue
4564 for line_number, line in f.ChangedContents():
4565 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4566 problems.append(
4567 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4568
4569 if problems:
4570 return [output_api.PresubmitPromptWarning(
4571 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4572 else:
4573 return []
4574
[email protected]b00342e7f2013-03-26 16:21:544575
Saagar Sanghavifceeaae2020-08-12 16:40:364576def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054577 """Check to make sure no files being submitted have long paths.
4578 This causes issues on Windows.
4579 """
4580 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194581 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054582 local_path = f.LocalPath()
4583 # Windows has a path limit of 260 characters. Limit path length to 200 so
4584 # that we have some extra for the prefix on dev machines and the bots.
4585 if len(local_path) > 200:
4586 problems.append(local_path)
4587
4588 if problems:
4589 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4590 else:
4591 return []
4592
4593
Saagar Sanghavifceeaae2020-08-12 16:40:364594def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144595 """Check that header files have proper guards against multiple inclusion.
4596 If a file should not have such guards (and it probably should) then it
4597 should include the string "no-include-guard-because-multiply-included".
4598 """
Daniel Bratell6a75baef62018-06-04 10:04:454599 def is_chromium_header_file(f):
4600 # We only check header files under the control of the Chromium
4601 # project. That is, those outside third_party apart from
4602 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324603 # We also exclude *_message_generator.h headers as they use
4604 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454605 file_with_path = input_api.os_path.normpath(f.LocalPath())
4606 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324607 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454608 (not file_with_path.startswith('third_party') or
4609 file_with_path.startswith(
4610 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144611
4612 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344613 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144614
4615 errors = []
4616
Daniel Bratell6a75baef62018-06-04 10:04:454617 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144618 guard_name = None
4619 guard_line_number = None
4620 seen_guard_end = False
4621
4622 file_with_path = input_api.os_path.normpath(f.LocalPath())
4623 base_file_name = input_api.os_path.splitext(
4624 input_api.os_path.basename(file_with_path))[0]
4625 upper_base_file_name = base_file_name.upper()
4626
4627 expected_guard = replace_special_with_underscore(
4628 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144629
4630 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574631 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4632 # are too many (1000+) files with slight deviations from the
4633 # coding style. The most important part is that the include guard
4634 # is there, and that it's unique, not the name so this check is
4635 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144636 #
4637 # As code becomes more uniform, this could be made stricter.
4638
4639 guard_name_pattern_list = [
4640 # Anything with the right suffix (maybe with an extra _).
4641 r'\w+_H__?',
4642
Daniel Bratell39b5b062018-05-16 18:09:574643 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144644 r'\w+_h',
4645
4646 # Anything including the uppercase name of the file.
4647 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4648 upper_base_file_name)) + r'\w*',
4649 ]
4650 guard_name_pattern = '|'.join(guard_name_pattern_list)
4651 guard_pattern = input_api.re.compile(
4652 r'#ifndef\s+(' + guard_name_pattern + ')')
4653
4654 for line_number, line in enumerate(f.NewContents()):
4655 if 'no-include-guard-because-multiply-included' in line:
4656 guard_name = 'DUMMY' # To not trigger check outside the loop.
4657 break
4658
4659 if guard_name is None:
4660 match = guard_pattern.match(line)
4661 if match:
4662 guard_name = match.group(1)
4663 guard_line_number = line_number
4664
Daniel Bratell39b5b062018-05-16 18:09:574665 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454666 # don't match the chromium style guide, but new files should
4667 # get it right.
4668 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574669 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144670 errors.append(output_api.PresubmitPromptWarning(
4671 'Header using the wrong include guard name %s' % guard_name,
4672 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574673 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144674 else:
4675 # The line after #ifndef should have a #define of the same name.
4676 if line_number == guard_line_number + 1:
4677 expected_line = '#define %s' % guard_name
4678 if line != expected_line:
4679 errors.append(output_api.PresubmitPromptWarning(
4680 'Missing "%s" for include guard' % expected_line,
4681 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4682 'Expected: %r\nGot: %r' % (expected_line, line)))
4683
4684 if not seen_guard_end and line == '#endif // %s' % guard_name:
4685 seen_guard_end = True
4686 elif seen_guard_end:
4687 if line.strip() != '':
4688 errors.append(output_api.PresubmitPromptWarning(
4689 'Include guard %s not covering the whole file' % (
4690 guard_name), [f.LocalPath()]))
4691 break # Nothing else to check and enough to warn once.
4692
4693 if guard_name is None:
4694 errors.append(output_api.PresubmitPromptWarning(
4695 'Missing include guard %s' % expected_guard,
4696 [f.LocalPath()],
4697 'Missing include guard in %s\n'
4698 'Recommended name: %s\n'
4699 'This check can be disabled by having the string\n'
4700 'no-include-guard-because-multiply-included in the header.' %
4701 (f.LocalPath(), expected_guard)))
4702
4703 return errors
4704
4705
Saagar Sanghavifceeaae2020-08-12 16:40:364706def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234707 """Check source code and known ascii text files for Windows style line
4708 endings.
4709 """
earthdok1b5e0ee2015-03-10 15:19:104710 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234711
4712 file_inclusion_pattern = (
4713 known_text_files,
4714 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4715 )
4716
mostynbb639aca52015-01-07 20:31:234717 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534718 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444719 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534720 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504721 include_file = False
4722 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234723 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504724 include_file = True
4725 if include_file:
4726 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234727
4728 if problems:
4729 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4730 'these files to contain Windows style line endings?\n' +
4731 '\n'.join(problems))]
4732
4733 return []
4734
4735
Saagar Sanghavifceeaae2020-08-12 16:40:364736def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134737 """Checks that all source files use SYSLOG properly."""
4738 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364739 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564740 for line_number, line in f.ChangedContents():
4741 if 'SYSLOG' in line:
4742 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4743
pastarmovj89f7ee12016-09-20 14:58:134744 if syslog_files:
4745 return [output_api.PresubmitPromptWarning(
4746 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4747 ' calls.\nFiles to check:\n', items=syslog_files)]
4748 return []
4749
4750
[email protected]1f7b4172010-01-28 01:17:344751def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364752 if input_api.version < [2, 0, 0]:
4753 return [output_api.PresubmitError("Your depot_tools is out of date. "
4754 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4755 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344756 results = []
scottmg39b29952014-12-08 18:31:284757 results.extend(
jam93a6ee792017-02-08 23:59:224758 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544759 return results
[email protected]ca8d1982009-02-19 16:33:124760
4761
[email protected]1bfb8322014-04-23 01:02:414762def GetTryServerMasterForBot(bot):
4763 """Returns the Try Server master for the given bot.
4764
[email protected]0bb112362014-07-26 04:38:324765 It tries to guess the master from the bot name, but may still fail
4766 and return None. There is no longer a default master.
4767 """
4768 # Potentially ambiguous bot names are listed explicitly.
4769 master_map = {
tandriie5587792016-07-14 00:34:504770 'chromium_presubmit': 'master.tryserver.chromium.linux',
4771 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414772 }
[email protected]0bb112362014-07-26 04:38:324773 master = master_map.get(bot)
4774 if not master:
wnwen4fbaab82016-05-25 12:54:364775 if 'android' in bot:
tandriie5587792016-07-14 00:34:504776 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364777 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504778 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324779 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504780 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324781 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504782 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324783 return master
[email protected]1bfb8322014-04-23 01:02:414784
4785
[email protected]ca8d1982009-02-19 16:33:124786def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364787 if input_api.version < [2, 0, 0]:
4788 return [output_api.PresubmitError("Your depot_tools is out of date. "
4789 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4790 "but your version is %d.%d.%d" % tuple(input_api.version))]
4791
[email protected]fe5f57c52009-06-05 14:25:544792 results = []
[email protected]fe5f57c52009-06-05 14:25:544793 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274794 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344795 input_api,
4796 output_api,
[email protected]2fdd1f362013-01-16 03:56:034797 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274798
jam93a6ee792017-02-08 23:59:224799 results.extend(
4800 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544801 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4802 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384803 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4804 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414805 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4806 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544807 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144808
4809
Saagar Sanghavifceeaae2020-08-12 16:40:364810def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264811 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024812 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4813 # footer is set to true.
4814 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264815 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024816 footer.lower()
4817 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264818 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024819
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144820 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264821 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144822 import sys
4823 from io import StringIO
4824
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144825 new_or_added_paths = set(f.LocalPath()
4826 for f in input_api.AffectedFiles()
4827 if (f.Action() == 'A' or f.Action() == 'M'))
4828 removed_paths = set(f.LocalPath()
4829 for f in input_api.AffectedFiles(include_deletes=True)
4830 if f.Action() == 'D')
4831
Andrew Grieve0e8790c2020-09-03 17:27:324832 affected_grds = [
4833 f for f in input_api.AffectedFiles()
4834 if f.LocalPath().endswith(('.grd', '.grdp'))
4835 ]
4836 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164837 if not affected_grds:
4838 return []
4839
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144840 affected_png_paths = [f.AbsoluteLocalPath()
4841 for f in input_api.AffectedFiles()
4842 if (f.LocalPath().endswith('.png'))]
4843
4844 # Check for screenshots. Developers can upload screenshots using
4845 # tools/translation/upload_screenshots.py which finds and uploads
4846 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4847 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4848 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4849 #
4850 # The logic here is as follows:
4851 #
4852 # - If the CL has a .png file under the screenshots directory for a grd
4853 # file, warn the developer. Actual images should never be checked into the
4854 # Chrome repo.
4855 #
4856 # - If the CL contains modified or new messages in grd files and doesn't
4857 # contain the corresponding .sha1 files, warn the developer to add images
4858 # and upload them via tools/translation/upload_screenshots.py.
4859 #
4860 # - If the CL contains modified or new messages in grd files and the
4861 # corresponding .sha1 files, everything looks good.
4862 #
4863 # - If the CL contains removed messages in grd files but the corresponding
4864 # .sha1 files aren't removed, warn the developer to remove them.
4865 unnecessary_screenshots = []
4866 missing_sha1 = []
4867 unnecessary_sha1_files = []
4868
Rainhard Findlingfc31844c52020-05-15 09:58:264869 # This checks verifies that the ICU syntax of messages this CL touched is
4870 # valid, and reports any found syntax errors.
4871 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4872 # without developers being aware of them. Later on, such ICU syntax errors
4873 # break message extraction for translation, hence would block Chromium
4874 # translations until they are fixed.
4875 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144876
4877 def _CheckScreenshotAdded(screenshots_dir, message_id):
4878 sha1_path = input_api.os_path.join(
4879 screenshots_dir, message_id + '.png.sha1')
4880 if sha1_path not in new_or_added_paths:
4881 missing_sha1.append(sha1_path)
4882
4883
4884 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4885 sha1_path = input_api.os_path.join(
4886 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034887 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144888 unnecessary_sha1_files.append(sha1_path)
4889
Rainhard Findlingfc31844c52020-05-15 09:58:264890
4891 def _ValidateIcuSyntax(text, level, signatures):
4892 """Validates ICU syntax of a text string.
4893
4894 Check if text looks similar to ICU and checks for ICU syntax correctness
4895 in this case. Reports various issues with ICU syntax and values of
4896 variants. Supports checking of nested messages. Accumulate information of
4897 each ICU messages found in the text for further checking.
4898
4899 Args:
4900 text: a string to check.
4901 level: a number of current nesting level.
4902 signatures: an accumulator, a list of tuple of (level, variable,
4903 kind, variants).
4904
4905 Returns:
4906 None if a string is not ICU or no issue detected.
4907 A tuple of (message, start index, end index) if an issue detected.
4908 """
4909 valid_types = {
4910 'plural': (frozenset(
4911 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4912 frozenset(['=1', 'other'])),
4913 'selectordinal': (frozenset(
4914 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4915 frozenset(['one', 'other'])),
4916 'select': (frozenset(), frozenset(['other'])),
4917 }
4918
4919 # Check if the message looks like an attempt to use ICU
4920 # plural. If yes - check if its syntax strictly matches ICU format.
4921 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4922 if not like:
4923 signatures.append((level, None, None, None))
4924 return
4925
4926 # Check for valid prefix and suffix
4927 m = re.match(
4928 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4929 r'(plural|selectordinal|select),\s*'
4930 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4931 if not m:
4932 return (('This message looks like an ICU plural, '
4933 'but does not follow ICU syntax.'), like.start(), like.end())
4934 starting, variable, kind, variant_pairs = m.groups()
4935 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4936 if depth:
4937 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4938 len(text))
4939 first = text[0]
4940 ending = text[last_pos:]
4941 if not starting:
4942 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4943 last_pos)
4944 if not ending or '}' not in ending:
4945 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4946 last_pos)
4947 elif first != '{':
4948 return (
4949 ('Invalid ICU format. Extra characters at the start of a complex '
4950 'message (go/icu-message-migration): "%s"') %
4951 starting, 0, len(starting))
4952 elif ending != '}':
4953 return (('Invalid ICU format. Extra characters at the end of a complex '
4954 'message (go/icu-message-migration): "%s"')
4955 % ending, last_pos - 1, len(text) - 1)
4956 if kind not in valid_types:
4957 return (('Unknown ICU message type %s. '
4958 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4959 known, required = valid_types[kind]
4960 defined_variants = set()
4961 for variant, variant_range, value, value_range in variants:
4962 start, end = variant_range
4963 if variant in defined_variants:
4964 return ('Variant "%s" is defined more than once' % variant,
4965 start, end)
4966 elif known and variant not in known:
4967 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4968 start, end)
4969 defined_variants.add(variant)
4970 # Check for nested structure
4971 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4972 if res:
4973 return (res[0], res[1] + value_range[0] + 1,
4974 res[2] + value_range[0] + 1)
4975 missing = required - defined_variants
4976 if missing:
4977 return ('Required variants missing: %s' % ', '.join(missing), 0,
4978 len(text))
4979 signatures.append((level, variable, kind, defined_variants))
4980
4981
4982 def _ParseIcuVariants(text, offset=0):
4983 """Parse variants part of ICU complex message.
4984
4985 Builds a tuple of variant names and values, as well as
4986 their offsets in the input string.
4987
4988 Args:
4989 text: a string to parse
4990 offset: additional offset to add to positions in the text to get correct
4991 position in the complete ICU string.
4992
4993 Returns:
4994 List of tuples, each tuple consist of four fields: variant name,
4995 variant name span (tuple of two integers), variant value, value
4996 span (tuple of two integers).
4997 """
4998 depth, start, end = 0, -1, -1
4999 variants = []
5000 key = None
5001 for idx, char in enumerate(text):
5002 if char == '{':
5003 if not depth:
5004 start = idx
5005 chunk = text[end + 1:start]
5006 key = chunk.strip()
5007 pos = offset + end + 1 + chunk.find(key)
5008 span = (pos, pos + len(key))
5009 depth += 1
5010 elif char == '}':
5011 if not depth:
5012 return variants, depth, offset + idx
5013 depth -= 1
5014 if not depth:
5015 end = idx
5016 variants.append((key, span, text[start:end + 1], (offset + start,
5017 offset + end + 1)))
5018 return variants, depth, offset + end + 1
5019
meacer8c0d3832019-12-26 21:46:165020 try:
5021 old_sys_path = sys.path
5022 sys.path = sys.path + [input_api.os_path.join(
5023 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5024 from helper import grd_helper
5025 finally:
5026 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145027
5028 for f in affected_grds:
5029 file_path = f.LocalPath()
5030 old_id_to_msg_map = {}
5031 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385032 # Note that this code doesn't check if the file has been deleted. This is
5033 # OK because it only uses the old and new file contents and doesn't load
5034 # the file via its path.
5035 # It's also possible that a file's content refers to a renamed or deleted
5036 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5037 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5038 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145039 if file_path.endswith('.grdp'):
5040 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585041 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395042 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145043 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585044 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395045 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145046 else:
meacerff8a9b62019-12-10 19:43:585047 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145048 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585049 old_id_to_msg_map = grd_helper.GetGrdMessages(
5050 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145051 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585052 new_id_to_msg_map = grd_helper.GetGrdMessages(
5053 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145054
Rainhard Findlingd8d04372020-08-13 13:30:095055 grd_name, ext = input_api.os_path.splitext(
5056 input_api.os_path.basename(file_path))
5057 screenshots_dir = input_api.os_path.join(
5058 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5059
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145060 # Compute added, removed and modified message IDs.
5061 old_ids = set(old_id_to_msg_map)
5062 new_ids = set(new_id_to_msg_map)
5063 added_ids = new_ids - old_ids
5064 removed_ids = old_ids - new_ids
5065 modified_ids = set([])
5066 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355067 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095068 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5069 # The message content itself changed. Require an updated screenshot.
5070 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355071 elif old_id_to_msg_map[key].attrs['meaning'] != \
5072 new_id_to_msg_map[key].attrs['meaning']:
5073 # The message meaning changed. Ensure there is a screenshot for it.
5074 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5075 if sha1_path not in new_or_added_paths and not \
5076 input_api.os_path.exists(sha1_path):
5077 # There is neither a previous screenshot nor is a new one added now.
5078 # Require a screenshot.
5079 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145080
Rainhard Findlingfc31844c52020-05-15 09:58:265081 if run_screenshot_check:
5082 # Check the screenshot directory for .png files. Warn if there is any.
5083 for png_path in affected_png_paths:
5084 if png_path.startswith(screenshots_dir):
5085 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145086
Rainhard Findlingfc31844c52020-05-15 09:58:265087 for added_id in added_ids:
5088 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145089
Rainhard Findlingfc31844c52020-05-15 09:58:265090 for modified_id in modified_ids:
5091 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145092
Rainhard Findlingfc31844c52020-05-15 09:58:265093 for removed_id in removed_ids:
5094 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5095
5096 # Check new and changed strings for ICU syntax errors.
5097 for key in added_ids.union(modified_ids):
5098 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5099 err = _ValidateIcuSyntax(msg, 0, [])
5100 if err is not None:
5101 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145102
5103 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265104 if run_screenshot_check:
5105 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005106 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265107 'Do not include actual screenshots in the changelist. Run '
5108 'tools/translate/upload_screenshots.py to upload them instead:',
5109 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145110
Rainhard Findlingfc31844c52020-05-15 09:58:265111 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005112 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265113 'You are adding or modifying UI strings.\n'
5114 'To ensure the best translations, take screenshots of the relevant UI '
5115 '(https://g.co/chrome/translation) and add these files to your '
5116 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145117
Rainhard Findlingfc31844c52020-05-15 09:58:265118 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005119 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265120 'You removed strings associated with these files. Remove:',
5121 sorted(unnecessary_sha1_files)))
5122 else:
5123 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5124 'screenshots check.'))
5125
5126 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075127 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265128 'ICU syntax errors were found in the following strings (problems or '
5129 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145130
5131 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125132
5133
Saagar Sanghavifceeaae2020-08-12 16:40:365134def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125135 repo_root=None,
5136 translation_expectations_path=None,
5137 grd_files=None):
5138 import sys
5139 affected_grds = [f for f in input_api.AffectedFiles()
5140 if (f.LocalPath().endswith('.grd') or
5141 f.LocalPath().endswith('.grdp'))]
5142 if not affected_grds:
5143 return []
5144
5145 try:
5146 old_sys_path = sys.path
5147 sys.path = sys.path + [
5148 input_api.os_path.join(
5149 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5150 from helper import git_helper
5151 from helper import translation_helper
5152 finally:
5153 sys.path = old_sys_path
5154
5155 # Check that translation expectations can be parsed and we can get a list of
5156 # translatable grd files. |repo_root| and |translation_expectations_path| are
5157 # only passed by tests.
5158 if not repo_root:
5159 repo_root = input_api.PresubmitLocalPath()
5160 if not translation_expectations_path:
5161 translation_expectations_path = input_api.os_path.join(
5162 repo_root, 'tools', 'gritsettings',
5163 'translation_expectations.pyl')
5164 if not grd_files:
5165 grd_files = git_helper.list_grds_in_repository(repo_root)
5166
dpapad8e21b472020-10-23 17:15:035167 # Ignore bogus grd files used only for testing
5168 # ui/webui/resoucres/tools/generate_grd.py.
5169 ignore_path = input_api.os_path.join(
5170 'ui', 'webui', 'resources', 'tools', 'tests')
5171 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5172
Mustafa Emre Acer51f2f742020-03-09 19:41:125173 try:
5174 translation_helper.get_translatable_grds(repo_root, grd_files,
5175 translation_expectations_path)
5176 except Exception as e:
5177 return [output_api.PresubmitNotifyResult(
5178 'Failed to get a list of translatable grd files. This happens when:\n'
5179 ' - One of the modified grd or grdp files cannot be parsed or\n'
5180 ' - %s is not updated.\n'
5181 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5182 return []
Ken Rockotc31f4832020-05-29 18:58:515183
5184
Saagar Sanghavifceeaae2020-08-12 16:40:365185def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515186 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095187 changed_mojoms = input_api.AffectedFiles(
5188 include_deletes=True,
5189 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515190 delta = []
5191 for mojom in changed_mojoms:
5192 old_contents = ''.join(mojom.OldContents()) or None
5193 new_contents = ''.join(mojom.NewContents()) or None
5194 delta.append({
5195 'filename': mojom.LocalPath(),
5196 'old': '\n'.join(mojom.OldContents()) or None,
5197 'new': '\n'.join(mojom.NewContents()) or None,
5198 })
5199
5200 process = input_api.subprocess.Popen(
5201 [input_api.python_executable,
5202 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5203 'public', 'tools', 'mojom',
5204 'check_stable_mojom_compatibility.py'),
5205 '--src-root', input_api.PresubmitLocalPath()],
5206 stdin=input_api.subprocess.PIPE,
5207 stdout=input_api.subprocess.PIPE,
5208 stderr=input_api.subprocess.PIPE,
5209 universal_newlines=True)
5210 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5211 if process.returncode:
5212 return [output_api.PresubmitError(
5213 'One or more [Stable] mojom definitions appears to have been changed '
5214 'in a way that is not backward-compatible.',
5215 long_text=error)]
5216 return []
Dominic Battre645d42342020-12-04 16:14:105217
5218def CheckDeprecationOfPreferences(input_api, output_api):
5219 """Removing a preference should come with a deprecation."""
5220
5221 def FilterFile(affected_file):
5222 """Accept only .cc files and the like."""
5223 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5224 files_to_skip = (_EXCLUDED_PATHS +
5225 _TEST_CODE_EXCLUDED_PATHS +
5226 input_api.DEFAULT_FILES_TO_SKIP)
5227 return input_api.FilterSourceFile(
5228 affected_file,
5229 files_to_check=file_inclusion_pattern,
5230 files_to_skip=files_to_skip)
5231
5232 def ModifiedLines(affected_file):
5233 """Returns a list of tuples (line number, line text) of added and removed
5234 lines.
5235
5236 Deleted lines share the same line number as the previous line.
5237
5238 This relies on the scm diff output describing each changed code section
5239 with a line of the form
5240
5241 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5242 """
5243 line_num = 0
5244 modified_lines = []
5245 for line in affected_file.GenerateScmDiff().splitlines():
5246 # Extract <new line num> of the patch fragment (see format above).
5247 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5248 if m:
5249 line_num = int(m.groups(1)[0])
5250 continue
5251 if ((line.startswith('+') and not line.startswith('++')) or
5252 (line.startswith('-') and not line.startswith('--'))):
5253 modified_lines.append((line_num, line))
5254
5255 if not line.startswith('-'):
5256 line_num += 1
5257 return modified_lines
5258
5259 def FindLineWith(lines, needle):
5260 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5261
5262 If 0 or >1 lines contain `needle`, -1 is returned.
5263 """
5264 matching_line_numbers = [
5265 # + 1 for 1-based counting of line numbers.
5266 i + 1 for i, line
5267 in enumerate(lines)
5268 if needle in line]
5269 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5270
5271 def ModifiedPrefMigration(affected_file):
5272 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5273 # Determine first and last lines of MigrateObsolete.*Pref functions.
5274 new_contents = affected_file.NewContents();
5275 range_1 = (
5276 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5277 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5278 range_2 = (
5279 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5280 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5281 if (-1 in range_1 + range_2):
5282 raise Exception(
5283 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5284
5285 # Check whether any of the modified lines are part of the
5286 # MigrateObsolete.*Pref functions.
5287 for line_nr, line in ModifiedLines(affected_file):
5288 if (range_1[0] <= line_nr <= range_1[1] or
5289 range_2[0] <= line_nr <= range_2[1]):
5290 return True
5291 return False
5292
5293 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5294 browser_prefs_file_pattern = input_api.re.compile(
5295 r'chrome/browser/prefs/browser_prefs.cc')
5296
5297 changes = input_api.AffectedFiles(include_deletes=True,
5298 file_filter=FilterFile)
5299 potential_problems = []
5300 for f in changes:
5301 for line in f.GenerateScmDiff().splitlines():
5302 # Check deleted lines for pref registrations.
5303 if (line.startswith('-') and not line.startswith('--') and
5304 register_pref_pattern.search(line)):
5305 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5306
5307 if browser_prefs_file_pattern.search(f.LocalPath()):
5308 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5309 # assume that they knew that they have to deprecate preferences and don't
5310 # warn.
5311 try:
5312 if ModifiedPrefMigration(f):
5313 return []
5314 except Exception as e:
5315 return [output_api.PresubmitError(str(e))]
5316
5317 if potential_problems:
5318 return [output_api.PresubmitPromptWarning(
5319 'Discovered possible removal of preference registrations.\n\n'
5320 'Please make sure to properly deprecate preferences by clearing their\n'
5321 'value for a couple of milestones before finally removing the code.\n'
5322 'Otherwise data may stay in the preferences files forever. See\n'
5323 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5324 'This may be a false positive warning (e.g. if you move preference\n'
5325 'registrations to a different place).\n',
5326 potential_problems
5327 )]
5328 return []