blob: fb8122f8f247fd82d0bfdcb0f46357dfe66a2fe6 [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
John Abd-El-Malek759fea62021-03-13 03:41:1438_EXCLUDED_SET_NO_PARENT_PATHS = (
39 # It's for historical reasons that blink isn't a top level directory, where
40 # it would be allowed to have "set noparent" to avoid top level owners
41 # accidentally +1ing changes.
42 'third_party/blink/OWNERS',
43)
44
wnwenbdc444e2016-05-25 13:44:1545
[email protected]06e6d0ff2012-12-11 01:36:4446# Fragment of a regular expression that matches C++ and Objective-C++
47# implementation files.
48_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
49
wnwenbdc444e2016-05-25 13:44:1550
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1951# Fragment of a regular expression that matches C++ and Objective-C++
52# header files.
53_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
54
55
[email protected]06e6d0ff2012-12-11 01:36:4456# Regular expression that matches code only used for test binaries
57# (best effort).
58_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0459 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4460 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1361 # Test suite files, like:
62 # foo_browsertest.cc
63 # bar_unittest_mac.cc (suffix)
64 # baz_unittests.cc (plural)
65 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1266 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1867 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4468 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0469 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4370 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0471 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4372 # Web test harness.
73 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4774 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0475 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0876 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0477 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4178 # EarlGrey app side code for tests.
79 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1780 # Views Examples code
81 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4182 # Chromium Codelab
83 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4484)
[email protected]ca8d1982009-02-19 16:33:1285
Daniel Bratell609102be2019-03-27 20:53:2186_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1587
[email protected]eea609a2011-11-18 13:10:1288_TEST_ONLY_WARNING = (
89 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5590 'production code. If you are doing this from inside another method\n'
91 'named as *ForTesting(), then consider exposing things to have tests\n'
92 'make that same call directly.\n'
93 'If that is not possible, you may put a comment on the same line with\n'
94 ' // IN-TEST \n'
95 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
96 'method and can be ignored. Do not do this inside production code.\n'
97 'The android-binary-size trybot will block if the method exists in the\n'
98 'release apk.')
[email protected]eea609a2011-11-18 13:10:1299
100
[email protected]cf9b78f2012-11-14 11:40:28101_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:40102 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:21103 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
104 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:28105
Michael Thiessen44457642020-02-06 00:24:15106# Format: Sequence of tuples containing:
107# * Full import path.
108# * Sequence of strings to show when the pattern matches.
109# * Sequence of path or filename exceptions to this rule
110_BANNED_JAVA_IMPORTS = (
111 (
Colin Blundell170d78c82020-03-12 13:56:04112 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15113 (
114 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
115 ),
116 (
117 'net/android/javatests/src/org/chromium/net/'
118 'AndroidProxySelectorTest.java',
119 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04120 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15121 ),
122 ),
Michael Thiessened631912020-08-07 19:01:31123 (
124 'android.support.test.rule.UiThreadTestRule;',
125 (
126 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43127 '@org.chromium.base.test.UiThreadTest on test methods that should run '
128 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31129 ),
130 (),
131 ),
132 (
133 'android.support.test.annotation.UiThreadTest;',
134 (
135 'Do not use android.support.test.annotation.UiThreadTest, use '
136 'org.chromium.base.test.UiThreadTest instead. See '
137 'https://crbug.com/1111893.',
138 ),
139 ()
Michael Thiessenfd6919b2020-12-08 20:44:01140 ),
141 (
142 'android.support.test.rule.ActivityTestRule;',
143 (
144 'Do not use ActivityTestRule, use '
145 'org.chromium.base.test.BaseActivityTestRule instead.',
146 ),
147 (
148 'components/cronet/',
149 )
Michael Thiessened631912020-08-07 19:01:31150 )
Michael Thiessen44457642020-02-06 00:24:15151)
wnwenbdc444e2016-05-25 13:44:15152
Daniel Bratell609102be2019-03-27 20:53:21153# Format: Sequence of tuples containing:
154# * String pattern or, if starting with a slash, a regular expression.
155# * Sequence of strings to show when the pattern matches.
156# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41157_BANNED_JAVA_FUNCTIONS = (
158 (
159 'StrictMode.allowThreadDiskReads()',
160 (
161 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
162 'directly.',
163 ),
164 False,
165 ),
166 (
167 'StrictMode.allowThreadDiskWrites()',
168 (
169 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
170 'directly.',
171 ),
172 False,
173 ),
Michael Thiessen0f2547e2020-07-27 21:55:36174 (
175 '.waitForIdleSync()',
176 (
177 'Do not use waitForIdleSync as it masks underlying issues. There is '
178 'almost always something else you should wait on instead.',
179 ),
180 False,
181 ),
Eric Stevensona9a980972017-09-23 00:04:41182)
183
Daniel Bratell609102be2019-03-27 20:53:21184# Format: Sequence of tuples containing:
185# * String pattern or, if starting with a slash, a regular expression.
186# * Sequence of strings to show when the pattern matches.
187# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59188_BANNED_OBJC_FUNCTIONS = (
189 (
190 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20191 (
192 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59193 'prohibited. Please use CrTrackingArea instead.',
194 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
195 ),
196 False,
197 ),
198 (
[email protected]eaae1972014-04-16 04:17:26199 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20200 (
201 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59202 'instead.',
203 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
204 ),
205 False,
206 ),
207 (
208 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20209 (
210 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59211 'Please use |convertPoint:(point) fromView:nil| instead.',
212 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
213 ),
214 True,
215 ),
216 (
217 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20218 (
219 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59220 'Please use |convertPoint:(point) toView:nil| instead.',
221 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
222 ),
223 True,
224 ),
225 (
226 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20227 (
228 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59229 'Please use |convertRect:(point) fromView:nil| instead.',
230 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
231 ),
232 True,
233 ),
234 (
235 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20236 (
237 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59238 'Please use |convertRect:(point) toView:nil| instead.',
239 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
240 ),
241 True,
242 ),
243 (
244 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20245 (
246 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59247 'Please use |convertSize:(point) fromView:nil| instead.',
248 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
249 ),
250 True,
251 ),
252 (
253 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20254 (
255 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59256 'Please use |convertSize:(point) toView:nil| instead.',
257 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
258 ),
259 True,
260 ),
jif65398702016-10-27 10:19:48261 (
262 r"/\s+UTF8String\s*]",
263 (
264 'The use of -[NSString UTF8String] is dangerous as it can return null',
265 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
266 'Please use |SysNSStringToUTF8| instead.',
267 ),
268 True,
269 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34270 (
271 r'__unsafe_unretained',
272 (
273 'The use of __unsafe_unretained is almost certainly wrong, unless',
274 'when interacting with NSFastEnumeration or NSInvocation.',
275 'Please use __weak in files build with ARC, nothing otherwise.',
276 ),
277 False,
278 ),
Avi Drissman7382afa02019-04-29 23:27:13279 (
280 'freeWhenDone:NO',
281 (
282 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
283 'Foundation types is prohibited.',
284 ),
285 True,
286 ),
[email protected]127f18ec2012-06-16 05:05:59287)
288
Daniel Bratell609102be2019-03-27 20:53:21289# Format: Sequence of tuples containing:
290# * String pattern or, if starting with a slash, a regular expression.
291# * Sequence of strings to show when the pattern matches.
292# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54293_BANNED_IOS_OBJC_FUNCTIONS = (
294 (
295 r'/\bTEST[(]',
296 (
297 'TEST() macro should not be used in Objective-C++ code as it does not ',
298 'drain the autorelease pool at the end of the test. Use TEST_F() ',
299 'macro instead with a fixture inheriting from PlatformTest (or a ',
300 'typedef).'
301 ),
302 True,
303 ),
304 (
305 r'/\btesting::Test\b',
306 (
307 'testing::Test should not be used in Objective-C++ code as it does ',
308 'not drain the autorelease pool at the end of the test. Use ',
309 'PlatformTest instead.'
310 ),
311 True,
312 ),
313)
314
Peter K. Lee6c03ccff2019-07-15 14:40:05315# Format: Sequence of tuples containing:
316# * String pattern or, if starting with a slash, a regular expression.
317# * Sequence of strings to show when the pattern matches.
318# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
319_BANNED_IOS_EGTEST_FUNCTIONS = (
320 (
321 r'/\bEXPECT_OCMOCK_VERIFY\b',
322 (
323 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
324 'it is meant for GTests. Use [mock verify] instead.'
325 ),
326 True,
327 ),
328)
329
danakj7a2b7082019-05-21 21:13:51330# Directories that contain deprecated Bind() or Callback types.
331# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36332# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51333# echo "-- $i"
Alexander Cooperd1244c582021-01-26 02:25:27334# (cd $i; git grep -nP \
335# 'base::(Bind\(|(Cancelable)?(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51336# done
337#
338# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
339# when they have been converted to modern callback types (OnceCallback,
340# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
341# checks for them and prevent regressions.
342_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51343 '^base/callback.h', # Intentional.
Alex Turnerb3ea38c2020-11-25 18:03:07344 '^base/cancelable_callback.h', # Intentional.
Alexander Cooperb3f1af662021-02-01 19:47:26345 "^chrome/browser/ash/accessibility/",
Alexander Cooper6b447b22020-07-22 00:47:18346 '^chrome/browser/media_galleries/',
Alexander Cooperb3f1af662021-02-01 19:47:26347 "^chrome/browser/metrics/",
Alexander Cooperb3f1af662021-02-01 19:47:26348 "^chrome/browser/prefetch/no_state_prefetch/",
349 '^chrome/browser/previews/',
Alexander Cooper6b447b22020-07-22 00:47:18350 '^chrome/browser/resources/chromeos/accessibility/',
Alexander Cooper6b447b22020-07-22 00:47:18351 '^chrome/browser/sync_file_system/',
Alexander Cooperb3f1af662021-02-01 19:47:26352 "^components/browsing_data/content/",
Alexander Cooperb3f1af662021-02-01 19:47:26353 "^components/feature_engagement/internal/",
354 "^docs/callback\\.md", # Intentional
355 "^docs/webui_explainer\\.md",
356 "^docs/process/lsc/large_scale_changes\\.md", # Intentional
357 "^docs/security/mojo\\.md",
358 "^docs/threading_and_tasks\\.md",
359 "^docs/ui/learn/bestpractices/layout\\.md",
Alan Cutter04a00642020-03-02 01:45:20360 '^extensions/browser/',
361 '^extensions/renderer/',
danakj7a2b7082019-05-21 21:13:51362 '^ppapi/proxy/',
Alexander Cooperb3f1af662021-02-01 19:47:26363 '^third_party/blink/PRESUBMIT_test.py', # Intentional.
364 '^third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py' # Intentional pylint: disable=line-too-long
danakj7a2b7082019-05-21 21:13:51365 '^tools/clang/base_bind_rewriters/', # Intentional.
366 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51367))
[email protected]127f18ec2012-06-16 05:05:59368
Alexander Cooper46a92712021-01-30 00:00:20369# Directories that contain deprecated CallbackList types.
370# Find sub-directories from a given directory by running:
371# for i in `find . -maxdepth 1 -type d|sort`; do
372# echo "-- $i"
373# (cd $i; git grep -nP 'base::CallbackList<'|wc -l)
374# done
375#
376# TODO(crbug.com/1113007): Remove (or narrow the scope of) paths from this list
377# when they have been converted to modern callback list types (OnceCallback,
378# RepeatingCallback) in order to enable presubmit checks for them and prevent
379# regressions.
380_NOT_CONVERTED_TO_MODERN_CALLBACK_LIST = '|'.join((
381 r'^chrome/browser/android/oom_intervention/near_oom_monitor\.h',
382 r'^chrome/browser/ash/account_manager/child_account_type_changed_user_data\.h', # pylint: disable=line-too-long
383 r'^chrome/browser/browser_switcher/',
384 r'^chrome/browser/chromeos/',
385 r'^chrome/browser/media/router/providers/cast/',
386 r'^chrome/brwoser/sessions/session_restore\.cc',
387 r'^chrome/browser/supervised_user/',
388 r'^chrome/browser/ui/',
389 r'^chromecast/external_mojo/external_service_support/',
390 r'^components/captive_portal/content/captive_portal_service\.h',
391 r'^components/keyed_service/core/keyed_service_shutdown_notifier\.h',
392 r'^components/media_router/browser/',
393 r'^components/ntp_tils/custom_links_manager_impl\.h',
394 r'^components/password_manager/core/browser/hash_password_manager\.h',
395 r'^components/suggestions/suggestions_service\.h',
396 r'^components/sync_device_info/',
397 r'^components/sync_sessions/session_sync_service_impl\.h',
398 r'^components/zoom/zoom_event_manager\.h',
399 r'^content/browser/host_zoom_map_impl\.h',
400 r'^content/browser/network_service_instance_impl\.h',
401 r'^content/browser/rendeer_host/render_process_host_impl\.cc',
402 r'^extensions/test/extension_test_notification_observer\.h',
403 r'^ios/chrome/browser/tabs/tab_parenting_global_observer\.h',
404 r'^ios/net/cookies/cookie_store_ios\.h',
405 r'^net/cookies/cookie_monster_change_dispatcher\.h',
406 r'^remoting/signaling/messaging_client\.h',
407 r'^services/device/battery/battery_status_service\.h',
408 r'^services/device/geolocation/',
409 r'^weblayer/browser/i18n_util\.cc',
410 r'^weblayer/public/cookie_manager\.h',
411))
412
Daniel Bratell609102be2019-03-27 20:53:21413# Format: Sequence of tuples containing:
414# * String pattern or, if starting with a slash, a regular expression.
415# * Sequence of strings to show when the pattern matches.
416# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
417# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59418_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20419 (
Peter Kasting94a56c42019-10-25 21:54:04420 r'/\busing namespace ',
421 (
422 'Using directives ("using namespace x") are banned by the Google Style',
423 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
424 'Explicitly qualify symbols or use using declarations ("using x::foo").',
425 ),
426 True,
427 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
428 ),
Antonio Gomes07300d02019-03-13 20:59:57429 # Make sure that gtest's FRIEND_TEST() macro is not used; the
430 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
431 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53432 (
[email protected]23e6cbc2012-06-16 18:51:20433 'FRIEND_TEST(',
434 (
[email protected]e3c945502012-06-26 20:01:49435 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20436 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
437 ),
438 False,
[email protected]7345da02012-11-27 14:31:49439 (),
[email protected]23e6cbc2012-06-16 18:51:20440 ),
441 (
tomhudsone2c14d552016-05-26 17:07:46442 'setMatrixClip',
443 (
444 'Overriding setMatrixClip() is prohibited; ',
445 'the base function is deprecated. ',
446 ),
447 True,
448 (),
449 ),
450 (
[email protected]52657f62013-05-20 05:30:31451 'SkRefPtr',
452 (
453 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22454 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31455 ),
456 True,
457 (),
458 ),
459 (
460 'SkAutoRef',
461 (
462 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22463 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31464 ),
465 True,
466 (),
467 ),
468 (
469 'SkAutoTUnref',
470 (
471 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22472 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31473 ),
474 True,
475 (),
476 ),
477 (
478 'SkAutoUnref',
479 (
480 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
481 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22482 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31483 ),
484 True,
485 (),
486 ),
[email protected]d89eec82013-12-03 14:10:59487 (
488 r'/HANDLE_EINTR\(.*close',
489 (
490 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
491 'descriptor will be closed, and it is incorrect to retry the close.',
492 'Either call close directly and ignore its return value, or wrap close',
493 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
494 ),
495 True,
496 (),
497 ),
498 (
499 r'/IGNORE_EINTR\((?!.*close)',
500 (
501 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
502 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
503 ),
504 True,
505 (
506 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04507 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
508 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59509 ),
510 ),
[email protected]ec5b3f02014-04-04 18:43:43511 (
512 r'/v8::Extension\(',
513 (
514 'Do not introduce new v8::Extensions into the code base, use',
515 'gin::Wrappable instead. See http://crbug.com/334679',
516 ),
517 True,
[email protected]f55c90ee62014-04-12 00:50:03518 (
Egor Paskoce145c42018-09-28 19:31:04519 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03520 ),
[email protected]ec5b3f02014-04-04 18:43:43521 ),
skyostilf9469f72015-04-20 10:38:52522 (
jame2d1a952016-04-02 00:27:10523 '#pragma comment(lib,',
524 (
525 'Specify libraries to link with in build files and not in the source.',
526 ),
527 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41528 (
tzik3f295992018-12-04 20:32:23529 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04530 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41531 ),
jame2d1a952016-04-02 00:27:10532 ),
fdorayc4ac18d2017-05-01 21:39:59533 (
Gabriel Charette7cc6c432018-04-25 20:52:02534 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59535 (
536 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
537 ),
538 False,
539 (),
540 ),
541 (
Gabriel Charette7cc6c432018-04-25 20:52:02542 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59543 (
544 'Consider using THREAD_CHECKER macros instead of the class directly.',
545 ),
546 False,
547 (),
548 ),
dbeamb6f4fde2017-06-15 04:03:06549 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06550 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
551 (
552 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
553 'deprecated (http://crbug.com/634507). Please avoid converting away',
554 'from the Time types in Chromium code, especially if any math is',
555 'being done on time values. For interfacing with platform/library',
556 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
557 'type converter methods instead. For faking TimeXXX values (for unit',
558 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
559 'other use cases, please contact base/time/OWNERS.',
560 ),
561 False,
562 (),
563 ),
564 (
dbeamb6f4fde2017-06-15 04:03:06565 'CallJavascriptFunctionUnsafe',
566 (
567 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
568 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
569 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
570 ),
571 False,
572 (
Egor Paskoce145c42018-09-28 19:31:04573 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
574 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
575 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06576 ),
577 ),
dskiba1474c2bfd62017-07-20 02:19:24578 (
579 'leveldb::DB::Open',
580 (
581 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
582 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
583 "Chrome's tracing, making their memory usage visible.",
584 ),
585 True,
586 (
587 r'^third_party/leveldatabase/.*\.(cc|h)$',
588 ),
Gabriel Charette0592c3a2017-07-26 12:02:04589 ),
590 (
Chris Mumfordc38afb62017-10-09 17:55:08591 'leveldb::NewMemEnv',
592 (
593 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58594 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
595 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08596 ),
597 True,
598 (
599 r'^third_party/leveldatabase/.*\.(cc|h)$',
600 ),
601 ),
602 (
Gabriel Charetted9839bc2017-07-29 14:17:47603 'RunLoop::QuitCurrent',
604 (
Robert Liao64b7ab22017-08-04 23:03:43605 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
606 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47607 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41608 False,
Gabriel Charetted9839bc2017-07-29 14:17:47609 (),
Gabriel Charettea44975052017-08-21 23:14:04610 ),
611 (
612 'base::ScopedMockTimeMessageLoopTaskRunner',
613 (
Gabriel Charette87cc1af2018-04-25 20:52:51614 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11615 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51616 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
617 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
618 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04619 ),
Gabriel Charette87cc1af2018-04-25 20:52:51620 False,
Gabriel Charettea44975052017-08-21 23:14:04621 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57622 ),
623 (
Dave Tapuska98199b612019-07-10 13:30:44624 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57625 (
626 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02627 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57628 ),
629 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16630 # Abseil's benchmarks never linked into chrome.
631 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38632 ),
633 (
Peter Kasting991618a62019-06-17 22:00:09634 r'/\bstd::stoi\b',
635 (
636 'std::stoi uses exceptions to communicate results. ',
637 'Use base::StringToInt() instead.',
638 ),
639 True,
640 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
641 ),
642 (
643 r'/\bstd::stol\b',
644 (
645 'std::stol uses exceptions to communicate results. ',
646 'Use base::StringToInt() instead.',
647 ),
648 True,
649 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
650 ),
651 (
652 r'/\bstd::stoul\b',
653 (
654 'std::stoul uses exceptions to communicate results. ',
655 'Use base::StringToUint() instead.',
656 ),
657 True,
658 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
659 ),
660 (
661 r'/\bstd::stoll\b',
662 (
663 'std::stoll uses exceptions to communicate results. ',
664 'Use base::StringToInt64() instead.',
665 ),
666 True,
667 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
668 ),
669 (
670 r'/\bstd::stoull\b',
671 (
672 'std::stoull uses exceptions to communicate results. ',
673 'Use base::StringToUint64() instead.',
674 ),
675 True,
676 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
677 ),
678 (
679 r'/\bstd::stof\b',
680 (
681 'std::stof uses exceptions to communicate results. ',
682 'For locale-independent values, e.g. reading numbers from disk',
683 'profiles, use base::StringToDouble().',
684 'For user-visible values, parse using ICU.',
685 ),
686 True,
687 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
688 ),
689 (
690 r'/\bstd::stod\b',
691 (
692 'std::stod uses exceptions to communicate results. ',
693 'For locale-independent values, e.g. reading numbers from disk',
694 'profiles, use base::StringToDouble().',
695 'For user-visible values, parse using ICU.',
696 ),
697 True,
698 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
699 ),
700 (
701 r'/\bstd::stold\b',
702 (
703 'std::stold uses exceptions to communicate results. ',
704 'For locale-independent values, e.g. reading numbers from disk',
705 'profiles, use base::StringToDouble().',
706 'For user-visible values, parse using ICU.',
707 ),
708 True,
709 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
710 ),
711 (
Daniel Bratell69334cc2019-03-26 11:07:45712 r'/\bstd::to_string\b',
713 (
714 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09715 'For locale-independent strings, e.g. writing numbers to disk',
716 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45717 'For user-visible strings, use base::FormatNumber() and',
718 'the related functions in base/i18n/number_formatting.h.',
719 ),
Peter Kasting991618a62019-06-17 22:00:09720 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21721 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45722 ),
723 (
724 r'/\bstd::shared_ptr\b',
725 (
726 'std::shared_ptr should not be used. Use scoped_refptr instead.',
727 ),
728 True,
Ulan Degenbaev947043882021-02-10 14:02:31729 [
730 # Needed for interop with third-party library.
731 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57732 'array_buffer_contents\.(cc|h)',
Ulan Degenbaev947043882021-02-10 14:02:31733 'gin/array_buffer.cc',
734 'gin/array_buffer.h',
Alex Chau9eb03cdd52020-07-13 21:04:57735 'chrome/services/sharing/nearby/',
736 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21737 ),
738 (
Peter Kasting991618a62019-06-17 22:00:09739 r'/\bstd::weak_ptr\b',
740 (
741 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
742 ),
743 True,
744 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
745 ),
746 (
Daniel Bratell609102be2019-03-27 20:53:21747 r'/\blong long\b',
748 (
749 'long long is banned. Use stdint.h if you need a 64 bit number.',
750 ),
751 False, # Only a warning since it is already used.
752 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
753 ),
754 (
755 r'/\bstd::bind\b',
756 (
757 'std::bind is banned because of lifetime risks.',
758 'Use base::BindOnce or base::BindRepeating instead.',
759 ),
760 True,
761 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
762 ),
763 (
764 r'/\b#include <chrono>\b',
765 (
766 '<chrono> overlaps with Time APIs in base. Keep using',
767 'base classes.',
768 ),
769 True,
770 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
771 ),
772 (
773 r'/\b#include <exception>\b',
774 (
775 'Exceptions are banned and disabled in Chromium.',
776 ),
777 True,
778 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
779 ),
780 (
781 r'/\bstd::function\b',
782 (
783 'std::function is banned. Instead use base::Callback which directly',
784 'supports Chromium\'s weak pointers, ref counting and more.',
785 ),
Peter Kasting991618a62019-06-17 22:00:09786 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21787 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
788 ),
789 (
790 r'/\b#include <random>\b',
791 (
792 'Do not use any random number engines from <random>. Instead',
793 'use base::RandomBitGenerator.',
794 ),
795 True,
796 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
797 ),
798 (
Tom Andersona95e12042020-09-09 23:08:00799 r'/\b#include <X11/',
800 (
801 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
802 ),
803 True,
804 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
805 ),
806 (
Daniel Bratell609102be2019-03-27 20:53:21807 r'/\bstd::ratio\b',
808 (
809 'std::ratio is banned by the Google Style Guide.',
810 ),
811 True,
812 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45813 ),
814 (
Francois Doray43670e32017-09-27 12:40:38815 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
816 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
817 (
818 'Use the new API in base/threading/thread_restrictions.h.',
819 ),
Gabriel Charette04b138f2018-08-06 00:03:22820 False,
Francois Doray43670e32017-09-27 12:40:38821 (),
822 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38823 (
danakj7a2b7082019-05-21 21:13:51824 r'/\bbase::Bind\(',
825 (
826 'Please use base::Bind{Once,Repeating} instead',
827 'of base::Bind. (crbug.com/714018)',
828 ),
829 False,
Erik Staaba737d7602019-11-25 18:41:07830 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51831 ),
832 (
833 r'/\bbase::Callback[<:]',
834 (
835 'Please use base::{Once,Repeating}Callback instead',
836 'of base::Callback. (crbug.com/714018)',
837 ),
838 False,
Erik Staaba737d7602019-11-25 18:41:07839 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51840 ),
841 (
842 r'/\bbase::Closure\b',
843 (
844 'Please use base::{Once,Repeating}Closure instead',
845 'of base::Closure. (crbug.com/714018)',
846 ),
847 False,
Erik Staaba737d7602019-11-25 18:41:07848 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51849 ),
850 (
Alex Turnerb3ea38c2020-11-25 18:03:07851 r'/\bbase::CancelableCallback[<:]',
852 (
853 'Please use base::Cancelable{Once,Repeating}Callback instead',
854 'of base::CancelableCallback. (crbug.com/714018)',
855 ),
856 False,
857 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
858 ),
859 (
860 r'/\bbase::CancelableClosure\b',
861 (
862 'Please use base::Cancelable{Once,Repeating}Closure instead',
863 'of base::CancelableClosure. (crbug.com/714018)',
864 ),
865 False,
866 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
867 ),
868 (
Alexander Cooper46a92712021-01-30 00:00:20869 r'/\bbase::CallbackList<',
870 (
871 'Please use base::{Once,Repeating}CallbackList instead',
872 'of base::CallbackList. (crbug.com/1113007)'
873 ),
874 False,
875 (_NOT_CONVERTED_TO_MODERN_CALLBACK_LIST,),
876 ),
877 (
Michael Giuffrida7f93d6922019-04-19 14:39:58878 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19879 (
880 'RunMessageLoop is deprecated, use RunLoop instead.',
881 ),
882 False,
883 (),
884 ),
885 (
Dave Tapuska98199b612019-07-10 13:30:44886 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19887 (
888 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
889 ),
890 False,
891 (),
892 ),
893 (
Dave Tapuska98199b612019-07-10 13:30:44894 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19895 (
896 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
897 "if you're convinced you need this.",
898 ),
899 False,
900 (),
901 ),
902 (
Dave Tapuska98199b612019-07-10 13:30:44903 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19904 (
905 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04906 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19907 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
908 'async events instead of flushing threads.',
909 ),
910 False,
911 (),
912 ),
913 (
914 r'MessageLoopRunner',
915 (
916 'MessageLoopRunner is deprecated, use RunLoop instead.',
917 ),
918 False,
919 (),
920 ),
921 (
Dave Tapuska98199b612019-07-10 13:30:44922 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19923 (
924 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
925 "gab@ if you found a use case where this is the only solution.",
926 ),
927 False,
928 (),
929 ),
930 (
Victor Costane48a2e82019-03-15 22:02:34931 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16932 (
Victor Costane48a2e82019-03-15 22:02:34933 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16934 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
935 ),
936 True,
937 (
938 r'^sql/initialization\.(cc|h)$',
939 r'^third_party/sqlite/.*\.(c|cc|h)$',
940 ),
941 ),
Matt Menke7f520a82018-03-28 21:38:37942 (
Dave Tapuska98199b612019-07-10 13:30:44943 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47944 (
945 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
946 'base::RandomShuffle instead.'
947 ),
948 True,
949 (),
950 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24951 (
952 'ios/web/public/test/http_server',
953 (
954 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
955 ),
956 False,
957 (),
958 ),
Robert Liao764c9492019-01-24 18:46:28959 (
960 'GetAddressOf',
961 (
962 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53963 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11964 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53965 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28966 ),
967 True,
968 (),
969 ),
Antonio Gomes07300d02019-03-13 20:59:57970 (
Ben Lewisa9514602019-04-29 17:53:05971 'SHFileOperation',
972 (
973 'SHFileOperation was deprecated in Windows Vista, and there are less ',
974 'complex functions to achieve the same goals. Use IFileOperation for ',
975 'any esoteric actions instead.'
976 ),
977 True,
978 (),
979 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18980 (
Cliff Smolinsky81951642019-04-30 21:39:51981 'StringFromGUID2',
982 (
983 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24984 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51985 ),
986 True,
987 (
988 r'/base/win/win_util_unittest.cc'
989 ),
990 ),
991 (
992 'StringFromCLSID',
993 (
994 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24995 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51996 ),
997 True,
998 (
999 r'/base/win/win_util_unittest.cc'
1000 ),
1001 ),
1002 (
Avi Drissman7382afa02019-04-29 23:27:131003 'kCFAllocatorNull',
1004 (
1005 'The use of kCFAllocatorNull with the NoCopy creation of ',
1006 'CoreFoundation types is prohibited.',
1007 ),
1008 True,
1009 (),
1010 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291011 (
1012 'mojo::ConvertTo',
1013 (
1014 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1015 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1016 'StringTraits if you would like to convert between custom types and',
1017 'the wire format of mojom types.'
1018 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221019 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291020 (
Wezf89dec092019-09-11 19:38:331021 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1022 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291023 r'^third_party/blink/.*\.(cc|h)$',
1024 r'^content/renderer/.*\.(cc|h)$',
1025 ),
1026 ),
Robert Liao1d78df52019-11-11 20:02:011027 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161028 'GetInterfaceProvider',
1029 (
1030 'InterfaceProvider is deprecated.',
1031 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1032 'or Platform::GetBrowserInterfaceBroker.'
1033 ),
1034 False,
1035 (),
1036 ),
1037 (
Robert Liao1d78df52019-11-11 20:02:011038 'CComPtr',
1039 (
1040 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1041 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1042 'details.'
1043 ),
1044 False,
1045 (),
1046 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201047 (
1048 r'/\b(IFACE|STD)METHOD_?\(',
1049 (
1050 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1051 'Instead, always use IFACEMETHODIMP in the declaration.'
1052 ),
1053 False,
1054 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1055 ),
Allen Bauer53b43fb12020-03-12 17:21:471056 (
1057 'set_owned_by_client',
1058 (
1059 'set_owned_by_client is deprecated.',
1060 'views::View already owns the child views by default. This introduces ',
1061 'a competing ownership model which makes the code difficult to reason ',
1062 'about. See http://crbug.com/1044687 for more details.'
1063 ),
1064 False,
1065 (),
1066 ),
Eric Secklerbe6f48d2020-05-06 18:09:121067 (
1068 r'/\bTRACE_EVENT_ASYNC_',
1069 (
1070 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1071 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1072 ),
1073 False,
1074 (
1075 r'^base/trace_event/.*',
1076 r'^base/tracing/.*',
1077 ),
1078 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:261079 (
1080 r'/\bScopedObserver',
1081 (
1082 'ScopedObserver is deprecated.',
1083 'Please use base::ScopedObservation for observing a single source,',
1084 'or base::ScopedMultiSourceObservation for observing multple sources',
1085 ),
1086 False,
1087 (),
1088 ),
[email protected]127f18ec2012-06-16 05:05:591089)
1090
Mario Sanchez Prada2472cab2019-09-18 10:58:311091# Format: Sequence of tuples containing:
1092# * String pattern or, if starting with a slash, a regular expression.
1093# * Sequence of strings to show when the pattern matches.
1094_DEPRECATED_MOJO_TYPES = (
1095 (
1096 r'/\bmojo::AssociatedBinding\b',
1097 (
1098 'mojo::AssociatedBinding<Interface> is deprecated.',
1099 'Use mojo::AssociatedReceiver<Interface> instead.',
1100 ),
1101 ),
1102 (
1103 r'/\bmojo::AssociatedBindingSet\b',
1104 (
1105 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1106 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1107 ),
1108 ),
1109 (
1110 r'/\bmojo::AssociatedInterfacePtr\b',
1111 (
1112 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1113 'Use mojo::AssociatedRemote<Interface> instead.',
1114 ),
1115 ),
1116 (
1117 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1118 (
1119 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1120 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1121 ),
1122 ),
1123 (
1124 r'/\bmojo::AssociatedInterfaceRequest\b',
1125 (
1126 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1127 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1128 ),
1129 ),
1130 (
1131 r'/\bmojo::Binding\b',
1132 (
1133 'mojo::Binding<Interface> is deprecated.',
1134 'Use mojo::Receiver<Interface> instead.',
1135 ),
1136 ),
1137 (
1138 r'/\bmojo::BindingSet\b',
1139 (
1140 'mojo::BindingSet<Interface> is deprecated.',
1141 'Use mojo::ReceiverSet<Interface> instead.',
1142 ),
1143 ),
1144 (
1145 r'/\bmojo::InterfacePtr\b',
1146 (
1147 'mojo::InterfacePtr<Interface> is deprecated.',
1148 'Use mojo::Remote<Interface> instead.',
1149 ),
1150 ),
1151 (
1152 r'/\bmojo::InterfacePtrInfo\b',
1153 (
1154 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1155 'Use mojo::PendingRemote<Interface> instead.',
1156 ),
1157 ),
1158 (
1159 r'/\bmojo::InterfaceRequest\b',
1160 (
1161 'mojo::InterfaceRequest<Interface> is deprecated.',
1162 'Use mojo::PendingReceiver<Interface> instead.',
1163 ),
1164 ),
1165 (
1166 r'/\bmojo::MakeRequest\b',
1167 (
1168 'mojo::MakeRequest is deprecated.',
1169 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1170 ),
1171 ),
1172 (
1173 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1174 (
1175 'mojo::MakeRequest is deprecated.',
1176 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181177 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311178 ),
1179 ),
1180 (
1181 r'/\bmojo::MakeStrongBinding\b',
1182 (
1183 'mojo::MakeStrongBinding is deprecated.',
1184 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1185 'mojo::MakeSelfOwnedReceiver() instead.',
1186 ),
1187 ),
1188 (
1189 r'/\bmojo::MakeStrongAssociatedBinding\b',
1190 (
1191 'mojo::MakeStrongAssociatedBinding is deprecated.',
1192 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1193 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1194 ),
1195 ),
1196 (
Gyuyoung Kim4952ba62020-07-07 07:33:441197 r'/\bmojo::StrongAssociatedBinding\b',
1198 (
1199 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1200 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1201 ),
1202 ),
1203 (
1204 r'/\bmojo::StrongBinding\b',
1205 (
1206 'mojo::StrongBinding<Interface> is deprecated.',
1207 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1208 ),
1209 ),
1210 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311211 r'/\bmojo::StrongAssociatedBindingSet\b',
1212 (
1213 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1214 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1215 ),
1216 ),
1217 (
1218 r'/\bmojo::StrongBindingSet\b',
1219 (
1220 'mojo::StrongBindingSet<Interface> is deprecated.',
1221 'Use mojo::UniqueReceiverSet<Interface> instead.',
1222 ),
1223 ),
1224)
wnwenbdc444e2016-05-25 13:44:151225
mlamouria82272622014-09-16 18:45:041226_IPC_ENUM_TRAITS_DEPRECATED = (
1227 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501228 'See http://www.chromium.org/Home/chromium-security/education/'
1229 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041230
Stephen Martinis97a394142018-06-07 23:06:051231_LONG_PATH_ERROR = (
1232 'Some files included in this CL have file names that are too long (> 200'
1233 ' characters). If committed, these files will cause issues on Windows. See'
1234 ' https://crbug.com/612667 for more details.'
1235)
1236
Shenghua Zhangbfaa38b82017-11-16 21:58:021237_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041238 r".*[\\/]BuildHooksAndroidImpl\.java",
1239 r".*[\\/]LicenseContentProvider\.java",
1240 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281241 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021242]
[email protected]127f18ec2012-06-16 05:05:591243
Mohamed Heikald048240a2019-11-12 16:57:371244# List of image extensions that are used as resources in chromium.
1245_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1246
Sean Kau46e29bc2017-08-28 16:31:161247# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401248_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041249 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401250 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041251 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1252 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041253 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431254 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161255]
1256
1257
[email protected]b00342e7f2013-03-26 16:21:541258_VALID_OS_MACROS = (
1259 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081260 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541261 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441262 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121263 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541264 'OS_BSD',
1265 'OS_CAT', # For testing.
1266 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041267 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541268 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371269 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541270 'OS_IOS',
1271 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441272 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541273 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211274 'OS_NACL_NONSFI',
1275 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121276 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541277 'OS_OPENBSD',
1278 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371279 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541280 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541281 'OS_WIN',
1282)
1283
1284
Andrew Grieveb773bad2020-06-05 18:00:381285# These are not checked on the public chromium-presubmit trybot.
1286# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041287# checkouts.
agrievef32bcc72016-04-04 14:57:401288_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381289 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381290]
1291
1292
1293_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041294 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361295 'base/android/jni_generator/jni_generator.pydeps',
1296 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361297 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041298 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361299 'build/android/gyp/aar.pydeps',
1300 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271301 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361302 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381303 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361304 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021305 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221306 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111307 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361308 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361309 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361310 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111311 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041312 'build/android/gyp/create_app_bundle_apks.pydeps',
1313 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361314 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121315 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091316 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221317 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001318 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361319 'build/android/gyp/desugar.pydeps',
1320 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421321 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041322 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361323 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/filter_zip.pydeps',
1325 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361326 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361327 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581328 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361329 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141330 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261331 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011332 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041333 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361334 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361335 'build/android/gyp/merge_manifest.pydeps',
1336 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221337 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361338 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461339 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241340 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361341 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461342 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561343 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361344 'build/android/incremental_install/generate_android_manifest.pydeps',
1345 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041346 'build/android/resource_sizes.pydeps',
1347 'build/android/test_runner.pydeps',
1348 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361349 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361350 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321351 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271352 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1353 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041354 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001355 'components/cronet/tools/generate_javadoc.pydeps',
1356 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381357 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001358 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381359 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041360 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181361 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041362 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421363 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1364 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131365 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061366 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221367 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401368]
1369
wnwenbdc444e2016-05-25 13:44:151370
agrievef32bcc72016-04-04 14:57:401371_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1372
1373
Eric Boren6fd2b932018-01-25 15:05:081374# Bypass the AUTHORS check for these accounts.
1375_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591376 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451377 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591378 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521379 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071380 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041381 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271382 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041383 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301384 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081385
1386
Daniel Bratell65b033262019-04-23 08:17:061387def _IsCPlusPlusFile(input_api, file_path):
1388 """Returns True if this file contains C++-like code (and not Python,
1389 Go, Java, MarkDown, ...)"""
1390
1391 ext = input_api.os_path.splitext(file_path)[1]
1392 # This list is compatible with CppChecker.IsCppFile but we should
1393 # consider adding ".c" to it. If we do that we can use this function
1394 # at more places in the code.
1395 return ext in (
1396 '.h',
1397 '.cc',
1398 '.cpp',
1399 '.m',
1400 '.mm',
1401 )
1402
1403def _IsCPlusPlusHeaderFile(input_api, file_path):
1404 return input_api.os_path.splitext(file_path)[1] == ".h"
1405
1406
1407def _IsJavaFile(input_api, file_path):
1408 return input_api.os_path.splitext(file_path)[1] == ".java"
1409
1410
1411def _IsProtoFile(input_api, file_path):
1412 return input_api.os_path.splitext(file_path)[1] == ".proto"
1413
Mohamed Heikal5e5b7922020-10-29 18:57:591414
1415def CheckNoUpstreamDepsOnClank(input_api, output_api):
1416 """Prevent additions of dependencies from the upstream repo on //clank."""
1417 # clank can depend on clank
1418 if input_api.change.RepositoryRoot().endswith('clank'):
1419 return []
1420 build_file_patterns = [
1421 r'(.+/)?BUILD\.gn',
1422 r'.+\.gni',
1423 ]
1424 excluded_files = [
1425 r'build[/\\]config[/\\]android[/\\]config\.gni'
1426 ]
1427 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1428
1429 error_message = 'Disallowed import on //clank in an upstream build file:'
1430
1431 def FilterFile(affected_file):
1432 return input_api.FilterSourceFile(
1433 affected_file,
1434 files_to_check=build_file_patterns,
1435 files_to_skip=excluded_files)
1436
1437 problems = []
1438 for f in input_api.AffectedSourceFiles(FilterFile):
1439 local_path = f.LocalPath()
1440 for line_number, line in f.ChangedContents():
1441 if (bad_pattern.search(line)):
1442 problems.append(
1443 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1444 if problems:
1445 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1446 else:
1447 return []
1448
1449
Saagar Sanghavifceeaae2020-08-12 16:40:361450def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191451 """Attempts to prevent use of functions intended only for testing in
1452 non-testing code. For now this is just a best-effort implementation
1453 that ignores header files and may have some false positives. A
1454 better implementation would probably need a proper C++ parser.
1455 """
1456 # We only scan .cc files and the like, as the declaration of
1457 # for-testing functions in header files are hard to distinguish from
1458 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491459 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191460
jochenc0d4808c2015-07-27 09:25:421461 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191462 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091463 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131464 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191465 exclusion_pattern = input_api.re.compile(
1466 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1467 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131468 # Avoid a false positive in this case, where the method name, the ::, and
1469 # the closing { are all on different lines due to line wrapping.
1470 # HelperClassForTesting::
1471 # HelperClassForTesting(
1472 # args)
1473 # : member(0) {}
1474 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191475
1476 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441477 files_to_skip = (_EXCLUDED_PATHS +
1478 _TEST_CODE_EXCLUDED_PATHS +
1479 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191480 return input_api.FilterSourceFile(
1481 affected_file,
James Cook24a504192020-07-23 00:08:441482 files_to_check=file_inclusion_pattern,
1483 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191484
1485 problems = []
1486 for f in input_api.AffectedSourceFiles(FilterFile):
1487 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131488 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241489 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031490 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461491 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131492 not exclusion_pattern.search(line) and
1493 not allowlist_pattern.search(line) and
1494 not in_method_defn):
[email protected]55459852011-08-10 15:17:191495 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031496 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131497 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191498
1499 if problems:
[email protected]f7051d52013-04-02 18:31:421500 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031501 else:
1502 return []
[email protected]55459852011-08-10 15:17:191503
1504
Saagar Sanghavifceeaae2020-08-12 16:40:361505def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231506 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591507 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231508 """
1509 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1510 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1511 name_pattern = r'ForTest(s|ing)?'
1512 # Describes an occurrence of "ForTest*" inside a // comment.
1513 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501514 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551515 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231516 # Catch calls.
1517 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1518 # Ignore definitions. (Comments are ignored separately.)
1519 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1520
1521 problems = []
1522 sources = lambda x: input_api.FilterSourceFile(
1523 x,
James Cook24a504192020-07-23 00:08:441524 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1525 + input_api.DEFAULT_FILES_TO_SKIP),
1526 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231527 )
1528 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1529 local_path = f.LocalPath()
1530 is_inside_javadoc = False
1531 for line_number, line in f.ChangedContents():
1532 if is_inside_javadoc and javadoc_end_re.search(line):
1533 is_inside_javadoc = False
1534 if not is_inside_javadoc and javadoc_start_re.search(line):
1535 is_inside_javadoc = True
1536 if is_inside_javadoc:
1537 continue
1538 if (inclusion_re.search(line) and
1539 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501540 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231541 not exclusion_re.search(line)):
1542 problems.append(
1543 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1544
1545 if problems:
1546 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1547 else:
1548 return []
1549
1550
Saagar Sanghavifceeaae2020-08-12 16:40:361551def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541552 """Checks to make sure no .h files include <iostream>."""
1553 files = []
1554 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1555 input_api.re.MULTILINE)
1556 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1557 if not f.LocalPath().endswith('.h'):
1558 continue
1559 contents = input_api.ReadFile(f)
1560 if pattern.search(contents):
1561 files.append(f)
1562
1563 if len(files):
yolandyandaabc6d2016-04-18 18:29:391564 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061565 'Do not #include <iostream> in header files, since it inserts static '
1566 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541567 '#include <ostream>. See http://crbug.com/94794',
1568 files) ]
1569 return []
1570
Danil Chapovalov3518f362018-08-11 16:13:431571def _CheckNoStrCatRedefines(input_api, output_api):
1572 """Checks no windows headers with StrCat redefined are included directly."""
1573 files = []
1574 pattern_deny = input_api.re.compile(
1575 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1576 input_api.re.MULTILINE)
1577 pattern_allow = input_api.re.compile(
1578 r'^#include\s"base/win/windows_defines.inc"',
1579 input_api.re.MULTILINE)
1580 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1581 contents = input_api.ReadFile(f)
1582 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1583 files.append(f.LocalPath())
1584
1585 if len(files):
1586 return [output_api.PresubmitError(
1587 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1588 'directly since they pollute code with StrCat macro. Instead, '
1589 'include matching header from base/win. See http://crbug.com/856536',
1590 files) ]
1591 return []
1592
[email protected]10689ca2011-09-02 02:31:541593
Saagar Sanghavifceeaae2020-08-12 16:40:361594def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521595 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181596 problems = []
1597 for f in input_api.AffectedFiles():
1598 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1599 continue
1600
1601 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041602 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181603 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1604
1605 if not problems:
1606 return []
1607 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1608 '\n'.join(problems))]
1609
Saagar Sanghavifceeaae2020-08-12 16:40:361610def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341611 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1612
1613 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1614 instead of DISABLED_. To filter false positives, reports are only generated
1615 if a corresponding MAYBE_ line exists.
1616 """
1617 problems = []
1618
1619 # The following two patterns are looked for in tandem - is a test labeled
1620 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1621 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1622 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1623
1624 # This is for the case that a test is disabled on all platforms.
1625 full_disable_pattern = input_api.re.compile(
1626 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1627 input_api.re.MULTILINE)
1628
Katie Df13948e2018-09-25 07:33:441629 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341630 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1631 continue
1632
1633 # Search for MABYE_, DISABLE_ pairs.
1634 disable_lines = {} # Maps of test name to line number.
1635 maybe_lines = {}
1636 for line_num, line in f.ChangedContents():
1637 disable_match = disable_pattern.search(line)
1638 if disable_match:
1639 disable_lines[disable_match.group(1)] = line_num
1640 maybe_match = maybe_pattern.search(line)
1641 if maybe_match:
1642 maybe_lines[maybe_match.group(1)] = line_num
1643
1644 # Search for DISABLE_ occurrences within a TEST() macro.
1645 disable_tests = set(disable_lines.keys())
1646 maybe_tests = set(maybe_lines.keys())
1647 for test in disable_tests.intersection(maybe_tests):
1648 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1649
1650 contents = input_api.ReadFile(f)
1651 full_disable_match = full_disable_pattern.search(contents)
1652 if full_disable_match:
1653 problems.append(' %s' % f.LocalPath())
1654
1655 if not problems:
1656 return []
1657 return [
1658 output_api.PresubmitPromptWarning(
1659 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1660 '\n'.join(problems))
1661 ]
1662
[email protected]72df4e782012-06-21 16:28:181663
Saagar Sanghavifceeaae2020-08-12 16:40:361664def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571665 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521666 errors = []
Hans Wennborg944479f2020-06-25 21:39:251667 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521668 input_api.re.MULTILINE)
1669 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1670 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1671 continue
1672 for lnum, line in f.ChangedContents():
1673 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171674 errors.append(output_api.PresubmitError(
1675 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571676 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171677 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521678 return errors
1679
1680
Weilun Shia487fad2020-10-28 00:10:341681# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1682# more reliable way. See
1683# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191684
wnwenbdc444e2016-05-25 13:44:151685
Saagar Sanghavifceeaae2020-08-12 16:40:361686def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391687 """Check that FlakyTest annotation is our own instead of the android one"""
1688 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1689 files = []
1690 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1691 if f.LocalPath().endswith('Test.java'):
1692 if pattern.search(input_api.ReadFile(f)):
1693 files.append(f)
1694 if len(files):
1695 return [output_api.PresubmitError(
1696 'Use org.chromium.base.test.util.FlakyTest instead of '
1697 'android.test.FlakyTest',
1698 files)]
1699 return []
mcasasb7440c282015-02-04 14:52:191700
wnwenbdc444e2016-05-25 13:44:151701
Saagar Sanghavifceeaae2020-08-12 16:40:361702def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221703 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271704 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221705 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201706 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571707 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341708 '/win/' in f.LocalPath() or
1709 'chrome_elf' in f.LocalPath() or
1710 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201711 continue
[email protected]8ea5d4b2011-09-13 21:49:221712
[email protected]a11dbe9b2012-08-07 01:32:581713 allowWString = False
[email protected]b5c24292011-11-28 14:38:201714 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581715 if 'presubmit: allow wstring' in line:
1716 allowWString = True
1717 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271718 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581719 allowWString = False
1720 else:
1721 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221722
[email protected]55463aa62011-10-12 00:48:271723 if not problems:
1724 return []
1725 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581726 ' If you are calling a cross-platform API that accepts a wstring, '
1727 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271728 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221729
1730
Saagar Sanghavifceeaae2020-08-12 16:40:361731def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441732 """Make sure .DEPS.git is never modified manually."""
1733 if any(f.LocalPath().endswith('.DEPS.git') for f in
1734 input_api.AffectedFiles()):
1735 return [output_api.PresubmitError(
1736 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1737 'automated system based on what\'s in DEPS and your changes will be\n'
1738 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501739 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1740 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441741 'for more information')]
1742 return []
1743
1744
Saagar Sanghavifceeaae2020-08-12 16:40:361745def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471746 """Checks that DEPS file deps are from allowed_hosts."""
1747 # Run only if DEPS file has been modified to annoy fewer bystanders.
1748 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1749 return []
1750 # Outsource work to gclient verify
1751 try:
John Budorickf20c0042019-04-25 23:23:401752 gclient_path = input_api.os_path.join(
1753 input_api.PresubmitLocalPath(),
1754 'third_party', 'depot_tools', 'gclient.py')
1755 input_api.subprocess.check_output(
1756 [input_api.python_executable, gclient_path, 'verify'],
1757 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471758 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201759 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471760 return [output_api.PresubmitError(
1761 'DEPS file must have only git dependencies.',
1762 long_text=error.output)]
1763
1764
Mario Sanchez Prada2472cab2019-09-18 10:58:311765def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1766 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591767 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311768
1769 Returns an string composed of the name of the file, the line number where the
1770 match has been found and the additional text passed as |message| in case the
1771 target type name matches the text inside the line passed as parameter.
1772 """
Peng Huang9c5949a02020-06-11 19:20:541773 result = []
1774
danakjd18e8892020-12-17 17:42:011775 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1776 return result
1777 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541778 return result
1779
Mario Sanchez Prada2472cab2019-09-18 10:58:311780 matched = False
1781 if type_name[0:1] == '/':
1782 regex = type_name[1:]
1783 if input_api.re.search(regex, line):
1784 matched = True
1785 elif type_name in line:
1786 matched = True
1787
Mario Sanchez Prada2472cab2019-09-18 10:58:311788 if matched:
1789 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1790 for message_line in message:
1791 result.append(' %s' % message_line)
1792
1793 return result
1794
1795
Saagar Sanghavifceeaae2020-08-12 16:40:361796def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591797 """Make sure that banned functions are not used."""
1798 warnings = []
1799 errors = []
1800
James Cook24a504192020-07-23 00:08:441801 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151802 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441803 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151804 if input_api.re.match(item, local_path):
1805 return True
1806 return False
1807
Peter K. Lee6c03ccff2019-07-15 14:40:051808 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541809 local_path = affected_file.LocalPath()
1810 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1811 return False
1812 basename = input_api.os_path.basename(local_path)
1813 if 'ios' in basename.split('_'):
1814 return True
1815 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1816 if sep and 'ios' in local_path.split(sep):
1817 return True
1818 return False
1819
wnwenbdc444e2016-05-25 13:44:151820 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311821 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1822 func_name, message)
1823 if problems:
wnwenbdc444e2016-05-25 13:44:151824 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311825 errors.extend(problems)
1826 else:
1827 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151828
Eric Stevensona9a980972017-09-23 00:04:411829 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1830 for f in input_api.AffectedFiles(file_filter=file_filter):
1831 for line_num, line in f.ChangedContents():
1832 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1833 CheckForMatch(f, line_num, line, func_name, message, error)
1834
[email protected]127f18ec2012-06-16 05:05:591835 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1836 for f in input_api.AffectedFiles(file_filter=file_filter):
1837 for line_num, line in f.ChangedContents():
1838 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151839 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591840
Peter K. Lee6c03ccff2019-07-15 14:40:051841 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541842 for line_num, line in f.ChangedContents():
1843 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1844 CheckForMatch(f, line_num, line, func_name, message, error)
1845
Peter K. Lee6c03ccff2019-07-15 14:40:051846 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1847 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1848 for line_num, line in f.ChangedContents():
1849 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1850 CheckForMatch(f, line_num, line, func_name, message, error)
1851
[email protected]127f18ec2012-06-16 05:05:591852 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1853 for f in input_api.AffectedFiles(file_filter=file_filter):
1854 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491855 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441856 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491857 continue
wnwenbdc444e2016-05-25 13:44:151858 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591859
1860 result = []
1861 if (warnings):
1862 result.append(output_api.PresubmitPromptWarning(
1863 'Banned functions were used.\n' + '\n'.join(warnings)))
1864 if (errors):
1865 result.append(output_api.PresubmitError(
1866 'Banned functions were used.\n' + '\n'.join(errors)))
1867 return result
1868
1869
Michael Thiessen44457642020-02-06 00:24:151870def _CheckAndroidNoBannedImports(input_api, output_api):
1871 """Make sure that banned java imports are not used."""
1872 errors = []
1873
1874 def IsException(path, exceptions):
1875 for exception in exceptions:
1876 if (path.startswith(exception)):
1877 return True
1878 return False
1879
1880 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1881 for f in input_api.AffectedFiles(file_filter=file_filter):
1882 for line_num, line in f.ChangedContents():
1883 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1884 if IsException(f.LocalPath(), exceptions):
1885 continue;
1886 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1887 'import ' + import_name, message)
1888 if problems:
1889 errors.extend(problems)
1890 result = []
1891 if (errors):
1892 result.append(output_api.PresubmitError(
1893 'Banned imports were used.\n' + '\n'.join(errors)))
1894 return result
1895
1896
Saagar Sanghavifceeaae2020-08-12 16:40:361897def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311898 """Make sure that old Mojo types are not used."""
1899 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571900 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311901
Mario Sanchez Pradaaab91382019-12-19 08:57:091902 # For any path that is not an "ok" or an "error" path, a warning will be
1903 # raised if deprecated mojo types are found.
1904 ok_paths = ['components/arc']
1905 error_paths = ['third_party/blink', 'content']
1906
Mario Sanchez Prada2472cab2019-09-18 10:58:311907 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1908 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571909 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091910 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311911 continue
1912
1913 for line_num, line in f.ChangedContents():
1914 for func_name, message in _DEPRECATED_MOJO_TYPES:
1915 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1916 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571917
Mario Sanchez Prada2472cab2019-09-18 10:58:311918 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091919 # Raise errors inside |error_paths| and warnings everywhere else.
1920 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571921 errors.extend(problems)
1922 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311923 warnings.extend(problems)
1924
1925 result = []
1926 if (warnings):
1927 result.append(output_api.PresubmitPromptWarning(
1928 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571929 if (errors):
1930 result.append(output_api.PresubmitError(
1931 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311932 return result
1933
1934
Saagar Sanghavifceeaae2020-08-12 16:40:361935def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061936 """Make sure that banned functions are not used."""
1937 files = []
1938 pattern = input_api.re.compile(r'^#pragma\s+once',
1939 input_api.re.MULTILINE)
1940 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1941 if not f.LocalPath().endswith('.h'):
1942 continue
1943 contents = input_api.ReadFile(f)
1944 if pattern.search(contents):
1945 files.append(f)
1946
1947 if files:
1948 return [output_api.PresubmitError(
1949 'Do not use #pragma once in header files.\n'
1950 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1951 files)]
1952 return []
1953
[email protected]127f18ec2012-06-16 05:05:591954
Saagar Sanghavifceeaae2020-08-12 16:40:361955def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121956 """Checks to make sure we don't introduce use of foo ? true : false."""
1957 problems = []
1958 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1959 for f in input_api.AffectedFiles():
1960 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1961 continue
1962
1963 for line_num, line in f.ChangedContents():
1964 if pattern.match(line):
1965 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1966
1967 if not problems:
1968 return []
1969 return [output_api.PresubmitPromptWarning(
1970 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1971 '\n'.join(problems))]
1972
1973
Saagar Sanghavifceeaae2020-08-12 16:40:361974def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281975 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181976 change. Breaking - rules is an error, breaking ! rules is a
1977 warning.
1978 """
mohan.reddyf21db962014-10-16 12:26:471979 import sys
[email protected]55f9f382012-07-31 11:02:181980 # We need to wait until we have an input_api object and use this
1981 # roundabout construct to import checkdeps because this file is
1982 # eval-ed and thus doesn't have __file__.
1983 original_sys_path = sys.path
1984 try:
1985 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471986 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181987 import checkdeps
[email protected]55f9f382012-07-31 11:02:181988 from rules import Rule
1989 finally:
1990 # Restore sys.path to what it was before.
1991 sys.path = original_sys_path
1992
1993 added_includes = []
rhalavati08acd232017-04-03 07:23:281994 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241995 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181996 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061997 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501998 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081999 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062000 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502001 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082002 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062003 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502004 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082005 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182006
[email protected]26385172013-05-09 23:11:352007 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182008
2009 error_descriptions = []
2010 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282011 error_subjects = set()
2012 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362013
[email protected]55f9f382012-07-31 11:02:182014 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2015 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082016 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182017 description_with_path = '%s\n %s' % (path, rule_description)
2018 if rule_type == Rule.DISALLOW:
2019 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282020 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182021 else:
2022 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282023 warning_subjects.add("#includes")
2024
2025 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2026 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082027 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282028 description_with_path = '%s\n %s' % (path, rule_description)
2029 if rule_type == Rule.DISALLOW:
2030 error_descriptions.append(description_with_path)
2031 error_subjects.add("imports")
2032 else:
2033 warning_descriptions.append(description_with_path)
2034 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182035
Jinsuk Kim5a092672017-10-24 22:42:242036 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022037 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082038 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242039 description_with_path = '%s\n %s' % (path, rule_description)
2040 if rule_type == Rule.DISALLOW:
2041 error_descriptions.append(description_with_path)
2042 error_subjects.add("imports")
2043 else:
2044 warning_descriptions.append(description_with_path)
2045 warning_subjects.add("imports")
2046
[email protected]55f9f382012-07-31 11:02:182047 results = []
2048 if error_descriptions:
2049 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282050 'You added one or more %s that violate checkdeps rules.'
2051 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182052 error_descriptions))
2053 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422054 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282055 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182056 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282057 '%s? See relevant DEPS file(s) for details and contacts.' %
2058 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182059 warning_descriptions))
2060 return results
2061
2062
Saagar Sanghavifceeaae2020-08-12 16:40:362063def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222064 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152065 if input_api.platform == 'win32':
2066 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292067 checkperms_tool = input_api.os_path.join(
2068 input_api.PresubmitLocalPath(),
2069 'tools', 'checkperms', 'checkperms.py')
2070 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472071 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392072 with input_api.CreateTemporaryFile() as file_list:
2073 for f in input_api.AffectedFiles():
2074 # checkperms.py file/directory arguments must be relative to the
2075 # repository.
2076 file_list.write(f.LocalPath() + '\n')
2077 file_list.close()
2078 args += ['--file-list', file_list.name]
2079 try:
2080 input_api.subprocess.check_output(args)
2081 return []
2082 except input_api.subprocess.CalledProcessError as error:
2083 return [output_api.PresubmitError(
2084 'checkperms.py failed:',
2085 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222086
2087
Saagar Sanghavifceeaae2020-08-12 16:40:362088def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492089 """Makes sure we don't include ui/aura/window_property.h
2090 in header files.
2091 """
2092 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2093 errors = []
2094 for f in input_api.AffectedFiles():
2095 if not f.LocalPath().endswith('.h'):
2096 continue
2097 for line_num, line in f.ChangedContents():
2098 if pattern.match(line):
2099 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2100
2101 results = []
2102 if errors:
2103 results.append(output_api.PresubmitError(
2104 'Header files should not include ui/aura/window_property.h', errors))
2105 return results
2106
2107
[email protected]70ca77752012-11-20 03:45:032108def _CheckForVersionControlConflictsInFile(input_api, f):
2109 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2110 errors = []
2111 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162112 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232113 # First-level headers in markdown look a lot like version control
2114 # conflict markers. http://daringfireball.net/projects/markdown/basics
2115 continue
[email protected]70ca77752012-11-20 03:45:032116 if pattern.match(line):
2117 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2118 return errors
2119
2120
Saagar Sanghavifceeaae2020-08-12 16:40:362121def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032122 """Usually this is not intentional and will cause a compile failure."""
2123 errors = []
2124 for f in input_api.AffectedFiles():
2125 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2126
2127 results = []
2128 if errors:
2129 results.append(output_api.PresubmitError(
2130 'Version control conflict markers found, please resolve.', errors))
2131 return results
2132
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202133
Saagar Sanghavifceeaae2020-08-12 16:40:362134def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162135 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2136 errors = []
2137 for f in input_api.AffectedFiles():
2138 for line_num, line in f.ChangedContents():
2139 if pattern.search(line):
2140 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2141
2142 results = []
2143 if errors:
2144 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502145 'Found Google support URL addressed by answer number. Please replace '
2146 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162147 return results
2148
[email protected]70ca77752012-11-20 03:45:032149
Saagar Sanghavifceeaae2020-08-12 16:40:362150def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442151 def FilterFile(affected_file):
2152 """Filter function for use with input_api.AffectedSourceFiles,
2153 below. This filters out everything except non-test files from
2154 top-level directories that generally speaking should not hard-code
2155 service URLs (e.g. src/android_webview/, src/content/ and others).
2156 """
2157 return input_api.FilterSourceFile(
2158 affected_file,
James Cook24a504192020-07-23 00:08:442159 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2160 files_to_skip=(_EXCLUDED_PATHS +
2161 _TEST_CODE_EXCLUDED_PATHS +
2162 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442163
reillyi38965732015-11-16 18:27:332164 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2165 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462166 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2167 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442168 problems = [] # items are (filename, line_number, line)
2169 for f in input_api.AffectedSourceFiles(FilterFile):
2170 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462171 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442172 problems.append((f.LocalPath(), line_num, line))
2173
2174 if problems:
[email protected]f7051d52013-04-02 18:31:422175 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442176 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582177 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442178 [' %s:%d: %s' % (
2179 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032180 else:
2181 return []
[email protected]06e6d0ff2012-12-11 01:36:442182
2183
Saagar Sanghavifceeaae2020-08-12 16:40:362184def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292185 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2186 def FileFilter(affected_file):
2187 """Includes directories known to be Chrome OS only."""
2188 return input_api.FilterSourceFile(
2189 affected_file,
James Cook24a504192020-07-23 00:08:442190 files_to_check=('^ash/',
2191 '^chromeos/', # Top-level src/chromeos.
2192 '/chromeos/', # Any path component.
2193 '^components/arc',
2194 '^components/exo'),
2195 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292196
2197 prefs = []
2198 priority_prefs = []
2199 for f in input_api.AffectedFiles(file_filter=FileFilter):
2200 for line_num, line in f.ChangedContents():
2201 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2202 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2203 prefs.append(' %s' % line)
2204 if input_api.re.search(
2205 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2206 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2207 priority_prefs.append(' %s' % line)
2208
2209 results = []
2210 if (prefs):
2211 results.append(output_api.PresubmitPromptWarning(
2212 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2213 'by browser sync settings. If these prefs should be controlled by OS '
2214 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2215 if (priority_prefs):
2216 results.append(output_api.PresubmitPromptWarning(
2217 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2218 'controlled by browser sync settings. If these prefs should be '
2219 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2220 'instead.\n' + '\n'.join(prefs)))
2221 return results
2222
2223
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492224# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362225def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272226 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312227 The native_client_sdk directory is excluded because it has auto-generated PNG
2228 files for documentation.
[email protected]d2530012013-01-25 16:39:272229 """
[email protected]d2530012013-01-25 16:39:272230 errors = []
James Cook24a504192020-07-23 00:08:442231 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2232 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312233 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442234 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312235 for f in input_api.AffectedFiles(include_deletes=False,
2236 file_filter=file_filter):
2237 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272238
2239 results = []
2240 if errors:
2241 results.append(output_api.PresubmitError(
2242 'The name of PNG files should not have abbreviations. \n'
2243 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2244 'Contact [email protected] if you have questions.', errors))
2245 return results
2246
2247
Daniel Cheng4dcdb6b2017-04-13 08:30:172248def _ExtractAddRulesFromParsedDeps(parsed_deps):
2249 """Extract the rules that add dependencies from a parsed DEPS file.
2250
2251 Args:
2252 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2253 add_rules = set()
2254 add_rules.update([
2255 rule[1:] for rule in parsed_deps.get('include_rules', [])
2256 if rule.startswith('+') or rule.startswith('!')
2257 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502258 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172259 {}).iteritems():
2260 add_rules.update([
2261 rule[1:] for rule in rules
2262 if rule.startswith('+') or rule.startswith('!')
2263 ])
2264 return add_rules
2265
2266
2267def _ParseDeps(contents):
2268 """Simple helper for parsing DEPS files."""
2269 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172270 class _VarImpl:
2271
2272 def __init__(self, local_scope):
2273 self._local_scope = local_scope
2274
2275 def Lookup(self, var_name):
2276 """Implements the Var syntax."""
2277 try:
2278 return self._local_scope['vars'][var_name]
2279 except KeyError:
2280 raise Exception('Var is not defined: %s' % var_name)
2281
2282 local_scope = {}
2283 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172284 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592285 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172286 }
2287 exec contents in global_scope, local_scope
2288 return local_scope
2289
2290
2291def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592292 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412293 a set of DEPS entries that we should look up.
2294
2295 For a directory (rather than a specific filename) we fake a path to
2296 a specific filename by adding /DEPS. This is chosen as a file that
2297 will seldom or never be subject to per-file include_rules.
2298 """
[email protected]2b438d62013-11-14 17:54:142299 # We ignore deps entries on auto-generated directories.
2300 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082301
Daniel Cheng4dcdb6b2017-04-13 08:30:172302 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2303 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2304
2305 added_deps = new_deps.difference(old_deps)
2306
[email protected]2b438d62013-11-14 17:54:142307 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172308 for added_dep in added_deps:
2309 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2310 continue
2311 # Assume that a rule that ends in .h is a rule for a specific file.
2312 if added_dep.endswith('.h'):
2313 results.add(added_dep)
2314 else:
2315 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082316 return results
2317
2318
Saagar Sanghavifceeaae2020-08-12 16:40:362319def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552320 """When a dependency prefixed with + is added to a DEPS file, we
2321 want to make sure that the change is reviewed by an OWNER of the
2322 target file or directory, to avoid layering violations from being
2323 introduced. This check verifies that this happens.
2324 """
Joey Mou57048132021-02-26 22:17:552325 # We rely on Gerrit's code-owners to check approvals.
2326 # input_api.gerrit is always set for Chromium, but other projects
2327 # might not use Gerrit.
2328 if not input_api.gerrit:
2329 return []
Edward Lesmes44feb2332021-03-19 01:27:522330 if (input_api.change.issue and
2331 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232332 # Skip OWNERS check when Owners-Override label is approved. This is intended
2333 # for global owners, trusted bots, and on-call sheriffs. Review is still
2334 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522335 return []
Edward Lesmes6fba51082021-01-20 04:20:232336
Daniel Cheng4dcdb6b2017-04-13 08:30:172337 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242338
2339 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492340 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242341 for f in input_api.AffectedFiles(include_deletes=False,
2342 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552343 filename = input_api.os_path.basename(f.LocalPath())
2344 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172345 virtual_depended_on_files.update(_CalculateAddedDeps(
2346 input_api.os_path,
2347 '\n'.join(f.OldContents()),
2348 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552349
[email protected]e871964c2013-05-13 14:14:552350 if not virtual_depended_on_files:
2351 return []
2352
2353 if input_api.is_committing:
2354 if input_api.tbr:
2355 return [output_api.PresubmitNotifyResult(
2356 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272357 if input_api.dry_run:
2358 return [output_api.PresubmitNotifyResult(
2359 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552360 if not input_api.change.issue:
2361 return [output_api.PresubmitError(
2362 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402363 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552364 output = output_api.PresubmitError
2365 else:
2366 output = output_api.PresubmitNotifyResult
2367
tandriied3b7e12016-05-12 14:38:502368 owner_email, reviewers = (
2369 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2370 input_api,
Edward Lesmesa3846442021-02-08 20:20:032371 None,
tandriied3b7e12016-05-12 14:38:502372 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552373
2374 owner_email = owner_email or input_api.change.author_email
2375
Edward Lesmesa3846442021-02-08 20:20:032376 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2377 virtual_depended_on_files, reviewers.union([owner_email]), [])
2378 missing_files = [
2379 f for f in virtual_depended_on_files
2380 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412381
2382 # We strip the /DEPS part that was added by
2383 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2384 # directory.
2385 def StripDeps(path):
2386 start_deps = path.rfind('/DEPS')
2387 if start_deps != -1:
2388 return path[:start_deps]
2389 else:
2390 return path
2391 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552392 for path in missing_files]
2393
2394 if unapproved_dependencies:
2395 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152396 output('You need LGTM from owners of depends-on paths in DEPS that were '
2397 'modified in this CL:\n %s' %
2398 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032399 suggested_owners = input_api.owners_client.SuggestOwners(
2400 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152401 output_list.append(output(
2402 'Suggested missing target path OWNERS:\n %s' %
2403 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552404 return output_list
2405
2406 return []
2407
2408
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492409# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362410def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492411 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442412 files_to_skip = (_EXCLUDED_PATHS +
2413 _TEST_CODE_EXCLUDED_PATHS +
2414 input_api.DEFAULT_FILES_TO_SKIP +
2415 (r"^base[\\/]logging\.h$",
2416 r"^base[\\/]logging\.cc$",
2417 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2418 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2419 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2420 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2421 r"startup_browser_creator\.cc$",
2422 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2423 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2424 r"diagnostics_writer\.cc$",
2425 r"^chrome[\\/]chrome_cleaner[\\/].*",
2426 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2427 r"dll_hash_main\.cc$",
2428 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2429 r"^chromecast[\\/]",
2430 r"^cloud_print[\\/]",
2431 r"^components[\\/]browser_watcher[\\/]"
2432 r"dump_stability_report_main_win.cc$",
2433 r"^components[\\/]media_control[\\/]renderer[\\/]"
2434 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352435 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2436 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442437 r"^components[\\/]zucchini[\\/].*",
2438 # TODO(peter): Remove exception. https://crbug.com/534537
2439 r"^content[\\/]browser[\\/]notifications[\\/]"
2440 r"notification_event_dispatcher_impl\.cc$",
2441 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2442 r"gl_helper_benchmark\.cc$",
2443 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2444 r"^courgette[\\/]courgette_tool\.cc$",
2445 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2446 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2447 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi1d4c7ee2021-03-10 21:24:082448 # TODO(https://crbug.com/1181062): Temporary debugging.
Alexei Svitkine64505a92021-03-11 22:00:542449 r"^fuchsia[\\/]engine[\\/]renderer[\\/]"
2450 r"web_engine_render_frame_observer.cc$",
James Cook24a504192020-07-23 00:08:442451 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2452 r"^ipc[\\/]ipc_logging\.cc$",
2453 r"^native_client_sdk[\\/]",
2454 r"^remoting[\\/]base[\\/]logging\.h$",
2455 r"^remoting[\\/]host[\\/].*",
2456 r"^sandbox[\\/]linux[\\/].*",
2457 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2458 r"dump_file_system.cc$",
2459 r"^tools[\\/]",
2460 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2461 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2462 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2463 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2464 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402465 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442466 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402467
thomasanderson625d3932017-03-29 07:16:582468 log_info = set([])
2469 printf = set([])
[email protected]85218562013-11-22 07:41:402470
2471 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582472 for _, line in f.ChangedContents():
2473 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2474 log_info.add(f.LocalPath())
2475 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2476 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372477
thomasanderson625d3932017-03-29 07:16:582478 if input_api.re.search(r"\bprintf\(", line):
2479 printf.add(f.LocalPath())
2480 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2481 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402482
2483 if log_info:
2484 return [output_api.PresubmitError(
2485 'These files spam the console log with LOG(INFO):',
2486 items=log_info)]
2487 if printf:
2488 return [output_api.PresubmitError(
2489 'These files spam the console log with printf/fprintf:',
2490 items=printf)]
2491 return []
2492
2493
Saagar Sanghavifceeaae2020-08-12 16:40:362494def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162495 """These types are all expected to hold locks while in scope and
2496 so should never be anonymous (which causes them to be immediately
2497 destroyed)."""
2498 they_who_must_be_named = [
2499 'base::AutoLock',
2500 'base::AutoReset',
2501 'base::AutoUnlock',
2502 'SkAutoAlphaRestore',
2503 'SkAutoBitmapShaderInstall',
2504 'SkAutoBlitterChoose',
2505 'SkAutoBounderCommit',
2506 'SkAutoCallProc',
2507 'SkAutoCanvasRestore',
2508 'SkAutoCommentBlock',
2509 'SkAutoDescriptor',
2510 'SkAutoDisableDirectionCheck',
2511 'SkAutoDisableOvalCheck',
2512 'SkAutoFree',
2513 'SkAutoGlyphCache',
2514 'SkAutoHDC',
2515 'SkAutoLockColors',
2516 'SkAutoLockPixels',
2517 'SkAutoMalloc',
2518 'SkAutoMaskFreeImage',
2519 'SkAutoMutexAcquire',
2520 'SkAutoPathBoundsUpdate',
2521 'SkAutoPDFRelease',
2522 'SkAutoRasterClipValidate',
2523 'SkAutoRef',
2524 'SkAutoTime',
2525 'SkAutoTrace',
2526 'SkAutoUnref',
2527 ]
2528 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2529 # bad: base::AutoLock(lock.get());
2530 # not bad: base::AutoLock lock(lock.get());
2531 bad_pattern = input_api.re.compile(anonymous)
2532 # good: new base::AutoLock(lock.get())
2533 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2534 errors = []
2535
2536 for f in input_api.AffectedFiles():
2537 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2538 continue
2539 for linenum, line in f.ChangedContents():
2540 if bad_pattern.search(line) and not good_pattern.search(line):
2541 errors.append('%s:%d' % (f.LocalPath(), linenum))
2542
2543 if errors:
2544 return [output_api.PresubmitError(
2545 'These lines create anonymous variables that need to be named:',
2546 items=errors)]
2547 return []
2548
2549
Saagar Sanghavifceeaae2020-08-12 16:40:362550def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532551 # Returns whether |template_str| is of the form <T, U...> for some types T
2552 # and U. Assumes that |template_str| is already in the form <...>.
2553 def HasMoreThanOneArg(template_str):
2554 # Level of <...> nesting.
2555 nesting = 0
2556 for c in template_str:
2557 if c == '<':
2558 nesting += 1
2559 elif c == '>':
2560 nesting -= 1
2561 elif c == ',' and nesting == 1:
2562 return True
2563 return False
2564
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492565 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102566 sources = lambda affected_file: input_api.FilterSourceFile(
2567 affected_file,
James Cook24a504192020-07-23 00:08:442568 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2569 input_api.DEFAULT_FILES_TO_SKIP),
2570 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552571
2572 # Pattern to capture a single "<...>" block of template arguments. It can
2573 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2574 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2575 # latter would likely require counting that < and > match, which is not
2576 # expressible in regular languages. Should the need arise, one can introduce
2577 # limited counting (matching up to a total number of nesting depth), which
2578 # should cover all practical cases for already a low nesting limit.
2579 template_arg_pattern = (
2580 r'<[^>]*' # Opening block of <.
2581 r'>([^<]*>)?') # Closing block of >.
2582 # Prefix expressing that whatever follows is not already inside a <...>
2583 # block.
2584 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102585 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552586 not_inside_template_arg_pattern
2587 + r'\bstd::unique_ptr'
2588 + template_arg_pattern
2589 + r'\(\)')
2590
2591 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2592 template_arg_no_array_pattern = (
2593 r'<[^>]*[^]]' # Opening block of <.
2594 r'>([^(<]*[^]]>)?') # Closing block of >.
2595 # Prefix saying that what follows is the start of an expression.
2596 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2597 # Suffix saying that what follows are call parentheses with a non-empty list
2598 # of arguments.
2599 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532600 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552601 return_construct_pattern = input_api.re.compile(
2602 start_of_expr_pattern
2603 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532604 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552605 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532606 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552607 + nonempty_arg_list_pattern)
2608
Vaclav Brozek851d9602018-04-04 16:13:052609 problems_constructor = []
2610 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102611 for f in input_api.AffectedSourceFiles(sources):
2612 for line_number, line in f.ChangedContents():
2613 # Disallow:
2614 # return std::unique_ptr<T>(foo);
2615 # bar = std::unique_ptr<T>(foo);
2616 # But allow:
2617 # return std::unique_ptr<T[]>(foo);
2618 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532619 # And also allow cases when the second template argument is present. Those
2620 # cases cannot be handled by std::make_unique:
2621 # return std::unique_ptr<T, U>(foo);
2622 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052623 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532624 return_construct_result = return_construct_pattern.search(line)
2625 if return_construct_result and not HasMoreThanOneArg(
2626 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052627 problems_constructor.append(
2628 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102629 # Disallow:
2630 # std::unique_ptr<T>()
2631 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052632 problems_nullptr.append(
2633 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2634
2635 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162636 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052637 errors.append(output_api.PresubmitError(
2638 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162639 problems_nullptr))
2640 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052641 errors.append(output_api.PresubmitError(
2642 'The following files use explicit std::unique_ptr constructor.'
2643 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162644 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102645 return errors
2646
2647
Saagar Sanghavifceeaae2020-08-12 16:40:362648def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082649 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522650 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082651 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522652 # If actions.xml is already included in the changelist, the PRESUBMIT
2653 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082654 return []
2655
Alexei Svitkine64505a92021-03-11 22:00:542656 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2657 files_to_skip = (_EXCLUDED_PATHS +
2658 _TEST_CODE_EXCLUDED_PATHS +
2659 input_api.DEFAULT_FILES_TO_SKIP )
2660 file_filter = lambda f: input_api.FilterSourceFile(
2661 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2662
[email protected]999261d2014-03-03 20:08:082663 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522664 current_actions = None
[email protected]999261d2014-03-03 20:08:082665 for f in input_api.AffectedFiles(file_filter=file_filter):
2666 for line_num, line in f.ChangedContents():
2667 match = input_api.re.search(action_re, line)
2668 if match:
[email protected]2f92dec2014-03-07 19:21:522669 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2670 # loaded only once.
2671 if not current_actions:
2672 with open('tools/metrics/actions/actions.xml') as actions_f:
2673 current_actions = actions_f.read()
2674 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082675 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522676 action = 'name="{0}"'.format(action_name)
2677 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082678 return [output_api.PresubmitPromptWarning(
2679 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522680 'tools/metrics/actions/actions.xml. Please run '
2681 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082682 % (f.LocalPath(), line_num, action_name))]
2683 return []
2684
2685
Daniel Cheng13ca61a882017-08-25 15:11:252686def _ImportJSONCommentEater(input_api):
2687 import sys
2688 sys.path = sys.path + [input_api.os_path.join(
2689 input_api.PresubmitLocalPath(),
2690 'tools', 'json_comment_eater')]
2691 import json_comment_eater
2692 return json_comment_eater
2693
2694
[email protected]99171a92014-06-03 08:44:472695def _GetJSONParseError(input_api, filename, eat_comments=True):
2696 try:
2697 contents = input_api.ReadFile(filename)
2698 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252699 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132700 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472701
2702 input_api.json.loads(contents)
2703 except ValueError as e:
2704 return e
2705 return None
2706
2707
2708def _GetIDLParseError(input_api, filename):
2709 try:
2710 contents = input_api.ReadFile(filename)
2711 idl_schema = input_api.os_path.join(
2712 input_api.PresubmitLocalPath(),
2713 'tools', 'json_schema_compiler', 'idl_schema.py')
2714 process = input_api.subprocess.Popen(
2715 [input_api.python_executable, idl_schema],
2716 stdin=input_api.subprocess.PIPE,
2717 stdout=input_api.subprocess.PIPE,
2718 stderr=input_api.subprocess.PIPE,
2719 universal_newlines=True)
2720 (_, error) = process.communicate(input=contents)
2721 return error or None
2722 except ValueError as e:
2723 return e
2724
2725
Saagar Sanghavifceeaae2020-08-12 16:40:362726def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472727 """Check that IDL and JSON files do not contain syntax errors."""
2728 actions = {
2729 '.idl': _GetIDLParseError,
2730 '.json': _GetJSONParseError,
2731 }
[email protected]99171a92014-06-03 08:44:472732 # Most JSON files are preprocessed and support comments, but these do not.
2733 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042734 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472735 ]
2736 # Only run IDL checker on files in these directories.
2737 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042738 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2739 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472740 ]
2741
2742 def get_action(affected_file):
2743 filename = affected_file.LocalPath()
2744 return actions.get(input_api.os_path.splitext(filename)[1])
2745
[email protected]99171a92014-06-03 08:44:472746 def FilterFile(affected_file):
2747 action = get_action(affected_file)
2748 if not action:
2749 return False
2750 path = affected_file.LocalPath()
2751
Erik Staab2dd72b12020-04-16 15:03:402752 if _MatchesFile(input_api,
2753 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2754 path):
[email protected]99171a92014-06-03 08:44:472755 return False
2756
2757 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162758 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472759 return False
2760 return True
2761
2762 results = []
2763 for affected_file in input_api.AffectedFiles(
2764 file_filter=FilterFile, include_deletes=False):
2765 action = get_action(affected_file)
2766 kwargs = {}
2767 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162768 _MatchesFile(input_api, json_no_comments_patterns,
2769 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472770 kwargs['eat_comments'] = False
2771 parse_error = action(input_api,
2772 affected_file.AbsoluteLocalPath(),
2773 **kwargs)
2774 if parse_error:
2775 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2776 (affected_file.LocalPath(), parse_error)))
2777 return results
2778
2779
Saagar Sanghavifceeaae2020-08-12 16:40:362780def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492781 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472782 import sys
[email protected]760deea2013-12-10 19:33:492783 original_sys_path = sys.path
2784 try:
2785 sys.path = sys.path + [input_api.os_path.join(
2786 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2787 import checkstyle
2788 finally:
2789 # Restore sys.path to what it was before.
2790 sys.path = original_sys_path
2791
2792 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092793 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442794 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492795
2796
Saagar Sanghavifceeaae2020-08-12 16:40:362797def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002798 """Checks to make sure devil is initialized correctly in python scripts."""
2799 script_common_initialize_pattern = input_api.re.compile(
2800 r'script_common\.InitializeEnvironment\(')
2801 devil_env_config_initialize = input_api.re.compile(
2802 r'devil_env\.config\.Initialize\(')
2803
2804 errors = []
2805
2806 sources = lambda affected_file: input_api.FilterSourceFile(
2807 affected_file,
James Cook24a504192020-07-23 00:08:442808 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2809 (r'^build[\\/]android[\\/]devil_chromium\.py',
2810 r'^third_party[\\/].*',)),
2811 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002812
2813 for f in input_api.AffectedSourceFiles(sources):
2814 for line_num, line in f.ChangedContents():
2815 if (script_common_initialize_pattern.search(line) or
2816 devil_env_config_initialize.search(line)):
2817 errors.append("%s:%d" % (f.LocalPath(), line_num))
2818
2819 results = []
2820
2821 if errors:
2822 results.append(output_api.PresubmitError(
2823 'Devil initialization should always be done using '
2824 'devil_chromium.Initialize() in the chromium project, to use better '
2825 'defaults for dependencies (ex. up-to-date version of adb).',
2826 errors))
2827
2828 return results
2829
2830
Sean Kau46e29bc2017-08-28 16:31:162831def _MatchesFile(input_api, patterns, path):
2832 for pattern in patterns:
2833 if input_api.re.search(pattern, path):
2834 return True
2835 return False
2836
2837
Daniel Cheng7052cdf2017-11-21 19:23:292838def _GetOwnersFilesToCheckForIpcOwners(input_api):
2839 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172840
Daniel Cheng7052cdf2017-11-21 19:23:292841 Returns:
2842 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2843 contain to cover IPC-related files with noparent reviewer rules.
2844 """
2845 # Whether or not a file affects IPC is (mostly) determined by a simple list
2846 # of filename patterns.
dchenge07de812016-06-20 19:27:172847 file_patterns = [
palmerb19a0932017-01-24 04:00:312848 # Legacy IPC:
dchenge07de812016-06-20 19:27:172849 '*_messages.cc',
2850 '*_messages*.h',
2851 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312852 # Mojo IPC:
dchenge07de812016-06-20 19:27:172853 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472854 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172855 '*_struct_traits*.*',
2856 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312857 '*.typemap',
2858 # Android native IPC:
2859 '*.aidl',
2860 # Blink uses a different file naming convention:
2861 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472862 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172863 '*StructTraits*.*',
2864 '*TypeConverter*.*',
2865 ]
2866
scottmg7a6ed5ba2016-11-04 18:22:042867 # These third_party directories do not contain IPCs, but contain files
2868 # matching the above patterns, which trigger false positives.
2869 exclude_paths = [
2870 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162871 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232872 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292873 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542874 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162875 # These files are just used to communicate between class loaders running
2876 # in the same process.
2877 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572878 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2879
scottmg7a6ed5ba2016-11-04 18:22:042880 ]
2881
dchenge07de812016-06-20 19:27:172882 # Dictionary mapping an OWNERS file path to Patterns.
2883 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2884 # rules ) to a PatternEntry.
2885 # PatternEntry is a dictionary with two keys:
2886 # - 'files': the files that are matched by this pattern
2887 # - 'rules': the per-file rules needed for this pattern
2888 # For example, if we expect OWNERS file to contain rules for *.mojom and
2889 # *_struct_traits*.*, Patterns might look like this:
2890 # {
2891 # '*.mojom': {
2892 # 'files': ...,
2893 # 'rules': [
2894 # 'per-file *.mojom=set noparent',
2895 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2896 # ],
2897 # },
2898 # '*_struct_traits*.*': {
2899 # 'files': ...,
2900 # 'rules': [
2901 # 'per-file *_struct_traits*.*=set noparent',
2902 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2903 # ],
2904 # },
2905 # }
2906 to_check = {}
2907
Daniel Cheng13ca61a882017-08-25 15:11:252908 def AddPatternToCheck(input_file, pattern):
2909 owners_file = input_api.os_path.join(
2910 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2911 if owners_file not in to_check:
2912 to_check[owners_file] = {}
2913 if pattern not in to_check[owners_file]:
2914 to_check[owners_file][pattern] = {
2915 'files': [],
2916 'rules': [
2917 'per-file %s=set noparent' % pattern,
2918 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2919 ]
2920 }
Vaclav Brozekd5de76a2018-03-17 07:57:502921 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252922
dchenge07de812016-06-20 19:27:172923 # Iterate through the affected files to see what we actually need to check
2924 # for. We should only nag patch authors about per-file rules if a file in that
2925 # directory would match that pattern. If a directory only contains *.mojom
2926 # files and no *_messages*.h files, we should only nag about rules for
2927 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252928 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262929 # Manifest files don't have a strong naming convention. Instead, try to find
2930 # affected .cc and .h files which look like they contain a manifest
2931 # definition.
2932 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2933 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2934 if (manifest_pattern.search(f.LocalPath()) and not
2935 test_manifest_pattern.search(f.LocalPath())):
2936 # We expect all actual service manifest files to contain at least one
2937 # qualified reference to service_manager::Manifest.
2938 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252939 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172940 for pattern in file_patterns:
2941 if input_api.fnmatch.fnmatch(
2942 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042943 skip = False
2944 for exclude in exclude_paths:
2945 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2946 skip = True
2947 break
2948 if skip:
2949 continue
Daniel Cheng13ca61a882017-08-25 15:11:252950 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172951 break
2952
Daniel Cheng7052cdf2017-11-21 19:23:292953 return to_check
2954
2955
Wez17c66962020-04-29 15:26:032956def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2957 """Adds OWNERS files to check for correct Fuchsia security owners."""
2958
2959 file_patterns = [
2960 # Component specifications.
2961 '*.cml', # Component Framework v2.
2962 '*.cmx', # Component Framework v1.
2963
2964 # Fuchsia IDL protocol specifications.
2965 '*.fidl',
2966 ]
2967
Joshua Peraza1ca6d392020-12-08 00:14:092968 # Don't check for owners files for changes in these directories.
2969 exclude_paths = [
2970 'third_party/crashpad/*',
2971 ]
2972
Wez17c66962020-04-29 15:26:032973 def AddPatternToCheck(input_file, pattern):
2974 owners_file = input_api.os_path.join(
2975 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2976 if owners_file not in to_check:
2977 to_check[owners_file] = {}
2978 if pattern not in to_check[owners_file]:
2979 to_check[owners_file][pattern] = {
2980 'files': [],
2981 'rules': [
2982 'per-file %s=set noparent' % pattern,
2983 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2984 ]
2985 }
2986 to_check[owners_file][pattern]['files'].append(input_file)
2987
2988 # Iterate through the affected files to see what we actually need to check
2989 # for. We should only nag patch authors about per-file rules if a file in that
2990 # directory would match that pattern.
2991 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092992 skip = False
2993 for exclude in exclude_paths:
2994 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2995 skip = True
2996 if skip:
2997 continue
2998
Wez17c66962020-04-29 15:26:032999 for pattern in file_patterns:
3000 if input_api.fnmatch.fnmatch(
3001 input_api.os_path.basename(f.LocalPath()), pattern):
3002 AddPatternToCheck(f, pattern)
3003 break
3004
3005 return to_check
3006
3007
Saagar Sanghavifceeaae2020-08-12 16:40:363008def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293009 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3010 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033011 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293012
3013 if to_check:
3014 # If there are any OWNERS files to check, there are IPC-related changes in
3015 # this CL. Auto-CC the review list.
3016 output_api.AppendCC('[email protected]')
3017
3018 # Go through the OWNERS files to check, filtering out rules that are already
3019 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173020 for owners_file, patterns in to_check.iteritems():
3021 try:
3022 with file(owners_file) as f:
3023 lines = set(f.read().splitlines())
3024 for entry in patterns.itervalues():
3025 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3026 ]
3027 except IOError:
3028 # No OWNERS file, so all the rules are definitely missing.
3029 continue
3030
3031 # All the remaining lines weren't found in OWNERS files, so emit an error.
3032 errors = []
3033 for owners_file, patterns in to_check.iteritems():
3034 missing_lines = []
3035 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503036 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173037 missing_lines.extend(entry['rules'])
3038 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3039 if missing_lines:
3040 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053041 'Because of the presence of files:\n%s\n\n'
3042 '%s needs the following %d lines added:\n\n%s' %
3043 ('\n'.join(files), owners_file, len(missing_lines),
3044 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173045
3046 results = []
3047 if errors:
vabrf5ce3bf92016-07-11 14:52:413048 if input_api.is_committing:
3049 output = output_api.PresubmitError
3050 else:
3051 output = output_api.PresubmitPromptWarning
3052 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593053 'Found OWNERS files that need to be updated for IPC security ' +
3054 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173055 long_text='\n\n'.join(errors)))
3056
3057 return results
3058
3059
Robert Sesek2c905332020-05-06 23:17:133060def _GetFilesUsingSecurityCriticalFunctions(input_api):
3061 """Checks affected files for changes to security-critical calls. This
3062 function checks the full change diff, to catch both additions/changes
3063 and removals.
3064
3065 Returns a dict keyed by file name, and the value is a set of detected
3066 functions.
3067 """
3068 # Map of function pretty name (displayed in an error) to the pattern to
3069 # match it with.
3070 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373071 'content::GetServiceSandboxType<>()':
3072 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133073 }
3074 _PATTERNS_TO_CHECK = {
3075 k: input_api.re.compile(v)
3076 for k, v in _PATTERNS_TO_CHECK.items()
3077 }
3078
3079 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3080 files_to_functions = {}
3081 for f in input_api.AffectedFiles():
3082 diff = f.GenerateScmDiff()
3083 for line in diff.split('\n'):
3084 # Not using just RightHandSideLines() because removing a
3085 # call to a security-critical function can be just as important
3086 # as adding or changing the arguments.
3087 if line.startswith('-') or (line.startswith('+') and
3088 not line.startswith('++')):
3089 for name, pattern in _PATTERNS_TO_CHECK.items():
3090 if pattern.search(line):
3091 path = f.LocalPath()
3092 if not path in files_to_functions:
3093 files_to_functions[path] = set()
3094 files_to_functions[path].add(name)
3095 return files_to_functions
3096
3097
Saagar Sanghavifceeaae2020-08-12 16:40:363098def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133099 """Checks that changes involving security-critical functions are reviewed
3100 by the security team.
3101 """
3102 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:123103 if not len(files_to_functions):
3104 return []
Robert Sesek2c905332020-05-06 23:17:133105
Edward Lesmes1e9fade2021-02-08 20:31:123106 owner_email, reviewers = (
3107 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3108 input_api,
3109 None,
3110 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:133111
Edward Lesmes1e9fade2021-02-08 20:31:123112 # Load the OWNERS file for security changes.
3113 owners_file = 'ipc/SECURITY_OWNERS'
3114 security_owners = input_api.owners_client.ListOwners(owners_file)
3115 has_security_owner = any([owner in reviewers for owner in security_owners])
3116 if has_security_owner:
3117 return []
Robert Sesek2c905332020-05-06 23:17:133118
Edward Lesmes1e9fade2021-02-08 20:31:123119 msg = 'The following files change calls to security-sensive functions\n' \
3120 'that need to be reviewed by {}.\n'.format(owners_file)
3121 for path, names in files_to_functions.items():
3122 msg += ' {}\n'.format(path)
3123 for name in names:
3124 msg += ' {}\n'.format(name)
3125 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133126
Edward Lesmes1e9fade2021-02-08 20:31:123127 if input_api.is_committing:
3128 output = output_api.PresubmitError
3129 else:
3130 output = output_api.PresubmitNotifyResult
3131 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133132
3133
Saagar Sanghavifceeaae2020-08-12 16:40:363134def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263135 """Checks that set noparent is only used together with an OWNERS file in
3136 //build/OWNERS.setnoparent (see also
3137 //docs/code_reviews.md#owners-files-details)
3138 """
3139 errors = []
3140
3141 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3142 allowed_owners_files = set()
3143 with open(allowed_owners_files_file, 'r') as f:
3144 for line in f:
3145 line = line.strip()
3146 if not line or line.startswith('#'):
3147 continue
3148 allowed_owners_files.add(line)
3149
3150 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3151
3152 for f in input_api.AffectedFiles(include_deletes=False):
3153 if not f.LocalPath().endswith('OWNERS'):
3154 continue
3155
3156 found_owners_files = set()
3157 found_set_noparent_lines = dict()
3158
3159 # Parse the OWNERS file.
3160 for lineno, line in enumerate(f.NewContents(), 1):
3161 line = line.strip()
3162 if line.startswith('set noparent'):
3163 found_set_noparent_lines[''] = lineno
3164 if line.startswith('file://'):
3165 if line in allowed_owners_files:
3166 found_owners_files.add('')
3167 if line.startswith('per-file'):
3168 match = per_file_pattern.match(line)
3169 if match:
3170 glob = match.group(1).strip()
3171 directive = match.group(2).strip()
3172 if directive == 'set noparent':
3173 found_set_noparent_lines[glob] = lineno
3174 if directive.startswith('file://'):
3175 if directive in allowed_owners_files:
3176 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153177
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263178 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403179 # listed in build/OWNERS.setnoparent. An exception is made for top level
3180 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143181 if (f.LocalPath().count('/') != 1 and
3182 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403183 for set_noparent_line in found_set_noparent_lines:
3184 if set_noparent_line in found_owners_files:
3185 continue
3186 errors.append(' %s:%d' % (f.LocalPath(),
3187 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263188
3189 results = []
3190 if errors:
3191 if input_api.is_committing:
3192 output = output_api.PresubmitError
3193 else:
3194 output = output_api.PresubmitPromptWarning
3195 results.append(output(
3196 'Found the following "set noparent" restrictions in OWNERS files that '
3197 'do not include owners from build/OWNERS.setnoparent:',
3198 long_text='\n\n'.join(errors)))
3199 return results
3200
3201
Saagar Sanghavifceeaae2020-08-12 16:40:363202def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313203 """Checks that added or removed lines in non third party affected
3204 header files do not lead to new useless class or struct forward
3205 declaration.
jbriance9e12f162016-11-25 07:57:503206 """
3207 results = []
3208 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3209 input_api.re.MULTILINE)
3210 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3211 input_api.re.MULTILINE)
3212 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313213 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193214 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493215 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313216 continue
3217
jbriance9e12f162016-11-25 07:57:503218 if not f.LocalPath().endswith('.h'):
3219 continue
3220
3221 contents = input_api.ReadFile(f)
3222 fwd_decls = input_api.re.findall(class_pattern, contents)
3223 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3224
3225 useless_fwd_decls = []
3226 for decl in fwd_decls:
3227 count = sum(1 for _ in input_api.re.finditer(
3228 r'\b%s\b' % input_api.re.escape(decl), contents))
3229 if count == 1:
3230 useless_fwd_decls.append(decl)
3231
3232 if not useless_fwd_decls:
3233 continue
3234
3235 for line in f.GenerateScmDiff().splitlines():
3236 if (line.startswith('-') and not line.startswith('--') or
3237 line.startswith('+') and not line.startswith('++')):
3238 for decl in useless_fwd_decls:
3239 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3240 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243241 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503242 (f.LocalPath(), decl)))
3243 useless_fwd_decls.remove(decl)
3244
3245 return results
3246
Jinsong Fan91ebbbd2019-04-16 14:57:173247def _CheckAndroidDebuggableBuild(input_api, output_api):
3248 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3249 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3250 this is a debuggable build of Android.
3251 """
3252 build_type_check_pattern = input_api.re.compile(
3253 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3254
3255 errors = []
3256
3257 sources = lambda affected_file: input_api.FilterSourceFile(
3258 affected_file,
James Cook24a504192020-07-23 00:08:443259 files_to_skip=(_EXCLUDED_PATHS +
3260 _TEST_CODE_EXCLUDED_PATHS +
3261 input_api.DEFAULT_FILES_TO_SKIP +
3262 (r"^android_webview[\\/]support_library[\\/]"
3263 "boundary_interfaces[\\/]",
3264 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3265 r'^third_party[\\/].*',
3266 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3267 r"webview[\\/]chromium[\\/]License.*",)),
3268 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173269
3270 for f in input_api.AffectedSourceFiles(sources):
3271 for line_num, line in f.ChangedContents():
3272 if build_type_check_pattern.search(line):
3273 errors.append("%s:%d" % (f.LocalPath(), line_num))
3274
3275 results = []
3276
3277 if errors:
3278 results.append(output_api.PresubmitPromptWarning(
3279 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3280 ' Please use BuildInfo.isDebugAndroid() instead.',
3281 errors))
3282
3283 return results
jbriance9e12f162016-11-25 07:57:503284
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493285# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293286def _CheckAndroidToastUsage(input_api, output_api):
3287 """Checks that code uses org.chromium.ui.widget.Toast instead of
3288 android.widget.Toast (Chromium Toast doesn't force hardware
3289 acceleration on low-end devices, saving memory).
3290 """
3291 toast_import_pattern = input_api.re.compile(
3292 r'^import android\.widget\.Toast;$')
3293
3294 errors = []
3295
3296 sources = lambda affected_file: input_api.FilterSourceFile(
3297 affected_file,
James Cook24a504192020-07-23 00:08:443298 files_to_skip=(_EXCLUDED_PATHS +
3299 _TEST_CODE_EXCLUDED_PATHS +
3300 input_api.DEFAULT_FILES_TO_SKIP +
3301 (r'^chromecast[\\/].*',
3302 r'^remoting[\\/].*')),
3303 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293304
3305 for f in input_api.AffectedSourceFiles(sources):
3306 for line_num, line in f.ChangedContents():
3307 if toast_import_pattern.search(line):
3308 errors.append("%s:%d" % (f.LocalPath(), line_num))
3309
3310 results = []
3311
3312 if errors:
3313 results.append(output_api.PresubmitError(
3314 'android.widget.Toast usage is detected. Android toasts use hardware'
3315 ' acceleration, and can be\ncostly on low-end devices. Please use'
3316 ' org.chromium.ui.widget.Toast instead.\n'
3317 'Contact [email protected] if you have any questions.',
3318 errors))
3319
3320 return results
3321
3322
dgnaa68d5e2015-06-10 10:08:223323def _CheckAndroidCrLogUsage(input_api, output_api):
3324 """Checks that new logs using org.chromium.base.Log:
3325 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513326 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223327 """
pkotwicza1dd0b002016-05-16 14:41:043328
torne89540622017-03-24 19:41:303329 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043330 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303331 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043332 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303333 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043334 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3335 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093336 # The customtabs_benchmark is a small app that does not depend on Chromium
3337 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043338 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043339 ]
3340
dgnaa68d5e2015-06-10 10:08:223341 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123342 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3343 class_in_base_pattern = input_api.re.compile(
3344 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3345 has_some_log_import_pattern = input_api.re.compile(
3346 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223347 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553348 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223349 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463350 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553351 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223352
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463353 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443354 sources = lambda x: input_api.FilterSourceFile(x,
3355 files_to_check=[r'.*\.java$'],
3356 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123357
dgnaa68d5e2015-06-10 10:08:223358 tag_decl_errors = []
3359 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123360 tag_errors = []
dgn38736db2015-09-18 19:20:513361 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123362 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223363
3364 for f in input_api.AffectedSourceFiles(sources):
3365 file_content = input_api.ReadFile(f)
3366 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223367 # Per line checks
dgn87d9fb62015-06-12 09:15:123368 if (cr_log_import_pattern.search(file_content) or
3369 (class_in_base_pattern.search(file_content) and
3370 not has_some_log_import_pattern.search(file_content))):
3371 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223372 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553373 if rough_log_decl_pattern.search(line):
3374 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223375
3376 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123377 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223378 if match:
3379 has_modified_logs = True
3380
3381 # Make sure it uses "TAG"
3382 if not match.group('tag') == 'TAG':
3383 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123384 else:
3385 # Report non cr Log function calls in changed lines
3386 for line_num, line in f.ChangedContents():
3387 if log_call_pattern.search(line):
3388 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223389
3390 # Per file checks
3391 if has_modified_logs:
3392 # Make sure the tag is using the "cr" prefix and is not too long
3393 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513394 tag_name = match.group('name') if match else None
3395 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223396 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513397 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223398 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513399 elif '.' in tag_name:
3400 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223401
3402 results = []
3403 if tag_decl_errors:
3404 results.append(output_api.PresubmitPromptWarning(
3405 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513406 '"private static final String TAG = "<package tag>".\n'
3407 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223408 tag_decl_errors))
3409
3410 if tag_length_errors:
3411 results.append(output_api.PresubmitError(
3412 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513413 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223414 tag_length_errors))
3415
3416 if tag_errors:
3417 results.append(output_api.PresubmitPromptWarning(
3418 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3419 tag_errors))
3420
dgn87d9fb62015-06-12 09:15:123421 if util_log_errors:
dgn4401aa52015-04-29 16:26:173422 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123423 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3424 util_log_errors))
3425
dgn38736db2015-09-18 19:20:513426 if tag_with_dot_errors:
3427 results.append(output_api.PresubmitPromptWarning(
3428 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3429 tag_with_dot_errors))
3430
dgn4401aa52015-04-29 16:26:173431 return results
3432
3433
Yoland Yanb92fa522017-08-28 17:37:063434def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3435 """Checks that junit.framework.* is no longer used."""
3436 deprecated_junit_framework_pattern = input_api.re.compile(
3437 r'^import junit\.framework\..*;',
3438 input_api.re.MULTILINE)
3439 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443440 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063441 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133442 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063443 for line_num, line in f.ChangedContents():
3444 if deprecated_junit_framework_pattern.search(line):
3445 errors.append("%s:%d" % (f.LocalPath(), line_num))
3446
3447 results = []
3448 if errors:
3449 results.append(output_api.PresubmitError(
3450 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3451 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3452 ' if you have any question.', errors))
3453 return results
3454
3455
3456def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3457 """Checks that if new Java test classes have inheritance.
3458 Either the new test class is JUnit3 test or it is a JUnit4 test class
3459 with a base class, either case is undesirable.
3460 """
3461 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3462
3463 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443464 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063465 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133466 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063467 if not f.OldContents():
3468 class_declaration_start_flag = False
3469 for line_num, line in f.ChangedContents():
3470 if class_declaration_pattern.search(line):
3471 class_declaration_start_flag = True
3472 if class_declaration_start_flag and ' extends ' in line:
3473 errors.append('%s:%d' % (f.LocalPath(), line_num))
3474 if '{' in line:
3475 class_declaration_start_flag = False
3476
3477 results = []
3478 if errors:
3479 results.append(output_api.PresubmitPromptWarning(
3480 'The newly created files include Test classes that inherits from base'
3481 ' class. Please do not use inheritance in JUnit4 tests or add new'
3482 ' JUnit3 tests. Contact [email protected] if you have any'
3483 ' questions.', errors))
3484 return results
3485
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203486
yolandyan45001472016-12-21 21:12:423487def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3488 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3489 deprecated_annotation_import_pattern = input_api.re.compile(
3490 r'^import android\.test\.suitebuilder\.annotation\..*;',
3491 input_api.re.MULTILINE)
3492 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443493 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423494 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133495 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423496 for line_num, line in f.ChangedContents():
3497 if deprecated_annotation_import_pattern.search(line):
3498 errors.append("%s:%d" % (f.LocalPath(), line_num))
3499
3500 results = []
3501 if errors:
3502 results.append(output_api.PresubmitError(
3503 'Annotations in android.test.suitebuilder.annotation have been'
3504 ' deprecated since API level 24. Please use android.support.test.filters'
3505 ' from //third_party/android_support_test_runner:runner_java instead.'
3506 ' Contact [email protected] if you have any questions.', errors))
3507 return results
3508
3509
agrieve7b6479d82015-10-07 14:24:223510def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3511 """Checks if MDPI assets are placed in a correct directory."""
3512 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3513 ('/res/drawable/' in f.LocalPath() or
3514 '/res/drawable-ldrtl/' in f.LocalPath()))
3515 errors = []
3516 for f in input_api.AffectedFiles(include_deletes=False,
3517 file_filter=file_filter):
3518 errors.append(' %s' % f.LocalPath())
3519
3520 results = []
3521 if errors:
3522 results.append(output_api.PresubmitError(
3523 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3524 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3525 '/res/drawable-ldrtl/.\n'
3526 'Contact [email protected] if you have questions.', errors))
3527 return results
3528
3529
Nate Fischer535972b2017-09-16 01:06:183530def _CheckAndroidWebkitImports(input_api, output_api):
3531 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353532 android.webview.ValueCallback except in the WebView glue layer
3533 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183534 """
3535 valuecallback_import_pattern = input_api.re.compile(
3536 r'^import android\.webkit\.ValueCallback;$')
3537
3538 errors = []
3539
3540 sources = lambda affected_file: input_api.FilterSourceFile(
3541 affected_file,
James Cook24a504192020-07-23 00:08:443542 files_to_skip=(_EXCLUDED_PATHS +
3543 _TEST_CODE_EXCLUDED_PATHS +
3544 input_api.DEFAULT_FILES_TO_SKIP +
3545 (r'^android_webview[\\/]glue[\\/].*',
3546 r'^weblayer[\\/].*',)),
3547 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183548
3549 for f in input_api.AffectedSourceFiles(sources):
3550 for line_num, line in f.ChangedContents():
3551 if valuecallback_import_pattern.search(line):
3552 errors.append("%s:%d" % (f.LocalPath(), line_num))
3553
3554 results = []
3555
3556 if errors:
3557 results.append(output_api.PresubmitError(
3558 'android.webkit.ValueCallback usage is detected outside of the glue'
3559 ' layer. To stay compatible with the support library, android.webkit.*'
3560 ' classes should only be used inside the glue layer and'
3561 ' org.chromium.base.Callback should be used instead.',
3562 errors))
3563
3564 return results
3565
3566
Becky Zhou7c69b50992018-12-10 19:37:573567def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3568 """Checks Android XML styles """
3569 import sys
3570 original_sys_path = sys.path
3571 try:
3572 sys.path = sys.path + [input_api.os_path.join(
3573 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3574 import checkxmlstyle
3575 finally:
3576 # Restore sys.path to what it was before.
3577 sys.path = original_sys_path
3578
3579 if is_check_on_upload:
3580 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3581 else:
3582 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3583
3584
agrievef32bcc72016-04-04 14:57:403585class PydepsChecker(object):
3586 def __init__(self, input_api, pydeps_files):
3587 self._file_cache = {}
3588 self._input_api = input_api
3589 self._pydeps_files = pydeps_files
3590
3591 def _LoadFile(self, path):
3592 """Returns the list of paths within a .pydeps file relative to //."""
3593 if path not in self._file_cache:
3594 with open(path) as f:
3595 self._file_cache[path] = f.read()
3596 return self._file_cache[path]
3597
3598 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3599 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393600 pydeps_data = self._LoadFile(pydeps_path)
3601 uses_gn_paths = '--gn-paths' in pydeps_data
3602 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3603 if uses_gn_paths:
3604 # Paths look like: //foo/bar/baz
3605 return (e[2:] for e in entries)
3606 else:
3607 # Paths look like: path/relative/to/file.pydeps
3608 os_path = self._input_api.os_path
3609 pydeps_dir = os_path.dirname(pydeps_path)
3610 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403611
3612 def _CreateFilesToPydepsMap(self):
3613 """Returns a map of local_path -> list_of_pydeps."""
3614 ret = {}
3615 for pydep_local_path in self._pydeps_files:
3616 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3617 ret.setdefault(path, []).append(pydep_local_path)
3618 return ret
3619
3620 def ComputeAffectedPydeps(self):
3621 """Returns an iterable of .pydeps files that might need regenerating."""
3622 affected_pydeps = set()
3623 file_to_pydeps_map = None
3624 for f in self._input_api.AffectedFiles(include_deletes=True):
3625 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463626 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3627 # subrepositories. We can't figure out which files change, so re-check
3628 # all files.
3629 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383630 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3631 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403632 return self._pydeps_files
3633 elif local_path.endswith('.pydeps'):
3634 if local_path in self._pydeps_files:
3635 affected_pydeps.add(local_path)
3636 elif local_path.endswith('.py'):
3637 if file_to_pydeps_map is None:
3638 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3639 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3640 return affected_pydeps
3641
3642 def DetermineIfStale(self, pydeps_path):
3643 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413644 import difflib
John Budorick47ca3fe2018-02-10 00:53:103645 import os
3646
agrievef32bcc72016-04-04 14:57:403647 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033648 if old_pydeps_data:
3649 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393650 if '--output' not in cmd:
3651 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033652 old_contents = old_pydeps_data[2:]
3653 else:
3654 # A default cmd that should work in most cases (as long as pydeps filename
3655 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3656 # file is empty/new.
3657 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3658 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3659 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103660 env = dict(os.environ)
3661 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403662 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103663 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413664 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033665 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413666 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403667
3668
Tibor Goldschwendt360793f72019-06-25 18:23:493669def _ParseGclientArgs():
3670 args = {}
3671 with open('build/config/gclient_args.gni', 'r') as f:
3672 for line in f:
3673 line = line.strip()
3674 if not line or line.startswith('#'):
3675 continue
3676 attribute, value = line.split('=')
3677 args[attribute.strip()] = value.strip()
3678 return args
3679
3680
Saagar Sanghavifceeaae2020-08-12 16:40:363681def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403682 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403683 # This check is for Python dependency lists (.pydeps files), and involves
3684 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3685 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283686 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003687 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493688 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403689 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403690 results = []
3691 # First, check for new / deleted .pydeps.
3692 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033693 # Check whether we are running the presubmit check for a file in src.
3694 # f.LocalPath is relative to repo (src, or internal repo).
3695 # os_path.exists is relative to src repo.
3696 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3697 # to src and we can conclude that the pydeps is in src.
3698 if input_api.os_path.exists(f.LocalPath()):
3699 if f.LocalPath().endswith('.pydeps'):
3700 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3701 results.append(output_api.PresubmitError(
3702 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3703 'remove %s' % f.LocalPath()))
3704 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3705 results.append(output_api.PresubmitError(
3706 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3707 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403708
3709 if results:
3710 return results
3711
Mohamed Heikal7cd4d8312020-06-16 16:49:403712 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3713 affected_pydeps = set(checker.ComputeAffectedPydeps())
3714 affected_android_pydeps = affected_pydeps.intersection(
3715 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3716 if affected_android_pydeps and not is_android:
3717 results.append(output_api.PresubmitPromptOrNotify(
3718 'You have changed python files that may affect pydeps for android\n'
3719 'specific scripts. However, the relevant presumbit check cannot be\n'
3720 'run because you are not using an Android checkout. To validate that\n'
3721 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3722 'use the android-internal-presubmit optional trybot.\n'
3723 'Possibly stale pydeps files:\n{}'.format(
3724 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403725
Mohamed Heikal7cd4d8312020-06-16 16:49:403726 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3727 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403728 try:
phajdan.jr0d9878552016-11-04 10:49:413729 result = checker.DetermineIfStale(pydep_path)
3730 if result:
3731 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403732 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413733 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3734 'To regenerate, run:\n\n %s' %
3735 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403736 except input_api.subprocess.CalledProcessError as error:
3737 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3738 long_text=error.output)]
3739
3740 return results
3741
3742
Saagar Sanghavifceeaae2020-08-12 16:40:363743def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433744 """Checks to make sure no header files have |Singleton<|."""
3745 def FileFilter(affected_file):
3746 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443747 files_to_skip = (_EXCLUDED_PATHS +
3748 input_api.DEFAULT_FILES_TO_SKIP +
3749 (r"^base[\\/]memory[\\/]singleton\.h$",
3750 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3751 r"quic_singleton_impl\.h$"))
3752 return input_api.FilterSourceFile(affected_file,
3753 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433754
sergeyu34d21222015-09-16 00:11:443755 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433756 files = []
3757 for f in input_api.AffectedSourceFiles(FileFilter):
3758 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3759 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3760 contents = input_api.ReadFile(f)
3761 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243762 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433763 pattern.search(line)):
3764 files.append(f)
3765 break
3766
3767 if files:
yolandyandaabc6d2016-04-18 18:29:393768 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443769 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433770 'Please move them to an appropriate source file so that the ' +
3771 'template gets instantiated in a single compilation unit.',
3772 files) ]
3773 return []
3774
3775
[email protected]fd20b902014-05-09 02:14:533776_DEPRECATED_CSS = [
3777 # Values
3778 ( "-webkit-box", "flex" ),
3779 ( "-webkit-inline-box", "inline-flex" ),
3780 ( "-webkit-flex", "flex" ),
3781 ( "-webkit-inline-flex", "inline-flex" ),
3782 ( "-webkit-min-content", "min-content" ),
3783 ( "-webkit-max-content", "max-content" ),
3784
3785 # Properties
3786 ( "-webkit-background-clip", "background-clip" ),
3787 ( "-webkit-background-origin", "background-origin" ),
3788 ( "-webkit-background-size", "background-size" ),
3789 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443790 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533791
3792 # Functions
3793 ( "-webkit-gradient", "gradient" ),
3794 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3795 ( "-webkit-linear-gradient", "linear-gradient" ),
3796 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3797 ( "-webkit-radial-gradient", "radial-gradient" ),
3798 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3799]
3800
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203801
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493802# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363803def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533804 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253805 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343806 documentation and iOS CSS for dom distiller
3807 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253808 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533809 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493810 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443811 files_to_skip = (_EXCLUDED_PATHS +
3812 _TEST_CODE_EXCLUDED_PATHS +
3813 input_api.DEFAULT_FILES_TO_SKIP +
3814 (r"^chrome/common/extensions/docs",
3815 r"^chrome/docs",
3816 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3817 r"^components/neterror/resources/neterror.css",
3818 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253819 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443820 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533821 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3822 for line_num, line in fpath.ChangedContents():
3823 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023824 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533825 results.append(output_api.PresubmitError(
3826 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3827 (fpath.LocalPath(), line_num, deprecated_value, value)))
3828 return results
3829
mohan.reddyf21db962014-10-16 12:26:473830
Saagar Sanghavifceeaae2020-08-12 16:40:363831def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363832 bad_files = {}
3833 for f in input_api.AffectedFiles(include_deletes=False):
3834 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493835 not f.LocalPath().startswith('third_party/blink') and
3836 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363837 continue
3838
Daniel Bratell65b033262019-04-23 08:17:063839 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363840 continue
3841
Vaclav Brozekd5de76a2018-03-17 07:57:503842 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363843 if "#include" in line and "../" in line]
3844 if not relative_includes:
3845 continue
3846 bad_files[f.LocalPath()] = relative_includes
3847
3848 if not bad_files:
3849 return []
3850
3851 error_descriptions = []
3852 for file_path, bad_lines in bad_files.iteritems():
3853 error_description = file_path
3854 for line in bad_lines:
3855 error_description += '\n ' + line
3856 error_descriptions.append(error_description)
3857
3858 results = []
3859 results.append(output_api.PresubmitError(
3860 'You added one or more relative #include paths (including "../").\n'
3861 'These shouldn\'t be used because they can be used to include headers\n'
3862 'from code that\'s not correctly specified as a dependency in the\n'
3863 'relevant BUILD.gn file(s).',
3864 error_descriptions))
3865
3866 return results
3867
Takeshi Yoshinoe387aa32017-08-02 13:16:133868
Saagar Sanghavifceeaae2020-08-12 16:40:363869def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063870 """Check that nobody tries to include a cc file. It's a relatively
3871 common error which results in duplicate symbols in object
3872 files. This may not always break the build until someone later gets
3873 very confusing linking errors."""
3874 results = []
3875 for f in input_api.AffectedFiles(include_deletes=False):
3876 # We let third_party code do whatever it wants
3877 if (f.LocalPath().startswith('third_party') and
3878 not f.LocalPath().startswith('third_party/blink') and
3879 not f.LocalPath().startswith('third_party\\blink')):
3880 continue
3881
3882 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3883 continue
3884
3885 for _, line in f.ChangedContents():
3886 if line.startswith('#include "'):
3887 included_file = line.split('"')[1]
3888 if _IsCPlusPlusFile(input_api, included_file):
3889 # The most common naming for external files with C++ code,
3890 # apart from standard headers, is to call them foo.inc, but
3891 # Chromium sometimes uses foo-inc.cc so allow that as well.
3892 if not included_file.endswith(('.h', '-inc.cc')):
3893 results.append(output_api.PresubmitError(
3894 'Only header files or .inc files should be included in other\n'
3895 'C++ files. Compiling the contents of a cc file more than once\n'
3896 'will cause duplicate information in the build which may later\n'
3897 'result in strange link_errors.\n' +
3898 f.LocalPath() + ':\n ' +
3899 line))
3900
3901 return results
3902
3903
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203904def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3905 if not isinstance(key, ast.Str):
3906 return 'Key at line %d must be a string literal' % key.lineno
3907 if not isinstance(value, ast.Dict):
3908 return 'Value at line %d must be a dict' % value.lineno
3909 if len(value.keys) != 1:
3910 return 'Dict at line %d must have single entry' % value.lineno
3911 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3912 return (
3913 'Entry at line %d must have a string literal \'filepath\' as key' %
3914 value.lineno)
3915 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133916
Takeshi Yoshinoe387aa32017-08-02 13:16:133917
Sergey Ulanov4af16052018-11-08 02:41:463918def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203919 if not isinstance(key, ast.Str):
3920 return 'Key at line %d must be a string literal' % key.lineno
3921 if not isinstance(value, ast.List):
3922 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463923 for element in value.elts:
3924 if not isinstance(element, ast.Str):
3925 return 'Watchlist elements on line %d is not a string' % key.lineno
3926 if not email_regex.match(element.s):
3927 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3928 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203929 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133930
Takeshi Yoshinoe387aa32017-08-02 13:16:133931
Sergey Ulanov4af16052018-11-08 02:41:463932def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203933 mismatch_template = (
3934 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3935 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133936
Sergey Ulanov4af16052018-11-08 02:41:463937 email_regex = input_api.re.compile(
3938 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3939
3940 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203941 i = 0
3942 last_key = ''
3943 while True:
3944 if i >= len(wd_dict.keys):
3945 if i >= len(w_dict.keys):
3946 return None
3947 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3948 elif i >= len(w_dict.keys):
3949 return (
3950 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133951
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203952 wd_key = wd_dict.keys[i]
3953 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133954
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203955 result = _CheckWatchlistDefinitionsEntrySyntax(
3956 wd_key, wd_dict.values[i], ast)
3957 if result is not None:
3958 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133959
Sergey Ulanov4af16052018-11-08 02:41:463960 result = _CheckWatchlistsEntrySyntax(
3961 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203962 if result is not None:
3963 return 'Bad entry in WATCHLISTS dict: %s' % result
3964
3965 if wd_key.s != w_key.s:
3966 return mismatch_template % (
3967 '%s at line %d' % (wd_key.s, wd_key.lineno),
3968 '%s at line %d' % (w_key.s, w_key.lineno))
3969
3970 if wd_key.s < last_key:
3971 return (
3972 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3973 (wd_key.lineno, w_key.lineno))
3974 last_key = wd_key.s
3975
3976 i = i + 1
3977
3978
Sergey Ulanov4af16052018-11-08 02:41:463979def _CheckWATCHLISTSSyntax(expression, input_api):
3980 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203981 if not isinstance(expression, ast.Expression):
3982 return 'WATCHLISTS file must contain a valid expression'
3983 dictionary = expression.body
3984 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3985 return 'WATCHLISTS file must have single dict with exactly two entries'
3986
3987 first_key = dictionary.keys[0]
3988 first_value = dictionary.values[0]
3989 second_key = dictionary.keys[1]
3990 second_value = dictionary.values[1]
3991
3992 if (not isinstance(first_key, ast.Str) or
3993 first_key.s != 'WATCHLIST_DEFINITIONS' or
3994 not isinstance(first_value, ast.Dict)):
3995 return (
3996 'The first entry of the dict in WATCHLISTS file must be '
3997 'WATCHLIST_DEFINITIONS dict')
3998
3999 if (not isinstance(second_key, ast.Str) or
4000 second_key.s != 'WATCHLISTS' or
4001 not isinstance(second_value, ast.Dict)):
4002 return (
4003 'The second entry of the dict in WATCHLISTS file must be '
4004 'WATCHLISTS dict')
4005
Sergey Ulanov4af16052018-11-08 02:41:464006 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134007
4008
Saagar Sanghavifceeaae2020-08-12 16:40:364009def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:134010 for f in input_api.AffectedFiles(include_deletes=False):
4011 if f.LocalPath() == 'WATCHLISTS':
4012 contents = input_api.ReadFile(f, 'r')
4013
4014 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204015 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134016 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204017 # Get an AST tree for it and scan the tree for detailed style checking.
4018 expression = input_api.ast.parse(
4019 contents, filename='WATCHLISTS', mode='eval')
4020 except ValueError as e:
4021 return [output_api.PresubmitError(
4022 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4023 except SyntaxError as e:
4024 return [output_api.PresubmitError(
4025 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4026 except TypeError as e:
4027 return [output_api.PresubmitError(
4028 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134029
Sergey Ulanov4af16052018-11-08 02:41:464030 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204031 if result is not None:
4032 return [output_api.PresubmitError(result)]
4033 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134034
4035 return []
4036
4037
Andrew Grieve1b290e4a22020-11-24 20:07:014038def CheckGnGlobForward(input_api, output_api):
4039 """Checks that forward_variables_from(invoker, "*") follows best practices.
4040
4041 As documented at //build/docs/writing_gn_templates.md
4042 """
4043 def gn_files(f):
4044 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
4045
4046 problems = []
4047 for f in input_api.AffectedSourceFiles(gn_files):
4048 for line_num, line in f.ChangedContents():
4049 if 'forward_variables_from(invoker, "*")' in line:
4050 problems.append(
4051 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
4052 f.LocalPath(), line_num))
4053
4054 if problems:
4055 return [output_api.PresubmitPromptWarning(
4056 'forward_variables_from("*") without exclusions',
4057 items=sorted(problems),
4058 long_text=('The variables "visibilty" and "test_only" should be '
4059 'explicitly listed in forward_variables_from(). For more '
4060 'details, see:\n'
4061 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4062 'build/docs/writing_gn_templates.md'
4063 '#Using-forward_variables_from'))]
4064 return []
4065
4066
Saagar Sanghavifceeaae2020-08-12 16:40:364067def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194068 """Checks that newly added header files have corresponding GN changes.
4069 Note that this is only a heuristic. To be precise, run script:
4070 build/check_gn_headers.py.
4071 """
4072
4073 def headers(f):
4074 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444075 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194076
4077 new_headers = []
4078 for f in input_api.AffectedSourceFiles(headers):
4079 if f.Action() != 'A':
4080 continue
4081 new_headers.append(f.LocalPath())
4082
4083 def gn_files(f):
James Cook24a504192020-07-23 00:08:444084 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194085
4086 all_gn_changed_contents = ''
4087 for f in input_api.AffectedSourceFiles(gn_files):
4088 for _, line in f.ChangedContents():
4089 all_gn_changed_contents += line
4090
4091 problems = []
4092 for header in new_headers:
4093 basename = input_api.os_path.basename(header)
4094 if basename not in all_gn_changed_contents:
4095 problems.append(header)
4096
4097 if problems:
4098 return [output_api.PresubmitPromptWarning(
4099 'Missing GN changes for new header files', items=sorted(problems),
4100 long_text='Please double check whether newly added header files need '
4101 'corresponding changes in gn or gni files.\nThis checking is only a '
4102 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4103 'Read https://crbug.com/661774 for more info.')]
4104 return []
4105
4106
Saagar Sanghavifceeaae2020-08-12 16:40:364107def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024108 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4109
4110 This assumes we won't intentionally reference one product from the other
4111 product.
4112 """
4113 all_problems = []
4114 test_cases = [{
4115 "filename_postfix": "google_chrome_strings.grd",
4116 "correct_name": "Chrome",
4117 "incorrect_name": "Chromium",
4118 }, {
4119 "filename_postfix": "chromium_strings.grd",
4120 "correct_name": "Chromium",
4121 "incorrect_name": "Chrome",
4122 }]
4123
4124 for test_case in test_cases:
4125 problems = []
4126 filename_filter = lambda x: x.LocalPath().endswith(
4127 test_case["filename_postfix"])
4128
4129 # Check each new line. Can yield false positives in multiline comments, but
4130 # easier than trying to parse the XML because messages can have nested
4131 # children, and associating message elements with affected lines is hard.
4132 for f in input_api.AffectedSourceFiles(filename_filter):
4133 for line_num, line in f.ChangedContents():
4134 if "<message" in line or "<!--" in line or "-->" in line:
4135 continue
4136 if test_case["incorrect_name"] in line:
4137 problems.append(
4138 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4139
4140 if problems:
4141 message = (
4142 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4143 % (test_case["correct_name"], test_case["correct_name"],
4144 test_case["incorrect_name"]))
4145 all_problems.append(
4146 output_api.PresubmitPromptWarning(message, items=problems))
4147
4148 return all_problems
4149
4150
Saagar Sanghavifceeaae2020-08-12 16:40:364151def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364152 """Avoid large files, especially binary files, in the repository since
4153 git doesn't scale well for those. They will be in everyone's repo
4154 clones forever, forever making Chromium slower to clone and work
4155 with."""
4156
4157 # Uploading files to cloud storage is not trivial so we don't want
4158 # to set the limit too low, but the upper limit for "normal" large
4159 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4160 # anything over 20 MB is exceptional.
4161 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4162
4163 too_large_files = []
4164 for f in input_api.AffectedFiles():
4165 # Check both added and modified files (but not deleted files).
4166 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384167 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364168 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4169 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4170
4171 if too_large_files:
4172 message = (
4173 'Do not commit large files to git since git scales badly for those.\n' +
4174 'Instead put the large files in cloud storage and use DEPS to\n' +
4175 'fetch them.\n' + '\n'.join(too_large_files)
4176 )
4177 return [output_api.PresubmitError(
4178 'Too large files found in commit', long_text=message + '\n')]
4179 else:
4180 return []
4181
Max Morozb47503b2019-08-08 21:03:274182
Saagar Sanghavifceeaae2020-08-12 16:40:364183def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274184 """Checks specific for fuzz target sources."""
4185 EXPORTED_SYMBOLS = [
4186 'LLVMFuzzerInitialize',
4187 'LLVMFuzzerCustomMutator',
4188 'LLVMFuzzerCustomCrossOver',
4189 'LLVMFuzzerMutate',
4190 ]
4191
4192 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4193
4194 def FilterFile(affected_file):
4195 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444196 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4197 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274198
4199 return input_api.FilterSourceFile(
4200 affected_file,
James Cook24a504192020-07-23 00:08:444201 files_to_check=[files_to_check],
4202 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274203
4204 files_with_missing_header = []
4205 for f in input_api.AffectedSourceFiles(FilterFile):
4206 contents = input_api.ReadFile(f, 'r')
4207 if REQUIRED_HEADER in contents:
4208 continue
4209
4210 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4211 files_with_missing_header.append(f.LocalPath())
4212
4213 if not files_with_missing_header:
4214 return []
4215
4216 long_text = (
4217 'If you define any of the libFuzzer optional functions (%s), it is '
4218 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4219 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4220 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4221 'to access command line arguments passed to the fuzzer. Instead, prefer '
4222 'static initialization and shared resources as documented in '
4223 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4224 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4225 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4226 )
4227
4228 return [output_api.PresubmitPromptWarning(
4229 message="Missing '%s' in:" % REQUIRED_HEADER,
4230 items=files_with_missing_header,
4231 long_text=long_text)]
4232
4233
Mohamed Heikald048240a2019-11-12 16:57:374234def _CheckNewImagesWarning(input_api, output_api):
4235 """
4236 Warns authors who add images into the repo to make sure their images are
4237 optimized before committing.
4238 """
4239 images_added = False
4240 image_paths = []
4241 errors = []
4242 filter_lambda = lambda x: input_api.FilterSourceFile(
4243 x,
James Cook24a504192020-07-23 00:08:444244 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4245 + input_api.DEFAULT_FILES_TO_SKIP),
4246 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374247 )
4248 for f in input_api.AffectedFiles(
4249 include_deletes=False, file_filter=filter_lambda):
4250 local_path = f.LocalPath().lower()
4251 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4252 images_added = True
4253 image_paths.append(f)
4254 if images_added:
4255 errors.append(output_api.PresubmitPromptWarning(
4256 'It looks like you are trying to commit some images. If these are '
4257 'non-test-only images, please make sure to read and apply the tips in '
4258 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4259 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4260 'FYI only and will not block your CL on the CQ.', image_paths))
4261 return errors
4262
4263
Saagar Sanghavifceeaae2020-08-12 16:40:364264def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574265 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224266 results = []
dgnaa68d5e2015-06-10 10:08:224267 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174268 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224269 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294270 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064271 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4272 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424273 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184274 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574275 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374276 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154277 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574278 return results
4279
Saagar Sanghavifceeaae2020-08-12 16:40:364280def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574281 """Groups commit checks that target android code."""
4282 results = []
4283 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224284 return results
4285
Chris Hall59f8d0c72020-05-01 07:31:194286# TODO(chrishall): could we additionally match on any path owned by
4287# ui/accessibility/OWNERS ?
4288_ACCESSIBILITY_PATHS = (
4289 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4290 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4291 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4292 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4293 r"^content[\\/]browser[\\/]accessibility[\\/]",
4294 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4295 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4296 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4297 r"^ui[\\/]accessibility[\\/]",
4298 r"^ui[\\/]views[\\/]accessibility[\\/]",
4299)
4300
Saagar Sanghavifceeaae2020-08-12 16:40:364301def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194302 """Checks that commits to accessibility code contain an AX-Relnotes field in
4303 their commit message."""
4304 def FileFilter(affected_file):
4305 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444306 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194307
4308 # Only consider changes affecting accessibility paths.
4309 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4310 return []
4311
Akihiro Ota08108e542020-05-20 15:30:534312 # AX-Relnotes can appear in either the description or the footer.
4313 # When searching the description, require 'AX-Relnotes:' to appear at the
4314 # beginning of a line.
4315 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4316 description_has_relnotes = any(ax_regex.match(line)
4317 for line in input_api.change.DescriptionText().lower().splitlines())
4318
4319 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4320 'AX-Relnotes', [])
4321 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194322 return []
4323
4324 # TODO(chrishall): link to Relnotes documentation in message.
4325 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4326 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4327 "user-facing changes"
4328 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4329 "user-facing effects"
4330 "\n if this is confusing or annoying then please contact members "
4331 "of ui/accessibility/OWNERS.")
4332
4333 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224334
Saagar Sanghavifceeaae2020-08-12 16:40:364335def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394336 """Checks common to both upload and commit."""
4337 results = []
4338 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384339 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544340 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084341
4342 author = input_api.change.author_email
4343 if author and author not in _KNOWN_ROBOTS:
4344 results.extend(
4345 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4346
[email protected]9f919cc2013-07-31 03:04:044347 results.extend(
4348 input_api.canned_checks.CheckChangeHasNoTabs(
4349 input_api,
4350 output_api,
4351 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434352 results.extend(input_api.RunTests(
4353 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244354
Edward Lesmesce51df52020-08-04 22:10:174355 dirmd_bin = input_api.os_path.join(
4356 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4357 results.extend(input_api.RunTests(
4358 input_api.canned_checks.CheckDirMetadataFormat(
4359 input_api, output_api, dirmd_bin)))
4360 results.extend(
4361 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4362 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554363 results.extend(
4364 input_api.canned_checks.CheckNoNewMetadataInOwners(
4365 input_api, output_api))
Edward Lesmesce51df52020-08-04 22:10:174366
Vaclav Brozekcdc7defb2018-03-20 09:54:354367 for f in input_api.AffectedFiles():
4368 path, name = input_api.os_path.split(f.LocalPath())
4369 if name == 'PRESUBMIT.py':
4370 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004371 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4372 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074373 # The PRESUBMIT.py file (and the directory containing it) might
4374 # have been affected by being moved or removed, so only try to
4375 # run the tests if they still exist.
4376 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4377 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444378 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394379 return results
[email protected]1f7b4172010-01-28 01:17:344380
[email protected]b337cb5b2011-01-23 21:24:054381
Saagar Sanghavifceeaae2020-08-12 16:40:364382def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494383 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4384 if f.LocalPath().endswith(('.orig', '.rej'))]
4385 if problems:
4386 return [output_api.PresubmitError(
4387 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034388 else:
4389 return []
[email protected]b8079ae4a2012-12-05 19:56:494390
4391
Saagar Sanghavifceeaae2020-08-12 16:40:364392def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214393 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4394 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4395 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074396 include_re = input_api.re.compile(
4397 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4398 extension_re = input_api.re.compile(r'\.[a-z]+$')
4399 errors = []
4400 for f in input_api.AffectedFiles():
4401 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4402 continue
4403 found_line_number = None
4404 found_macro = None
4405 for line_num, line in f.ChangedContents():
4406 match = macro_re.search(line)
4407 if match:
4408 found_line_number = line_num
4409 found_macro = match.group(2)
4410 break
4411 if not found_line_number:
4412 continue
4413
4414 found_include = False
4415 for line in f.NewContents():
4416 if include_re.search(line):
4417 found_include = True
4418 break
4419 if found_include:
4420 continue
4421
4422 if not f.LocalPath().endswith('.h'):
4423 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4424 try:
4425 content = input_api.ReadFile(primary_header_path, 'r')
4426 if include_re.search(content):
4427 continue
4428 except IOError:
4429 pass
4430 errors.append('%s:%d %s macro is used without including build/'
4431 'build_config.h.'
4432 % (f.LocalPath(), found_line_number, found_macro))
4433 if errors:
4434 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4435 return []
4436
4437
[email protected]b00342e7f2013-03-26 16:21:544438def _DidYouMeanOSMacro(bad_macro):
4439 try:
4440 return {'A': 'OS_ANDROID',
4441 'B': 'OS_BSD',
4442 'C': 'OS_CHROMEOS',
4443 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444444 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544445 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444446 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544447 'N': 'OS_NACL',
4448 'O': 'OS_OPENBSD',
4449 'P': 'OS_POSIX',
4450 'S': 'OS_SOLARIS',
4451 'W': 'OS_WIN'}[bad_macro[3].upper()]
4452 except KeyError:
4453 return ''
4454
4455
4456def _CheckForInvalidOSMacrosInFile(input_api, f):
4457 """Check for sensible looking, totally invalid OS macros."""
4458 preprocessor_statement = input_api.re.compile(r'^\s*#')
4459 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4460 results = []
4461 for lnum, line in f.ChangedContents():
4462 if preprocessor_statement.search(line):
4463 for match in os_macro.finditer(line):
4464 if not match.group(1) in _VALID_OS_MACROS:
4465 good = _DidYouMeanOSMacro(match.group(1))
4466 did_you_mean = ' (did you mean %s?)' % good if good else ''
4467 results.append(' %s:%d %s%s' % (f.LocalPath(),
4468 lnum,
4469 match.group(1),
4470 did_you_mean))
4471 return results
4472
4473
Saagar Sanghavifceeaae2020-08-12 16:40:364474def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544475 """Check all affected files for invalid OS macros."""
4476 bad_macros = []
tzik3f295992018-12-04 20:32:234477 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474478 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544479 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4480
4481 if not bad_macros:
4482 return []
4483
4484 return [output_api.PresubmitError(
4485 'Possibly invalid OS macro[s] found. Please fix your code\n'
4486 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4487
lliabraa35bab3932014-10-01 12:16:444488
4489def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4490 """Check all affected files for invalid "if defined" macros."""
4491 ALWAYS_DEFINED_MACROS = (
4492 "TARGET_CPU_PPC",
4493 "TARGET_CPU_PPC64",
4494 "TARGET_CPU_68K",
4495 "TARGET_CPU_X86",
4496 "TARGET_CPU_ARM",
4497 "TARGET_CPU_MIPS",
4498 "TARGET_CPU_SPARC",
4499 "TARGET_CPU_ALPHA",
4500 "TARGET_IPHONE_SIMULATOR",
4501 "TARGET_OS_EMBEDDED",
4502 "TARGET_OS_IPHONE",
4503 "TARGET_OS_MAC",
4504 "TARGET_OS_UNIX",
4505 "TARGET_OS_WIN32",
4506 )
4507 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4508 results = []
4509 for lnum, line in f.ChangedContents():
4510 for match in ifdef_macro.finditer(line):
4511 if match.group(1) in ALWAYS_DEFINED_MACROS:
4512 always_defined = ' %s is always defined. ' % match.group(1)
4513 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4514 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4515 lnum,
4516 always_defined,
4517 did_you_mean))
4518 return results
4519
4520
Saagar Sanghavifceeaae2020-08-12 16:40:364521def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444522 """Check all affected files for invalid "if defined" macros."""
4523 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054524 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444525 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054526 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214527 continue
lliabraa35bab3932014-10-01 12:16:444528 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4529 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4530
4531 if not bad_macros:
4532 return []
4533
4534 return [output_api.PresubmitError(
4535 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4536 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4537 bad_macros)]
4538
4539
Saagar Sanghavifceeaae2020-08-12 16:40:364540def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044541 """Check for same IPC rules described in
4542 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4543 """
4544 base_pattern = r'IPC_ENUM_TRAITS\('
4545 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4546 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4547
4548 problems = []
4549 for f in input_api.AffectedSourceFiles(None):
4550 local_path = f.LocalPath()
4551 if not local_path.endswith('.h'):
4552 continue
4553 for line_number, line in f.ChangedContents():
4554 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4555 problems.append(
4556 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4557
4558 if problems:
4559 return [output_api.PresubmitPromptWarning(
4560 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4561 else:
4562 return []
4563
[email protected]b00342e7f2013-03-26 16:21:544564
Saagar Sanghavifceeaae2020-08-12 16:40:364565def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054566 """Check to make sure no files being submitted have long paths.
4567 This causes issues on Windows.
4568 """
4569 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194570 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054571 local_path = f.LocalPath()
4572 # Windows has a path limit of 260 characters. Limit path length to 200 so
4573 # that we have some extra for the prefix on dev machines and the bots.
4574 if len(local_path) > 200:
4575 problems.append(local_path)
4576
4577 if problems:
4578 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4579 else:
4580 return []
4581
4582
Saagar Sanghavifceeaae2020-08-12 16:40:364583def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144584 """Check that header files have proper guards against multiple inclusion.
4585 If a file should not have such guards (and it probably should) then it
4586 should include the string "no-include-guard-because-multiply-included".
4587 """
Daniel Bratell6a75baef62018-06-04 10:04:454588 def is_chromium_header_file(f):
4589 # We only check header files under the control of the Chromium
4590 # project. That is, those outside third_party apart from
4591 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324592 # We also exclude *_message_generator.h headers as they use
4593 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454594 file_with_path = input_api.os_path.normpath(f.LocalPath())
4595 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324596 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454597 (not file_with_path.startswith('third_party') or
4598 file_with_path.startswith(
4599 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144600
4601 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344602 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144603
4604 errors = []
4605
Daniel Bratell6a75baef62018-06-04 10:04:454606 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144607 guard_name = None
4608 guard_line_number = None
4609 seen_guard_end = False
4610
4611 file_with_path = input_api.os_path.normpath(f.LocalPath())
4612 base_file_name = input_api.os_path.splitext(
4613 input_api.os_path.basename(file_with_path))[0]
4614 upper_base_file_name = base_file_name.upper()
4615
4616 expected_guard = replace_special_with_underscore(
4617 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144618
4619 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574620 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4621 # are too many (1000+) files with slight deviations from the
4622 # coding style. The most important part is that the include guard
4623 # is there, and that it's unique, not the name so this check is
4624 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144625 #
4626 # As code becomes more uniform, this could be made stricter.
4627
4628 guard_name_pattern_list = [
4629 # Anything with the right suffix (maybe with an extra _).
4630 r'\w+_H__?',
4631
Daniel Bratell39b5b062018-05-16 18:09:574632 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144633 r'\w+_h',
4634
4635 # Anything including the uppercase name of the file.
4636 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4637 upper_base_file_name)) + r'\w*',
4638 ]
4639 guard_name_pattern = '|'.join(guard_name_pattern_list)
4640 guard_pattern = input_api.re.compile(
4641 r'#ifndef\s+(' + guard_name_pattern + ')')
4642
4643 for line_number, line in enumerate(f.NewContents()):
4644 if 'no-include-guard-because-multiply-included' in line:
4645 guard_name = 'DUMMY' # To not trigger check outside the loop.
4646 break
4647
4648 if guard_name is None:
4649 match = guard_pattern.match(line)
4650 if match:
4651 guard_name = match.group(1)
4652 guard_line_number = line_number
4653
Daniel Bratell39b5b062018-05-16 18:09:574654 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454655 # don't match the chromium style guide, but new files should
4656 # get it right.
4657 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574658 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144659 errors.append(output_api.PresubmitPromptWarning(
4660 'Header using the wrong include guard name %s' % guard_name,
4661 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574662 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144663 else:
4664 # The line after #ifndef should have a #define of the same name.
4665 if line_number == guard_line_number + 1:
4666 expected_line = '#define %s' % guard_name
4667 if line != expected_line:
4668 errors.append(output_api.PresubmitPromptWarning(
4669 'Missing "%s" for include guard' % expected_line,
4670 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4671 'Expected: %r\nGot: %r' % (expected_line, line)))
4672
4673 if not seen_guard_end and line == '#endif // %s' % guard_name:
4674 seen_guard_end = True
4675 elif seen_guard_end:
4676 if line.strip() != '':
4677 errors.append(output_api.PresubmitPromptWarning(
4678 'Include guard %s not covering the whole file' % (
4679 guard_name), [f.LocalPath()]))
4680 break # Nothing else to check and enough to warn once.
4681
4682 if guard_name is None:
4683 errors.append(output_api.PresubmitPromptWarning(
4684 'Missing include guard %s' % expected_guard,
4685 [f.LocalPath()],
4686 'Missing include guard in %s\n'
4687 'Recommended name: %s\n'
4688 'This check can be disabled by having the string\n'
4689 'no-include-guard-because-multiply-included in the header.' %
4690 (f.LocalPath(), expected_guard)))
4691
4692 return errors
4693
4694
Saagar Sanghavifceeaae2020-08-12 16:40:364695def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234696 """Check source code and known ascii text files for Windows style line
4697 endings.
4698 """
earthdok1b5e0ee2015-03-10 15:19:104699 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234700
4701 file_inclusion_pattern = (
4702 known_text_files,
4703 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4704 )
4705
mostynbb639aca52015-01-07 20:31:234706 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534707 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444708 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534709 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504710 include_file = False
4711 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234712 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504713 include_file = True
4714 if include_file:
4715 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234716
4717 if problems:
4718 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4719 'these files to contain Windows style line endings?\n' +
4720 '\n'.join(problems))]
4721
4722 return []
4723
Jose Magana2b456f22021-03-09 23:26:404724def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4725 """Check source code for use of Chrome App technologies being
4726 deprecated.
4727 """
4728
4729 def _CheckForDeprecatedTech(input_api, output_api,
4730 detection_list, files_to_check = None, files_to_skip = None):
4731
4732 if (files_to_check or files_to_skip):
4733 source_file_filter = lambda f: input_api.FilterSourceFile(
4734 f, files_to_check=files_to_check,
4735 files_to_skip=files_to_skip)
4736 else:
4737 source_file_filter = None
4738
4739 problems = []
4740
4741 for f in input_api.AffectedSourceFiles(source_file_filter):
4742 if f.Action() == 'D':
4743 continue
4744 for _, line in f.ChangedContents():
4745 if any( detect in line for detect in detection_list ):
4746 problems.append(f.LocalPath())
4747
4748 return problems
4749
4750 # to avoid this presubmit script triggering warnings
4751 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4752
4753 problems =[]
4754
4755 # NMF: any files with extensions .nmf or NMF
4756 _NMF_FILES = r'\.(nmf|NMF)$'
4757 problems += _CheckForDeprecatedTech(input_api, output_api,
4758 detection_list = [''], # any change to the file will trigger warning
4759 files_to_check = [ r'.+%s' % _NMF_FILES ])
4760
4761 # MANIFEST: any manifest.json that in its diff includes "app":
4762 _MANIFEST_FILES = r'(manifest\.json)$'
4763 problems += _CheckForDeprecatedTech(input_api, output_api,
4764 detection_list = ['"app":'],
4765 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4766
4767 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4768 problems += _CheckForDeprecatedTech(input_api, output_api,
4769 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4770 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4771
4772 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4773 problems += _CheckForDeprecatedTech(input_api, output_api,
4774 detection_list = ['#include "ppapi','#include <ppapi'],
4775 files_to_check = (
4776 r'.+%s' % _HEADER_EXTENSIONS,
4777 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4778 files_to_skip = [r"^ppapi[\\/]"] )
4779
4780 # Chrome Apps: any JS/TS file that references an API in the list below.
4781 # This should include the list of Chrome Apps APIs that are not Chrome
4782 # Extensions APIs as documented in:
4783 # https://developer.chrome.com/docs/apps/migration/
4784 detection_list_chrome_apps = [
4785 'chrome.accessibilityFeatures',
4786 'chrome.alarms',
4787 'chrome.app.runtime',
4788 'chrome.app.window',
4789 'chrome.audio',
4790 'chrome.bluetooth',
4791 'chrome.bluetoothLowEnergy',
4792 'chrome.bluetoothSocket',
4793 'chrome.browser',
4794 'chrome.commands',
4795 'chrome.contextMenus',
4796 'chrome.documentScan',
4797 'chrome.events',
4798 'chrome.extensionTypes',
4799 'chrome.fileSystem',
4800 'chrome.fileSystemProvider',
4801 'chrome.gcm',
4802 'chrome.hid',
4803 'chrome.i18n',
4804 'chrome.identity',
4805 'chrome.idle',
4806 'chrome.instanceID',
4807 'chrome.mdns',
4808 'chrome.mediaGalleries',
4809 'chrome.networking.onc',
4810 'chrome.notifications',
4811 'chrome.permissions',
4812 'chrome.power',
4813 'chrome.printerProvider',
4814 'chrome.runtime',
4815 'chrome.serial',
4816 'chrome.sockets.tcp',
4817 'chrome.sockets.tcpServer',
4818 'chrome.sockets.udp',
4819 'chrome.storage',
4820 'chrome.syncFileSystem',
4821 'chrome.system.cpu',
4822 'chrome.system.display',
4823 'chrome.system.memory',
4824 'chrome.system.network',
4825 'chrome.system.storage',
4826 'chrome.tts',
4827 'chrome.types',
4828 'chrome.usb',
4829 'chrome.virtualKeyboard',
4830 'chrome.vpnProvider',
4831 'chrome.wallpaper'
4832 ]
4833 _JS_FILES = r'\.(js|ts)$'
4834 problems += _CheckForDeprecatedTech(input_api, output_api,
4835 detection_list = detection_list_chrome_apps,
4836 files_to_check = [ r'.+%s' % _JS_FILES ],
4837 files_to_skip = files_to_skip)
4838
4839 if problems:
4840 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4841 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4842 ' PNaCl, PPAPI). See this blog post for more details:\n'
4843 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4844 'and this documentation for options to replace these technologies:\n'
4845 'https://developer.chrome.com/docs/apps/migration/\n'+
4846 '\n'.join(problems))]
4847
4848 return []
4849
mostynbb639aca52015-01-07 20:31:234850
Saagar Sanghavifceeaae2020-08-12 16:40:364851def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134852 """Checks that all source files use SYSLOG properly."""
4853 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364854 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564855 for line_number, line in f.ChangedContents():
4856 if 'SYSLOG' in line:
4857 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4858
pastarmovj89f7ee12016-09-20 14:58:134859 if syslog_files:
4860 return [output_api.PresubmitPromptWarning(
4861 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4862 ' calls.\nFiles to check:\n', items=syslog_files)]
4863 return []
4864
4865
[email protected]1f7b4172010-01-28 01:17:344866def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364867 if input_api.version < [2, 0, 0]:
4868 return [output_api.PresubmitError("Your depot_tools is out of date. "
4869 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4870 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344871 results = []
scottmg39b29952014-12-08 18:31:284872 results.extend(
jam93a6ee792017-02-08 23:59:224873 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544874 return results
[email protected]ca8d1982009-02-19 16:33:124875
4876
[email protected]1bfb8322014-04-23 01:02:414877def GetTryServerMasterForBot(bot):
4878 """Returns the Try Server master for the given bot.
4879
[email protected]0bb112362014-07-26 04:38:324880 It tries to guess the master from the bot name, but may still fail
4881 and return None. There is no longer a default master.
4882 """
4883 # Potentially ambiguous bot names are listed explicitly.
4884 master_map = {
tandriie5587792016-07-14 00:34:504885 'chromium_presubmit': 'master.tryserver.chromium.linux',
4886 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414887 }
[email protected]0bb112362014-07-26 04:38:324888 master = master_map.get(bot)
4889 if not master:
wnwen4fbaab82016-05-25 12:54:364890 if 'android' in bot:
tandriie5587792016-07-14 00:34:504891 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364892 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504893 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324894 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504895 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324896 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504897 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324898 return master
[email protected]1bfb8322014-04-23 01:02:414899
4900
[email protected]ca8d1982009-02-19 16:33:124901def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364902 if input_api.version < [2, 0, 0]:
4903 return [output_api.PresubmitError("Your depot_tools is out of date. "
4904 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4905 "but your version is %d.%d.%d" % tuple(input_api.version))]
4906
[email protected]fe5f57c52009-06-05 14:25:544907 results = []
[email protected]fe5f57c52009-06-05 14:25:544908 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274909 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344910 input_api,
4911 output_api,
[email protected]2fdd1f362013-01-16 03:56:034912 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274913
jam93a6ee792017-02-08 23:59:224914 results.extend(
4915 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544916 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4917 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384918 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4919 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414920 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4921 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544922 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144923
4924
Saagar Sanghavifceeaae2020-08-12 16:40:364925def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264926 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024927 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4928 # footer is set to true.
4929 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264930 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024931 footer.lower()
4932 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264933 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024934
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144935 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264936 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144937 import sys
4938 from io import StringIO
4939
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144940 new_or_added_paths = set(f.LocalPath()
4941 for f in input_api.AffectedFiles()
4942 if (f.Action() == 'A' or f.Action() == 'M'))
4943 removed_paths = set(f.LocalPath()
4944 for f in input_api.AffectedFiles(include_deletes=True)
4945 if f.Action() == 'D')
4946
Andrew Grieve0e8790c2020-09-03 17:27:324947 affected_grds = [
4948 f for f in input_api.AffectedFiles()
4949 if f.LocalPath().endswith(('.grd', '.grdp'))
4950 ]
4951 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164952 if not affected_grds:
4953 return []
4954
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144955 affected_png_paths = [f.AbsoluteLocalPath()
4956 for f in input_api.AffectedFiles()
4957 if (f.LocalPath().endswith('.png'))]
4958
4959 # Check for screenshots. Developers can upload screenshots using
4960 # tools/translation/upload_screenshots.py which finds and uploads
4961 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4962 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4963 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4964 #
4965 # The logic here is as follows:
4966 #
4967 # - If the CL has a .png file under the screenshots directory for a grd
4968 # file, warn the developer. Actual images should never be checked into the
4969 # Chrome repo.
4970 #
4971 # - If the CL contains modified or new messages in grd files and doesn't
4972 # contain the corresponding .sha1 files, warn the developer to add images
4973 # and upload them via tools/translation/upload_screenshots.py.
4974 #
4975 # - If the CL contains modified or new messages in grd files and the
4976 # corresponding .sha1 files, everything looks good.
4977 #
4978 # - If the CL contains removed messages in grd files but the corresponding
4979 # .sha1 files aren't removed, warn the developer to remove them.
4980 unnecessary_screenshots = []
4981 missing_sha1 = []
4982 unnecessary_sha1_files = []
4983
Rainhard Findlingfc31844c52020-05-15 09:58:264984 # This checks verifies that the ICU syntax of messages this CL touched is
4985 # valid, and reports any found syntax errors.
4986 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4987 # without developers being aware of them. Later on, such ICU syntax errors
4988 # break message extraction for translation, hence would block Chromium
4989 # translations until they are fixed.
4990 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144991
4992 def _CheckScreenshotAdded(screenshots_dir, message_id):
4993 sha1_path = input_api.os_path.join(
4994 screenshots_dir, message_id + '.png.sha1')
4995 if sha1_path not in new_or_added_paths:
4996 missing_sha1.append(sha1_path)
4997
4998
4999 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5000 sha1_path = input_api.os_path.join(
5001 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:035002 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145003 unnecessary_sha1_files.append(sha1_path)
5004
Rainhard Findlingfc31844c52020-05-15 09:58:265005
5006 def _ValidateIcuSyntax(text, level, signatures):
5007 """Validates ICU syntax of a text string.
5008
5009 Check if text looks similar to ICU and checks for ICU syntax correctness
5010 in this case. Reports various issues with ICU syntax and values of
5011 variants. Supports checking of nested messages. Accumulate information of
5012 each ICU messages found in the text for further checking.
5013
5014 Args:
5015 text: a string to check.
5016 level: a number of current nesting level.
5017 signatures: an accumulator, a list of tuple of (level, variable,
5018 kind, variants).
5019
5020 Returns:
5021 None if a string is not ICU or no issue detected.
5022 A tuple of (message, start index, end index) if an issue detected.
5023 """
5024 valid_types = {
5025 'plural': (frozenset(
5026 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5027 frozenset(['=1', 'other'])),
5028 'selectordinal': (frozenset(
5029 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5030 frozenset(['one', 'other'])),
5031 'select': (frozenset(), frozenset(['other'])),
5032 }
5033
5034 # Check if the message looks like an attempt to use ICU
5035 # plural. If yes - check if its syntax strictly matches ICU format.
5036 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
5037 if not like:
5038 signatures.append((level, None, None, None))
5039 return
5040
5041 # Check for valid prefix and suffix
5042 m = re.match(
5043 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5044 r'(plural|selectordinal|select),\s*'
5045 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5046 if not m:
5047 return (('This message looks like an ICU plural, '
5048 'but does not follow ICU syntax.'), like.start(), like.end())
5049 starting, variable, kind, variant_pairs = m.groups()
5050 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5051 if depth:
5052 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5053 len(text))
5054 first = text[0]
5055 ending = text[last_pos:]
5056 if not starting:
5057 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5058 last_pos)
5059 if not ending or '}' not in ending:
5060 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5061 last_pos)
5062 elif first != '{':
5063 return (
5064 ('Invalid ICU format. Extra characters at the start of a complex '
5065 'message (go/icu-message-migration): "%s"') %
5066 starting, 0, len(starting))
5067 elif ending != '}':
5068 return (('Invalid ICU format. Extra characters at the end of a complex '
5069 'message (go/icu-message-migration): "%s"')
5070 % ending, last_pos - 1, len(text) - 1)
5071 if kind not in valid_types:
5072 return (('Unknown ICU message type %s. '
5073 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5074 known, required = valid_types[kind]
5075 defined_variants = set()
5076 for variant, variant_range, value, value_range in variants:
5077 start, end = variant_range
5078 if variant in defined_variants:
5079 return ('Variant "%s" is defined more than once' % variant,
5080 start, end)
5081 elif known and variant not in known:
5082 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5083 start, end)
5084 defined_variants.add(variant)
5085 # Check for nested structure
5086 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5087 if res:
5088 return (res[0], res[1] + value_range[0] + 1,
5089 res[2] + value_range[0] + 1)
5090 missing = required - defined_variants
5091 if missing:
5092 return ('Required variants missing: %s' % ', '.join(missing), 0,
5093 len(text))
5094 signatures.append((level, variable, kind, defined_variants))
5095
5096
5097 def _ParseIcuVariants(text, offset=0):
5098 """Parse variants part of ICU complex message.
5099
5100 Builds a tuple of variant names and values, as well as
5101 their offsets in the input string.
5102
5103 Args:
5104 text: a string to parse
5105 offset: additional offset to add to positions in the text to get correct
5106 position in the complete ICU string.
5107
5108 Returns:
5109 List of tuples, each tuple consist of four fields: variant name,
5110 variant name span (tuple of two integers), variant value, value
5111 span (tuple of two integers).
5112 """
5113 depth, start, end = 0, -1, -1
5114 variants = []
5115 key = None
5116 for idx, char in enumerate(text):
5117 if char == '{':
5118 if not depth:
5119 start = idx
5120 chunk = text[end + 1:start]
5121 key = chunk.strip()
5122 pos = offset + end + 1 + chunk.find(key)
5123 span = (pos, pos + len(key))
5124 depth += 1
5125 elif char == '}':
5126 if not depth:
5127 return variants, depth, offset + idx
5128 depth -= 1
5129 if not depth:
5130 end = idx
5131 variants.append((key, span, text[start:end + 1], (offset + start,
5132 offset + end + 1)))
5133 return variants, depth, offset + end + 1
5134
meacer8c0d3832019-12-26 21:46:165135 try:
5136 old_sys_path = sys.path
5137 sys.path = sys.path + [input_api.os_path.join(
5138 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5139 from helper import grd_helper
5140 finally:
5141 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145142
5143 for f in affected_grds:
5144 file_path = f.LocalPath()
5145 old_id_to_msg_map = {}
5146 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385147 # Note that this code doesn't check if the file has been deleted. This is
5148 # OK because it only uses the old and new file contents and doesn't load
5149 # the file via its path.
5150 # It's also possible that a file's content refers to a renamed or deleted
5151 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5152 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5153 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145154 if file_path.endswith('.grdp'):
5155 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585156 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395157 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145158 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585159 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395160 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145161 else:
meacerff8a9b62019-12-10 19:43:585162 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145163 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585164 old_id_to_msg_map = grd_helper.GetGrdMessages(
5165 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145166 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585167 new_id_to_msg_map = grd_helper.GetGrdMessages(
5168 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145169
Rainhard Findlingd8d04372020-08-13 13:30:095170 grd_name, ext = input_api.os_path.splitext(
5171 input_api.os_path.basename(file_path))
5172 screenshots_dir = input_api.os_path.join(
5173 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5174
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145175 # Compute added, removed and modified message IDs.
5176 old_ids = set(old_id_to_msg_map)
5177 new_ids = set(new_id_to_msg_map)
5178 added_ids = new_ids - old_ids
5179 removed_ids = old_ids - new_ids
5180 modified_ids = set([])
5181 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355182 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095183 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5184 # The message content itself changed. Require an updated screenshot.
5185 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355186 elif old_id_to_msg_map[key].attrs['meaning'] != \
5187 new_id_to_msg_map[key].attrs['meaning']:
5188 # The message meaning changed. Ensure there is a screenshot for it.
5189 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5190 if sha1_path not in new_or_added_paths and not \
5191 input_api.os_path.exists(sha1_path):
5192 # There is neither a previous screenshot nor is a new one added now.
5193 # Require a screenshot.
5194 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145195
Rainhard Findlingfc31844c52020-05-15 09:58:265196 if run_screenshot_check:
5197 # Check the screenshot directory for .png files. Warn if there is any.
5198 for png_path in affected_png_paths:
5199 if png_path.startswith(screenshots_dir):
5200 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145201
Rainhard Findlingfc31844c52020-05-15 09:58:265202 for added_id in added_ids:
5203 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145204
Rainhard Findlingfc31844c52020-05-15 09:58:265205 for modified_id in modified_ids:
5206 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145207
Rainhard Findlingfc31844c52020-05-15 09:58:265208 for removed_id in removed_ids:
5209 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5210
5211 # Check new and changed strings for ICU syntax errors.
5212 for key in added_ids.union(modified_ids):
5213 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5214 err = _ValidateIcuSyntax(msg, 0, [])
5215 if err is not None:
5216 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145217
5218 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265219 if run_screenshot_check:
5220 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005221 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265222 'Do not include actual screenshots in the changelist. Run '
5223 'tools/translate/upload_screenshots.py to upload them instead:',
5224 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145225
Rainhard Findlingfc31844c52020-05-15 09:58:265226 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005227 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265228 'You are adding or modifying UI strings.\n'
5229 'To ensure the best translations, take screenshots of the relevant UI '
5230 '(https://g.co/chrome/translation) and add these files to your '
5231 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145232
Rainhard Findlingfc31844c52020-05-15 09:58:265233 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005234 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265235 'You removed strings associated with these files. Remove:',
5236 sorted(unnecessary_sha1_files)))
5237 else:
5238 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5239 'screenshots check.'))
5240
5241 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075242 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265243 'ICU syntax errors were found in the following strings (problems or '
5244 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145245
5246 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125247
5248
Saagar Sanghavifceeaae2020-08-12 16:40:365249def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125250 repo_root=None,
5251 translation_expectations_path=None,
5252 grd_files=None):
5253 import sys
5254 affected_grds = [f for f in input_api.AffectedFiles()
5255 if (f.LocalPath().endswith('.grd') or
5256 f.LocalPath().endswith('.grdp'))]
5257 if not affected_grds:
5258 return []
5259
5260 try:
5261 old_sys_path = sys.path
5262 sys.path = sys.path + [
5263 input_api.os_path.join(
5264 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5265 from helper import git_helper
5266 from helper import translation_helper
5267 finally:
5268 sys.path = old_sys_path
5269
5270 # Check that translation expectations can be parsed and we can get a list of
5271 # translatable grd files. |repo_root| and |translation_expectations_path| are
5272 # only passed by tests.
5273 if not repo_root:
5274 repo_root = input_api.PresubmitLocalPath()
5275 if not translation_expectations_path:
5276 translation_expectations_path = input_api.os_path.join(
5277 repo_root, 'tools', 'gritsettings',
5278 'translation_expectations.pyl')
5279 if not grd_files:
5280 grd_files = git_helper.list_grds_in_repository(repo_root)
5281
dpapad8e21b472020-10-23 17:15:035282 # Ignore bogus grd files used only for testing
5283 # ui/webui/resoucres/tools/generate_grd.py.
5284 ignore_path = input_api.os_path.join(
5285 'ui', 'webui', 'resources', 'tools', 'tests')
5286 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5287
Mustafa Emre Acer51f2f742020-03-09 19:41:125288 try:
5289 translation_helper.get_translatable_grds(repo_root, grd_files,
5290 translation_expectations_path)
5291 except Exception as e:
5292 return [output_api.PresubmitNotifyResult(
5293 'Failed to get a list of translatable grd files. This happens when:\n'
5294 ' - One of the modified grd or grdp files cannot be parsed or\n'
5295 ' - %s is not updated.\n'
5296 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5297 return []
Ken Rockotc31f4832020-05-29 18:58:515298
5299
Saagar Sanghavifceeaae2020-08-12 16:40:365300def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515301 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095302 changed_mojoms = input_api.AffectedFiles(
5303 include_deletes=True,
5304 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515305 delta = []
5306 for mojom in changed_mojoms:
5307 old_contents = ''.join(mojom.OldContents()) or None
5308 new_contents = ''.join(mojom.NewContents()) or None
5309 delta.append({
5310 'filename': mojom.LocalPath(),
5311 'old': '\n'.join(mojom.OldContents()) or None,
5312 'new': '\n'.join(mojom.NewContents()) or None,
5313 })
5314
5315 process = input_api.subprocess.Popen(
5316 [input_api.python_executable,
5317 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5318 'public', 'tools', 'mojom',
5319 'check_stable_mojom_compatibility.py'),
5320 '--src-root', input_api.PresubmitLocalPath()],
5321 stdin=input_api.subprocess.PIPE,
5322 stdout=input_api.subprocess.PIPE,
5323 stderr=input_api.subprocess.PIPE,
5324 universal_newlines=True)
5325 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5326 if process.returncode:
5327 return [output_api.PresubmitError(
5328 'One or more [Stable] mojom definitions appears to have been changed '
5329 'in a way that is not backward-compatible.',
5330 long_text=error)]
5331 return []
Dominic Battre645d42342020-12-04 16:14:105332
5333def CheckDeprecationOfPreferences(input_api, output_api):
5334 """Removing a preference should come with a deprecation."""
5335
5336 def FilterFile(affected_file):
5337 """Accept only .cc files and the like."""
5338 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5339 files_to_skip = (_EXCLUDED_PATHS +
5340 _TEST_CODE_EXCLUDED_PATHS +
5341 input_api.DEFAULT_FILES_TO_SKIP)
5342 return input_api.FilterSourceFile(
5343 affected_file,
5344 files_to_check=file_inclusion_pattern,
5345 files_to_skip=files_to_skip)
5346
5347 def ModifiedLines(affected_file):
5348 """Returns a list of tuples (line number, line text) of added and removed
5349 lines.
5350
5351 Deleted lines share the same line number as the previous line.
5352
5353 This relies on the scm diff output describing each changed code section
5354 with a line of the form
5355
5356 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5357 """
5358 line_num = 0
5359 modified_lines = []
5360 for line in affected_file.GenerateScmDiff().splitlines():
5361 # Extract <new line num> of the patch fragment (see format above).
5362 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5363 if m:
5364 line_num = int(m.groups(1)[0])
5365 continue
5366 if ((line.startswith('+') and not line.startswith('++')) or
5367 (line.startswith('-') and not line.startswith('--'))):
5368 modified_lines.append((line_num, line))
5369
5370 if not line.startswith('-'):
5371 line_num += 1
5372 return modified_lines
5373
5374 def FindLineWith(lines, needle):
5375 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5376
5377 If 0 or >1 lines contain `needle`, -1 is returned.
5378 """
5379 matching_line_numbers = [
5380 # + 1 for 1-based counting of line numbers.
5381 i + 1 for i, line
5382 in enumerate(lines)
5383 if needle in line]
5384 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5385
5386 def ModifiedPrefMigration(affected_file):
5387 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5388 # Determine first and last lines of MigrateObsolete.*Pref functions.
5389 new_contents = affected_file.NewContents();
5390 range_1 = (
5391 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5392 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5393 range_2 = (
5394 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5395 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5396 if (-1 in range_1 + range_2):
5397 raise Exception(
5398 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5399
5400 # Check whether any of the modified lines are part of the
5401 # MigrateObsolete.*Pref functions.
5402 for line_nr, line in ModifiedLines(affected_file):
5403 if (range_1[0] <= line_nr <= range_1[1] or
5404 range_2[0] <= line_nr <= range_2[1]):
5405 return True
5406 return False
5407
5408 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5409 browser_prefs_file_pattern = input_api.re.compile(
5410 r'chrome/browser/prefs/browser_prefs.cc')
5411
5412 changes = input_api.AffectedFiles(include_deletes=True,
5413 file_filter=FilterFile)
5414 potential_problems = []
5415 for f in changes:
5416 for line in f.GenerateScmDiff().splitlines():
5417 # Check deleted lines for pref registrations.
5418 if (line.startswith('-') and not line.startswith('--') and
5419 register_pref_pattern.search(line)):
5420 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5421
5422 if browser_prefs_file_pattern.search(f.LocalPath()):
5423 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5424 # assume that they knew that they have to deprecate preferences and don't
5425 # warn.
5426 try:
5427 if ModifiedPrefMigration(f):
5428 return []
5429 except Exception as e:
5430 return [output_api.PresubmitError(str(e))]
5431
5432 if potential_problems:
5433 return [output_api.PresubmitPromptWarning(
5434 'Discovered possible removal of preference registrations.\n\n'
5435 'Please make sure to properly deprecate preferences by clearing their\n'
5436 'value for a couple of milestones before finally removing the code.\n'
5437 'Otherwise data may stay in the preferences files forever. See\n'
5438 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5439 'This may be a false positive warning (e.g. if you move preference\n'
5440 'registrations to a different place).\n',
5441 potential_problems
5442 )]
5443 return []