blob: c3b5701a799df34617f8285a50146a9a5ab867cc [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 ()
Michael Thiessenfd6919b2020-12-08 20:44:01129 ),
130 (
131 'android.support.test.rule.ActivityTestRule;',
132 (
133 'Do not use ActivityTestRule, use '
134 'org.chromium.base.test.BaseActivityTestRule instead.',
135 ),
136 (
137 'components/cronet/',
138 )
Michael Thiessened631912020-08-07 19:01:31139 )
Michael Thiessen44457642020-02-06 00:24:15140)
wnwenbdc444e2016-05-25 13:44:15141
Daniel Bratell609102be2019-03-27 20:53:21142# Format: Sequence of tuples containing:
143# * String pattern or, if starting with a slash, a regular expression.
144# * Sequence of strings to show when the pattern matches.
145# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41146_BANNED_JAVA_FUNCTIONS = (
147 (
148 'StrictMode.allowThreadDiskReads()',
149 (
150 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
151 'directly.',
152 ),
153 False,
154 ),
155 (
156 'StrictMode.allowThreadDiskWrites()',
157 (
158 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
159 'directly.',
160 ),
161 False,
162 ),
Michael Thiessen0f2547e2020-07-27 21:55:36163 (
164 '.waitForIdleSync()',
165 (
166 'Do not use waitForIdleSync as it masks underlying issues. There is '
167 'almost always something else you should wait on instead.',
168 ),
169 False,
170 ),
Eric Stevensona9a980972017-09-23 00:04:41171)
172
Daniel Bratell609102be2019-03-27 20:53:21173# Format: Sequence of tuples containing:
174# * String pattern or, if starting with a slash, a regular expression.
175# * Sequence of strings to show when the pattern matches.
176# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59177_BANNED_OBJC_FUNCTIONS = (
178 (
179 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20180 (
181 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59182 'prohibited. Please use CrTrackingArea instead.',
183 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
184 ),
185 False,
186 ),
187 (
[email protected]eaae1972014-04-16 04:17:26188 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20189 (
190 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59191 'instead.',
192 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
193 ),
194 False,
195 ),
196 (
197 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20198 (
199 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59200 'Please use |convertPoint:(point) fromView:nil| instead.',
201 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
202 ),
203 True,
204 ),
205 (
206 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20207 (
208 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59209 'Please use |convertPoint:(point) toView:nil| instead.',
210 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
211 ),
212 True,
213 ),
214 (
215 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20216 (
217 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59218 'Please use |convertRect:(point) fromView:nil| instead.',
219 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
220 ),
221 True,
222 ),
223 (
224 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20225 (
226 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59227 'Please use |convertRect:(point) toView:nil| instead.',
228 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
229 ),
230 True,
231 ),
232 (
233 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20234 (
235 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59236 'Please use |convertSize:(point) fromView:nil| instead.',
237 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
238 ),
239 True,
240 ),
241 (
242 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20243 (
244 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59245 'Please use |convertSize:(point) toView:nil| instead.',
246 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
247 ),
248 True,
249 ),
jif65398702016-10-27 10:19:48250 (
251 r"/\s+UTF8String\s*]",
252 (
253 'The use of -[NSString UTF8String] is dangerous as it can return null',
254 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
255 'Please use |SysNSStringToUTF8| instead.',
256 ),
257 True,
258 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34259 (
260 r'__unsafe_unretained',
261 (
262 'The use of __unsafe_unretained is almost certainly wrong, unless',
263 'when interacting with NSFastEnumeration or NSInvocation.',
264 'Please use __weak in files build with ARC, nothing otherwise.',
265 ),
266 False,
267 ),
Avi Drissman7382afa02019-04-29 23:27:13268 (
269 'freeWhenDone:NO',
270 (
271 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
272 'Foundation types is prohibited.',
273 ),
274 True,
275 ),
[email protected]127f18ec2012-06-16 05:05:59276)
277
Daniel Bratell609102be2019-03-27 20:53:21278# Format: Sequence of tuples containing:
279# * String pattern or, if starting with a slash, a regular expression.
280# * Sequence of strings to show when the pattern matches.
281# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54282_BANNED_IOS_OBJC_FUNCTIONS = (
283 (
284 r'/\bTEST[(]',
285 (
286 'TEST() macro should not be used in Objective-C++ code as it does not ',
287 'drain the autorelease pool at the end of the test. Use TEST_F() ',
288 'macro instead with a fixture inheriting from PlatformTest (or a ',
289 'typedef).'
290 ),
291 True,
292 ),
293 (
294 r'/\btesting::Test\b',
295 (
296 'testing::Test should not be used in Objective-C++ code as it does ',
297 'not drain the autorelease pool at the end of the test. Use ',
298 'PlatformTest instead.'
299 ),
300 True,
301 ),
302)
303
Peter K. Lee6c03ccff2019-07-15 14:40:05304# Format: Sequence of tuples containing:
305# * String pattern or, if starting with a slash, a regular expression.
306# * Sequence of strings to show when the pattern matches.
307# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
308_BANNED_IOS_EGTEST_FUNCTIONS = (
309 (
310 r'/\bEXPECT_OCMOCK_VERIFY\b',
311 (
312 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
313 'it is meant for GTests. Use [mock verify] instead.'
314 ),
315 True,
316 ),
317)
318
danakj7a2b7082019-05-21 21:13:51319# Directories that contain deprecated Bind() or Callback types.
320# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36321# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51322# echo "-- $i"
danakj710b4c02019-11-28 16:08:45323# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51324# done
325#
326# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
327# when they have been converted to modern callback types (OnceCallback,
328# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
329# checks for them and prevent regressions.
330_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51331 '^base/callback.h', # Intentional.
Alex Turnerb3ea38c2020-11-25 18:03:07332 '^base/cancelable_callback.h', # Intentional.
Alexander Cooper6b447b22020-07-22 00:47:18333 '^chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc',
334 '^chrome/browser/apps/guest_view/',
Alexander Cooper6b447b22020-07-22 00:47:18335 '^chrome/browser/browsing_data/',
336 '^chrome/browser/captive_portal/captive_portal_browsertest.cc',
337 '^chrome/browser/chromeos/',
338 '^chrome/browser/component_updater/',
Peter Wen6367b882020-08-05 16:55:50339 '^chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc', # pylint: disable=line-too-long
Alexander Cooper6b447b22020-07-22 00:47:18340 '^chrome/browser/devtools/',
341 '^chrome/browser/download/',
342 '^chrome/browser/extensions/',
Alexander Cooper6b447b22020-07-22 00:47:18343 '^chrome/browser/history/',
Alexander Cooper6b447b22020-07-22 00:47:18344 '^chrome/browser/lifetime/',
345 '^chrome/browser/media_galleries/',
Alexander Cooper6b447b22020-07-22 00:47:18346 '^chrome/browser/net/',
347 '^chrome/browser/notifications/',
348 '^chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc',
349 '^chrome/browser/offline_pages/',
Peter Wen6367b882020-08-05 16:55:50350 '^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:18351 '^chrome/browser/payments/payment_manifest_parser_browsertest.cc',
352 '^chrome/browser/pdf/pdf_extension_test.cc',
353 '^chrome/browser/plugins/',
354 '^chrome/browser/policy/',
355 '^chrome/browser/portal/portal_browsertest.cc',
356 '^chrome/browser/prefs/profile_pref_store_manager_unittest.cc',
357 '^chrome/browser/prerender/',
358 '^chrome/browser/previews/',
359 '^chrome/browser/printing/printing_message_filter.cc',
360 '^chrome/browser/profiles/',
361 '^chrome/browser/profiling_host/profiling_process_host.cc',
362 '^chrome/browser/push_messaging/',
363 '^chrome/browser/recovery/recovery_install_global_error.cc',
364 '^chrome/browser/renderer_context_menu/',
365 '^chrome/browser/renderer_host/pepper/',
366 '^chrome/browser/resource_coordinator/',
367 '^chrome/browser/resources/chromeos/accessibility/',
368 '^chrome/browser/rlz/chrome_rlz_tracker_delegate.cc',
Alexander Cooper6b447b22020-07-22 00:47:18369 '^chrome/browser/search_engines/',
370 '^chrome/browser/service_process/',
371 '^chrome/browser/signin/',
372 '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
Alexander Cooper6b447b22020-07-22 00:47:18373 '^chrome/browser/supervised_user/',
374 '^chrome/browser/sync_file_system/',
Alexander Cooper6b447b22020-07-22 00:47:18375 '^chrome/browser/translate/',
376 '^chrome/browser/ui/',
Alexander Cooper6b447b22020-07-22 00:47:18377 '^chrome/browser/web_applications/',
378 '^chrome/browser/win/',
Alex Turner1dc2e1022020-10-22 16:31:54379 '^chrome/test/chromedriver/server/http_handler.cc',
danakj7a2b7082019-05-21 21:13:51380 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51381 '^components/drive/',
danakj7a2b7082019-05-21 21:13:51382 '^components/search_engines/',
danakj7a2b7082019-05-21 21:13:51383 '^components/webcrypto/',
Alan Cutter04a00642020-03-02 01:45:20384 '^extensions/browser/',
385 '^extensions/renderer/',
David Bienvenu0cf6ec02020-12-04 21:03:21386 '^media/blink/',
Daniel Hosseinian41af1882020-10-29 23:10:10387 '^media/cdm/',
Steve Kobes334b6ed2020-07-09 07:26:31388 '^net/http/',
389 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51390 '^ppapi/proxy/',
danakj7a2b7082019-05-21 21:13:51391 '^services/',
danakj7a2b7082019-05-21 21:13:51392 '^tools/clang/base_bind_rewriters/', # Intentional.
393 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51394))
[email protected]127f18ec2012-06-16 05:05:59395
Daniel Bratell609102be2019-03-27 20:53:21396# Format: Sequence of tuples containing:
397# * String pattern or, if starting with a slash, a regular expression.
398# * Sequence of strings to show when the pattern matches.
399# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
400# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59401_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20402 (
Peter Kasting94a56c42019-10-25 21:54:04403 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,
Danil Chapovalov7bc42a72020-12-09 18:20:16613 # Abseil's benchmarks never linked into chrome.
614 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38615 ),
616 (
Peter Kasting991618a62019-06-17 22:00:09617 r'/\bstd::stoi\b',
618 (
619 'std::stoi uses exceptions to communicate results. ',
620 'Use base::StringToInt() instead.',
621 ),
622 True,
623 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
624 ),
625 (
626 r'/\bstd::stol\b',
627 (
628 'std::stol uses exceptions to communicate results. ',
629 'Use base::StringToInt() instead.',
630 ),
631 True,
632 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
633 ),
634 (
635 r'/\bstd::stoul\b',
636 (
637 'std::stoul uses exceptions to communicate results. ',
638 'Use base::StringToUint() instead.',
639 ),
640 True,
641 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
642 ),
643 (
644 r'/\bstd::stoll\b',
645 (
646 'std::stoll uses exceptions to communicate results. ',
647 'Use base::StringToInt64() instead.',
648 ),
649 True,
650 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
651 ),
652 (
653 r'/\bstd::stoull\b',
654 (
655 'std::stoull uses exceptions to communicate results. ',
656 'Use base::StringToUint64() instead.',
657 ),
658 True,
659 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
660 ),
661 (
662 r'/\bstd::stof\b',
663 (
664 'std::stof uses exceptions to communicate results. ',
665 'For locale-independent values, e.g. reading numbers from disk',
666 'profiles, use base::StringToDouble().',
667 'For user-visible values, parse using ICU.',
668 ),
669 True,
670 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
671 ),
672 (
673 r'/\bstd::stod\b',
674 (
675 'std::stod uses exceptions to communicate results. ',
676 'For locale-independent values, e.g. reading numbers from disk',
677 'profiles, use base::StringToDouble().',
678 'For user-visible values, parse using ICU.',
679 ),
680 True,
681 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
682 ),
683 (
684 r'/\bstd::stold\b',
685 (
686 'std::stold uses exceptions to communicate results. ',
687 'For locale-independent values, e.g. reading numbers from disk',
688 'profiles, use base::StringToDouble().',
689 'For user-visible values, parse using ICU.',
690 ),
691 True,
692 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
693 ),
694 (
Daniel Bratell69334cc2019-03-26 11:07:45695 r'/\bstd::to_string\b',
696 (
697 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09698 'For locale-independent strings, e.g. writing numbers to disk',
699 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45700 'For user-visible strings, use base::FormatNumber() and',
701 'the related functions in base/i18n/number_formatting.h.',
702 ),
Peter Kasting991618a62019-06-17 22:00:09703 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21704 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45705 ),
706 (
707 r'/\bstd::shared_ptr\b',
708 (
709 'std::shared_ptr should not be used. Use scoped_refptr instead.',
710 ),
711 True,
Alex Chau9eb03cdd52020-07-13 21:04:57712 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
713 'array_buffer_contents\.(cc|h)',
714 # Needed for interop with third-party library
715 'chrome/services/sharing/nearby/',
716 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21717 ),
718 (
Peter Kasting991618a62019-06-17 22:00:09719 r'/\bstd::weak_ptr\b',
720 (
721 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
722 ),
723 True,
724 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
725 ),
726 (
Daniel Bratell609102be2019-03-27 20:53:21727 r'/\blong long\b',
728 (
729 'long long is banned. Use stdint.h if you need a 64 bit number.',
730 ),
731 False, # Only a warning since it is already used.
732 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
733 ),
734 (
735 r'/\bstd::bind\b',
736 (
737 'std::bind is banned because of lifetime risks.',
738 'Use base::BindOnce or base::BindRepeating instead.',
739 ),
740 True,
741 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
742 ),
743 (
744 r'/\b#include <chrono>\b',
745 (
746 '<chrono> overlaps with Time APIs in base. Keep using',
747 'base classes.',
748 ),
749 True,
750 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
751 ),
752 (
753 r'/\b#include <exception>\b',
754 (
755 'Exceptions are banned and disabled in Chromium.',
756 ),
757 True,
758 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
759 ),
760 (
761 r'/\bstd::function\b',
762 (
763 'std::function is banned. Instead use base::Callback which directly',
764 'supports Chromium\'s weak pointers, ref counting and more.',
765 ),
Peter Kasting991618a62019-06-17 22:00:09766 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21767 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
768 ),
769 (
770 r'/\b#include <random>\b',
771 (
772 'Do not use any random number engines from <random>. Instead',
773 'use base::RandomBitGenerator.',
774 ),
775 True,
776 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
777 ),
778 (
Tom Andersona95e12042020-09-09 23:08:00779 r'/\b#include <X11/',
780 (
781 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
782 ),
783 True,
784 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
785 ),
786 (
Daniel Bratell609102be2019-03-27 20:53:21787 r'/\bstd::ratio\b',
788 (
789 'std::ratio is banned by the Google Style Guide.',
790 ),
791 True,
792 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45793 ),
794 (
Francois Doray43670e32017-09-27 12:40:38795 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
796 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
797 (
798 'Use the new API in base/threading/thread_restrictions.h.',
799 ),
Gabriel Charette04b138f2018-08-06 00:03:22800 False,
Francois Doray43670e32017-09-27 12:40:38801 (),
802 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38803 (
danakj7a2b7082019-05-21 21:13:51804 r'/\bbase::Bind\(',
805 (
806 'Please use base::Bind{Once,Repeating} instead',
807 'of base::Bind. (crbug.com/714018)',
808 ),
809 False,
Erik Staaba737d7602019-11-25 18:41:07810 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51811 ),
812 (
813 r'/\bbase::Callback[<:]',
814 (
815 'Please use base::{Once,Repeating}Callback instead',
816 'of base::Callback. (crbug.com/714018)',
817 ),
818 False,
Erik Staaba737d7602019-11-25 18:41:07819 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51820 ),
821 (
822 r'/\bbase::Closure\b',
823 (
824 'Please use base::{Once,Repeating}Closure instead',
825 'of base::Closure. (crbug.com/714018)',
826 ),
827 False,
Erik Staaba737d7602019-11-25 18:41:07828 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51829 ),
830 (
Alex Turnerb3ea38c2020-11-25 18:03:07831 r'/\bbase::CancelableCallback[<:]',
832 (
833 'Please use base::Cancelable{Once,Repeating}Callback instead',
834 'of base::CancelableCallback. (crbug.com/714018)',
835 ),
836 False,
837 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
838 ),
839 (
840 r'/\bbase::CancelableClosure\b',
841 (
842 'Please use base::Cancelable{Once,Repeating}Closure instead',
843 'of base::CancelableClosure. (crbug.com/714018)',
844 ),
845 False,
846 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
847 ),
848 (
Michael Giuffrida7f93d6922019-04-19 14:39:58849 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19850 (
851 'RunMessageLoop is deprecated, use RunLoop instead.',
852 ),
853 False,
854 (),
855 ),
856 (
Dave Tapuska98199b612019-07-10 13:30:44857 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19858 (
859 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
860 ),
861 False,
862 (),
863 ),
864 (
Dave Tapuska98199b612019-07-10 13:30:44865 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19866 (
867 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
868 "if you're convinced you need this.",
869 ),
870 False,
871 (),
872 ),
873 (
Dave Tapuska98199b612019-07-10 13:30:44874 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19875 (
876 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04877 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19878 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
879 'async events instead of flushing threads.',
880 ),
881 False,
882 (),
883 ),
884 (
885 r'MessageLoopRunner',
886 (
887 'MessageLoopRunner is deprecated, use RunLoop instead.',
888 ),
889 False,
890 (),
891 ),
892 (
Dave Tapuska98199b612019-07-10 13:30:44893 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19894 (
895 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
896 "gab@ if you found a use case where this is the only solution.",
897 ),
898 False,
899 (),
900 ),
901 (
Victor Costane48a2e82019-03-15 22:02:34902 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16903 (
Victor Costane48a2e82019-03-15 22:02:34904 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16905 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
906 ),
907 True,
908 (
909 r'^sql/initialization\.(cc|h)$',
910 r'^third_party/sqlite/.*\.(c|cc|h)$',
911 ),
912 ),
Matt Menke7f520a82018-03-28 21:38:37913 (
Dave Tapuska98199b612019-07-10 13:30:44914 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47915 (
916 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
917 'base::RandomShuffle instead.'
918 ),
919 True,
920 (),
921 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24922 (
923 'ios/web/public/test/http_server',
924 (
925 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
926 ),
927 False,
928 (),
929 ),
Robert Liao764c9492019-01-24 18:46:28930 (
931 'GetAddressOf',
932 (
933 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53934 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11935 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53936 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28937 ),
938 True,
939 (),
940 ),
Antonio Gomes07300d02019-03-13 20:59:57941 (
942 'DEFINE_TYPE_CASTS',
943 (
944 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
945 '//third_party/blink/renderer/platform/casting.h.'
946 ),
947 True,
948 (
949 r'^third_party/blink/renderer/.*\.(cc|h)$',
950 ),
951 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38952 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45953 r'/\bIsHTML.+Element\(\b',
954 (
955 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
956 ' helpers IsA<HTMLXXXXElement> from ',
957 '//third_party/blink/renderer/platform/casting.h.'
958 ),
959 False,
960 (
961 r'^third_party/blink/renderer/.*\.(cc|h)$',
962 ),
963 ),
964 (
965 r'/\bToHTML.+Element(|OrNull)\(\b',
966 (
967 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
968 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
969 'and DynamicTo<HTMLXXXXElement> from ',
970 '//third_party/blink/renderer/platform/casting.h.'
971 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
972 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
973 ),
974 False,
975 (
976 r'^third_party/blink/renderer/.*\.(cc|h)$',
977 ),
978 ),
979 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37980 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38981 (
982 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
983 ),
984 True,
985 (),
986 ),
Ben Lewisa9514602019-04-29 17:53:05987 (
988 'SHFileOperation',
989 (
990 'SHFileOperation was deprecated in Windows Vista, and there are less ',
991 'complex functions to achieve the same goals. Use IFileOperation for ',
992 'any esoteric actions instead.'
993 ),
994 True,
995 (),
996 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18997 (
Cliff Smolinsky81951642019-04-30 21:39:51998 'StringFromGUID2',
999 (
1000 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241001 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511002 ),
1003 True,
1004 (
1005 r'/base/win/win_util_unittest.cc'
1006 ),
1007 ),
1008 (
1009 'StringFromCLSID',
1010 (
1011 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241012 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511013 ),
1014 True,
1015 (
1016 r'/base/win/win_util_unittest.cc'
1017 ),
1018 ),
1019 (
Avi Drissman7382afa02019-04-29 23:27:131020 'kCFAllocatorNull',
1021 (
1022 'The use of kCFAllocatorNull with the NoCopy creation of ',
1023 'CoreFoundation types is prohibited.',
1024 ),
1025 True,
1026 (),
1027 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291028 (
1029 'mojo::ConvertTo',
1030 (
1031 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1032 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1033 'StringTraits if you would like to convert between custom types and',
1034 'the wire format of mojom types.'
1035 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221036 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291037 (
Wezf89dec092019-09-11 19:38:331038 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1039 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291040 r'^third_party/blink/.*\.(cc|h)$',
1041 r'^content/renderer/.*\.(cc|h)$',
1042 ),
1043 ),
Robert Liao1d78df52019-11-11 20:02:011044 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161045 'GetInterfaceProvider',
1046 (
1047 'InterfaceProvider is deprecated.',
1048 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1049 'or Platform::GetBrowserInterfaceBroker.'
1050 ),
1051 False,
1052 (),
1053 ),
1054 (
Robert Liao1d78df52019-11-11 20:02:011055 'CComPtr',
1056 (
1057 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1058 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1059 'details.'
1060 ),
1061 False,
1062 (),
1063 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201064 (
1065 r'/\b(IFACE|STD)METHOD_?\(',
1066 (
1067 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1068 'Instead, always use IFACEMETHODIMP in the declaration.'
1069 ),
1070 False,
1071 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1072 ),
Allen Bauer53b43fb12020-03-12 17:21:471073 (
1074 'set_owned_by_client',
1075 (
1076 'set_owned_by_client is deprecated.',
1077 'views::View already owns the child views by default. This introduces ',
1078 'a competing ownership model which makes the code difficult to reason ',
1079 'about. See http://crbug.com/1044687 for more details.'
1080 ),
1081 False,
1082 (),
1083 ),
Eric Secklerbe6f48d2020-05-06 18:09:121084 (
1085 r'/\bTRACE_EVENT_ASYNC_',
1086 (
1087 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1088 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1089 ),
1090 False,
1091 (
1092 r'^base/trace_event/.*',
1093 r'^base/tracing/.*',
1094 ),
1095 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:261096 (
1097 r'/\bScopedObserver',
1098 (
1099 'ScopedObserver is deprecated.',
1100 'Please use base::ScopedObservation for observing a single source,',
1101 'or base::ScopedMultiSourceObservation for observing multple sources',
1102 ),
1103 False,
1104 (),
1105 ),
[email protected]127f18ec2012-06-16 05:05:591106)
1107
Mario Sanchez Prada2472cab2019-09-18 10:58:311108# Format: Sequence of tuples containing:
1109# * String pattern or, if starting with a slash, a regular expression.
1110# * Sequence of strings to show when the pattern matches.
1111_DEPRECATED_MOJO_TYPES = (
1112 (
1113 r'/\bmojo::AssociatedBinding\b',
1114 (
1115 'mojo::AssociatedBinding<Interface> is deprecated.',
1116 'Use mojo::AssociatedReceiver<Interface> instead.',
1117 ),
1118 ),
1119 (
1120 r'/\bmojo::AssociatedBindingSet\b',
1121 (
1122 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1123 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1124 ),
1125 ),
1126 (
1127 r'/\bmojo::AssociatedInterfacePtr\b',
1128 (
1129 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1130 'Use mojo::AssociatedRemote<Interface> instead.',
1131 ),
1132 ),
1133 (
1134 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1135 (
1136 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1137 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1138 ),
1139 ),
1140 (
1141 r'/\bmojo::AssociatedInterfaceRequest\b',
1142 (
1143 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1144 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1145 ),
1146 ),
1147 (
1148 r'/\bmojo::Binding\b',
1149 (
1150 'mojo::Binding<Interface> is deprecated.',
1151 'Use mojo::Receiver<Interface> instead.',
1152 ),
1153 ),
1154 (
1155 r'/\bmojo::BindingSet\b',
1156 (
1157 'mojo::BindingSet<Interface> is deprecated.',
1158 'Use mojo::ReceiverSet<Interface> instead.',
1159 ),
1160 ),
1161 (
1162 r'/\bmojo::InterfacePtr\b',
1163 (
1164 'mojo::InterfacePtr<Interface> is deprecated.',
1165 'Use mojo::Remote<Interface> instead.',
1166 ),
1167 ),
1168 (
1169 r'/\bmojo::InterfacePtrInfo\b',
1170 (
1171 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1172 'Use mojo::PendingRemote<Interface> instead.',
1173 ),
1174 ),
1175 (
1176 r'/\bmojo::InterfaceRequest\b',
1177 (
1178 'mojo::InterfaceRequest<Interface> is deprecated.',
1179 'Use mojo::PendingReceiver<Interface> instead.',
1180 ),
1181 ),
1182 (
1183 r'/\bmojo::MakeRequest\b',
1184 (
1185 'mojo::MakeRequest is deprecated.',
1186 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1187 ),
1188 ),
1189 (
1190 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1191 (
1192 'mojo::MakeRequest is deprecated.',
1193 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181194 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311195 ),
1196 ),
1197 (
1198 r'/\bmojo::MakeStrongBinding\b',
1199 (
1200 'mojo::MakeStrongBinding is deprecated.',
1201 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1202 'mojo::MakeSelfOwnedReceiver() instead.',
1203 ),
1204 ),
1205 (
1206 r'/\bmojo::MakeStrongAssociatedBinding\b',
1207 (
1208 'mojo::MakeStrongAssociatedBinding is deprecated.',
1209 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1210 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1211 ),
1212 ),
1213 (
Gyuyoung Kim4952ba62020-07-07 07:33:441214 r'/\bmojo::StrongAssociatedBinding\b',
1215 (
1216 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1217 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1218 ),
1219 ),
1220 (
1221 r'/\bmojo::StrongBinding\b',
1222 (
1223 'mojo::StrongBinding<Interface> is deprecated.',
1224 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1225 ),
1226 ),
1227 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311228 r'/\bmojo::StrongAssociatedBindingSet\b',
1229 (
1230 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1231 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1232 ),
1233 ),
1234 (
1235 r'/\bmojo::StrongBindingSet\b',
1236 (
1237 'mojo::StrongBindingSet<Interface> is deprecated.',
1238 'Use mojo::UniqueReceiverSet<Interface> instead.',
1239 ),
1240 ),
1241)
wnwenbdc444e2016-05-25 13:44:151242
mlamouria82272622014-09-16 18:45:041243_IPC_ENUM_TRAITS_DEPRECATED = (
1244 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501245 'See http://www.chromium.org/Home/chromium-security/education/'
1246 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041247
Stephen Martinis97a394142018-06-07 23:06:051248_LONG_PATH_ERROR = (
1249 'Some files included in this CL have file names that are too long (> 200'
1250 ' characters). If committed, these files will cause issues on Windows. See'
1251 ' https://crbug.com/612667 for more details.'
1252)
1253
Shenghua Zhangbfaa38b82017-11-16 21:58:021254_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041255 r".*[\\/]BuildHooksAndroidImpl\.java",
1256 r".*[\\/]LicenseContentProvider\.java",
1257 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281258 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021259]
[email protected]127f18ec2012-06-16 05:05:591260
Mohamed Heikald048240a2019-11-12 16:57:371261# List of image extensions that are used as resources in chromium.
1262_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1263
Sean Kau46e29bc2017-08-28 16:31:161264# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401265_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041266 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401267 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041268 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1269 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041270 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431271 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161272]
1273
1274
[email protected]b00342e7f2013-03-26 16:21:541275_VALID_OS_MACROS = (
1276 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081277 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541278 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441279 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121280 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541281 'OS_BSD',
1282 'OS_CAT', # For testing.
1283 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041284 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541285 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371286 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541287 'OS_IOS',
1288 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441289 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541290 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211291 'OS_NACL_NONSFI',
1292 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121293 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541294 'OS_OPENBSD',
1295 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371296 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541297 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541298 'OS_WIN',
1299)
1300
1301
Andrew Grieveb773bad2020-06-05 18:00:381302# These are not checked on the public chromium-presubmit trybot.
1303# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041304# checkouts.
agrievef32bcc72016-04-04 14:57:401305_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381306 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381307]
1308
1309
1310_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041311 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361312 'base/android/jni_generator/jni_generator.pydeps',
1313 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361314 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041315 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361316 'build/android/gyp/aar.pydeps',
1317 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271318 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361319 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381320 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361321 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021322 'build/android/gyp/bytecode_rewriter.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111323 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361325 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361326 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111327 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041328 'build/android/gyp/create_app_bundle_apks.pydeps',
1329 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361330 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121331 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221332 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001333 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361334 'build/android/gyp/desugar.pydeps',
1335 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421336 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041337 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361338 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361339 'build/android/gyp/filter_zip.pydeps',
1340 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361341 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361342 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581343 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361344 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141345 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261346 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011347 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041348 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361349 'build/android/gyp/lint.pydeps',
1350 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361351 'build/android/gyp/merge_manifest.pydeps',
1352 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221353 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361354 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461355 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241356 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361357 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461358 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561359 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361360 'build/android/incremental_install/generate_android_manifest.pydeps',
1361 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041362 'build/android/resource_sizes.pydeps',
1363 'build/android/test_runner.pydeps',
1364 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361365 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361366 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321367 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271368 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1369 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001370 'components/cronet/tools/generate_javadoc.pydeps',
1371 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381372 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001373 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381374 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041375 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181376 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041377 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421378 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1379 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131380 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061381 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221382 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401383]
1384
wnwenbdc444e2016-05-25 13:44:151385
agrievef32bcc72016-04-04 14:57:401386_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1387
1388
Eric Boren6fd2b932018-01-25 15:05:081389# Bypass the AUTHORS check for these accounts.
1390_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591391 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451392 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591393 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521394 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071395 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041396 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271397 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041398 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301399 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081400
1401
Daniel Bratell65b033262019-04-23 08:17:061402def _IsCPlusPlusFile(input_api, file_path):
1403 """Returns True if this file contains C++-like code (and not Python,
1404 Go, Java, MarkDown, ...)"""
1405
1406 ext = input_api.os_path.splitext(file_path)[1]
1407 # This list is compatible with CppChecker.IsCppFile but we should
1408 # consider adding ".c" to it. If we do that we can use this function
1409 # at more places in the code.
1410 return ext in (
1411 '.h',
1412 '.cc',
1413 '.cpp',
1414 '.m',
1415 '.mm',
1416 )
1417
1418def _IsCPlusPlusHeaderFile(input_api, file_path):
1419 return input_api.os_path.splitext(file_path)[1] == ".h"
1420
1421
1422def _IsJavaFile(input_api, file_path):
1423 return input_api.os_path.splitext(file_path)[1] == ".java"
1424
1425
1426def _IsProtoFile(input_api, file_path):
1427 return input_api.os_path.splitext(file_path)[1] == ".proto"
1428
Mohamed Heikal5e5b7922020-10-29 18:57:591429
1430def CheckNoUpstreamDepsOnClank(input_api, output_api):
1431 """Prevent additions of dependencies from the upstream repo on //clank."""
1432 # clank can depend on clank
1433 if input_api.change.RepositoryRoot().endswith('clank'):
1434 return []
1435 build_file_patterns = [
1436 r'(.+/)?BUILD\.gn',
1437 r'.+\.gni',
1438 ]
1439 excluded_files = [
1440 r'build[/\\]config[/\\]android[/\\]config\.gni'
1441 ]
1442 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1443
1444 error_message = 'Disallowed import on //clank in an upstream build file:'
1445
1446 def FilterFile(affected_file):
1447 return input_api.FilterSourceFile(
1448 affected_file,
1449 files_to_check=build_file_patterns,
1450 files_to_skip=excluded_files)
1451
1452 problems = []
1453 for f in input_api.AffectedSourceFiles(FilterFile):
1454 local_path = f.LocalPath()
1455 for line_number, line in f.ChangedContents():
1456 if (bad_pattern.search(line)):
1457 problems.append(
1458 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1459 if problems:
1460 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1461 else:
1462 return []
1463
1464
Saagar Sanghavifceeaae2020-08-12 16:40:361465def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191466 """Attempts to prevent use of functions intended only for testing in
1467 non-testing code. For now this is just a best-effort implementation
1468 that ignores header files and may have some false positives. A
1469 better implementation would probably need a proper C++ parser.
1470 """
1471 # We only scan .cc files and the like, as the declaration of
1472 # for-testing functions in header files are hard to distinguish from
1473 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491474 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191475
jochenc0d4808c2015-07-27 09:25:421476 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191477 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091478 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131479 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191480 exclusion_pattern = input_api.re.compile(
1481 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1482 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131483 # Avoid a false positive in this case, where the method name, the ::, and
1484 # the closing { are all on different lines due to line wrapping.
1485 # HelperClassForTesting::
1486 # HelperClassForTesting(
1487 # args)
1488 # : member(0) {}
1489 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191490
1491 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441492 files_to_skip = (_EXCLUDED_PATHS +
1493 _TEST_CODE_EXCLUDED_PATHS +
1494 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191495 return input_api.FilterSourceFile(
1496 affected_file,
James Cook24a504192020-07-23 00:08:441497 files_to_check=file_inclusion_pattern,
1498 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191499
1500 problems = []
1501 for f in input_api.AffectedSourceFiles(FilterFile):
1502 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131503 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241504 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031505 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461506 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131507 not exclusion_pattern.search(line) and
1508 not allowlist_pattern.search(line) and
1509 not in_method_defn):
[email protected]55459852011-08-10 15:17:191510 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031511 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131512 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191513
1514 if problems:
[email protected]f7051d52013-04-02 18:31:421515 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031516 else:
1517 return []
[email protected]55459852011-08-10 15:17:191518
1519
Saagar Sanghavifceeaae2020-08-12 16:40:361520def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231521 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591522 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231523 """
1524 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1525 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1526 name_pattern = r'ForTest(s|ing)?'
1527 # Describes an occurrence of "ForTest*" inside a // comment.
1528 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501529 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551530 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231531 # Catch calls.
1532 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1533 # Ignore definitions. (Comments are ignored separately.)
1534 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1535
1536 problems = []
1537 sources = lambda x: input_api.FilterSourceFile(
1538 x,
James Cook24a504192020-07-23 00:08:441539 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1540 + input_api.DEFAULT_FILES_TO_SKIP),
1541 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231542 )
1543 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1544 local_path = f.LocalPath()
1545 is_inside_javadoc = False
1546 for line_number, line in f.ChangedContents():
1547 if is_inside_javadoc and javadoc_end_re.search(line):
1548 is_inside_javadoc = False
1549 if not is_inside_javadoc and javadoc_start_re.search(line):
1550 is_inside_javadoc = True
1551 if is_inside_javadoc:
1552 continue
1553 if (inclusion_re.search(line) and
1554 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501555 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231556 not exclusion_re.search(line)):
1557 problems.append(
1558 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1559
1560 if problems:
1561 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1562 else:
1563 return []
1564
1565
Saagar Sanghavifceeaae2020-08-12 16:40:361566def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541567 """Checks to make sure no .h files include <iostream>."""
1568 files = []
1569 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1570 input_api.re.MULTILINE)
1571 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1572 if not f.LocalPath().endswith('.h'):
1573 continue
1574 contents = input_api.ReadFile(f)
1575 if pattern.search(contents):
1576 files.append(f)
1577
1578 if len(files):
yolandyandaabc6d2016-04-18 18:29:391579 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061580 'Do not #include <iostream> in header files, since it inserts static '
1581 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541582 '#include <ostream>. See http://crbug.com/94794',
1583 files) ]
1584 return []
1585
Danil Chapovalov3518f362018-08-11 16:13:431586def _CheckNoStrCatRedefines(input_api, output_api):
1587 """Checks no windows headers with StrCat redefined are included directly."""
1588 files = []
1589 pattern_deny = input_api.re.compile(
1590 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1591 input_api.re.MULTILINE)
1592 pattern_allow = input_api.re.compile(
1593 r'^#include\s"base/win/windows_defines.inc"',
1594 input_api.re.MULTILINE)
1595 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1596 contents = input_api.ReadFile(f)
1597 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1598 files.append(f.LocalPath())
1599
1600 if len(files):
1601 return [output_api.PresubmitError(
1602 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1603 'directly since they pollute code with StrCat macro. Instead, '
1604 'include matching header from base/win. See http://crbug.com/856536',
1605 files) ]
1606 return []
1607
[email protected]10689ca2011-09-02 02:31:541608
Saagar Sanghavifceeaae2020-08-12 16:40:361609def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521610 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181611 problems = []
1612 for f in input_api.AffectedFiles():
1613 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1614 continue
1615
1616 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041617 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181618 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1619
1620 if not problems:
1621 return []
1622 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1623 '\n'.join(problems))]
1624
Saagar Sanghavifceeaae2020-08-12 16:40:361625def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341626 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1627
1628 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1629 instead of DISABLED_. To filter false positives, reports are only generated
1630 if a corresponding MAYBE_ line exists.
1631 """
1632 problems = []
1633
1634 # The following two patterns are looked for in tandem - is a test labeled
1635 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1636 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1637 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1638
1639 # This is for the case that a test is disabled on all platforms.
1640 full_disable_pattern = input_api.re.compile(
1641 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1642 input_api.re.MULTILINE)
1643
Katie Df13948e2018-09-25 07:33:441644 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341645 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1646 continue
1647
1648 # Search for MABYE_, DISABLE_ pairs.
1649 disable_lines = {} # Maps of test name to line number.
1650 maybe_lines = {}
1651 for line_num, line in f.ChangedContents():
1652 disable_match = disable_pattern.search(line)
1653 if disable_match:
1654 disable_lines[disable_match.group(1)] = line_num
1655 maybe_match = maybe_pattern.search(line)
1656 if maybe_match:
1657 maybe_lines[maybe_match.group(1)] = line_num
1658
1659 # Search for DISABLE_ occurrences within a TEST() macro.
1660 disable_tests = set(disable_lines.keys())
1661 maybe_tests = set(maybe_lines.keys())
1662 for test in disable_tests.intersection(maybe_tests):
1663 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1664
1665 contents = input_api.ReadFile(f)
1666 full_disable_match = full_disable_pattern.search(contents)
1667 if full_disable_match:
1668 problems.append(' %s' % f.LocalPath())
1669
1670 if not problems:
1671 return []
1672 return [
1673 output_api.PresubmitPromptWarning(
1674 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1675 '\n'.join(problems))
1676 ]
1677
[email protected]72df4e782012-06-21 16:28:181678
Saagar Sanghavifceeaae2020-08-12 16:40:361679def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571680 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521681 errors = []
Hans Wennborg944479f2020-06-25 21:39:251682 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521683 input_api.re.MULTILINE)
1684 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1685 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1686 continue
1687 for lnum, line in f.ChangedContents():
1688 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171689 errors.append(output_api.PresubmitError(
1690 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571691 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171692 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521693 return errors
1694
1695
Weilun Shia487fad2020-10-28 00:10:341696# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1697# more reliable way. See
1698# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191699
wnwenbdc444e2016-05-25 13:44:151700
Saagar Sanghavifceeaae2020-08-12 16:40:361701def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391702 """Check that FlakyTest annotation is our own instead of the android one"""
1703 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1704 files = []
1705 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1706 if f.LocalPath().endswith('Test.java'):
1707 if pattern.search(input_api.ReadFile(f)):
1708 files.append(f)
1709 if len(files):
1710 return [output_api.PresubmitError(
1711 'Use org.chromium.base.test.util.FlakyTest instead of '
1712 'android.test.FlakyTest',
1713 files)]
1714 return []
mcasasb7440c282015-02-04 14:52:191715
wnwenbdc444e2016-05-25 13:44:151716
Saagar Sanghavifceeaae2020-08-12 16:40:361717def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221718 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271719 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221720 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201721 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571722 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341723 '/win/' in f.LocalPath() or
1724 'chrome_elf' in f.LocalPath() or
1725 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201726 continue
[email protected]8ea5d4b2011-09-13 21:49:221727
[email protected]a11dbe9b2012-08-07 01:32:581728 allowWString = False
[email protected]b5c24292011-11-28 14:38:201729 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581730 if 'presubmit: allow wstring' in line:
1731 allowWString = True
1732 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271733 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581734 allowWString = False
1735 else:
1736 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221737
[email protected]55463aa62011-10-12 00:48:271738 if not problems:
1739 return []
1740 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581741 ' If you are calling a cross-platform API that accepts a wstring, '
1742 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271743 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221744
1745
Saagar Sanghavifceeaae2020-08-12 16:40:361746def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441747 """Make sure .DEPS.git is never modified manually."""
1748 if any(f.LocalPath().endswith('.DEPS.git') for f in
1749 input_api.AffectedFiles()):
1750 return [output_api.PresubmitError(
1751 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1752 'automated system based on what\'s in DEPS and your changes will be\n'
1753 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501754 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1755 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441756 'for more information')]
1757 return []
1758
1759
Saagar Sanghavifceeaae2020-08-12 16:40:361760def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471761 """Checks that DEPS file deps are from allowed_hosts."""
1762 # Run only if DEPS file has been modified to annoy fewer bystanders.
1763 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1764 return []
1765 # Outsource work to gclient verify
1766 try:
John Budorickf20c0042019-04-25 23:23:401767 gclient_path = input_api.os_path.join(
1768 input_api.PresubmitLocalPath(),
1769 'third_party', 'depot_tools', 'gclient.py')
1770 input_api.subprocess.check_output(
1771 [input_api.python_executable, gclient_path, 'verify'],
1772 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471773 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201774 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471775 return [output_api.PresubmitError(
1776 'DEPS file must have only git dependencies.',
1777 long_text=error.output)]
1778
1779
Mario Sanchez Prada2472cab2019-09-18 10:58:311780def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1781 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591782 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311783
1784 Returns an string composed of the name of the file, the line number where the
1785 match has been found and the additional text passed as |message| in case the
1786 target type name matches the text inside the line passed as parameter.
1787 """
Peng Huang9c5949a02020-06-11 19:20:541788 result = []
1789
1790 if line.endswith(" nocheck"):
1791 return result
1792
Mario Sanchez Prada2472cab2019-09-18 10:58:311793 matched = False
1794 if type_name[0:1] == '/':
1795 regex = type_name[1:]
1796 if input_api.re.search(regex, line):
1797 matched = True
1798 elif type_name in line:
1799 matched = True
1800
Mario Sanchez Prada2472cab2019-09-18 10:58:311801 if matched:
1802 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1803 for message_line in message:
1804 result.append(' %s' % message_line)
1805
1806 return result
1807
1808
Saagar Sanghavifceeaae2020-08-12 16:40:361809def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591810 """Make sure that banned functions are not used."""
1811 warnings = []
1812 errors = []
1813
James Cook24a504192020-07-23 00:08:441814 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151815 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441816 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151817 if input_api.re.match(item, local_path):
1818 return True
1819 return False
1820
Peter K. Lee6c03ccff2019-07-15 14:40:051821 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541822 local_path = affected_file.LocalPath()
1823 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1824 return False
1825 basename = input_api.os_path.basename(local_path)
1826 if 'ios' in basename.split('_'):
1827 return True
1828 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1829 if sep and 'ios' in local_path.split(sep):
1830 return True
1831 return False
1832
wnwenbdc444e2016-05-25 13:44:151833 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311834 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1835 func_name, message)
1836 if problems:
wnwenbdc444e2016-05-25 13:44:151837 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311838 errors.extend(problems)
1839 else:
1840 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151841
Eric Stevensona9a980972017-09-23 00:04:411842 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1843 for f in input_api.AffectedFiles(file_filter=file_filter):
1844 for line_num, line in f.ChangedContents():
1845 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1846 CheckForMatch(f, line_num, line, func_name, message, error)
1847
[email protected]127f18ec2012-06-16 05:05:591848 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1849 for f in input_api.AffectedFiles(file_filter=file_filter):
1850 for line_num, line in f.ChangedContents():
1851 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151852 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591853
Peter K. Lee6c03ccff2019-07-15 14:40:051854 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541855 for line_num, line in f.ChangedContents():
1856 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1857 CheckForMatch(f, line_num, line, func_name, message, error)
1858
Peter K. Lee6c03ccff2019-07-15 14:40:051859 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1860 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1861 for line_num, line in f.ChangedContents():
1862 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1863 CheckForMatch(f, line_num, line, func_name, message, error)
1864
[email protected]127f18ec2012-06-16 05:05:591865 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1866 for f in input_api.AffectedFiles(file_filter=file_filter):
1867 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491868 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441869 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491870 continue
wnwenbdc444e2016-05-25 13:44:151871 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591872
1873 result = []
1874 if (warnings):
1875 result.append(output_api.PresubmitPromptWarning(
1876 'Banned functions were used.\n' + '\n'.join(warnings)))
1877 if (errors):
1878 result.append(output_api.PresubmitError(
1879 'Banned functions were used.\n' + '\n'.join(errors)))
1880 return result
1881
1882
Michael Thiessen44457642020-02-06 00:24:151883def _CheckAndroidNoBannedImports(input_api, output_api):
1884 """Make sure that banned java imports are not used."""
1885 errors = []
1886
1887 def IsException(path, exceptions):
1888 for exception in exceptions:
1889 if (path.startswith(exception)):
1890 return True
1891 return False
1892
1893 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1894 for f in input_api.AffectedFiles(file_filter=file_filter):
1895 for line_num, line in f.ChangedContents():
1896 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1897 if IsException(f.LocalPath(), exceptions):
1898 continue;
1899 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1900 'import ' + import_name, message)
1901 if problems:
1902 errors.extend(problems)
1903 result = []
1904 if (errors):
1905 result.append(output_api.PresubmitError(
1906 'Banned imports were used.\n' + '\n'.join(errors)))
1907 return result
1908
1909
Saagar Sanghavifceeaae2020-08-12 16:40:361910def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311911 """Make sure that old Mojo types are not used."""
1912 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571913 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311914
Mario Sanchez Pradaaab91382019-12-19 08:57:091915 # For any path that is not an "ok" or an "error" path, a warning will be
1916 # raised if deprecated mojo types are found.
1917 ok_paths = ['components/arc']
1918 error_paths = ['third_party/blink', 'content']
1919
Mario Sanchez Prada2472cab2019-09-18 10:58:311920 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1921 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571922 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091923 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311924 continue
1925
1926 for line_num, line in f.ChangedContents():
1927 for func_name, message in _DEPRECATED_MOJO_TYPES:
1928 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1929 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571930
Mario Sanchez Prada2472cab2019-09-18 10:58:311931 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091932 # Raise errors inside |error_paths| and warnings everywhere else.
1933 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571934 errors.extend(problems)
1935 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311936 warnings.extend(problems)
1937
1938 result = []
1939 if (warnings):
1940 result.append(output_api.PresubmitPromptWarning(
1941 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571942 if (errors):
1943 result.append(output_api.PresubmitError(
1944 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311945 return result
1946
1947
Saagar Sanghavifceeaae2020-08-12 16:40:361948def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061949 """Make sure that banned functions are not used."""
1950 files = []
1951 pattern = input_api.re.compile(r'^#pragma\s+once',
1952 input_api.re.MULTILINE)
1953 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1954 if not f.LocalPath().endswith('.h'):
1955 continue
1956 contents = input_api.ReadFile(f)
1957 if pattern.search(contents):
1958 files.append(f)
1959
1960 if files:
1961 return [output_api.PresubmitError(
1962 'Do not use #pragma once in header files.\n'
1963 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1964 files)]
1965 return []
1966
[email protected]127f18ec2012-06-16 05:05:591967
Saagar Sanghavifceeaae2020-08-12 16:40:361968def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121969 """Checks to make sure we don't introduce use of foo ? true : false."""
1970 problems = []
1971 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1972 for f in input_api.AffectedFiles():
1973 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1974 continue
1975
1976 for line_num, line in f.ChangedContents():
1977 if pattern.match(line):
1978 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1979
1980 if not problems:
1981 return []
1982 return [output_api.PresubmitPromptWarning(
1983 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1984 '\n'.join(problems))]
1985
1986
Saagar Sanghavifceeaae2020-08-12 16:40:361987def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281988 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181989 change. Breaking - rules is an error, breaking ! rules is a
1990 warning.
1991 """
mohan.reddyf21db962014-10-16 12:26:471992 import sys
[email protected]55f9f382012-07-31 11:02:181993 # We need to wait until we have an input_api object and use this
1994 # roundabout construct to import checkdeps because this file is
1995 # eval-ed and thus doesn't have __file__.
1996 original_sys_path = sys.path
1997 try:
1998 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471999 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182000 import checkdeps
[email protected]55f9f382012-07-31 11:02:182001 from rules import Rule
2002 finally:
2003 # Restore sys.path to what it was before.
2004 sys.path = original_sys_path
2005
2006 added_includes = []
rhalavati08acd232017-04-03 07:23:282007 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242008 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182009 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062010 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502011 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082012 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062013 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502014 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082015 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062016 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502017 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082018 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182019
[email protected]26385172013-05-09 23:11:352020 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182021
2022 error_descriptions = []
2023 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282024 error_subjects = set()
2025 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362026
[email protected]55f9f382012-07-31 11:02:182027 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2028 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082029 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182030 description_with_path = '%s\n %s' % (path, rule_description)
2031 if rule_type == Rule.DISALLOW:
2032 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282033 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182034 else:
2035 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282036 warning_subjects.add("#includes")
2037
2038 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2039 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082040 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282041 description_with_path = '%s\n %s' % (path, rule_description)
2042 if rule_type == Rule.DISALLOW:
2043 error_descriptions.append(description_with_path)
2044 error_subjects.add("imports")
2045 else:
2046 warning_descriptions.append(description_with_path)
2047 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182048
Jinsuk Kim5a092672017-10-24 22:42:242049 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022050 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082051 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242052 description_with_path = '%s\n %s' % (path, rule_description)
2053 if rule_type == Rule.DISALLOW:
2054 error_descriptions.append(description_with_path)
2055 error_subjects.add("imports")
2056 else:
2057 warning_descriptions.append(description_with_path)
2058 warning_subjects.add("imports")
2059
[email protected]55f9f382012-07-31 11:02:182060 results = []
2061 if error_descriptions:
2062 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282063 'You added one or more %s that violate checkdeps rules.'
2064 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182065 error_descriptions))
2066 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422067 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282068 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182069 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282070 '%s? See relevant DEPS file(s) for details and contacts.' %
2071 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182072 warning_descriptions))
2073 return results
2074
2075
Saagar Sanghavifceeaae2020-08-12 16:40:362076def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222077 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152078 if input_api.platform == 'win32':
2079 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292080 checkperms_tool = input_api.os_path.join(
2081 input_api.PresubmitLocalPath(),
2082 'tools', 'checkperms', 'checkperms.py')
2083 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472084 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392085 with input_api.CreateTemporaryFile() as file_list:
2086 for f in input_api.AffectedFiles():
2087 # checkperms.py file/directory arguments must be relative to the
2088 # repository.
2089 file_list.write(f.LocalPath() + '\n')
2090 file_list.close()
2091 args += ['--file-list', file_list.name]
2092 try:
2093 input_api.subprocess.check_output(args)
2094 return []
2095 except input_api.subprocess.CalledProcessError as error:
2096 return [output_api.PresubmitError(
2097 'checkperms.py failed:',
2098 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222099
2100
Saagar Sanghavifceeaae2020-08-12 16:40:362101def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492102 """Makes sure we don't include ui/aura/window_property.h
2103 in header files.
2104 """
2105 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2106 errors = []
2107 for f in input_api.AffectedFiles():
2108 if not f.LocalPath().endswith('.h'):
2109 continue
2110 for line_num, line in f.ChangedContents():
2111 if pattern.match(line):
2112 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2113
2114 results = []
2115 if errors:
2116 results.append(output_api.PresubmitError(
2117 'Header files should not include ui/aura/window_property.h', errors))
2118 return results
2119
2120
[email protected]70ca77752012-11-20 03:45:032121def _CheckForVersionControlConflictsInFile(input_api, f):
2122 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2123 errors = []
2124 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162125 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232126 # First-level headers in markdown look a lot like version control
2127 # conflict markers. http://daringfireball.net/projects/markdown/basics
2128 continue
[email protected]70ca77752012-11-20 03:45:032129 if pattern.match(line):
2130 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2131 return errors
2132
2133
Saagar Sanghavifceeaae2020-08-12 16:40:362134def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032135 """Usually this is not intentional and will cause a compile failure."""
2136 errors = []
2137 for f in input_api.AffectedFiles():
2138 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2139
2140 results = []
2141 if errors:
2142 results.append(output_api.PresubmitError(
2143 'Version control conflict markers found, please resolve.', errors))
2144 return results
2145
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202146
Saagar Sanghavifceeaae2020-08-12 16:40:362147def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162148 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2149 errors = []
2150 for f in input_api.AffectedFiles():
2151 for line_num, line in f.ChangedContents():
2152 if pattern.search(line):
2153 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2154
2155 results = []
2156 if errors:
2157 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502158 'Found Google support URL addressed by answer number. Please replace '
2159 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162160 return results
2161
[email protected]70ca77752012-11-20 03:45:032162
Saagar Sanghavifceeaae2020-08-12 16:40:362163def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442164 def FilterFile(affected_file):
2165 """Filter function for use with input_api.AffectedSourceFiles,
2166 below. This filters out everything except non-test files from
2167 top-level directories that generally speaking should not hard-code
2168 service URLs (e.g. src/android_webview/, src/content/ and others).
2169 """
2170 return input_api.FilterSourceFile(
2171 affected_file,
James Cook24a504192020-07-23 00:08:442172 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2173 files_to_skip=(_EXCLUDED_PATHS +
2174 _TEST_CODE_EXCLUDED_PATHS +
2175 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442176
reillyi38965732015-11-16 18:27:332177 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2178 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462179 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2180 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442181 problems = [] # items are (filename, line_number, line)
2182 for f in input_api.AffectedSourceFiles(FilterFile):
2183 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462184 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442185 problems.append((f.LocalPath(), line_num, line))
2186
2187 if problems:
[email protected]f7051d52013-04-02 18:31:422188 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442189 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582190 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442191 [' %s:%d: %s' % (
2192 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032193 else:
2194 return []
[email protected]06e6d0ff2012-12-11 01:36:442195
2196
Saagar Sanghavifceeaae2020-08-12 16:40:362197def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292198 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2199 def FileFilter(affected_file):
2200 """Includes directories known to be Chrome OS only."""
2201 return input_api.FilterSourceFile(
2202 affected_file,
James Cook24a504192020-07-23 00:08:442203 files_to_check=('^ash/',
2204 '^chromeos/', # Top-level src/chromeos.
2205 '/chromeos/', # Any path component.
2206 '^components/arc',
2207 '^components/exo'),
2208 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292209
2210 prefs = []
2211 priority_prefs = []
2212 for f in input_api.AffectedFiles(file_filter=FileFilter):
2213 for line_num, line in f.ChangedContents():
2214 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2215 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2216 prefs.append(' %s' % line)
2217 if input_api.re.search(
2218 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2219 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2220 priority_prefs.append(' %s' % line)
2221
2222 results = []
2223 if (prefs):
2224 results.append(output_api.PresubmitPromptWarning(
2225 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2226 'by browser sync settings. If these prefs should be controlled by OS '
2227 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2228 if (priority_prefs):
2229 results.append(output_api.PresubmitPromptWarning(
2230 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2231 'controlled by browser sync settings. If these prefs should be '
2232 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2233 'instead.\n' + '\n'.join(prefs)))
2234 return results
2235
2236
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492237# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362238def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272239 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312240 The native_client_sdk directory is excluded because it has auto-generated PNG
2241 files for documentation.
[email protected]d2530012013-01-25 16:39:272242 """
[email protected]d2530012013-01-25 16:39:272243 errors = []
James Cook24a504192020-07-23 00:08:442244 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2245 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312246 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442247 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312248 for f in input_api.AffectedFiles(include_deletes=False,
2249 file_filter=file_filter):
2250 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272251
2252 results = []
2253 if errors:
2254 results.append(output_api.PresubmitError(
2255 'The name of PNG files should not have abbreviations. \n'
2256 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2257 'Contact [email protected] if you have questions.', errors))
2258 return results
2259
2260
Daniel Cheng4dcdb6b2017-04-13 08:30:172261def _ExtractAddRulesFromParsedDeps(parsed_deps):
2262 """Extract the rules that add dependencies from a parsed DEPS file.
2263
2264 Args:
2265 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2266 add_rules = set()
2267 add_rules.update([
2268 rule[1:] for rule in parsed_deps.get('include_rules', [])
2269 if rule.startswith('+') or rule.startswith('!')
2270 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502271 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172272 {}).iteritems():
2273 add_rules.update([
2274 rule[1:] for rule in rules
2275 if rule.startswith('+') or rule.startswith('!')
2276 ])
2277 return add_rules
2278
2279
2280def _ParseDeps(contents):
2281 """Simple helper for parsing DEPS files."""
2282 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172283 class _VarImpl:
2284
2285 def __init__(self, local_scope):
2286 self._local_scope = local_scope
2287
2288 def Lookup(self, var_name):
2289 """Implements the Var syntax."""
2290 try:
2291 return self._local_scope['vars'][var_name]
2292 except KeyError:
2293 raise Exception('Var is not defined: %s' % var_name)
2294
2295 local_scope = {}
2296 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172297 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592298 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172299 }
2300 exec contents in global_scope, local_scope
2301 return local_scope
2302
2303
2304def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592305 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412306 a set of DEPS entries that we should look up.
2307
2308 For a directory (rather than a specific filename) we fake a path to
2309 a specific filename by adding /DEPS. This is chosen as a file that
2310 will seldom or never be subject to per-file include_rules.
2311 """
[email protected]2b438d62013-11-14 17:54:142312 # We ignore deps entries on auto-generated directories.
2313 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082314
Daniel Cheng4dcdb6b2017-04-13 08:30:172315 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2316 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2317
2318 added_deps = new_deps.difference(old_deps)
2319
[email protected]2b438d62013-11-14 17:54:142320 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172321 for added_dep in added_deps:
2322 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2323 continue
2324 # Assume that a rule that ends in .h is a rule for a specific file.
2325 if added_dep.endswith('.h'):
2326 results.add(added_dep)
2327 else:
2328 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082329 return results
2330
2331
Saagar Sanghavifceeaae2020-08-12 16:40:362332def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552333 """When a dependency prefixed with + is added to a DEPS file, we
2334 want to make sure that the change is reviewed by an OWNER of the
2335 target file or directory, to avoid layering violations from being
2336 introduced. This check verifies that this happens.
2337 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172338 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242339
2340 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492341 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242342 for f in input_api.AffectedFiles(include_deletes=False,
2343 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552344 filename = input_api.os_path.basename(f.LocalPath())
2345 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172346 virtual_depended_on_files.update(_CalculateAddedDeps(
2347 input_api.os_path,
2348 '\n'.join(f.OldContents()),
2349 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552350
[email protected]e871964c2013-05-13 14:14:552351 if not virtual_depended_on_files:
2352 return []
2353
2354 if input_api.is_committing:
2355 if input_api.tbr:
2356 return [output_api.PresubmitNotifyResult(
2357 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272358 if input_api.dry_run:
2359 return [output_api.PresubmitNotifyResult(
2360 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552361 if not input_api.change.issue:
2362 return [output_api.PresubmitError(
2363 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402364 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552365 output = output_api.PresubmitError
2366 else:
2367 output = output_api.PresubmitNotifyResult
2368
2369 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502370 owner_email, reviewers = (
2371 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2372 input_api,
2373 owners_db.email_regexp,
2374 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552375
2376 owner_email = owner_email or input_api.change.author_email
2377
[email protected]de4f7d22013-05-23 14:27:462378 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512379 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462380 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552381 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2382 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412383
2384 # We strip the /DEPS part that was added by
2385 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2386 # directory.
2387 def StripDeps(path):
2388 start_deps = path.rfind('/DEPS')
2389 if start_deps != -1:
2390 return path[:start_deps]
2391 else:
2392 return path
2393 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552394 for path in missing_files]
2395
2396 if unapproved_dependencies:
2397 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152398 output('You need LGTM from owners of depends-on paths in DEPS that were '
2399 'modified in this CL:\n %s' %
2400 '\n '.join(sorted(unapproved_dependencies)))]
2401 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2402 output_list.append(output(
2403 'Suggested missing target path OWNERS:\n %s' %
2404 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552405 return output_list
2406
2407 return []
2408
2409
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492410# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362411def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492412 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442413 files_to_skip = (_EXCLUDED_PATHS +
2414 _TEST_CODE_EXCLUDED_PATHS +
2415 input_api.DEFAULT_FILES_TO_SKIP +
2416 (r"^base[\\/]logging\.h$",
2417 r"^base[\\/]logging\.cc$",
2418 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2419 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2420 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2421 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2422 r"startup_browser_creator\.cc$",
2423 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2424 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2425 r"diagnostics_writer\.cc$",
2426 r"^chrome[\\/]chrome_cleaner[\\/].*",
2427 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2428 r"dll_hash_main\.cc$",
2429 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2430 r"^chromecast[\\/]",
2431 r"^cloud_print[\\/]",
2432 r"^components[\\/]browser_watcher[\\/]"
2433 r"dump_stability_report_main_win.cc$",
2434 r"^components[\\/]media_control[\\/]renderer[\\/]"
2435 r"media_playback_options\.cc$",
2436 r"^components[\\/]zucchini[\\/].*",
2437 # TODO(peter): Remove exception. https://crbug.com/534537
2438 r"^content[\\/]browser[\\/]notifications[\\/]"
2439 r"notification_event_dispatcher_impl\.cc$",
2440 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2441 r"gl_helper_benchmark\.cc$",
2442 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2443 r"^courgette[\\/]courgette_tool\.cc$",
2444 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2445 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2446 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2447 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2448 r"^ipc[\\/]ipc_logging\.cc$",
2449 r"^native_client_sdk[\\/]",
2450 r"^remoting[\\/]base[\\/]logging\.h$",
2451 r"^remoting[\\/]host[\\/].*",
2452 r"^sandbox[\\/]linux[\\/].*",
2453 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2454 r"dump_file_system.cc$",
2455 r"^tools[\\/]",
2456 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2457 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2458 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2459 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2460 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402461 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442462 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402463
thomasanderson625d3932017-03-29 07:16:582464 log_info = set([])
2465 printf = set([])
[email protected]85218562013-11-22 07:41:402466
2467 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582468 for _, line in f.ChangedContents():
2469 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2470 log_info.add(f.LocalPath())
2471 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2472 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372473
thomasanderson625d3932017-03-29 07:16:582474 if input_api.re.search(r"\bprintf\(", line):
2475 printf.add(f.LocalPath())
2476 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2477 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402478
2479 if log_info:
2480 return [output_api.PresubmitError(
2481 'These files spam the console log with LOG(INFO):',
2482 items=log_info)]
2483 if printf:
2484 return [output_api.PresubmitError(
2485 'These files spam the console log with printf/fprintf:',
2486 items=printf)]
2487 return []
2488
2489
Saagar Sanghavifceeaae2020-08-12 16:40:362490def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162491 """These types are all expected to hold locks while in scope and
2492 so should never be anonymous (which causes them to be immediately
2493 destroyed)."""
2494 they_who_must_be_named = [
2495 'base::AutoLock',
2496 'base::AutoReset',
2497 'base::AutoUnlock',
2498 'SkAutoAlphaRestore',
2499 'SkAutoBitmapShaderInstall',
2500 'SkAutoBlitterChoose',
2501 'SkAutoBounderCommit',
2502 'SkAutoCallProc',
2503 'SkAutoCanvasRestore',
2504 'SkAutoCommentBlock',
2505 'SkAutoDescriptor',
2506 'SkAutoDisableDirectionCheck',
2507 'SkAutoDisableOvalCheck',
2508 'SkAutoFree',
2509 'SkAutoGlyphCache',
2510 'SkAutoHDC',
2511 'SkAutoLockColors',
2512 'SkAutoLockPixels',
2513 'SkAutoMalloc',
2514 'SkAutoMaskFreeImage',
2515 'SkAutoMutexAcquire',
2516 'SkAutoPathBoundsUpdate',
2517 'SkAutoPDFRelease',
2518 'SkAutoRasterClipValidate',
2519 'SkAutoRef',
2520 'SkAutoTime',
2521 'SkAutoTrace',
2522 'SkAutoUnref',
2523 ]
2524 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2525 # bad: base::AutoLock(lock.get());
2526 # not bad: base::AutoLock lock(lock.get());
2527 bad_pattern = input_api.re.compile(anonymous)
2528 # good: new base::AutoLock(lock.get())
2529 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2530 errors = []
2531
2532 for f in input_api.AffectedFiles():
2533 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2534 continue
2535 for linenum, line in f.ChangedContents():
2536 if bad_pattern.search(line) and not good_pattern.search(line):
2537 errors.append('%s:%d' % (f.LocalPath(), linenum))
2538
2539 if errors:
2540 return [output_api.PresubmitError(
2541 'These lines create anonymous variables that need to be named:',
2542 items=errors)]
2543 return []
2544
2545
Saagar Sanghavifceeaae2020-08-12 16:40:362546def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532547 # Returns whether |template_str| is of the form <T, U...> for some types T
2548 # and U. Assumes that |template_str| is already in the form <...>.
2549 def HasMoreThanOneArg(template_str):
2550 # Level of <...> nesting.
2551 nesting = 0
2552 for c in template_str:
2553 if c == '<':
2554 nesting += 1
2555 elif c == '>':
2556 nesting -= 1
2557 elif c == ',' and nesting == 1:
2558 return True
2559 return False
2560
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492561 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102562 sources = lambda affected_file: input_api.FilterSourceFile(
2563 affected_file,
James Cook24a504192020-07-23 00:08:442564 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2565 input_api.DEFAULT_FILES_TO_SKIP),
2566 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552567
2568 # Pattern to capture a single "<...>" block of template arguments. It can
2569 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2570 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2571 # latter would likely require counting that < and > match, which is not
2572 # expressible in regular languages. Should the need arise, one can introduce
2573 # limited counting (matching up to a total number of nesting depth), which
2574 # should cover all practical cases for already a low nesting limit.
2575 template_arg_pattern = (
2576 r'<[^>]*' # Opening block of <.
2577 r'>([^<]*>)?') # Closing block of >.
2578 # Prefix expressing that whatever follows is not already inside a <...>
2579 # block.
2580 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102581 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552582 not_inside_template_arg_pattern
2583 + r'\bstd::unique_ptr'
2584 + template_arg_pattern
2585 + r'\(\)')
2586
2587 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2588 template_arg_no_array_pattern = (
2589 r'<[^>]*[^]]' # Opening block of <.
2590 r'>([^(<]*[^]]>)?') # Closing block of >.
2591 # Prefix saying that what follows is the start of an expression.
2592 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2593 # Suffix saying that what follows are call parentheses with a non-empty list
2594 # of arguments.
2595 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532596 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552597 return_construct_pattern = input_api.re.compile(
2598 start_of_expr_pattern
2599 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532600 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552601 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532602 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552603 + nonempty_arg_list_pattern)
2604
Vaclav Brozek851d9602018-04-04 16:13:052605 problems_constructor = []
2606 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102607 for f in input_api.AffectedSourceFiles(sources):
2608 for line_number, line in f.ChangedContents():
2609 # Disallow:
2610 # return std::unique_ptr<T>(foo);
2611 # bar = std::unique_ptr<T>(foo);
2612 # But allow:
2613 # return std::unique_ptr<T[]>(foo);
2614 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532615 # And also allow cases when the second template argument is present. Those
2616 # cases cannot be handled by std::make_unique:
2617 # return std::unique_ptr<T, U>(foo);
2618 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052619 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532620 return_construct_result = return_construct_pattern.search(line)
2621 if return_construct_result and not HasMoreThanOneArg(
2622 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052623 problems_constructor.append(
2624 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102625 # Disallow:
2626 # std::unique_ptr<T>()
2627 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052628 problems_nullptr.append(
2629 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2630
2631 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162632 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052633 errors.append(output_api.PresubmitError(
2634 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162635 problems_nullptr))
2636 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052637 errors.append(output_api.PresubmitError(
2638 'The following files use explicit std::unique_ptr constructor.'
2639 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162640 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102641 return errors
2642
2643
Saagar Sanghavifceeaae2020-08-12 16:40:362644def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082645 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522646 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082647 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522648 # If actions.xml is already included in the changelist, the PRESUBMIT
2649 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082650 return []
2651
[email protected]999261d2014-03-03 20:08:082652 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2653 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522654 current_actions = None
[email protected]999261d2014-03-03 20:08:082655 for f in input_api.AffectedFiles(file_filter=file_filter):
2656 for line_num, line in f.ChangedContents():
2657 match = input_api.re.search(action_re, line)
2658 if match:
[email protected]2f92dec2014-03-07 19:21:522659 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2660 # loaded only once.
2661 if not current_actions:
2662 with open('tools/metrics/actions/actions.xml') as actions_f:
2663 current_actions = actions_f.read()
2664 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082665 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522666 action = 'name="{0}"'.format(action_name)
2667 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082668 return [output_api.PresubmitPromptWarning(
2669 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522670 'tools/metrics/actions/actions.xml. Please run '
2671 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082672 % (f.LocalPath(), line_num, action_name))]
2673 return []
2674
2675
Daniel Cheng13ca61a882017-08-25 15:11:252676def _ImportJSONCommentEater(input_api):
2677 import sys
2678 sys.path = sys.path + [input_api.os_path.join(
2679 input_api.PresubmitLocalPath(),
2680 'tools', 'json_comment_eater')]
2681 import json_comment_eater
2682 return json_comment_eater
2683
2684
[email protected]99171a92014-06-03 08:44:472685def _GetJSONParseError(input_api, filename, eat_comments=True):
2686 try:
2687 contents = input_api.ReadFile(filename)
2688 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252689 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132690 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472691
2692 input_api.json.loads(contents)
2693 except ValueError as e:
2694 return e
2695 return None
2696
2697
2698def _GetIDLParseError(input_api, filename):
2699 try:
2700 contents = input_api.ReadFile(filename)
2701 idl_schema = input_api.os_path.join(
2702 input_api.PresubmitLocalPath(),
2703 'tools', 'json_schema_compiler', 'idl_schema.py')
2704 process = input_api.subprocess.Popen(
2705 [input_api.python_executable, idl_schema],
2706 stdin=input_api.subprocess.PIPE,
2707 stdout=input_api.subprocess.PIPE,
2708 stderr=input_api.subprocess.PIPE,
2709 universal_newlines=True)
2710 (_, error) = process.communicate(input=contents)
2711 return error or None
2712 except ValueError as e:
2713 return e
2714
2715
Saagar Sanghavifceeaae2020-08-12 16:40:362716def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472717 """Check that IDL and JSON files do not contain syntax errors."""
2718 actions = {
2719 '.idl': _GetIDLParseError,
2720 '.json': _GetJSONParseError,
2721 }
[email protected]99171a92014-06-03 08:44:472722 # Most JSON files are preprocessed and support comments, but these do not.
2723 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042724 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472725 ]
2726 # Only run IDL checker on files in these directories.
2727 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042728 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2729 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472730 ]
2731
2732 def get_action(affected_file):
2733 filename = affected_file.LocalPath()
2734 return actions.get(input_api.os_path.splitext(filename)[1])
2735
[email protected]99171a92014-06-03 08:44:472736 def FilterFile(affected_file):
2737 action = get_action(affected_file)
2738 if not action:
2739 return False
2740 path = affected_file.LocalPath()
2741
Erik Staab2dd72b12020-04-16 15:03:402742 if _MatchesFile(input_api,
2743 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2744 path):
[email protected]99171a92014-06-03 08:44:472745 return False
2746
2747 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162748 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472749 return False
2750 return True
2751
2752 results = []
2753 for affected_file in input_api.AffectedFiles(
2754 file_filter=FilterFile, include_deletes=False):
2755 action = get_action(affected_file)
2756 kwargs = {}
2757 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162758 _MatchesFile(input_api, json_no_comments_patterns,
2759 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472760 kwargs['eat_comments'] = False
2761 parse_error = action(input_api,
2762 affected_file.AbsoluteLocalPath(),
2763 **kwargs)
2764 if parse_error:
2765 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2766 (affected_file.LocalPath(), parse_error)))
2767 return results
2768
2769
Saagar Sanghavifceeaae2020-08-12 16:40:362770def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492771 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472772 import sys
[email protected]760deea2013-12-10 19:33:492773 original_sys_path = sys.path
2774 try:
2775 sys.path = sys.path + [input_api.os_path.join(
2776 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2777 import checkstyle
2778 finally:
2779 # Restore sys.path to what it was before.
2780 sys.path = original_sys_path
2781
2782 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092783 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442784 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492785
2786
Saagar Sanghavifceeaae2020-08-12 16:40:362787def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002788 """Checks to make sure devil is initialized correctly in python scripts."""
2789 script_common_initialize_pattern = input_api.re.compile(
2790 r'script_common\.InitializeEnvironment\(')
2791 devil_env_config_initialize = input_api.re.compile(
2792 r'devil_env\.config\.Initialize\(')
2793
2794 errors = []
2795
2796 sources = lambda affected_file: input_api.FilterSourceFile(
2797 affected_file,
James Cook24a504192020-07-23 00:08:442798 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2799 (r'^build[\\/]android[\\/]devil_chromium\.py',
2800 r'^third_party[\\/].*',)),
2801 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002802
2803 for f in input_api.AffectedSourceFiles(sources):
2804 for line_num, line in f.ChangedContents():
2805 if (script_common_initialize_pattern.search(line) or
2806 devil_env_config_initialize.search(line)):
2807 errors.append("%s:%d" % (f.LocalPath(), line_num))
2808
2809 results = []
2810
2811 if errors:
2812 results.append(output_api.PresubmitError(
2813 'Devil initialization should always be done using '
2814 'devil_chromium.Initialize() in the chromium project, to use better '
2815 'defaults for dependencies (ex. up-to-date version of adb).',
2816 errors))
2817
2818 return results
2819
2820
Sean Kau46e29bc2017-08-28 16:31:162821def _MatchesFile(input_api, patterns, path):
2822 for pattern in patterns:
2823 if input_api.re.search(pattern, path):
2824 return True
2825 return False
2826
2827
Daniel Cheng7052cdf2017-11-21 19:23:292828def _GetOwnersFilesToCheckForIpcOwners(input_api):
2829 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172830
Daniel Cheng7052cdf2017-11-21 19:23:292831 Returns:
2832 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2833 contain to cover IPC-related files with noparent reviewer rules.
2834 """
2835 # Whether or not a file affects IPC is (mostly) determined by a simple list
2836 # of filename patterns.
dchenge07de812016-06-20 19:27:172837 file_patterns = [
palmerb19a0932017-01-24 04:00:312838 # Legacy IPC:
dchenge07de812016-06-20 19:27:172839 '*_messages.cc',
2840 '*_messages*.h',
2841 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312842 # Mojo IPC:
dchenge07de812016-06-20 19:27:172843 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472844 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172845 '*_struct_traits*.*',
2846 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312847 '*.typemap',
2848 # Android native IPC:
2849 '*.aidl',
2850 # Blink uses a different file naming convention:
2851 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472852 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172853 '*StructTraits*.*',
2854 '*TypeConverter*.*',
2855 ]
2856
scottmg7a6ed5ba2016-11-04 18:22:042857 # These third_party directories do not contain IPCs, but contain files
2858 # matching the above patterns, which trigger false positives.
2859 exclude_paths = [
2860 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162861 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232862 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292863 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542864 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162865 # These files are just used to communicate between class loaders running
2866 # in the same process.
2867 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572868 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2869
scottmg7a6ed5ba2016-11-04 18:22:042870 ]
2871
dchenge07de812016-06-20 19:27:172872 # Dictionary mapping an OWNERS file path to Patterns.
2873 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2874 # rules ) to a PatternEntry.
2875 # PatternEntry is a dictionary with two keys:
2876 # - 'files': the files that are matched by this pattern
2877 # - 'rules': the per-file rules needed for this pattern
2878 # For example, if we expect OWNERS file to contain rules for *.mojom and
2879 # *_struct_traits*.*, Patterns might look like this:
2880 # {
2881 # '*.mojom': {
2882 # 'files': ...,
2883 # 'rules': [
2884 # 'per-file *.mojom=set noparent',
2885 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2886 # ],
2887 # },
2888 # '*_struct_traits*.*': {
2889 # 'files': ...,
2890 # 'rules': [
2891 # 'per-file *_struct_traits*.*=set noparent',
2892 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2893 # ],
2894 # },
2895 # }
2896 to_check = {}
2897
Daniel Cheng13ca61a882017-08-25 15:11:252898 def AddPatternToCheck(input_file, pattern):
2899 owners_file = input_api.os_path.join(
2900 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2901 if owners_file not in to_check:
2902 to_check[owners_file] = {}
2903 if pattern not in to_check[owners_file]:
2904 to_check[owners_file][pattern] = {
2905 'files': [],
2906 'rules': [
2907 'per-file %s=set noparent' % pattern,
2908 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2909 ]
2910 }
Vaclav Brozekd5de76a2018-03-17 07:57:502911 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252912
dchenge07de812016-06-20 19:27:172913 # Iterate through the affected files to see what we actually need to check
2914 # for. We should only nag patch authors about per-file rules if a file in that
2915 # directory would match that pattern. If a directory only contains *.mojom
2916 # files and no *_messages*.h files, we should only nag about rules for
2917 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252918 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262919 # Manifest files don't have a strong naming convention. Instead, try to find
2920 # affected .cc and .h files which look like they contain a manifest
2921 # definition.
2922 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2923 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2924 if (manifest_pattern.search(f.LocalPath()) and not
2925 test_manifest_pattern.search(f.LocalPath())):
2926 # We expect all actual service manifest files to contain at least one
2927 # qualified reference to service_manager::Manifest.
2928 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252929 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172930 for pattern in file_patterns:
2931 if input_api.fnmatch.fnmatch(
2932 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042933 skip = False
2934 for exclude in exclude_paths:
2935 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2936 skip = True
2937 break
2938 if skip:
2939 continue
Daniel Cheng13ca61a882017-08-25 15:11:252940 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172941 break
2942
Daniel Cheng7052cdf2017-11-21 19:23:292943 return to_check
2944
2945
Wez17c66962020-04-29 15:26:032946def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2947 """Adds OWNERS files to check for correct Fuchsia security owners."""
2948
2949 file_patterns = [
2950 # Component specifications.
2951 '*.cml', # Component Framework v2.
2952 '*.cmx', # Component Framework v1.
2953
2954 # Fuchsia IDL protocol specifications.
2955 '*.fidl',
2956 ]
2957
Joshua Peraza1ca6d392020-12-08 00:14:092958 # Don't check for owners files for changes in these directories.
2959 exclude_paths = [
2960 'third_party/crashpad/*',
2961 ]
2962
Wez17c66962020-04-29 15:26:032963 def AddPatternToCheck(input_file, pattern):
2964 owners_file = input_api.os_path.join(
2965 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2966 if owners_file not in to_check:
2967 to_check[owners_file] = {}
2968 if pattern not in to_check[owners_file]:
2969 to_check[owners_file][pattern] = {
2970 'files': [],
2971 'rules': [
2972 'per-file %s=set noparent' % pattern,
2973 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2974 ]
2975 }
2976 to_check[owners_file][pattern]['files'].append(input_file)
2977
2978 # Iterate through the affected files to see what we actually need to check
2979 # for. We should only nag patch authors about per-file rules if a file in that
2980 # directory would match that pattern.
2981 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092982 skip = False
2983 for exclude in exclude_paths:
2984 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2985 skip = True
2986 if skip:
2987 continue
2988
Wez17c66962020-04-29 15:26:032989 for pattern in file_patterns:
2990 if input_api.fnmatch.fnmatch(
2991 input_api.os_path.basename(f.LocalPath()), pattern):
2992 AddPatternToCheck(f, pattern)
2993 break
2994
2995 return to_check
2996
2997
Saagar Sanghavifceeaae2020-08-12 16:40:362998def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292999 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3000 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033001 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293002
3003 if to_check:
3004 # If there are any OWNERS files to check, there are IPC-related changes in
3005 # this CL. Auto-CC the review list.
3006 output_api.AppendCC('[email protected]')
3007
3008 # Go through the OWNERS files to check, filtering out rules that are already
3009 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173010 for owners_file, patterns in to_check.iteritems():
3011 try:
3012 with file(owners_file) as f:
3013 lines = set(f.read().splitlines())
3014 for entry in patterns.itervalues():
3015 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3016 ]
3017 except IOError:
3018 # No OWNERS file, so all the rules are definitely missing.
3019 continue
3020
3021 # All the remaining lines weren't found in OWNERS files, so emit an error.
3022 errors = []
3023 for owners_file, patterns in to_check.iteritems():
3024 missing_lines = []
3025 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503026 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173027 missing_lines.extend(entry['rules'])
3028 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3029 if missing_lines:
3030 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053031 'Because of the presence of files:\n%s\n\n'
3032 '%s needs the following %d lines added:\n\n%s' %
3033 ('\n'.join(files), owners_file, len(missing_lines),
3034 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173035
3036 results = []
3037 if errors:
vabrf5ce3bf92016-07-11 14:52:413038 if input_api.is_committing:
3039 output = output_api.PresubmitError
3040 else:
3041 output = output_api.PresubmitPromptWarning
3042 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593043 'Found OWNERS files that need to be updated for IPC security ' +
3044 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173045 long_text='\n\n'.join(errors)))
3046
3047 return results
3048
3049
Robert Sesek2c905332020-05-06 23:17:133050def _GetFilesUsingSecurityCriticalFunctions(input_api):
3051 """Checks affected files for changes to security-critical calls. This
3052 function checks the full change diff, to catch both additions/changes
3053 and removals.
3054
3055 Returns a dict keyed by file name, and the value is a set of detected
3056 functions.
3057 """
3058 # Map of function pretty name (displayed in an error) to the pattern to
3059 # match it with.
3060 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373061 'content::GetServiceSandboxType<>()':
3062 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133063 }
3064 _PATTERNS_TO_CHECK = {
3065 k: input_api.re.compile(v)
3066 for k, v in _PATTERNS_TO_CHECK.items()
3067 }
3068
3069 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3070 files_to_functions = {}
3071 for f in input_api.AffectedFiles():
3072 diff = f.GenerateScmDiff()
3073 for line in diff.split('\n'):
3074 # Not using just RightHandSideLines() because removing a
3075 # call to a security-critical function can be just as important
3076 # as adding or changing the arguments.
3077 if line.startswith('-') or (line.startswith('+') and
3078 not line.startswith('++')):
3079 for name, pattern in _PATTERNS_TO_CHECK.items():
3080 if pattern.search(line):
3081 path = f.LocalPath()
3082 if not path in files_to_functions:
3083 files_to_functions[path] = set()
3084 files_to_functions[path].add(name)
3085 return files_to_functions
3086
3087
Saagar Sanghavifceeaae2020-08-12 16:40:363088def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133089 """Checks that changes involving security-critical functions are reviewed
3090 by the security team.
3091 """
3092 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3093 if len(files_to_functions):
3094 owners_db = input_api.owners_db
3095 owner_email, reviewers = (
3096 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3097 input_api,
3098 owners_db.email_regexp,
3099 approval_needed=input_api.is_committing))
3100
3101 # Load the OWNERS file for security changes.
3102 owners_file = 'ipc/SECURITY_OWNERS'
3103 security_owners = owners_db.owners_rooted_at_file(owners_file)
3104
3105 has_security_owner = any([owner in reviewers for owner in security_owners])
3106 if not has_security_owner:
3107 msg = 'The following files change calls to security-sensive functions\n' \
3108 'that need to be reviewed by {}.\n'.format(owners_file)
3109 for path, names in files_to_functions.items():
3110 msg += ' {}\n'.format(path)
3111 for name in names:
3112 msg += ' {}\n'.format(name)
3113 msg += '\n'
3114
3115 if input_api.is_committing:
3116 output = output_api.PresubmitError
3117 else:
3118 output = output_api.PresubmitNotifyResult
3119 return [output(msg)]
3120
3121 return []
3122
3123
Saagar Sanghavifceeaae2020-08-12 16:40:363124def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263125 """Checks that set noparent is only used together with an OWNERS file in
3126 //build/OWNERS.setnoparent (see also
3127 //docs/code_reviews.md#owners-files-details)
3128 """
3129 errors = []
3130
3131 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3132 allowed_owners_files = set()
3133 with open(allowed_owners_files_file, 'r') as f:
3134 for line in f:
3135 line = line.strip()
3136 if not line or line.startswith('#'):
3137 continue
3138 allowed_owners_files.add(line)
3139
3140 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3141
3142 for f in input_api.AffectedFiles(include_deletes=False):
3143 if not f.LocalPath().endswith('OWNERS'):
3144 continue
3145
3146 found_owners_files = set()
3147 found_set_noparent_lines = dict()
3148
3149 # Parse the OWNERS file.
3150 for lineno, line in enumerate(f.NewContents(), 1):
3151 line = line.strip()
3152 if line.startswith('set noparent'):
3153 found_set_noparent_lines[''] = lineno
3154 if line.startswith('file://'):
3155 if line in allowed_owners_files:
3156 found_owners_files.add('')
3157 if line.startswith('per-file'):
3158 match = per_file_pattern.match(line)
3159 if match:
3160 glob = match.group(1).strip()
3161 directive = match.group(2).strip()
3162 if directive == 'set noparent':
3163 found_set_noparent_lines[glob] = lineno
3164 if directive.startswith('file://'):
3165 if directive in allowed_owners_files:
3166 found_owners_files.add(glob)
3167
3168 # Check that every set noparent line has a corresponding file:// line
3169 # listed in build/OWNERS.setnoparent.
3170 for set_noparent_line in found_set_noparent_lines:
3171 if set_noparent_line in found_owners_files:
3172 continue
3173 errors.append(' %s:%d' % (f.LocalPath(),
3174 found_set_noparent_lines[set_noparent_line]))
3175
3176 results = []
3177 if errors:
3178 if input_api.is_committing:
3179 output = output_api.PresubmitError
3180 else:
3181 output = output_api.PresubmitPromptWarning
3182 results.append(output(
3183 'Found the following "set noparent" restrictions in OWNERS files that '
3184 'do not include owners from build/OWNERS.setnoparent:',
3185 long_text='\n\n'.join(errors)))
3186 return results
3187
3188
Saagar Sanghavifceeaae2020-08-12 16:40:363189def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313190 """Checks that added or removed lines in non third party affected
3191 header files do not lead to new useless class or struct forward
3192 declaration.
jbriance9e12f162016-11-25 07:57:503193 """
3194 results = []
3195 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3196 input_api.re.MULTILINE)
3197 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3198 input_api.re.MULTILINE)
3199 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313200 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193201 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493202 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313203 continue
3204
jbriance9e12f162016-11-25 07:57:503205 if not f.LocalPath().endswith('.h'):
3206 continue
3207
3208 contents = input_api.ReadFile(f)
3209 fwd_decls = input_api.re.findall(class_pattern, contents)
3210 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3211
3212 useless_fwd_decls = []
3213 for decl in fwd_decls:
3214 count = sum(1 for _ in input_api.re.finditer(
3215 r'\b%s\b' % input_api.re.escape(decl), contents))
3216 if count == 1:
3217 useless_fwd_decls.append(decl)
3218
3219 if not useless_fwd_decls:
3220 continue
3221
3222 for line in f.GenerateScmDiff().splitlines():
3223 if (line.startswith('-') and not line.startswith('--') or
3224 line.startswith('+') and not line.startswith('++')):
3225 for decl in useless_fwd_decls:
3226 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3227 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243228 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503229 (f.LocalPath(), decl)))
3230 useless_fwd_decls.remove(decl)
3231
3232 return results
3233
Jinsong Fan91ebbbd2019-04-16 14:57:173234def _CheckAndroidDebuggableBuild(input_api, output_api):
3235 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3236 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3237 this is a debuggable build of Android.
3238 """
3239 build_type_check_pattern = input_api.re.compile(
3240 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3241
3242 errors = []
3243
3244 sources = lambda affected_file: input_api.FilterSourceFile(
3245 affected_file,
James Cook24a504192020-07-23 00:08:443246 files_to_skip=(_EXCLUDED_PATHS +
3247 _TEST_CODE_EXCLUDED_PATHS +
3248 input_api.DEFAULT_FILES_TO_SKIP +
3249 (r"^android_webview[\\/]support_library[\\/]"
3250 "boundary_interfaces[\\/]",
3251 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3252 r'^third_party[\\/].*',
3253 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3254 r"webview[\\/]chromium[\\/]License.*",)),
3255 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173256
3257 for f in input_api.AffectedSourceFiles(sources):
3258 for line_num, line in f.ChangedContents():
3259 if build_type_check_pattern.search(line):
3260 errors.append("%s:%d" % (f.LocalPath(), line_num))
3261
3262 results = []
3263
3264 if errors:
3265 results.append(output_api.PresubmitPromptWarning(
3266 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3267 ' Please use BuildInfo.isDebugAndroid() instead.',
3268 errors))
3269
3270 return results
jbriance9e12f162016-11-25 07:57:503271
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493272# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293273def _CheckAndroidToastUsage(input_api, output_api):
3274 """Checks that code uses org.chromium.ui.widget.Toast instead of
3275 android.widget.Toast (Chromium Toast doesn't force hardware
3276 acceleration on low-end devices, saving memory).
3277 """
3278 toast_import_pattern = input_api.re.compile(
3279 r'^import android\.widget\.Toast;$')
3280
3281 errors = []
3282
3283 sources = lambda affected_file: input_api.FilterSourceFile(
3284 affected_file,
James Cook24a504192020-07-23 00:08:443285 files_to_skip=(_EXCLUDED_PATHS +
3286 _TEST_CODE_EXCLUDED_PATHS +
3287 input_api.DEFAULT_FILES_TO_SKIP +
3288 (r'^chromecast[\\/].*',
3289 r'^remoting[\\/].*')),
3290 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293291
3292 for f in input_api.AffectedSourceFiles(sources):
3293 for line_num, line in f.ChangedContents():
3294 if toast_import_pattern.search(line):
3295 errors.append("%s:%d" % (f.LocalPath(), line_num))
3296
3297 results = []
3298
3299 if errors:
3300 results.append(output_api.PresubmitError(
3301 'android.widget.Toast usage is detected. Android toasts use hardware'
3302 ' acceleration, and can be\ncostly on low-end devices. Please use'
3303 ' org.chromium.ui.widget.Toast instead.\n'
3304 'Contact [email protected] if you have any questions.',
3305 errors))
3306
3307 return results
3308
3309
dgnaa68d5e2015-06-10 10:08:223310def _CheckAndroidCrLogUsage(input_api, output_api):
3311 """Checks that new logs using org.chromium.base.Log:
3312 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513313 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223314 """
pkotwicza1dd0b002016-05-16 14:41:043315
torne89540622017-03-24 19:41:303316 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043317 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303318 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043319 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303320 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043321 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3322 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093323 # The customtabs_benchmark is a small app that does not depend on Chromium
3324 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043325 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043326 ]
3327
dgnaa68d5e2015-06-10 10:08:223328 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123329 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3330 class_in_base_pattern = input_api.re.compile(
3331 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3332 has_some_log_import_pattern = input_api.re.compile(
3333 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223334 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553335 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223336 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463337 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553338 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223339
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463340 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443341 sources = lambda x: input_api.FilterSourceFile(x,
3342 files_to_check=[r'.*\.java$'],
3343 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123344
dgnaa68d5e2015-06-10 10:08:223345 tag_decl_errors = []
3346 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123347 tag_errors = []
dgn38736db2015-09-18 19:20:513348 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123349 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223350
3351 for f in input_api.AffectedSourceFiles(sources):
3352 file_content = input_api.ReadFile(f)
3353 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223354 # Per line checks
dgn87d9fb62015-06-12 09:15:123355 if (cr_log_import_pattern.search(file_content) or
3356 (class_in_base_pattern.search(file_content) and
3357 not has_some_log_import_pattern.search(file_content))):
3358 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223359 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553360 if rough_log_decl_pattern.search(line):
3361 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223362
3363 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123364 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223365 if match:
3366 has_modified_logs = True
3367
3368 # Make sure it uses "TAG"
3369 if not match.group('tag') == 'TAG':
3370 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123371 else:
3372 # Report non cr Log function calls in changed lines
3373 for line_num, line in f.ChangedContents():
3374 if log_call_pattern.search(line):
3375 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223376
3377 # Per file checks
3378 if has_modified_logs:
3379 # Make sure the tag is using the "cr" prefix and is not too long
3380 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513381 tag_name = match.group('name') if match else None
3382 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223383 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513384 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223385 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513386 elif '.' in tag_name:
3387 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223388
3389 results = []
3390 if tag_decl_errors:
3391 results.append(output_api.PresubmitPromptWarning(
3392 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513393 '"private static final String TAG = "<package tag>".\n'
3394 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223395 tag_decl_errors))
3396
3397 if tag_length_errors:
3398 results.append(output_api.PresubmitError(
3399 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513400 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223401 tag_length_errors))
3402
3403 if tag_errors:
3404 results.append(output_api.PresubmitPromptWarning(
3405 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3406 tag_errors))
3407
dgn87d9fb62015-06-12 09:15:123408 if util_log_errors:
dgn4401aa52015-04-29 16:26:173409 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123410 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3411 util_log_errors))
3412
dgn38736db2015-09-18 19:20:513413 if tag_with_dot_errors:
3414 results.append(output_api.PresubmitPromptWarning(
3415 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3416 tag_with_dot_errors))
3417
dgn4401aa52015-04-29 16:26:173418 return results
3419
3420
Yoland Yanb92fa522017-08-28 17:37:063421def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3422 """Checks that junit.framework.* is no longer used."""
3423 deprecated_junit_framework_pattern = input_api.re.compile(
3424 r'^import junit\.framework\..*;',
3425 input_api.re.MULTILINE)
3426 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443427 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063428 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133429 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063430 for line_num, line in f.ChangedContents():
3431 if deprecated_junit_framework_pattern.search(line):
3432 errors.append("%s:%d" % (f.LocalPath(), line_num))
3433
3434 results = []
3435 if errors:
3436 results.append(output_api.PresubmitError(
3437 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3438 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3439 ' if you have any question.', errors))
3440 return results
3441
3442
3443def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3444 """Checks that if new Java test classes have inheritance.
3445 Either the new test class is JUnit3 test or it is a JUnit4 test class
3446 with a base class, either case is undesirable.
3447 """
3448 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3449
3450 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443451 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063452 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133453 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063454 if not f.OldContents():
3455 class_declaration_start_flag = False
3456 for line_num, line in f.ChangedContents():
3457 if class_declaration_pattern.search(line):
3458 class_declaration_start_flag = True
3459 if class_declaration_start_flag and ' extends ' in line:
3460 errors.append('%s:%d' % (f.LocalPath(), line_num))
3461 if '{' in line:
3462 class_declaration_start_flag = False
3463
3464 results = []
3465 if errors:
3466 results.append(output_api.PresubmitPromptWarning(
3467 'The newly created files include Test classes that inherits from base'
3468 ' class. Please do not use inheritance in JUnit4 tests or add new'
3469 ' JUnit3 tests. Contact [email protected] if you have any'
3470 ' questions.', errors))
3471 return results
3472
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203473
yolandyan45001472016-12-21 21:12:423474def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3475 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3476 deprecated_annotation_import_pattern = input_api.re.compile(
3477 r'^import android\.test\.suitebuilder\.annotation\..*;',
3478 input_api.re.MULTILINE)
3479 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443480 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423481 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133482 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423483 for line_num, line in f.ChangedContents():
3484 if deprecated_annotation_import_pattern.search(line):
3485 errors.append("%s:%d" % (f.LocalPath(), line_num))
3486
3487 results = []
3488 if errors:
3489 results.append(output_api.PresubmitError(
3490 'Annotations in android.test.suitebuilder.annotation have been'
3491 ' deprecated since API level 24. Please use android.support.test.filters'
3492 ' from //third_party/android_support_test_runner:runner_java instead.'
3493 ' Contact [email protected] if you have any questions.', errors))
3494 return results
3495
3496
agrieve7b6479d82015-10-07 14:24:223497def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3498 """Checks if MDPI assets are placed in a correct directory."""
3499 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3500 ('/res/drawable/' in f.LocalPath() or
3501 '/res/drawable-ldrtl/' in f.LocalPath()))
3502 errors = []
3503 for f in input_api.AffectedFiles(include_deletes=False,
3504 file_filter=file_filter):
3505 errors.append(' %s' % f.LocalPath())
3506
3507 results = []
3508 if errors:
3509 results.append(output_api.PresubmitError(
3510 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3511 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3512 '/res/drawable-ldrtl/.\n'
3513 'Contact [email protected] if you have questions.', errors))
3514 return results
3515
3516
Nate Fischer535972b2017-09-16 01:06:183517def _CheckAndroidWebkitImports(input_api, output_api):
3518 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353519 android.webview.ValueCallback except in the WebView glue layer
3520 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183521 """
3522 valuecallback_import_pattern = input_api.re.compile(
3523 r'^import android\.webkit\.ValueCallback;$')
3524
3525 errors = []
3526
3527 sources = lambda affected_file: input_api.FilterSourceFile(
3528 affected_file,
James Cook24a504192020-07-23 00:08:443529 files_to_skip=(_EXCLUDED_PATHS +
3530 _TEST_CODE_EXCLUDED_PATHS +
3531 input_api.DEFAULT_FILES_TO_SKIP +
3532 (r'^android_webview[\\/]glue[\\/].*',
3533 r'^weblayer[\\/].*',)),
3534 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183535
3536 for f in input_api.AffectedSourceFiles(sources):
3537 for line_num, line in f.ChangedContents():
3538 if valuecallback_import_pattern.search(line):
3539 errors.append("%s:%d" % (f.LocalPath(), line_num))
3540
3541 results = []
3542
3543 if errors:
3544 results.append(output_api.PresubmitError(
3545 'android.webkit.ValueCallback usage is detected outside of the glue'
3546 ' layer. To stay compatible with the support library, android.webkit.*'
3547 ' classes should only be used inside the glue layer and'
3548 ' org.chromium.base.Callback should be used instead.',
3549 errors))
3550
3551 return results
3552
3553
Becky Zhou7c69b50992018-12-10 19:37:573554def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3555 """Checks Android XML styles """
3556 import sys
3557 original_sys_path = sys.path
3558 try:
3559 sys.path = sys.path + [input_api.os_path.join(
3560 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3561 import checkxmlstyle
3562 finally:
3563 # Restore sys.path to what it was before.
3564 sys.path = original_sys_path
3565
3566 if is_check_on_upload:
3567 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3568 else:
3569 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3570
3571
agrievef32bcc72016-04-04 14:57:403572class PydepsChecker(object):
3573 def __init__(self, input_api, pydeps_files):
3574 self._file_cache = {}
3575 self._input_api = input_api
3576 self._pydeps_files = pydeps_files
3577
3578 def _LoadFile(self, path):
3579 """Returns the list of paths within a .pydeps file relative to //."""
3580 if path not in self._file_cache:
3581 with open(path) as f:
3582 self._file_cache[path] = f.read()
3583 return self._file_cache[path]
3584
3585 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3586 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393587 pydeps_data = self._LoadFile(pydeps_path)
3588 uses_gn_paths = '--gn-paths' in pydeps_data
3589 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3590 if uses_gn_paths:
3591 # Paths look like: //foo/bar/baz
3592 return (e[2:] for e in entries)
3593 else:
3594 # Paths look like: path/relative/to/file.pydeps
3595 os_path = self._input_api.os_path
3596 pydeps_dir = os_path.dirname(pydeps_path)
3597 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403598
3599 def _CreateFilesToPydepsMap(self):
3600 """Returns a map of local_path -> list_of_pydeps."""
3601 ret = {}
3602 for pydep_local_path in self._pydeps_files:
3603 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3604 ret.setdefault(path, []).append(pydep_local_path)
3605 return ret
3606
3607 def ComputeAffectedPydeps(self):
3608 """Returns an iterable of .pydeps files that might need regenerating."""
3609 affected_pydeps = set()
3610 file_to_pydeps_map = None
3611 for f in self._input_api.AffectedFiles(include_deletes=True):
3612 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463613 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3614 # subrepositories. We can't figure out which files change, so re-check
3615 # all files.
3616 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383617 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3618 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403619 return self._pydeps_files
3620 elif local_path.endswith('.pydeps'):
3621 if local_path in self._pydeps_files:
3622 affected_pydeps.add(local_path)
3623 elif local_path.endswith('.py'):
3624 if file_to_pydeps_map is None:
3625 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3626 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3627 return affected_pydeps
3628
3629 def DetermineIfStale(self, pydeps_path):
3630 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413631 import difflib
John Budorick47ca3fe2018-02-10 00:53:103632 import os
3633
agrievef32bcc72016-04-04 14:57:403634 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033635 if old_pydeps_data:
3636 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393637 if '--output' not in cmd:
3638 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033639 old_contents = old_pydeps_data[2:]
3640 else:
3641 # A default cmd that should work in most cases (as long as pydeps filename
3642 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3643 # file is empty/new.
3644 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3645 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3646 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103647 env = dict(os.environ)
3648 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403649 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103650 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413651 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033652 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413653 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403654
3655
Tibor Goldschwendt360793f72019-06-25 18:23:493656def _ParseGclientArgs():
3657 args = {}
3658 with open('build/config/gclient_args.gni', 'r') as f:
3659 for line in f:
3660 line = line.strip()
3661 if not line or line.startswith('#'):
3662 continue
3663 attribute, value = line.split('=')
3664 args[attribute.strip()] = value.strip()
3665 return args
3666
3667
Saagar Sanghavifceeaae2020-08-12 16:40:363668def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403669 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403670 # This check is for Python dependency lists (.pydeps files), and involves
3671 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3672 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283673 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003674 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493675 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403676 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403677 results = []
3678 # First, check for new / deleted .pydeps.
3679 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033680 # Check whether we are running the presubmit check for a file in src.
3681 # f.LocalPath is relative to repo (src, or internal repo).
3682 # os_path.exists is relative to src repo.
3683 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3684 # to src and we can conclude that the pydeps is in src.
3685 if input_api.os_path.exists(f.LocalPath()):
3686 if f.LocalPath().endswith('.pydeps'):
3687 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3688 results.append(output_api.PresubmitError(
3689 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3690 'remove %s' % f.LocalPath()))
3691 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3692 results.append(output_api.PresubmitError(
3693 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3694 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403695
3696 if results:
3697 return results
3698
Mohamed Heikal7cd4d8312020-06-16 16:49:403699 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3700 affected_pydeps = set(checker.ComputeAffectedPydeps())
3701 affected_android_pydeps = affected_pydeps.intersection(
3702 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3703 if affected_android_pydeps and not is_android:
3704 results.append(output_api.PresubmitPromptOrNotify(
3705 'You have changed python files that may affect pydeps for android\n'
3706 'specific scripts. However, the relevant presumbit check cannot be\n'
3707 'run because you are not using an Android checkout. To validate that\n'
3708 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3709 'use the android-internal-presubmit optional trybot.\n'
3710 'Possibly stale pydeps files:\n{}'.format(
3711 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403712
Mohamed Heikal7cd4d8312020-06-16 16:49:403713 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3714 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403715 try:
phajdan.jr0d9878552016-11-04 10:49:413716 result = checker.DetermineIfStale(pydep_path)
3717 if result:
3718 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403719 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413720 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3721 'To regenerate, run:\n\n %s' %
3722 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403723 except input_api.subprocess.CalledProcessError as error:
3724 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3725 long_text=error.output)]
3726
3727 return results
3728
3729
Saagar Sanghavifceeaae2020-08-12 16:40:363730def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433731 """Checks to make sure no header files have |Singleton<|."""
3732 def FileFilter(affected_file):
3733 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443734 files_to_skip = (_EXCLUDED_PATHS +
3735 input_api.DEFAULT_FILES_TO_SKIP +
3736 (r"^base[\\/]memory[\\/]singleton\.h$",
3737 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3738 r"quic_singleton_impl\.h$"))
3739 return input_api.FilterSourceFile(affected_file,
3740 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433741
sergeyu34d21222015-09-16 00:11:443742 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433743 files = []
3744 for f in input_api.AffectedSourceFiles(FileFilter):
3745 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3746 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3747 contents = input_api.ReadFile(f)
3748 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243749 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433750 pattern.search(line)):
3751 files.append(f)
3752 break
3753
3754 if files:
yolandyandaabc6d2016-04-18 18:29:393755 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443756 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433757 'Please move them to an appropriate source file so that the ' +
3758 'template gets instantiated in a single compilation unit.',
3759 files) ]
3760 return []
3761
3762
[email protected]fd20b902014-05-09 02:14:533763_DEPRECATED_CSS = [
3764 # Values
3765 ( "-webkit-box", "flex" ),
3766 ( "-webkit-inline-box", "inline-flex" ),
3767 ( "-webkit-flex", "flex" ),
3768 ( "-webkit-inline-flex", "inline-flex" ),
3769 ( "-webkit-min-content", "min-content" ),
3770 ( "-webkit-max-content", "max-content" ),
3771
3772 # Properties
3773 ( "-webkit-background-clip", "background-clip" ),
3774 ( "-webkit-background-origin", "background-origin" ),
3775 ( "-webkit-background-size", "background-size" ),
3776 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443777 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533778
3779 # Functions
3780 ( "-webkit-gradient", "gradient" ),
3781 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3782 ( "-webkit-linear-gradient", "linear-gradient" ),
3783 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3784 ( "-webkit-radial-gradient", "radial-gradient" ),
3785 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3786]
3787
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203788
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493789# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363790def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533791 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253792 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343793 documentation and iOS CSS for dom distiller
3794 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253795 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533796 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493797 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443798 files_to_skip = (_EXCLUDED_PATHS +
3799 _TEST_CODE_EXCLUDED_PATHS +
3800 input_api.DEFAULT_FILES_TO_SKIP +
3801 (r"^chrome/common/extensions/docs",
3802 r"^chrome/docs",
3803 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3804 r"^components/neterror/resources/neterror.css",
3805 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253806 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443807 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533808 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3809 for line_num, line in fpath.ChangedContents():
3810 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023811 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533812 results.append(output_api.PresubmitError(
3813 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3814 (fpath.LocalPath(), line_num, deprecated_value, value)))
3815 return results
3816
mohan.reddyf21db962014-10-16 12:26:473817
Saagar Sanghavifceeaae2020-08-12 16:40:363818def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363819 bad_files = {}
3820 for f in input_api.AffectedFiles(include_deletes=False):
3821 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493822 not f.LocalPath().startswith('third_party/blink') and
3823 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363824 continue
3825
Daniel Bratell65b033262019-04-23 08:17:063826 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363827 continue
3828
Vaclav Brozekd5de76a2018-03-17 07:57:503829 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363830 if "#include" in line and "../" in line]
3831 if not relative_includes:
3832 continue
3833 bad_files[f.LocalPath()] = relative_includes
3834
3835 if not bad_files:
3836 return []
3837
3838 error_descriptions = []
3839 for file_path, bad_lines in bad_files.iteritems():
3840 error_description = file_path
3841 for line in bad_lines:
3842 error_description += '\n ' + line
3843 error_descriptions.append(error_description)
3844
3845 results = []
3846 results.append(output_api.PresubmitError(
3847 'You added one or more relative #include paths (including "../").\n'
3848 'These shouldn\'t be used because they can be used to include headers\n'
3849 'from code that\'s not correctly specified as a dependency in the\n'
3850 'relevant BUILD.gn file(s).',
3851 error_descriptions))
3852
3853 return results
3854
Takeshi Yoshinoe387aa32017-08-02 13:16:133855
Saagar Sanghavifceeaae2020-08-12 16:40:363856def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063857 """Check that nobody tries to include a cc file. It's a relatively
3858 common error which results in duplicate symbols in object
3859 files. This may not always break the build until someone later gets
3860 very confusing linking errors."""
3861 results = []
3862 for f in input_api.AffectedFiles(include_deletes=False):
3863 # We let third_party code do whatever it wants
3864 if (f.LocalPath().startswith('third_party') and
3865 not f.LocalPath().startswith('third_party/blink') and
3866 not f.LocalPath().startswith('third_party\\blink')):
3867 continue
3868
3869 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3870 continue
3871
3872 for _, line in f.ChangedContents():
3873 if line.startswith('#include "'):
3874 included_file = line.split('"')[1]
3875 if _IsCPlusPlusFile(input_api, included_file):
3876 # The most common naming for external files with C++ code,
3877 # apart from standard headers, is to call them foo.inc, but
3878 # Chromium sometimes uses foo-inc.cc so allow that as well.
3879 if not included_file.endswith(('.h', '-inc.cc')):
3880 results.append(output_api.PresubmitError(
3881 'Only header files or .inc files should be included in other\n'
3882 'C++ files. Compiling the contents of a cc file more than once\n'
3883 'will cause duplicate information in the build which may later\n'
3884 'result in strange link_errors.\n' +
3885 f.LocalPath() + ':\n ' +
3886 line))
3887
3888 return results
3889
3890
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203891def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3892 if not isinstance(key, ast.Str):
3893 return 'Key at line %d must be a string literal' % key.lineno
3894 if not isinstance(value, ast.Dict):
3895 return 'Value at line %d must be a dict' % value.lineno
3896 if len(value.keys) != 1:
3897 return 'Dict at line %d must have single entry' % value.lineno
3898 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3899 return (
3900 'Entry at line %d must have a string literal \'filepath\' as key' %
3901 value.lineno)
3902 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133903
Takeshi Yoshinoe387aa32017-08-02 13:16:133904
Sergey Ulanov4af16052018-11-08 02:41:463905def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203906 if not isinstance(key, ast.Str):
3907 return 'Key at line %d must be a string literal' % key.lineno
3908 if not isinstance(value, ast.List):
3909 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463910 for element in value.elts:
3911 if not isinstance(element, ast.Str):
3912 return 'Watchlist elements on line %d is not a string' % key.lineno
3913 if not email_regex.match(element.s):
3914 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3915 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203916 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133917
Takeshi Yoshinoe387aa32017-08-02 13:16:133918
Sergey Ulanov4af16052018-11-08 02:41:463919def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203920 mismatch_template = (
3921 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3922 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133923
Sergey Ulanov4af16052018-11-08 02:41:463924 email_regex = input_api.re.compile(
3925 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3926
3927 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203928 i = 0
3929 last_key = ''
3930 while True:
3931 if i >= len(wd_dict.keys):
3932 if i >= len(w_dict.keys):
3933 return None
3934 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3935 elif i >= len(w_dict.keys):
3936 return (
3937 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133938
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203939 wd_key = wd_dict.keys[i]
3940 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133941
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203942 result = _CheckWatchlistDefinitionsEntrySyntax(
3943 wd_key, wd_dict.values[i], ast)
3944 if result is not None:
3945 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133946
Sergey Ulanov4af16052018-11-08 02:41:463947 result = _CheckWatchlistsEntrySyntax(
3948 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203949 if result is not None:
3950 return 'Bad entry in WATCHLISTS dict: %s' % result
3951
3952 if wd_key.s != w_key.s:
3953 return mismatch_template % (
3954 '%s at line %d' % (wd_key.s, wd_key.lineno),
3955 '%s at line %d' % (w_key.s, w_key.lineno))
3956
3957 if wd_key.s < last_key:
3958 return (
3959 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3960 (wd_key.lineno, w_key.lineno))
3961 last_key = wd_key.s
3962
3963 i = i + 1
3964
3965
Sergey Ulanov4af16052018-11-08 02:41:463966def _CheckWATCHLISTSSyntax(expression, input_api):
3967 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203968 if not isinstance(expression, ast.Expression):
3969 return 'WATCHLISTS file must contain a valid expression'
3970 dictionary = expression.body
3971 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3972 return 'WATCHLISTS file must have single dict with exactly two entries'
3973
3974 first_key = dictionary.keys[0]
3975 first_value = dictionary.values[0]
3976 second_key = dictionary.keys[1]
3977 second_value = dictionary.values[1]
3978
3979 if (not isinstance(first_key, ast.Str) or
3980 first_key.s != 'WATCHLIST_DEFINITIONS' or
3981 not isinstance(first_value, ast.Dict)):
3982 return (
3983 'The first entry of the dict in WATCHLISTS file must be '
3984 'WATCHLIST_DEFINITIONS dict')
3985
3986 if (not isinstance(second_key, ast.Str) or
3987 second_key.s != 'WATCHLISTS' or
3988 not isinstance(second_value, ast.Dict)):
3989 return (
3990 'The second entry of the dict in WATCHLISTS file must be '
3991 'WATCHLISTS dict')
3992
Sergey Ulanov4af16052018-11-08 02:41:463993 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133994
3995
Saagar Sanghavifceeaae2020-08-12 16:40:363996def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133997 for f in input_api.AffectedFiles(include_deletes=False):
3998 if f.LocalPath() == 'WATCHLISTS':
3999 contents = input_api.ReadFile(f, 'r')
4000
4001 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204002 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134003 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204004 # Get an AST tree for it and scan the tree for detailed style checking.
4005 expression = input_api.ast.parse(
4006 contents, filename='WATCHLISTS', mode='eval')
4007 except ValueError as e:
4008 return [output_api.PresubmitError(
4009 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4010 except SyntaxError as e:
4011 return [output_api.PresubmitError(
4012 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4013 except TypeError as e:
4014 return [output_api.PresubmitError(
4015 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134016
Sergey Ulanov4af16052018-11-08 02:41:464017 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204018 if result is not None:
4019 return [output_api.PresubmitError(result)]
4020 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134021
4022 return []
4023
4024
Andrew Grieve1b290e4a22020-11-24 20:07:014025def CheckGnGlobForward(input_api, output_api):
4026 """Checks that forward_variables_from(invoker, "*") follows best practices.
4027
4028 As documented at //build/docs/writing_gn_templates.md
4029 """
4030 def gn_files(f):
4031 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
4032
4033 problems = []
4034 for f in input_api.AffectedSourceFiles(gn_files):
4035 for line_num, line in f.ChangedContents():
4036 if 'forward_variables_from(invoker, "*")' in line:
4037 problems.append(
4038 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
4039 f.LocalPath(), line_num))
4040
4041 if problems:
4042 return [output_api.PresubmitPromptWarning(
4043 'forward_variables_from("*") without exclusions',
4044 items=sorted(problems),
4045 long_text=('The variables "visibilty" and "test_only" should be '
4046 'explicitly listed in forward_variables_from(). For more '
4047 'details, see:\n'
4048 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4049 'build/docs/writing_gn_templates.md'
4050 '#Using-forward_variables_from'))]
4051 return []
4052
4053
Saagar Sanghavifceeaae2020-08-12 16:40:364054def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194055 """Checks that newly added header files have corresponding GN changes.
4056 Note that this is only a heuristic. To be precise, run script:
4057 build/check_gn_headers.py.
4058 """
4059
4060 def headers(f):
4061 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444062 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194063
4064 new_headers = []
4065 for f in input_api.AffectedSourceFiles(headers):
4066 if f.Action() != 'A':
4067 continue
4068 new_headers.append(f.LocalPath())
4069
4070 def gn_files(f):
James Cook24a504192020-07-23 00:08:444071 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194072
4073 all_gn_changed_contents = ''
4074 for f in input_api.AffectedSourceFiles(gn_files):
4075 for _, line in f.ChangedContents():
4076 all_gn_changed_contents += line
4077
4078 problems = []
4079 for header in new_headers:
4080 basename = input_api.os_path.basename(header)
4081 if basename not in all_gn_changed_contents:
4082 problems.append(header)
4083
4084 if problems:
4085 return [output_api.PresubmitPromptWarning(
4086 'Missing GN changes for new header files', items=sorted(problems),
4087 long_text='Please double check whether newly added header files need '
4088 'corresponding changes in gn or gni files.\nThis checking is only a '
4089 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4090 'Read https://crbug.com/661774 for more info.')]
4091 return []
4092
4093
Saagar Sanghavifceeaae2020-08-12 16:40:364094def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024095 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4096
4097 This assumes we won't intentionally reference one product from the other
4098 product.
4099 """
4100 all_problems = []
4101 test_cases = [{
4102 "filename_postfix": "google_chrome_strings.grd",
4103 "correct_name": "Chrome",
4104 "incorrect_name": "Chromium",
4105 }, {
4106 "filename_postfix": "chromium_strings.grd",
4107 "correct_name": "Chromium",
4108 "incorrect_name": "Chrome",
4109 }]
4110
4111 for test_case in test_cases:
4112 problems = []
4113 filename_filter = lambda x: x.LocalPath().endswith(
4114 test_case["filename_postfix"])
4115
4116 # Check each new line. Can yield false positives in multiline comments, but
4117 # easier than trying to parse the XML because messages can have nested
4118 # children, and associating message elements with affected lines is hard.
4119 for f in input_api.AffectedSourceFiles(filename_filter):
4120 for line_num, line in f.ChangedContents():
4121 if "<message" in line or "<!--" in line or "-->" in line:
4122 continue
4123 if test_case["incorrect_name"] in line:
4124 problems.append(
4125 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4126
4127 if problems:
4128 message = (
4129 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4130 % (test_case["correct_name"], test_case["correct_name"],
4131 test_case["incorrect_name"]))
4132 all_problems.append(
4133 output_api.PresubmitPromptWarning(message, items=problems))
4134
4135 return all_problems
4136
4137
Saagar Sanghavifceeaae2020-08-12 16:40:364138def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514139 # TODO(crbug.com/941824): We need to make sure the entries in
4140 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4141 # so that users of //buildtools in other projects get the same tooling
4142 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4143 # support to gclient, we can eliminate the duplication and delete
4144 # this presubmit check.
4145
4146 # Update this regexp if new revisions are added to the files.
4147 rev_regexp = input_api.re.compile(
Michael Savigny8b078012020-12-09 16:19:054148 ("'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version|"
4149 "reclient_version)':"))
Dirk Pranke3c18a382019-03-15 01:07:514150
4151 # If a user is changing one revision, they need to change the same
4152 # line in both files. This means that any given change should contain
4153 # exactly the same list of changed lines that match the regexps. The
4154 # replace(' ', '') call allows us to ignore whitespace changes to the
4155 # lines. The 'long_text' parameter to the error will contain the
4156 # list of changed lines in both files, which should make it easy enough
4157 # to spot the error without going overboard in this implementation.
4158 revs_changes = {
4159 'DEPS': {},
4160 'buildtools/DEPS': {},
4161 }
4162 long_text = ''
4163
4164 for f in input_api.AffectedFiles(
4165 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4166 for line_num, line in f.ChangedContents():
4167 if rev_regexp.search(line):
4168 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4169 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4170
4171 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4172 return [output_api.PresubmitError(
4173 'Change buildtools revisions in sync in both //DEPS and '
4174 '//buildtools/DEPS.', long_text=long_text + '\n')]
4175 else:
4176 return []
4177
4178
Saagar Sanghavifceeaae2020-08-12 16:40:364179def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364180 """Avoid large files, especially binary files, in the repository since
4181 git doesn't scale well for those. They will be in everyone's repo
4182 clones forever, forever making Chromium slower to clone and work
4183 with."""
4184
4185 # Uploading files to cloud storage is not trivial so we don't want
4186 # to set the limit too low, but the upper limit for "normal" large
4187 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4188 # anything over 20 MB is exceptional.
4189 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4190
4191 too_large_files = []
4192 for f in input_api.AffectedFiles():
4193 # Check both added and modified files (but not deleted files).
4194 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384195 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364196 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4197 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4198
4199 if too_large_files:
4200 message = (
4201 'Do not commit large files to git since git scales badly for those.\n' +
4202 'Instead put the large files in cloud storage and use DEPS to\n' +
4203 'fetch them.\n' + '\n'.join(too_large_files)
4204 )
4205 return [output_api.PresubmitError(
4206 'Too large files found in commit', long_text=message + '\n')]
4207 else:
4208 return []
4209
Max Morozb47503b2019-08-08 21:03:274210
Saagar Sanghavifceeaae2020-08-12 16:40:364211def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274212 """Checks specific for fuzz target sources."""
4213 EXPORTED_SYMBOLS = [
4214 'LLVMFuzzerInitialize',
4215 'LLVMFuzzerCustomMutator',
4216 'LLVMFuzzerCustomCrossOver',
4217 'LLVMFuzzerMutate',
4218 ]
4219
4220 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4221
4222 def FilterFile(affected_file):
4223 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444224 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4225 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274226
4227 return input_api.FilterSourceFile(
4228 affected_file,
James Cook24a504192020-07-23 00:08:444229 files_to_check=[files_to_check],
4230 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274231
4232 files_with_missing_header = []
4233 for f in input_api.AffectedSourceFiles(FilterFile):
4234 contents = input_api.ReadFile(f, 'r')
4235 if REQUIRED_HEADER in contents:
4236 continue
4237
4238 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4239 files_with_missing_header.append(f.LocalPath())
4240
4241 if not files_with_missing_header:
4242 return []
4243
4244 long_text = (
4245 'If you define any of the libFuzzer optional functions (%s), it is '
4246 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4247 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4248 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4249 'to access command line arguments passed to the fuzzer. Instead, prefer '
4250 'static initialization and shared resources as documented in '
4251 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4252 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4253 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4254 )
4255
4256 return [output_api.PresubmitPromptWarning(
4257 message="Missing '%s' in:" % REQUIRED_HEADER,
4258 items=files_with_missing_header,
4259 long_text=long_text)]
4260
4261
Mohamed Heikald048240a2019-11-12 16:57:374262def _CheckNewImagesWarning(input_api, output_api):
4263 """
4264 Warns authors who add images into the repo to make sure their images are
4265 optimized before committing.
4266 """
4267 images_added = False
4268 image_paths = []
4269 errors = []
4270 filter_lambda = lambda x: input_api.FilterSourceFile(
4271 x,
James Cook24a504192020-07-23 00:08:444272 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4273 + input_api.DEFAULT_FILES_TO_SKIP),
4274 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374275 )
4276 for f in input_api.AffectedFiles(
4277 include_deletes=False, file_filter=filter_lambda):
4278 local_path = f.LocalPath().lower()
4279 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4280 images_added = True
4281 image_paths.append(f)
4282 if images_added:
4283 errors.append(output_api.PresubmitPromptWarning(
4284 'It looks like you are trying to commit some images. If these are '
4285 'non-test-only images, please make sure to read and apply the tips in '
4286 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4287 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4288 'FYI only and will not block your CL on the CQ.', image_paths))
4289 return errors
4290
4291
Saagar Sanghavifceeaae2020-08-12 16:40:364292def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574293 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224294 results = []
dgnaa68d5e2015-06-10 10:08:224295 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174296 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224297 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294298 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064299 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4300 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424301 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184302 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574303 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374304 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154305 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574306 return results
4307
Saagar Sanghavifceeaae2020-08-12 16:40:364308def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574309 """Groups commit checks that target android code."""
4310 results = []
4311 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224312 return results
4313
Chris Hall59f8d0c72020-05-01 07:31:194314# TODO(chrishall): could we additionally match on any path owned by
4315# ui/accessibility/OWNERS ?
4316_ACCESSIBILITY_PATHS = (
4317 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4318 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4319 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4320 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4321 r"^content[\\/]browser[\\/]accessibility[\\/]",
4322 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4323 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4324 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4325 r"^ui[\\/]accessibility[\\/]",
4326 r"^ui[\\/]views[\\/]accessibility[\\/]",
4327)
4328
Saagar Sanghavifceeaae2020-08-12 16:40:364329def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194330 """Checks that commits to accessibility code contain an AX-Relnotes field in
4331 their commit message."""
4332 def FileFilter(affected_file):
4333 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444334 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194335
4336 # Only consider changes affecting accessibility paths.
4337 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4338 return []
4339
Akihiro Ota08108e542020-05-20 15:30:534340 # AX-Relnotes can appear in either the description or the footer.
4341 # When searching the description, require 'AX-Relnotes:' to appear at the
4342 # beginning of a line.
4343 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4344 description_has_relnotes = any(ax_regex.match(line)
4345 for line in input_api.change.DescriptionText().lower().splitlines())
4346
4347 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4348 'AX-Relnotes', [])
4349 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194350 return []
4351
4352 # TODO(chrishall): link to Relnotes documentation in message.
4353 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4354 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4355 "user-facing changes"
4356 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4357 "user-facing effects"
4358 "\n if this is confusing or annoying then please contact members "
4359 "of ui/accessibility/OWNERS.")
4360
4361 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224362
Saagar Sanghavifceeaae2020-08-12 16:40:364363def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394364 """Checks common to both upload and commit."""
4365 results = []
4366 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384367 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544368 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084369
4370 author = input_api.change.author_email
4371 if author and author not in _KNOWN_ROBOTS:
4372 results.extend(
4373 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4374
[email protected]9f919cc2013-07-31 03:04:044375 results.extend(
4376 input_api.canned_checks.CheckChangeHasNoTabs(
4377 input_api,
4378 output_api,
4379 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434380 results.extend(input_api.RunTests(
4381 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244382
Edward Lesmesce51df52020-08-04 22:10:174383 dirmd_bin = input_api.os_path.join(
4384 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4385 results.extend(input_api.RunTests(
4386 input_api.canned_checks.CheckDirMetadataFormat(
4387 input_api, output_api, dirmd_bin)))
4388 results.extend(
4389 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4390 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554391 results.extend(
4392 input_api.canned_checks.CheckNoNewMetadataInOwners(
4393 input_api, output_api))
Edward Lesmesce51df52020-08-04 22:10:174394
Vaclav Brozekcdc7defb2018-03-20 09:54:354395 for f in input_api.AffectedFiles():
4396 path, name = input_api.os_path.split(f.LocalPath())
4397 if name == 'PRESUBMIT.py':
4398 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004399 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4400 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074401 # The PRESUBMIT.py file (and the directory containing it) might
4402 # have been affected by being moved or removed, so only try to
4403 # run the tests if they still exist.
4404 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4405 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444406 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394407 return results
[email protected]1f7b4172010-01-28 01:17:344408
[email protected]b337cb5b2011-01-23 21:24:054409
Saagar Sanghavifceeaae2020-08-12 16:40:364410def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494411 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4412 if f.LocalPath().endswith(('.orig', '.rej'))]
4413 if problems:
4414 return [output_api.PresubmitError(
4415 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034416 else:
4417 return []
[email protected]b8079ae4a2012-12-05 19:56:494418
4419
Saagar Sanghavifceeaae2020-08-12 16:40:364420def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214421 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4422 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4423 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074424 include_re = input_api.re.compile(
4425 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4426 extension_re = input_api.re.compile(r'\.[a-z]+$')
4427 errors = []
4428 for f in input_api.AffectedFiles():
4429 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4430 continue
4431 found_line_number = None
4432 found_macro = None
4433 for line_num, line in f.ChangedContents():
4434 match = macro_re.search(line)
4435 if match:
4436 found_line_number = line_num
4437 found_macro = match.group(2)
4438 break
4439 if not found_line_number:
4440 continue
4441
4442 found_include = False
4443 for line in f.NewContents():
4444 if include_re.search(line):
4445 found_include = True
4446 break
4447 if found_include:
4448 continue
4449
4450 if not f.LocalPath().endswith('.h'):
4451 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4452 try:
4453 content = input_api.ReadFile(primary_header_path, 'r')
4454 if include_re.search(content):
4455 continue
4456 except IOError:
4457 pass
4458 errors.append('%s:%d %s macro is used without including build/'
4459 'build_config.h.'
4460 % (f.LocalPath(), found_line_number, found_macro))
4461 if errors:
4462 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4463 return []
4464
4465
[email protected]b00342e7f2013-03-26 16:21:544466def _DidYouMeanOSMacro(bad_macro):
4467 try:
4468 return {'A': 'OS_ANDROID',
4469 'B': 'OS_BSD',
4470 'C': 'OS_CHROMEOS',
4471 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444472 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544473 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444474 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544475 'N': 'OS_NACL',
4476 'O': 'OS_OPENBSD',
4477 'P': 'OS_POSIX',
4478 'S': 'OS_SOLARIS',
4479 'W': 'OS_WIN'}[bad_macro[3].upper()]
4480 except KeyError:
4481 return ''
4482
4483
4484def _CheckForInvalidOSMacrosInFile(input_api, f):
4485 """Check for sensible looking, totally invalid OS macros."""
4486 preprocessor_statement = input_api.re.compile(r'^\s*#')
4487 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4488 results = []
4489 for lnum, line in f.ChangedContents():
4490 if preprocessor_statement.search(line):
4491 for match in os_macro.finditer(line):
4492 if not match.group(1) in _VALID_OS_MACROS:
4493 good = _DidYouMeanOSMacro(match.group(1))
4494 did_you_mean = ' (did you mean %s?)' % good if good else ''
4495 results.append(' %s:%d %s%s' % (f.LocalPath(),
4496 lnum,
4497 match.group(1),
4498 did_you_mean))
4499 return results
4500
4501
Saagar Sanghavifceeaae2020-08-12 16:40:364502def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544503 """Check all affected files for invalid OS macros."""
4504 bad_macros = []
tzik3f295992018-12-04 20:32:234505 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474506 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544507 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4508
4509 if not bad_macros:
4510 return []
4511
4512 return [output_api.PresubmitError(
4513 'Possibly invalid OS macro[s] found. Please fix your code\n'
4514 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4515
lliabraa35bab3932014-10-01 12:16:444516
4517def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4518 """Check all affected files for invalid "if defined" macros."""
4519 ALWAYS_DEFINED_MACROS = (
4520 "TARGET_CPU_PPC",
4521 "TARGET_CPU_PPC64",
4522 "TARGET_CPU_68K",
4523 "TARGET_CPU_X86",
4524 "TARGET_CPU_ARM",
4525 "TARGET_CPU_MIPS",
4526 "TARGET_CPU_SPARC",
4527 "TARGET_CPU_ALPHA",
4528 "TARGET_IPHONE_SIMULATOR",
4529 "TARGET_OS_EMBEDDED",
4530 "TARGET_OS_IPHONE",
4531 "TARGET_OS_MAC",
4532 "TARGET_OS_UNIX",
4533 "TARGET_OS_WIN32",
4534 )
4535 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4536 results = []
4537 for lnum, line in f.ChangedContents():
4538 for match in ifdef_macro.finditer(line):
4539 if match.group(1) in ALWAYS_DEFINED_MACROS:
4540 always_defined = ' %s is always defined. ' % match.group(1)
4541 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4542 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4543 lnum,
4544 always_defined,
4545 did_you_mean))
4546 return results
4547
4548
Saagar Sanghavifceeaae2020-08-12 16:40:364549def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444550 """Check all affected files for invalid "if defined" macros."""
4551 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054552 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444553 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054554 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214555 continue
lliabraa35bab3932014-10-01 12:16:444556 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4557 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4558
4559 if not bad_macros:
4560 return []
4561
4562 return [output_api.PresubmitError(
4563 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4564 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4565 bad_macros)]
4566
4567
Saagar Sanghavifceeaae2020-08-12 16:40:364568def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044569 """Check for same IPC rules described in
4570 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4571 """
4572 base_pattern = r'IPC_ENUM_TRAITS\('
4573 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4574 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4575
4576 problems = []
4577 for f in input_api.AffectedSourceFiles(None):
4578 local_path = f.LocalPath()
4579 if not local_path.endswith('.h'):
4580 continue
4581 for line_number, line in f.ChangedContents():
4582 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4583 problems.append(
4584 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4585
4586 if problems:
4587 return [output_api.PresubmitPromptWarning(
4588 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4589 else:
4590 return []
4591
[email protected]b00342e7f2013-03-26 16:21:544592
Saagar Sanghavifceeaae2020-08-12 16:40:364593def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054594 """Check to make sure no files being submitted have long paths.
4595 This causes issues on Windows.
4596 """
4597 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194598 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054599 local_path = f.LocalPath()
4600 # Windows has a path limit of 260 characters. Limit path length to 200 so
4601 # that we have some extra for the prefix on dev machines and the bots.
4602 if len(local_path) > 200:
4603 problems.append(local_path)
4604
4605 if problems:
4606 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4607 else:
4608 return []
4609
4610
Saagar Sanghavifceeaae2020-08-12 16:40:364611def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144612 """Check that header files have proper guards against multiple inclusion.
4613 If a file should not have such guards (and it probably should) then it
4614 should include the string "no-include-guard-because-multiply-included".
4615 """
Daniel Bratell6a75baef62018-06-04 10:04:454616 def is_chromium_header_file(f):
4617 # We only check header files under the control of the Chromium
4618 # project. That is, those outside third_party apart from
4619 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324620 # We also exclude *_message_generator.h headers as they use
4621 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454622 file_with_path = input_api.os_path.normpath(f.LocalPath())
4623 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324624 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454625 (not file_with_path.startswith('third_party') or
4626 file_with_path.startswith(
4627 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144628
4629 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344630 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144631
4632 errors = []
4633
Daniel Bratell6a75baef62018-06-04 10:04:454634 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144635 guard_name = None
4636 guard_line_number = None
4637 seen_guard_end = False
4638
4639 file_with_path = input_api.os_path.normpath(f.LocalPath())
4640 base_file_name = input_api.os_path.splitext(
4641 input_api.os_path.basename(file_with_path))[0]
4642 upper_base_file_name = base_file_name.upper()
4643
4644 expected_guard = replace_special_with_underscore(
4645 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144646
4647 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574648 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4649 # are too many (1000+) files with slight deviations from the
4650 # coding style. The most important part is that the include guard
4651 # is there, and that it's unique, not the name so this check is
4652 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144653 #
4654 # As code becomes more uniform, this could be made stricter.
4655
4656 guard_name_pattern_list = [
4657 # Anything with the right suffix (maybe with an extra _).
4658 r'\w+_H__?',
4659
Daniel Bratell39b5b062018-05-16 18:09:574660 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144661 r'\w+_h',
4662
4663 # Anything including the uppercase name of the file.
4664 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4665 upper_base_file_name)) + r'\w*',
4666 ]
4667 guard_name_pattern = '|'.join(guard_name_pattern_list)
4668 guard_pattern = input_api.re.compile(
4669 r'#ifndef\s+(' + guard_name_pattern + ')')
4670
4671 for line_number, line in enumerate(f.NewContents()):
4672 if 'no-include-guard-because-multiply-included' in line:
4673 guard_name = 'DUMMY' # To not trigger check outside the loop.
4674 break
4675
4676 if guard_name is None:
4677 match = guard_pattern.match(line)
4678 if match:
4679 guard_name = match.group(1)
4680 guard_line_number = line_number
4681
Daniel Bratell39b5b062018-05-16 18:09:574682 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454683 # don't match the chromium style guide, but new files should
4684 # get it right.
4685 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574686 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144687 errors.append(output_api.PresubmitPromptWarning(
4688 'Header using the wrong include guard name %s' % guard_name,
4689 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574690 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144691 else:
4692 # The line after #ifndef should have a #define of the same name.
4693 if line_number == guard_line_number + 1:
4694 expected_line = '#define %s' % guard_name
4695 if line != expected_line:
4696 errors.append(output_api.PresubmitPromptWarning(
4697 'Missing "%s" for include guard' % expected_line,
4698 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4699 'Expected: %r\nGot: %r' % (expected_line, line)))
4700
4701 if not seen_guard_end and line == '#endif // %s' % guard_name:
4702 seen_guard_end = True
4703 elif seen_guard_end:
4704 if line.strip() != '':
4705 errors.append(output_api.PresubmitPromptWarning(
4706 'Include guard %s not covering the whole file' % (
4707 guard_name), [f.LocalPath()]))
4708 break # Nothing else to check and enough to warn once.
4709
4710 if guard_name is None:
4711 errors.append(output_api.PresubmitPromptWarning(
4712 'Missing include guard %s' % expected_guard,
4713 [f.LocalPath()],
4714 'Missing include guard in %s\n'
4715 'Recommended name: %s\n'
4716 'This check can be disabled by having the string\n'
4717 'no-include-guard-because-multiply-included in the header.' %
4718 (f.LocalPath(), expected_guard)))
4719
4720 return errors
4721
4722
Saagar Sanghavifceeaae2020-08-12 16:40:364723def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234724 """Check source code and known ascii text files for Windows style line
4725 endings.
4726 """
earthdok1b5e0ee2015-03-10 15:19:104727 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234728
4729 file_inclusion_pattern = (
4730 known_text_files,
4731 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4732 )
4733
mostynbb639aca52015-01-07 20:31:234734 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534735 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444736 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534737 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504738 include_file = False
4739 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234740 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504741 include_file = True
4742 if include_file:
4743 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234744
4745 if problems:
4746 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4747 'these files to contain Windows style line endings?\n' +
4748 '\n'.join(problems))]
4749
4750 return []
4751
4752
Saagar Sanghavifceeaae2020-08-12 16:40:364753def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134754 """Checks that all source files use SYSLOG properly."""
4755 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364756 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564757 for line_number, line in f.ChangedContents():
4758 if 'SYSLOG' in line:
4759 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4760
pastarmovj89f7ee12016-09-20 14:58:134761 if syslog_files:
4762 return [output_api.PresubmitPromptWarning(
4763 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4764 ' calls.\nFiles to check:\n', items=syslog_files)]
4765 return []
4766
4767
[email protected]1f7b4172010-01-28 01:17:344768def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364769 if input_api.version < [2, 0, 0]:
4770 return [output_api.PresubmitError("Your depot_tools is out of date. "
4771 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4772 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344773 results = []
scottmg39b29952014-12-08 18:31:284774 results.extend(
jam93a6ee792017-02-08 23:59:224775 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544776 return results
[email protected]ca8d1982009-02-19 16:33:124777
4778
[email protected]1bfb8322014-04-23 01:02:414779def GetTryServerMasterForBot(bot):
4780 """Returns the Try Server master for the given bot.
4781
[email protected]0bb112362014-07-26 04:38:324782 It tries to guess the master from the bot name, but may still fail
4783 and return None. There is no longer a default master.
4784 """
4785 # Potentially ambiguous bot names are listed explicitly.
4786 master_map = {
tandriie5587792016-07-14 00:34:504787 'chromium_presubmit': 'master.tryserver.chromium.linux',
4788 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414789 }
[email protected]0bb112362014-07-26 04:38:324790 master = master_map.get(bot)
4791 if not master:
wnwen4fbaab82016-05-25 12:54:364792 if 'android' in bot:
tandriie5587792016-07-14 00:34:504793 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364794 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504795 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324796 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504797 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324798 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504799 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324800 return master
[email protected]1bfb8322014-04-23 01:02:414801
4802
[email protected]ca8d1982009-02-19 16:33:124803def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364804 if input_api.version < [2, 0, 0]:
4805 return [output_api.PresubmitError("Your depot_tools is out of date. "
4806 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4807 "but your version is %d.%d.%d" % tuple(input_api.version))]
4808
[email protected]fe5f57c52009-06-05 14:25:544809 results = []
[email protected]fe5f57c52009-06-05 14:25:544810 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274811 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344812 input_api,
4813 output_api,
[email protected]2fdd1f362013-01-16 03:56:034814 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274815
jam93a6ee792017-02-08 23:59:224816 results.extend(
4817 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544818 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4819 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384820 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4821 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414822 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4823 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544824 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144825
4826
Saagar Sanghavifceeaae2020-08-12 16:40:364827def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264828 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024829 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4830 # footer is set to true.
4831 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264832 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024833 footer.lower()
4834 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264835 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024836
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144837 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264838 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144839 import sys
4840 from io import StringIO
4841
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144842 new_or_added_paths = set(f.LocalPath()
4843 for f in input_api.AffectedFiles()
4844 if (f.Action() == 'A' or f.Action() == 'M'))
4845 removed_paths = set(f.LocalPath()
4846 for f in input_api.AffectedFiles(include_deletes=True)
4847 if f.Action() == 'D')
4848
Andrew Grieve0e8790c2020-09-03 17:27:324849 affected_grds = [
4850 f for f in input_api.AffectedFiles()
4851 if f.LocalPath().endswith(('.grd', '.grdp'))
4852 ]
4853 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164854 if not affected_grds:
4855 return []
4856
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144857 affected_png_paths = [f.AbsoluteLocalPath()
4858 for f in input_api.AffectedFiles()
4859 if (f.LocalPath().endswith('.png'))]
4860
4861 # Check for screenshots. Developers can upload screenshots using
4862 # tools/translation/upload_screenshots.py which finds and uploads
4863 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4864 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4865 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4866 #
4867 # The logic here is as follows:
4868 #
4869 # - If the CL has a .png file under the screenshots directory for a grd
4870 # file, warn the developer. Actual images should never be checked into the
4871 # Chrome repo.
4872 #
4873 # - If the CL contains modified or new messages in grd files and doesn't
4874 # contain the corresponding .sha1 files, warn the developer to add images
4875 # and upload them via tools/translation/upload_screenshots.py.
4876 #
4877 # - If the CL contains modified or new messages in grd files and the
4878 # corresponding .sha1 files, everything looks good.
4879 #
4880 # - If the CL contains removed messages in grd files but the corresponding
4881 # .sha1 files aren't removed, warn the developer to remove them.
4882 unnecessary_screenshots = []
4883 missing_sha1 = []
4884 unnecessary_sha1_files = []
4885
Rainhard Findlingfc31844c52020-05-15 09:58:264886 # This checks verifies that the ICU syntax of messages this CL touched is
4887 # valid, and reports any found syntax errors.
4888 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4889 # without developers being aware of them. Later on, such ICU syntax errors
4890 # break message extraction for translation, hence would block Chromium
4891 # translations until they are fixed.
4892 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144893
4894 def _CheckScreenshotAdded(screenshots_dir, message_id):
4895 sha1_path = input_api.os_path.join(
4896 screenshots_dir, message_id + '.png.sha1')
4897 if sha1_path not in new_or_added_paths:
4898 missing_sha1.append(sha1_path)
4899
4900
4901 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4902 sha1_path = input_api.os_path.join(
4903 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034904 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144905 unnecessary_sha1_files.append(sha1_path)
4906
Rainhard Findlingfc31844c52020-05-15 09:58:264907
4908 def _ValidateIcuSyntax(text, level, signatures):
4909 """Validates ICU syntax of a text string.
4910
4911 Check if text looks similar to ICU and checks for ICU syntax correctness
4912 in this case. Reports various issues with ICU syntax and values of
4913 variants. Supports checking of nested messages. Accumulate information of
4914 each ICU messages found in the text for further checking.
4915
4916 Args:
4917 text: a string to check.
4918 level: a number of current nesting level.
4919 signatures: an accumulator, a list of tuple of (level, variable,
4920 kind, variants).
4921
4922 Returns:
4923 None if a string is not ICU or no issue detected.
4924 A tuple of (message, start index, end index) if an issue detected.
4925 """
4926 valid_types = {
4927 'plural': (frozenset(
4928 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4929 frozenset(['=1', 'other'])),
4930 'selectordinal': (frozenset(
4931 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4932 frozenset(['one', 'other'])),
4933 'select': (frozenset(), frozenset(['other'])),
4934 }
4935
4936 # Check if the message looks like an attempt to use ICU
4937 # plural. If yes - check if its syntax strictly matches ICU format.
4938 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4939 if not like:
4940 signatures.append((level, None, None, None))
4941 return
4942
4943 # Check for valid prefix and suffix
4944 m = re.match(
4945 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4946 r'(plural|selectordinal|select),\s*'
4947 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4948 if not m:
4949 return (('This message looks like an ICU plural, '
4950 'but does not follow ICU syntax.'), like.start(), like.end())
4951 starting, variable, kind, variant_pairs = m.groups()
4952 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4953 if depth:
4954 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4955 len(text))
4956 first = text[0]
4957 ending = text[last_pos:]
4958 if not starting:
4959 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4960 last_pos)
4961 if not ending or '}' not in ending:
4962 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4963 last_pos)
4964 elif first != '{':
4965 return (
4966 ('Invalid ICU format. Extra characters at the start of a complex '
4967 'message (go/icu-message-migration): "%s"') %
4968 starting, 0, len(starting))
4969 elif ending != '}':
4970 return (('Invalid ICU format. Extra characters at the end of a complex '
4971 'message (go/icu-message-migration): "%s"')
4972 % ending, last_pos - 1, len(text) - 1)
4973 if kind not in valid_types:
4974 return (('Unknown ICU message type %s. '
4975 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4976 known, required = valid_types[kind]
4977 defined_variants = set()
4978 for variant, variant_range, value, value_range in variants:
4979 start, end = variant_range
4980 if variant in defined_variants:
4981 return ('Variant "%s" is defined more than once' % variant,
4982 start, end)
4983 elif known and variant not in known:
4984 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4985 start, end)
4986 defined_variants.add(variant)
4987 # Check for nested structure
4988 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4989 if res:
4990 return (res[0], res[1] + value_range[0] + 1,
4991 res[2] + value_range[0] + 1)
4992 missing = required - defined_variants
4993 if missing:
4994 return ('Required variants missing: %s' % ', '.join(missing), 0,
4995 len(text))
4996 signatures.append((level, variable, kind, defined_variants))
4997
4998
4999 def _ParseIcuVariants(text, offset=0):
5000 """Parse variants part of ICU complex message.
5001
5002 Builds a tuple of variant names and values, as well as
5003 their offsets in the input string.
5004
5005 Args:
5006 text: a string to parse
5007 offset: additional offset to add to positions in the text to get correct
5008 position in the complete ICU string.
5009
5010 Returns:
5011 List of tuples, each tuple consist of four fields: variant name,
5012 variant name span (tuple of two integers), variant value, value
5013 span (tuple of two integers).
5014 """
5015 depth, start, end = 0, -1, -1
5016 variants = []
5017 key = None
5018 for idx, char in enumerate(text):
5019 if char == '{':
5020 if not depth:
5021 start = idx
5022 chunk = text[end + 1:start]
5023 key = chunk.strip()
5024 pos = offset + end + 1 + chunk.find(key)
5025 span = (pos, pos + len(key))
5026 depth += 1
5027 elif char == '}':
5028 if not depth:
5029 return variants, depth, offset + idx
5030 depth -= 1
5031 if not depth:
5032 end = idx
5033 variants.append((key, span, text[start:end + 1], (offset + start,
5034 offset + end + 1)))
5035 return variants, depth, offset + end + 1
5036
meacer8c0d3832019-12-26 21:46:165037 try:
5038 old_sys_path = sys.path
5039 sys.path = sys.path + [input_api.os_path.join(
5040 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5041 from helper import grd_helper
5042 finally:
5043 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145044
5045 for f in affected_grds:
5046 file_path = f.LocalPath()
5047 old_id_to_msg_map = {}
5048 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385049 # Note that this code doesn't check if the file has been deleted. This is
5050 # OK because it only uses the old and new file contents and doesn't load
5051 # the file via its path.
5052 # It's also possible that a file's content refers to a renamed or deleted
5053 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5054 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5055 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145056 if file_path.endswith('.grdp'):
5057 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585058 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395059 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145060 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585061 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395062 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145063 else:
meacerff8a9b62019-12-10 19:43:585064 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145065 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585066 old_id_to_msg_map = grd_helper.GetGrdMessages(
5067 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145068 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585069 new_id_to_msg_map = grd_helper.GetGrdMessages(
5070 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145071
Rainhard Findlingd8d04372020-08-13 13:30:095072 grd_name, ext = input_api.os_path.splitext(
5073 input_api.os_path.basename(file_path))
5074 screenshots_dir = input_api.os_path.join(
5075 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5076
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145077 # Compute added, removed and modified message IDs.
5078 old_ids = set(old_id_to_msg_map)
5079 new_ids = set(new_id_to_msg_map)
5080 added_ids = new_ids - old_ids
5081 removed_ids = old_ids - new_ids
5082 modified_ids = set([])
5083 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355084 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095085 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5086 # The message content itself changed. Require an updated screenshot.
5087 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355088 elif old_id_to_msg_map[key].attrs['meaning'] != \
5089 new_id_to_msg_map[key].attrs['meaning']:
5090 # The message meaning changed. Ensure there is a screenshot for it.
5091 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5092 if sha1_path not in new_or_added_paths and not \
5093 input_api.os_path.exists(sha1_path):
5094 # There is neither a previous screenshot nor is a new one added now.
5095 # Require a screenshot.
5096 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145097
Rainhard Findlingfc31844c52020-05-15 09:58:265098 if run_screenshot_check:
5099 # Check the screenshot directory for .png files. Warn if there is any.
5100 for png_path in affected_png_paths:
5101 if png_path.startswith(screenshots_dir):
5102 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145103
Rainhard Findlingfc31844c52020-05-15 09:58:265104 for added_id in added_ids:
5105 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145106
Rainhard Findlingfc31844c52020-05-15 09:58:265107 for modified_id in modified_ids:
5108 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145109
Rainhard Findlingfc31844c52020-05-15 09:58:265110 for removed_id in removed_ids:
5111 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5112
5113 # Check new and changed strings for ICU syntax errors.
5114 for key in added_ids.union(modified_ids):
5115 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5116 err = _ValidateIcuSyntax(msg, 0, [])
5117 if err is not None:
5118 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145119
5120 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265121 if run_screenshot_check:
5122 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005123 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265124 'Do not include actual screenshots in the changelist. Run '
5125 'tools/translate/upload_screenshots.py to upload them instead:',
5126 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145127
Rainhard Findlingfc31844c52020-05-15 09:58:265128 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005129 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265130 'You are adding or modifying UI strings.\n'
5131 'To ensure the best translations, take screenshots of the relevant UI '
5132 '(https://g.co/chrome/translation) and add these files to your '
5133 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145134
Rainhard Findlingfc31844c52020-05-15 09:58:265135 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005136 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265137 'You removed strings associated with these files. Remove:',
5138 sorted(unnecessary_sha1_files)))
5139 else:
5140 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5141 'screenshots check.'))
5142
5143 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075144 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265145 'ICU syntax errors were found in the following strings (problems or '
5146 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145147
5148 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125149
5150
Saagar Sanghavifceeaae2020-08-12 16:40:365151def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125152 repo_root=None,
5153 translation_expectations_path=None,
5154 grd_files=None):
5155 import sys
5156 affected_grds = [f for f in input_api.AffectedFiles()
5157 if (f.LocalPath().endswith('.grd') or
5158 f.LocalPath().endswith('.grdp'))]
5159 if not affected_grds:
5160 return []
5161
5162 try:
5163 old_sys_path = sys.path
5164 sys.path = sys.path + [
5165 input_api.os_path.join(
5166 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5167 from helper import git_helper
5168 from helper import translation_helper
5169 finally:
5170 sys.path = old_sys_path
5171
5172 # Check that translation expectations can be parsed and we can get a list of
5173 # translatable grd files. |repo_root| and |translation_expectations_path| are
5174 # only passed by tests.
5175 if not repo_root:
5176 repo_root = input_api.PresubmitLocalPath()
5177 if not translation_expectations_path:
5178 translation_expectations_path = input_api.os_path.join(
5179 repo_root, 'tools', 'gritsettings',
5180 'translation_expectations.pyl')
5181 if not grd_files:
5182 grd_files = git_helper.list_grds_in_repository(repo_root)
5183
dpapad8e21b472020-10-23 17:15:035184 # Ignore bogus grd files used only for testing
5185 # ui/webui/resoucres/tools/generate_grd.py.
5186 ignore_path = input_api.os_path.join(
5187 'ui', 'webui', 'resources', 'tools', 'tests')
5188 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5189
Mustafa Emre Acer51f2f742020-03-09 19:41:125190 try:
5191 translation_helper.get_translatable_grds(repo_root, grd_files,
5192 translation_expectations_path)
5193 except Exception as e:
5194 return [output_api.PresubmitNotifyResult(
5195 'Failed to get a list of translatable grd files. This happens when:\n'
5196 ' - One of the modified grd or grdp files cannot be parsed or\n'
5197 ' - %s is not updated.\n'
5198 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5199 return []
Ken Rockotc31f4832020-05-29 18:58:515200
5201
Saagar Sanghavifceeaae2020-08-12 16:40:365202def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515203 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095204 changed_mojoms = input_api.AffectedFiles(
5205 include_deletes=True,
5206 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515207 delta = []
5208 for mojom in changed_mojoms:
5209 old_contents = ''.join(mojom.OldContents()) or None
5210 new_contents = ''.join(mojom.NewContents()) or None
5211 delta.append({
5212 'filename': mojom.LocalPath(),
5213 'old': '\n'.join(mojom.OldContents()) or None,
5214 'new': '\n'.join(mojom.NewContents()) or None,
5215 })
5216
5217 process = input_api.subprocess.Popen(
5218 [input_api.python_executable,
5219 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5220 'public', 'tools', 'mojom',
5221 'check_stable_mojom_compatibility.py'),
5222 '--src-root', input_api.PresubmitLocalPath()],
5223 stdin=input_api.subprocess.PIPE,
5224 stdout=input_api.subprocess.PIPE,
5225 stderr=input_api.subprocess.PIPE,
5226 universal_newlines=True)
5227 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5228 if process.returncode:
5229 return [output_api.PresubmitError(
5230 'One or more [Stable] mojom definitions appears to have been changed '
5231 'in a way that is not backward-compatible.',
5232 long_text=error)]
5233 return []
Dominic Battre645d42342020-12-04 16:14:105234
5235def CheckDeprecationOfPreferences(input_api, output_api):
5236 """Removing a preference should come with a deprecation."""
5237
5238 def FilterFile(affected_file):
5239 """Accept only .cc files and the like."""
5240 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5241 files_to_skip = (_EXCLUDED_PATHS +
5242 _TEST_CODE_EXCLUDED_PATHS +
5243 input_api.DEFAULT_FILES_TO_SKIP)
5244 return input_api.FilterSourceFile(
5245 affected_file,
5246 files_to_check=file_inclusion_pattern,
5247 files_to_skip=files_to_skip)
5248
5249 def ModifiedLines(affected_file):
5250 """Returns a list of tuples (line number, line text) of added and removed
5251 lines.
5252
5253 Deleted lines share the same line number as the previous line.
5254
5255 This relies on the scm diff output describing each changed code section
5256 with a line of the form
5257
5258 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5259 """
5260 line_num = 0
5261 modified_lines = []
5262 for line in affected_file.GenerateScmDiff().splitlines():
5263 # Extract <new line num> of the patch fragment (see format above).
5264 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5265 if m:
5266 line_num = int(m.groups(1)[0])
5267 continue
5268 if ((line.startswith('+') and not line.startswith('++')) or
5269 (line.startswith('-') and not line.startswith('--'))):
5270 modified_lines.append((line_num, line))
5271
5272 if not line.startswith('-'):
5273 line_num += 1
5274 return modified_lines
5275
5276 def FindLineWith(lines, needle):
5277 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5278
5279 If 0 or >1 lines contain `needle`, -1 is returned.
5280 """
5281 matching_line_numbers = [
5282 # + 1 for 1-based counting of line numbers.
5283 i + 1 for i, line
5284 in enumerate(lines)
5285 if needle in line]
5286 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5287
5288 def ModifiedPrefMigration(affected_file):
5289 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5290 # Determine first and last lines of MigrateObsolete.*Pref functions.
5291 new_contents = affected_file.NewContents();
5292 range_1 = (
5293 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5294 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5295 range_2 = (
5296 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5297 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5298 if (-1 in range_1 + range_2):
5299 raise Exception(
5300 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5301
5302 # Check whether any of the modified lines are part of the
5303 # MigrateObsolete.*Pref functions.
5304 for line_nr, line in ModifiedLines(affected_file):
5305 if (range_1[0] <= line_nr <= range_1[1] or
5306 range_2[0] <= line_nr <= range_2[1]):
5307 return True
5308 return False
5309
5310 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5311 browser_prefs_file_pattern = input_api.re.compile(
5312 r'chrome/browser/prefs/browser_prefs.cc')
5313
5314 changes = input_api.AffectedFiles(include_deletes=True,
5315 file_filter=FilterFile)
5316 potential_problems = []
5317 for f in changes:
5318 for line in f.GenerateScmDiff().splitlines():
5319 # Check deleted lines for pref registrations.
5320 if (line.startswith('-') and not line.startswith('--') and
5321 register_pref_pattern.search(line)):
5322 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5323
5324 if browser_prefs_file_pattern.search(f.LocalPath()):
5325 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5326 # assume that they knew that they have to deprecate preferences and don't
5327 # warn.
5328 try:
5329 if ModifiedPrefMigration(f):
5330 return []
5331 except Exception as e:
5332 return [output_api.PresubmitError(str(e))]
5333
5334 if potential_problems:
5335 return [output_api.PresubmitPromptWarning(
5336 'Discovered possible removal of preference registrations.\n\n'
5337 'Please make sure to properly deprecate preferences by clearing their\n'
5338 'value for a couple of milestones before finally removing the code.\n'
5339 'Otherwise data may stay in the preferences files forever. See\n'
5340 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5341 'This may be a false positive warning (e.g. if you move preference\n'
5342 'registrations to a different place).\n',
5343 potential_problems
5344 )]
5345 return []