blob: 605ab66dd86805dc65266623ec94ab95955ff5c5 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Saagar Sanghavifceeaae2020-08-12 16:40:3610PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Ilya Shermane8a7d2d2020-07-25 04:33:4713 # Generated file.
14 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2615 r"client_variations.js"),
Egor Paskoce145c42018-09-28 19:31:0416 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
17 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
18 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
19 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
20 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4921 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4623 # sqlite is an imported third party dependency.
24 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0425 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5426 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5327 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1228 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0429 r".+[\\/]pnacl_shim\.c$",
30 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0431 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1432 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0433 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5434 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0435 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4036)
[email protected]ca8d1982009-02-19 16:33:1237
wnwenbdc444e2016-05-25 13:44:1538
[email protected]06e6d0ff2012-12-11 01:36:4439# Fragment of a regular expression that matches C++ and Objective-C++
40# implementation files.
41_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
42
wnwenbdc444e2016-05-25 13:44:1543
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1944# Fragment of a regular expression that matches C++ and Objective-C++
45# header files.
46_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
47
48
[email protected]06e6d0ff2012-12-11 01:36:4449# Regular expression that matches code only used for test binaries
50# (best effort).
51_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0452 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4453 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1354 # Test suite files, like:
55 # foo_browsertest.cc
56 # bar_unittest_mac.cc (suffix)
57 # baz_unittests.cc (plural)
58 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1259 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1860 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4461 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0462 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4363 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0464 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4365 # Web test harness.
66 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4767 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0468 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0869 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0470 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4171 # EarlGrey app side code for tests.
72 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1773 # Views Examples code
74 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4175 # Chromium Codelab
76 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4477)
[email protected]ca8d1982009-02-19 16:33:1278
Daniel Bratell609102be2019-03-27 20:53:2179_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1580
[email protected]eea609a2011-11-18 13:10:1281_TEST_ONLY_WARNING = (
82 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5583 'production code. If you are doing this from inside another method\n'
84 'named as *ForTesting(), then consider exposing things to have tests\n'
85 'make that same call directly.\n'
86 'If that is not possible, you may put a comment on the same line with\n'
87 ' // IN-TEST \n'
88 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
89 'method and can be ignored. Do not do this inside production code.\n'
90 'The android-binary-size trybot will block if the method exists in the\n'
91 'release apk.')
[email protected]eea609a2011-11-18 13:10:1292
93
[email protected]cf9b78f2012-11-14 11:40:2894_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4095 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2196 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
97 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2898
Michael Thiessen44457642020-02-06 00:24:1599# Format: Sequence of tuples containing:
100# * Full import path.
101# * Sequence of strings to show when the pattern matches.
102# * Sequence of path or filename exceptions to this rule
103_BANNED_JAVA_IMPORTS = (
104 (
Colin Blundell170d78c82020-03-12 13:56:04105 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15106 (
107 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
108 ),
109 (
110 'net/android/javatests/src/org/chromium/net/'
111 'AndroidProxySelectorTest.java',
112 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04113 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15114 ),
115 ),
Michael Thiessened631912020-08-07 19:01:31116 (
117 'android.support.test.rule.UiThreadTestRule;',
118 (
119 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43120 '@org.chromium.base.test.UiThreadTest on test methods that should run '
121 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31122 ),
123 (),
124 ),
125 (
126 'android.support.test.annotation.UiThreadTest;',
127 (
128 'Do not use android.support.test.annotation.UiThreadTest, use '
129 'org.chromium.base.test.UiThreadTest instead. See '
130 'https://crbug.com/1111893.',
131 ),
132 ()
Michael Thiessenfd6919b2020-12-08 20:44:01133 ),
134 (
135 'android.support.test.rule.ActivityTestRule;',
136 (
137 'Do not use ActivityTestRule, use '
138 'org.chromium.base.test.BaseActivityTestRule instead.',
139 ),
140 (
141 'components/cronet/',
142 )
Michael Thiessened631912020-08-07 19:01:31143 )
Michael Thiessen44457642020-02-06 00:24:15144)
wnwenbdc444e2016-05-25 13:44:15145
Daniel Bratell609102be2019-03-27 20:53:21146# Format: Sequence of tuples containing:
147# * String pattern or, if starting with a slash, a regular expression.
148# * Sequence of strings to show when the pattern matches.
149# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41150_BANNED_JAVA_FUNCTIONS = (
151 (
152 'StrictMode.allowThreadDiskReads()',
153 (
154 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
155 'directly.',
156 ),
157 False,
158 ),
159 (
160 'StrictMode.allowThreadDiskWrites()',
161 (
162 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
163 'directly.',
164 ),
165 False,
166 ),
Michael Thiessen0f2547e2020-07-27 21:55:36167 (
168 '.waitForIdleSync()',
169 (
170 'Do not use waitForIdleSync as it masks underlying issues. There is '
171 'almost always something else you should wait on instead.',
172 ),
173 False,
174 ),
Eric Stevensona9a980972017-09-23 00:04:41175)
176
Daniel Bratell609102be2019-03-27 20:53:21177# Format: Sequence of tuples containing:
178# * String pattern or, if starting with a slash, a regular expression.
179# * Sequence of strings to show when the pattern matches.
180# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59181_BANNED_OBJC_FUNCTIONS = (
182 (
183 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20184 (
185 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59186 'prohibited. Please use CrTrackingArea instead.',
187 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
188 ),
189 False,
190 ),
191 (
[email protected]eaae1972014-04-16 04:17:26192 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20193 (
194 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59195 'instead.',
196 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
197 ),
198 False,
199 ),
200 (
201 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20202 (
203 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59204 'Please use |convertPoint:(point) fromView:nil| instead.',
205 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
206 ),
207 True,
208 ),
209 (
210 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20211 (
212 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59213 'Please use |convertPoint:(point) toView:nil| instead.',
214 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
215 ),
216 True,
217 ),
218 (
219 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20220 (
221 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59222 'Please use |convertRect:(point) fromView:nil| instead.',
223 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
224 ),
225 True,
226 ),
227 (
228 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20229 (
230 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59231 'Please use |convertRect:(point) toView:nil| instead.',
232 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
233 ),
234 True,
235 ),
236 (
237 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20238 (
239 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59240 'Please use |convertSize:(point) fromView:nil| instead.',
241 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
242 ),
243 True,
244 ),
245 (
246 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20247 (
248 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59249 'Please use |convertSize:(point) toView:nil| instead.',
250 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
251 ),
252 True,
253 ),
jif65398702016-10-27 10:19:48254 (
255 r"/\s+UTF8String\s*]",
256 (
257 'The use of -[NSString UTF8String] is dangerous as it can return null',
258 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
259 'Please use |SysNSStringToUTF8| instead.',
260 ),
261 True,
262 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34263 (
264 r'__unsafe_unretained',
265 (
266 'The use of __unsafe_unretained is almost certainly wrong, unless',
267 'when interacting with NSFastEnumeration or NSInvocation.',
268 'Please use __weak in files build with ARC, nothing otherwise.',
269 ),
270 False,
271 ),
Avi Drissman7382afa02019-04-29 23:27:13272 (
273 'freeWhenDone:NO',
274 (
275 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
276 'Foundation types is prohibited.',
277 ),
278 True,
279 ),
[email protected]127f18ec2012-06-16 05:05:59280)
281
Daniel Bratell609102be2019-03-27 20:53:21282# Format: Sequence of tuples containing:
283# * String pattern or, if starting with a slash, a regular expression.
284# * Sequence of strings to show when the pattern matches.
285# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54286_BANNED_IOS_OBJC_FUNCTIONS = (
287 (
288 r'/\bTEST[(]',
289 (
290 'TEST() macro should not be used in Objective-C++ code as it does not ',
291 'drain the autorelease pool at the end of the test. Use TEST_F() ',
292 'macro instead with a fixture inheriting from PlatformTest (or a ',
293 'typedef).'
294 ),
295 True,
296 ),
297 (
298 r'/\btesting::Test\b',
299 (
300 'testing::Test should not be used in Objective-C++ code as it does ',
301 'not drain the autorelease pool at the end of the test. Use ',
302 'PlatformTest instead.'
303 ),
304 True,
305 ),
306)
307
Peter K. Lee6c03ccff2019-07-15 14:40:05308# Format: Sequence of tuples containing:
309# * String pattern or, if starting with a slash, a regular expression.
310# * Sequence of strings to show when the pattern matches.
311# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
312_BANNED_IOS_EGTEST_FUNCTIONS = (
313 (
314 r'/\bEXPECT_OCMOCK_VERIFY\b',
315 (
316 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
317 'it is meant for GTests. Use [mock verify] instead.'
318 ),
319 True,
320 ),
321)
322
danakj7a2b7082019-05-21 21:13:51323# Directories that contain deprecated Bind() or Callback types.
324# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36325# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51326# echo "-- $i"
Alexander Cooperd1244c582021-01-26 02:25:27327# (cd $i; git grep -nP \
328# 'base::(Bind\(|(Cancelable)?(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51329# done
330#
331# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
332# when they have been converted to modern callback types (OnceCallback,
333# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
334# checks for them and prevent regressions.
335_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51336 '^base/callback.h', # Intentional.
Alex Turnerb3ea38c2020-11-25 18:03:07337 '^base/cancelable_callback.h', # Intentional.
Alexander Cooperb3f1af662021-02-01 19:47:26338 "^chrome/browser/ash/accessibility/",
Alexander Cooper6b447b22020-07-22 00:47:18339 '^chrome/browser/media_galleries/',
Alexander Cooperb3f1af662021-02-01 19:47:26340 "^chrome/browser/metrics/",
Alexander Cooperb3f1af662021-02-01 19:47:26341 "^chrome/browser/prefetch/no_state_prefetch/",
342 '^chrome/browser/previews/',
Alexander Cooper6b447b22020-07-22 00:47:18343 '^chrome/browser/resources/chromeos/accessibility/',
Alexander Cooper6b447b22020-07-22 00:47:18344 '^chrome/browser/sync_file_system/',
Alexander Cooperb3f1af662021-02-01 19:47:26345 "^components/browsing_data/content/",
Alexander Cooperb3f1af662021-02-01 19:47:26346 "^components/feature_engagement/internal/",
347 "^docs/callback\\.md", # Intentional
348 "^docs/webui_explainer\\.md",
349 "^docs/process/lsc/large_scale_changes\\.md", # Intentional
350 "^docs/security/mojo\\.md",
351 "^docs/threading_and_tasks\\.md",
352 "^docs/ui/learn/bestpractices/layout\\.md",
Alan Cutter04a00642020-03-02 01:45:20353 '^extensions/browser/',
354 '^extensions/renderer/',
danakj7a2b7082019-05-21 21:13:51355 '^ppapi/proxy/',
Alexander Cooperb3f1af662021-02-01 19:47:26356 '^third_party/blink/PRESUBMIT_test.py', # Intentional.
357 '^third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py' # Intentional pylint: disable=line-too-long
danakj7a2b7082019-05-21 21:13:51358 '^tools/clang/base_bind_rewriters/', # Intentional.
359 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51360))
[email protected]127f18ec2012-06-16 05:05:59361
Alexander Cooper46a92712021-01-30 00:00:20362# Directories that contain deprecated CallbackList types.
363# Find sub-directories from a given directory by running:
364# for i in `find . -maxdepth 1 -type d|sort`; do
365# echo "-- $i"
366# (cd $i; git grep -nP 'base::CallbackList<'|wc -l)
367# done
368#
369# TODO(crbug.com/1113007): Remove (or narrow the scope of) paths from this list
370# when they have been converted to modern callback list types (OnceCallback,
371# RepeatingCallback) in order to enable presubmit checks for them and prevent
372# regressions.
373_NOT_CONVERTED_TO_MODERN_CALLBACK_LIST = '|'.join((
374 r'^chrome/browser/android/oom_intervention/near_oom_monitor\.h',
375 r'^chrome/browser/ash/account_manager/child_account_type_changed_user_data\.h', # pylint: disable=line-too-long
376 r'^chrome/browser/browser_switcher/',
377 r'^chrome/browser/chromeos/',
378 r'^chrome/browser/media/router/providers/cast/',
379 r'^chrome/brwoser/sessions/session_restore\.cc',
380 r'^chrome/browser/supervised_user/',
381 r'^chrome/browser/ui/',
382 r'^chromecast/external_mojo/external_service_support/',
383 r'^components/captive_portal/content/captive_portal_service\.h',
384 r'^components/keyed_service/core/keyed_service_shutdown_notifier\.h',
385 r'^components/media_router/browser/',
386 r'^components/ntp_tils/custom_links_manager_impl\.h',
387 r'^components/password_manager/core/browser/hash_password_manager\.h',
388 r'^components/suggestions/suggestions_service\.h',
389 r'^components/sync_device_info/',
390 r'^components/sync_sessions/session_sync_service_impl\.h',
391 r'^components/zoom/zoom_event_manager\.h',
392 r'^content/browser/host_zoom_map_impl\.h',
393 r'^content/browser/network_service_instance_impl\.h',
394 r'^content/browser/rendeer_host/render_process_host_impl\.cc',
395 r'^extensions/test/extension_test_notification_observer\.h',
396 r'^ios/chrome/browser/tabs/tab_parenting_global_observer\.h',
397 r'^ios/net/cookies/cookie_store_ios\.h',
398 r'^net/cookies/cookie_monster_change_dispatcher\.h',
399 r'^remoting/signaling/messaging_client\.h',
400 r'^services/device/battery/battery_status_service\.h',
401 r'^services/device/geolocation/',
402 r'^weblayer/browser/i18n_util\.cc',
403 r'^weblayer/public/cookie_manager\.h',
404))
405
Daniel Bratell609102be2019-03-27 20:53:21406# Format: Sequence of tuples containing:
407# * String pattern or, if starting with a slash, a regular expression.
408# * Sequence of strings to show when the pattern matches.
409# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
410# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59411_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20412 (
Peter Kasting94a56c42019-10-25 21:54:04413 r'/\busing namespace ',
414 (
415 'Using directives ("using namespace x") are banned by the Google Style',
416 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
417 'Explicitly qualify symbols or use using declarations ("using x::foo").',
418 ),
419 True,
420 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
421 ),
Antonio Gomes07300d02019-03-13 20:59:57422 # Make sure that gtest's FRIEND_TEST() macro is not used; the
423 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
424 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53425 (
[email protected]23e6cbc2012-06-16 18:51:20426 'FRIEND_TEST(',
427 (
[email protected]e3c945502012-06-26 20:01:49428 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20429 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
430 ),
431 False,
[email protected]7345da02012-11-27 14:31:49432 (),
[email protected]23e6cbc2012-06-16 18:51:20433 ),
434 (
tomhudsone2c14d552016-05-26 17:07:46435 'setMatrixClip',
436 (
437 'Overriding setMatrixClip() is prohibited; ',
438 'the base function is deprecated. ',
439 ),
440 True,
441 (),
442 ),
443 (
[email protected]52657f62013-05-20 05:30:31444 'SkRefPtr',
445 (
446 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22447 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31448 ),
449 True,
450 (),
451 ),
452 (
453 'SkAutoRef',
454 (
455 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22456 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31457 ),
458 True,
459 (),
460 ),
461 (
462 'SkAutoTUnref',
463 (
464 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22465 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31466 ),
467 True,
468 (),
469 ),
470 (
471 'SkAutoUnref',
472 (
473 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
474 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22475 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31476 ),
477 True,
478 (),
479 ),
[email protected]d89eec82013-12-03 14:10:59480 (
481 r'/HANDLE_EINTR\(.*close',
482 (
483 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
484 'descriptor will be closed, and it is incorrect to retry the close.',
485 'Either call close directly and ignore its return value, or wrap close',
486 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
487 ),
488 True,
489 (),
490 ),
491 (
492 r'/IGNORE_EINTR\((?!.*close)',
493 (
494 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
495 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
496 ),
497 True,
498 (
499 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04500 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
501 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59502 ),
503 ),
[email protected]ec5b3f02014-04-04 18:43:43504 (
505 r'/v8::Extension\(',
506 (
507 'Do not introduce new v8::Extensions into the code base, use',
508 'gin::Wrappable instead. See http://crbug.com/334679',
509 ),
510 True,
[email protected]f55c90ee62014-04-12 00:50:03511 (
Egor Paskoce145c42018-09-28 19:31:04512 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03513 ),
[email protected]ec5b3f02014-04-04 18:43:43514 ),
skyostilf9469f72015-04-20 10:38:52515 (
jame2d1a952016-04-02 00:27:10516 '#pragma comment(lib,',
517 (
518 'Specify libraries to link with in build files and not in the source.',
519 ),
520 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41521 (
tzik3f295992018-12-04 20:32:23522 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04523 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41524 ),
jame2d1a952016-04-02 00:27:10525 ),
fdorayc4ac18d2017-05-01 21:39:59526 (
Gabriel Charette7cc6c432018-04-25 20:52:02527 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59528 (
529 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
530 ),
531 False,
532 (),
533 ),
534 (
Gabriel Charette7cc6c432018-04-25 20:52:02535 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59536 (
537 'Consider using THREAD_CHECKER macros instead of the class directly.',
538 ),
539 False,
540 (),
541 ),
dbeamb6f4fde2017-06-15 04:03:06542 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06543 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
544 (
545 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
546 'deprecated (http://crbug.com/634507). Please avoid converting away',
547 'from the Time types in Chromium code, especially if any math is',
548 'being done on time values. For interfacing with platform/library',
549 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
550 'type converter methods instead. For faking TimeXXX values (for unit',
551 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
552 'other use cases, please contact base/time/OWNERS.',
553 ),
554 False,
555 (),
556 ),
557 (
dbeamb6f4fde2017-06-15 04:03:06558 'CallJavascriptFunctionUnsafe',
559 (
560 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
561 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
562 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
563 ),
564 False,
565 (
Egor Paskoce145c42018-09-28 19:31:04566 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
567 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
568 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06569 ),
570 ),
dskiba1474c2bfd62017-07-20 02:19:24571 (
572 'leveldb::DB::Open',
573 (
574 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
575 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
576 "Chrome's tracing, making their memory usage visible.",
577 ),
578 True,
579 (
580 r'^third_party/leveldatabase/.*\.(cc|h)$',
581 ),
Gabriel Charette0592c3a2017-07-26 12:02:04582 ),
583 (
Chris Mumfordc38afb62017-10-09 17:55:08584 'leveldb::NewMemEnv',
585 (
586 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58587 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
588 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08589 ),
590 True,
591 (
592 r'^third_party/leveldatabase/.*\.(cc|h)$',
593 ),
594 ),
595 (
Gabriel Charetted9839bc2017-07-29 14:17:47596 'RunLoop::QuitCurrent',
597 (
Robert Liao64b7ab22017-08-04 23:03:43598 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
599 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47600 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41601 False,
Gabriel Charetted9839bc2017-07-29 14:17:47602 (),
Gabriel Charettea44975052017-08-21 23:14:04603 ),
604 (
605 'base::ScopedMockTimeMessageLoopTaskRunner',
606 (
Gabriel Charette87cc1af2018-04-25 20:52:51607 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11608 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51609 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
610 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
611 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04612 ),
Gabriel Charette87cc1af2018-04-25 20:52:51613 False,
Gabriel Charettea44975052017-08-21 23:14:04614 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57615 ),
616 (
Dave Tapuska98199b612019-07-10 13:30:44617 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57618 (
619 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02620 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57621 ),
622 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16623 # Abseil's benchmarks never linked into chrome.
624 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38625 ),
626 (
Peter Kasting991618a62019-06-17 22:00:09627 r'/\bstd::stoi\b',
628 (
629 'std::stoi uses exceptions to communicate results. ',
630 'Use base::StringToInt() instead.',
631 ),
632 True,
633 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
634 ),
635 (
636 r'/\bstd::stol\b',
637 (
638 'std::stol uses exceptions to communicate results. ',
639 'Use base::StringToInt() instead.',
640 ),
641 True,
642 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
643 ),
644 (
645 r'/\bstd::stoul\b',
646 (
647 'std::stoul uses exceptions to communicate results. ',
648 'Use base::StringToUint() instead.',
649 ),
650 True,
651 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
652 ),
653 (
654 r'/\bstd::stoll\b',
655 (
656 'std::stoll uses exceptions to communicate results. ',
657 'Use base::StringToInt64() instead.',
658 ),
659 True,
660 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
661 ),
662 (
663 r'/\bstd::stoull\b',
664 (
665 'std::stoull uses exceptions to communicate results. ',
666 'Use base::StringToUint64() instead.',
667 ),
668 True,
669 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
670 ),
671 (
672 r'/\bstd::stof\b',
673 (
674 'std::stof uses exceptions to communicate results. ',
675 'For locale-independent values, e.g. reading numbers from disk',
676 'profiles, use base::StringToDouble().',
677 'For user-visible values, parse using ICU.',
678 ),
679 True,
680 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
681 ),
682 (
683 r'/\bstd::stod\b',
684 (
685 'std::stod uses exceptions to communicate results. ',
686 'For locale-independent values, e.g. reading numbers from disk',
687 'profiles, use base::StringToDouble().',
688 'For user-visible values, parse using ICU.',
689 ),
690 True,
691 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
692 ),
693 (
694 r'/\bstd::stold\b',
695 (
696 'std::stold uses exceptions to communicate results. ',
697 'For locale-independent values, e.g. reading numbers from disk',
698 'profiles, use base::StringToDouble().',
699 'For user-visible values, parse using ICU.',
700 ),
701 True,
702 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
703 ),
704 (
Daniel Bratell69334cc2019-03-26 11:07:45705 r'/\bstd::to_string\b',
706 (
707 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09708 'For locale-independent strings, e.g. writing numbers to disk',
709 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45710 'For user-visible strings, use base::FormatNumber() and',
711 'the related functions in base/i18n/number_formatting.h.',
712 ),
Peter Kasting991618a62019-06-17 22:00:09713 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21714 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45715 ),
716 (
717 r'/\bstd::shared_ptr\b',
718 (
719 'std::shared_ptr should not be used. Use scoped_refptr instead.',
720 ),
721 True,
Ulan Degenbaev947043882021-02-10 14:02:31722 [
723 # Needed for interop with third-party library.
724 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57725 'array_buffer_contents\.(cc|h)',
Ulan Degenbaev947043882021-02-10 14:02:31726 'gin/array_buffer.cc',
727 'gin/array_buffer.h',
Alex Chau9eb03cdd52020-07-13 21:04:57728 'chrome/services/sharing/nearby/',
729 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21730 ),
731 (
Peter Kasting991618a62019-06-17 22:00:09732 r'/\bstd::weak_ptr\b',
733 (
734 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
735 ),
736 True,
737 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
738 ),
739 (
Daniel Bratell609102be2019-03-27 20:53:21740 r'/\blong long\b',
741 (
742 'long long is banned. Use stdint.h if you need a 64 bit number.',
743 ),
744 False, # Only a warning since it is already used.
745 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
746 ),
747 (
748 r'/\bstd::bind\b',
749 (
750 'std::bind is banned because of lifetime risks.',
751 'Use base::BindOnce or base::BindRepeating instead.',
752 ),
753 True,
754 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
755 ),
756 (
757 r'/\b#include <chrono>\b',
758 (
759 '<chrono> overlaps with Time APIs in base. Keep using',
760 'base classes.',
761 ),
762 True,
763 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
764 ),
765 (
766 r'/\b#include <exception>\b',
767 (
768 'Exceptions are banned and disabled in Chromium.',
769 ),
770 True,
771 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
772 ),
773 (
774 r'/\bstd::function\b',
775 (
776 'std::function is banned. Instead use base::Callback which directly',
777 'supports Chromium\'s weak pointers, ref counting and more.',
778 ),
Peter Kasting991618a62019-06-17 22:00:09779 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21780 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
781 ),
782 (
783 r'/\b#include <random>\b',
784 (
785 'Do not use any random number engines from <random>. Instead',
786 'use base::RandomBitGenerator.',
787 ),
788 True,
789 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
790 ),
791 (
Tom Andersona95e12042020-09-09 23:08:00792 r'/\b#include <X11/',
793 (
794 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
795 ),
796 True,
797 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
798 ),
799 (
Daniel Bratell609102be2019-03-27 20:53:21800 r'/\bstd::ratio\b',
801 (
802 'std::ratio is banned by the Google Style Guide.',
803 ),
804 True,
805 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45806 ),
807 (
Francois Doray43670e32017-09-27 12:40:38808 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
809 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
810 (
811 'Use the new API in base/threading/thread_restrictions.h.',
812 ),
Gabriel Charette04b138f2018-08-06 00:03:22813 False,
Francois Doray43670e32017-09-27 12:40:38814 (),
815 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38816 (
danakj7a2b7082019-05-21 21:13:51817 r'/\bbase::Bind\(',
818 (
819 'Please use base::Bind{Once,Repeating} instead',
820 'of base::Bind. (crbug.com/714018)',
821 ),
822 False,
Erik Staaba737d7602019-11-25 18:41:07823 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51824 ),
825 (
826 r'/\bbase::Callback[<:]',
827 (
828 'Please use base::{Once,Repeating}Callback instead',
829 'of base::Callback. (crbug.com/714018)',
830 ),
831 False,
Erik Staaba737d7602019-11-25 18:41:07832 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51833 ),
834 (
835 r'/\bbase::Closure\b',
836 (
837 'Please use base::{Once,Repeating}Closure instead',
838 'of base::Closure. (crbug.com/714018)',
839 ),
840 False,
Erik Staaba737d7602019-11-25 18:41:07841 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51842 ),
843 (
Alex Turnerb3ea38c2020-11-25 18:03:07844 r'/\bbase::CancelableCallback[<:]',
845 (
846 'Please use base::Cancelable{Once,Repeating}Callback instead',
847 'of base::CancelableCallback. (crbug.com/714018)',
848 ),
849 False,
850 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
851 ),
852 (
853 r'/\bbase::CancelableClosure\b',
854 (
855 'Please use base::Cancelable{Once,Repeating}Closure instead',
856 'of base::CancelableClosure. (crbug.com/714018)',
857 ),
858 False,
859 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
860 ),
861 (
Alexander Cooper46a92712021-01-30 00:00:20862 r'/\bbase::CallbackList<',
863 (
864 'Please use base::{Once,Repeating}CallbackList instead',
865 'of base::CallbackList. (crbug.com/1113007)'
866 ),
867 False,
868 (_NOT_CONVERTED_TO_MODERN_CALLBACK_LIST,),
869 ),
870 (
Michael Giuffrida7f93d6922019-04-19 14:39:58871 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19872 (
873 'RunMessageLoop is deprecated, use RunLoop instead.',
874 ),
875 False,
876 (),
877 ),
878 (
Dave Tapuska98199b612019-07-10 13:30:44879 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19880 (
881 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
882 ),
883 False,
884 (),
885 ),
886 (
Dave Tapuska98199b612019-07-10 13:30:44887 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19888 (
889 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
890 "if you're convinced you need this.",
891 ),
892 False,
893 (),
894 ),
895 (
Dave Tapuska98199b612019-07-10 13:30:44896 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19897 (
898 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04899 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19900 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
901 'async events instead of flushing threads.',
902 ),
903 False,
904 (),
905 ),
906 (
907 r'MessageLoopRunner',
908 (
909 'MessageLoopRunner is deprecated, use RunLoop instead.',
910 ),
911 False,
912 (),
913 ),
914 (
Dave Tapuska98199b612019-07-10 13:30:44915 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19916 (
917 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
918 "gab@ if you found a use case where this is the only solution.",
919 ),
920 False,
921 (),
922 ),
923 (
Victor Costane48a2e82019-03-15 22:02:34924 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16925 (
Victor Costane48a2e82019-03-15 22:02:34926 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16927 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
928 ),
929 True,
930 (
931 r'^sql/initialization\.(cc|h)$',
932 r'^third_party/sqlite/.*\.(c|cc|h)$',
933 ),
934 ),
Matt Menke7f520a82018-03-28 21:38:37935 (
Dave Tapuska98199b612019-07-10 13:30:44936 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47937 (
938 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
939 'base::RandomShuffle instead.'
940 ),
941 True,
942 (),
943 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24944 (
945 'ios/web/public/test/http_server',
946 (
947 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
948 ),
949 False,
950 (),
951 ),
Robert Liao764c9492019-01-24 18:46:28952 (
953 'GetAddressOf',
954 (
955 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53956 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11957 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53958 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28959 ),
960 True,
961 (),
962 ),
Antonio Gomes07300d02019-03-13 20:59:57963 (
Ben Lewisa9514602019-04-29 17:53:05964 'SHFileOperation',
965 (
966 'SHFileOperation was deprecated in Windows Vista, and there are less ',
967 'complex functions to achieve the same goals. Use IFileOperation for ',
968 'any esoteric actions instead.'
969 ),
970 True,
971 (),
972 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18973 (
Cliff Smolinsky81951642019-04-30 21:39:51974 'StringFromGUID2',
975 (
976 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24977 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51978 ),
979 True,
980 (
981 r'/base/win/win_util_unittest.cc'
982 ),
983 ),
984 (
985 'StringFromCLSID',
986 (
987 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24988 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51989 ),
990 True,
991 (
992 r'/base/win/win_util_unittest.cc'
993 ),
994 ),
995 (
Avi Drissman7382afa02019-04-29 23:27:13996 'kCFAllocatorNull',
997 (
998 'The use of kCFAllocatorNull with the NoCopy creation of ',
999 'CoreFoundation types is prohibited.',
1000 ),
1001 True,
1002 (),
1003 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291004 (
1005 'mojo::ConvertTo',
1006 (
1007 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1008 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1009 'StringTraits if you would like to convert between custom types and',
1010 'the wire format of mojom types.'
1011 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221012 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291013 (
Wezf89dec092019-09-11 19:38:331014 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1015 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291016 r'^third_party/blink/.*\.(cc|h)$',
1017 r'^content/renderer/.*\.(cc|h)$',
1018 ),
1019 ),
Robert Liao1d78df52019-11-11 20:02:011020 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161021 'GetInterfaceProvider',
1022 (
1023 'InterfaceProvider is deprecated.',
1024 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1025 'or Platform::GetBrowserInterfaceBroker.'
1026 ),
1027 False,
1028 (),
1029 ),
1030 (
Robert Liao1d78df52019-11-11 20:02:011031 'CComPtr',
1032 (
1033 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1034 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1035 'details.'
1036 ),
1037 False,
1038 (),
1039 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201040 (
1041 r'/\b(IFACE|STD)METHOD_?\(',
1042 (
1043 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1044 'Instead, always use IFACEMETHODIMP in the declaration.'
1045 ),
1046 False,
1047 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1048 ),
Allen Bauer53b43fb12020-03-12 17:21:471049 (
1050 'set_owned_by_client',
1051 (
1052 'set_owned_by_client is deprecated.',
1053 'views::View already owns the child views by default. This introduces ',
1054 'a competing ownership model which makes the code difficult to reason ',
1055 'about. See http://crbug.com/1044687 for more details.'
1056 ),
1057 False,
1058 (),
1059 ),
Eric Secklerbe6f48d2020-05-06 18:09:121060 (
1061 r'/\bTRACE_EVENT_ASYNC_',
1062 (
1063 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1064 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1065 ),
1066 False,
1067 (
1068 r'^base/trace_event/.*',
1069 r'^base/tracing/.*',
1070 ),
1071 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:261072 (
1073 r'/\bScopedObserver',
1074 (
1075 'ScopedObserver is deprecated.',
1076 'Please use base::ScopedObservation for observing a single source,',
1077 'or base::ScopedMultiSourceObservation for observing multple sources',
1078 ),
1079 False,
1080 (),
1081 ),
[email protected]127f18ec2012-06-16 05:05:591082)
1083
Mario Sanchez Prada2472cab2019-09-18 10:58:311084# Format: Sequence of tuples containing:
1085# * String pattern or, if starting with a slash, a regular expression.
1086# * Sequence of strings to show when the pattern matches.
1087_DEPRECATED_MOJO_TYPES = (
1088 (
1089 r'/\bmojo::AssociatedBinding\b',
1090 (
1091 'mojo::AssociatedBinding<Interface> is deprecated.',
1092 'Use mojo::AssociatedReceiver<Interface> instead.',
1093 ),
1094 ),
1095 (
1096 r'/\bmojo::AssociatedBindingSet\b',
1097 (
1098 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1099 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1100 ),
1101 ),
1102 (
1103 r'/\bmojo::AssociatedInterfacePtr\b',
1104 (
1105 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1106 'Use mojo::AssociatedRemote<Interface> instead.',
1107 ),
1108 ),
1109 (
1110 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1111 (
1112 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1113 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1114 ),
1115 ),
1116 (
1117 r'/\bmojo::AssociatedInterfaceRequest\b',
1118 (
1119 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1120 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1121 ),
1122 ),
1123 (
1124 r'/\bmojo::Binding\b',
1125 (
1126 'mojo::Binding<Interface> is deprecated.',
1127 'Use mojo::Receiver<Interface> instead.',
1128 ),
1129 ),
1130 (
1131 r'/\bmojo::BindingSet\b',
1132 (
1133 'mojo::BindingSet<Interface> is deprecated.',
1134 'Use mojo::ReceiverSet<Interface> instead.',
1135 ),
1136 ),
1137 (
1138 r'/\bmojo::InterfacePtr\b',
1139 (
1140 'mojo::InterfacePtr<Interface> is deprecated.',
1141 'Use mojo::Remote<Interface> instead.',
1142 ),
1143 ),
1144 (
1145 r'/\bmojo::InterfacePtrInfo\b',
1146 (
1147 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1148 'Use mojo::PendingRemote<Interface> instead.',
1149 ),
1150 ),
1151 (
1152 r'/\bmojo::InterfaceRequest\b',
1153 (
1154 'mojo::InterfaceRequest<Interface> is deprecated.',
1155 'Use mojo::PendingReceiver<Interface> instead.',
1156 ),
1157 ),
1158 (
1159 r'/\bmojo::MakeRequest\b',
1160 (
1161 'mojo::MakeRequest is deprecated.',
1162 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1163 ),
1164 ),
1165 (
1166 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1167 (
1168 'mojo::MakeRequest is deprecated.',
1169 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181170 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311171 ),
1172 ),
1173 (
1174 r'/\bmojo::MakeStrongBinding\b',
1175 (
1176 'mojo::MakeStrongBinding is deprecated.',
1177 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1178 'mojo::MakeSelfOwnedReceiver() instead.',
1179 ),
1180 ),
1181 (
1182 r'/\bmojo::MakeStrongAssociatedBinding\b',
1183 (
1184 'mojo::MakeStrongAssociatedBinding is deprecated.',
1185 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1186 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1187 ),
1188 ),
1189 (
Gyuyoung Kim4952ba62020-07-07 07:33:441190 r'/\bmojo::StrongAssociatedBinding\b',
1191 (
1192 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1193 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1194 ),
1195 ),
1196 (
1197 r'/\bmojo::StrongBinding\b',
1198 (
1199 'mojo::StrongBinding<Interface> is deprecated.',
1200 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1201 ),
1202 ),
1203 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311204 r'/\bmojo::StrongAssociatedBindingSet\b',
1205 (
1206 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1207 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1208 ),
1209 ),
1210 (
1211 r'/\bmojo::StrongBindingSet\b',
1212 (
1213 'mojo::StrongBindingSet<Interface> is deprecated.',
1214 'Use mojo::UniqueReceiverSet<Interface> instead.',
1215 ),
1216 ),
1217)
wnwenbdc444e2016-05-25 13:44:151218
mlamouria82272622014-09-16 18:45:041219_IPC_ENUM_TRAITS_DEPRECATED = (
1220 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501221 'See http://www.chromium.org/Home/chromium-security/education/'
1222 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041223
Stephen Martinis97a394142018-06-07 23:06:051224_LONG_PATH_ERROR = (
1225 'Some files included in this CL have file names that are too long (> 200'
1226 ' characters). If committed, these files will cause issues on Windows. See'
1227 ' https://crbug.com/612667 for more details.'
1228)
1229
Shenghua Zhangbfaa38b82017-11-16 21:58:021230_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041231 r".*[\\/]BuildHooksAndroidImpl\.java",
1232 r".*[\\/]LicenseContentProvider\.java",
1233 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281234 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021235]
[email protected]127f18ec2012-06-16 05:05:591236
Mohamed Heikald048240a2019-11-12 16:57:371237# List of image extensions that are used as resources in chromium.
1238_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1239
Sean Kau46e29bc2017-08-28 16:31:161240# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401241_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041242 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401243 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041244 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1245 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041246 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431247 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161248]
1249
1250
[email protected]b00342e7f2013-03-26 16:21:541251_VALID_OS_MACROS = (
1252 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081253 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541254 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441255 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121256 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541257 'OS_BSD',
1258 'OS_CAT', # For testing.
1259 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041260 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541261 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371262 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541263 'OS_IOS',
1264 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441265 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541266 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211267 'OS_NACL_NONSFI',
1268 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121269 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541270 'OS_OPENBSD',
1271 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371272 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541273 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541274 'OS_WIN',
1275)
1276
1277
Andrew Grieveb773bad2020-06-05 18:00:381278# These are not checked on the public chromium-presubmit trybot.
1279# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041280# checkouts.
agrievef32bcc72016-04-04 14:57:401281_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381282 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381283]
1284
1285
1286_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041287 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361288 'base/android/jni_generator/jni_generator.pydeps',
1289 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361290 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041291 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361292 'build/android/gyp/aar.pydeps',
1293 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271294 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361295 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381296 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361297 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021298 'build/android/gyp/bytecode_rewriter.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111299 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361300 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361301 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361302 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111303 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041304 'build/android/gyp/create_app_bundle_apks.pydeps',
1305 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361306 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121307 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091308 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221309 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001310 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361311 'build/android/gyp/desugar.pydeps',
1312 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421313 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041314 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361315 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361316 'build/android/gyp/filter_zip.pydeps',
1317 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361318 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361319 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581320 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361321 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141322 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261323 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011324 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041325 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361326 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361327 'build/android/gyp/merge_manifest.pydeps',
1328 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221329 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361330 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461331 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241332 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361333 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461334 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561335 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361336 'build/android/incremental_install/generate_android_manifest.pydeps',
1337 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041338 'build/android/resource_sizes.pydeps',
1339 'build/android/test_runner.pydeps',
1340 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361341 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361342 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321343 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271344 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1345 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001346 'components/cronet/tools/generate_javadoc.pydeps',
1347 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381348 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001349 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381350 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041351 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181352 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041353 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421354 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1355 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131356 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061357 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221358 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401359]
1360
wnwenbdc444e2016-05-25 13:44:151361
agrievef32bcc72016-04-04 14:57:401362_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1363
1364
Eric Boren6fd2b932018-01-25 15:05:081365# Bypass the AUTHORS check for these accounts.
1366_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591367 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451368 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591369 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521370 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071371 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041372 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271373 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041374 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301375 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081376
1377
Daniel Bratell65b033262019-04-23 08:17:061378def _IsCPlusPlusFile(input_api, file_path):
1379 """Returns True if this file contains C++-like code (and not Python,
1380 Go, Java, MarkDown, ...)"""
1381
1382 ext = input_api.os_path.splitext(file_path)[1]
1383 # This list is compatible with CppChecker.IsCppFile but we should
1384 # consider adding ".c" to it. If we do that we can use this function
1385 # at more places in the code.
1386 return ext in (
1387 '.h',
1388 '.cc',
1389 '.cpp',
1390 '.m',
1391 '.mm',
1392 )
1393
1394def _IsCPlusPlusHeaderFile(input_api, file_path):
1395 return input_api.os_path.splitext(file_path)[1] == ".h"
1396
1397
1398def _IsJavaFile(input_api, file_path):
1399 return input_api.os_path.splitext(file_path)[1] == ".java"
1400
1401
1402def _IsProtoFile(input_api, file_path):
1403 return input_api.os_path.splitext(file_path)[1] == ".proto"
1404
Mohamed Heikal5e5b7922020-10-29 18:57:591405
1406def CheckNoUpstreamDepsOnClank(input_api, output_api):
1407 """Prevent additions of dependencies from the upstream repo on //clank."""
1408 # clank can depend on clank
1409 if input_api.change.RepositoryRoot().endswith('clank'):
1410 return []
1411 build_file_patterns = [
1412 r'(.+/)?BUILD\.gn',
1413 r'.+\.gni',
1414 ]
1415 excluded_files = [
1416 r'build[/\\]config[/\\]android[/\\]config\.gni'
1417 ]
1418 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1419
1420 error_message = 'Disallowed import on //clank in an upstream build file:'
1421
1422 def FilterFile(affected_file):
1423 return input_api.FilterSourceFile(
1424 affected_file,
1425 files_to_check=build_file_patterns,
1426 files_to_skip=excluded_files)
1427
1428 problems = []
1429 for f in input_api.AffectedSourceFiles(FilterFile):
1430 local_path = f.LocalPath()
1431 for line_number, line in f.ChangedContents():
1432 if (bad_pattern.search(line)):
1433 problems.append(
1434 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1435 if problems:
1436 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1437 else:
1438 return []
1439
1440
Saagar Sanghavifceeaae2020-08-12 16:40:361441def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191442 """Attempts to prevent use of functions intended only for testing in
1443 non-testing code. For now this is just a best-effort implementation
1444 that ignores header files and may have some false positives. A
1445 better implementation would probably need a proper C++ parser.
1446 """
1447 # We only scan .cc files and the like, as the declaration of
1448 # for-testing functions in header files are hard to distinguish from
1449 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491450 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191451
jochenc0d4808c2015-07-27 09:25:421452 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191453 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091454 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131455 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191456 exclusion_pattern = input_api.re.compile(
1457 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1458 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131459 # Avoid a false positive in this case, where the method name, the ::, and
1460 # the closing { are all on different lines due to line wrapping.
1461 # HelperClassForTesting::
1462 # HelperClassForTesting(
1463 # args)
1464 # : member(0) {}
1465 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191466
1467 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441468 files_to_skip = (_EXCLUDED_PATHS +
1469 _TEST_CODE_EXCLUDED_PATHS +
1470 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191471 return input_api.FilterSourceFile(
1472 affected_file,
James Cook24a504192020-07-23 00:08:441473 files_to_check=file_inclusion_pattern,
1474 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191475
1476 problems = []
1477 for f in input_api.AffectedSourceFiles(FilterFile):
1478 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131479 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241480 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031481 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461482 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131483 not exclusion_pattern.search(line) and
1484 not allowlist_pattern.search(line) and
1485 not in_method_defn):
[email protected]55459852011-08-10 15:17:191486 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031487 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131488 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191489
1490 if problems:
[email protected]f7051d52013-04-02 18:31:421491 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031492 else:
1493 return []
[email protected]55459852011-08-10 15:17:191494
1495
Saagar Sanghavifceeaae2020-08-12 16:40:361496def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231497 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591498 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231499 """
1500 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1501 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1502 name_pattern = r'ForTest(s|ing)?'
1503 # Describes an occurrence of "ForTest*" inside a // comment.
1504 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501505 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551506 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231507 # Catch calls.
1508 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1509 # Ignore definitions. (Comments are ignored separately.)
1510 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1511
1512 problems = []
1513 sources = lambda x: input_api.FilterSourceFile(
1514 x,
James Cook24a504192020-07-23 00:08:441515 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1516 + input_api.DEFAULT_FILES_TO_SKIP),
1517 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231518 )
1519 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1520 local_path = f.LocalPath()
1521 is_inside_javadoc = False
1522 for line_number, line in f.ChangedContents():
1523 if is_inside_javadoc and javadoc_end_re.search(line):
1524 is_inside_javadoc = False
1525 if not is_inside_javadoc and javadoc_start_re.search(line):
1526 is_inside_javadoc = True
1527 if is_inside_javadoc:
1528 continue
1529 if (inclusion_re.search(line) and
1530 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501531 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231532 not exclusion_re.search(line)):
1533 problems.append(
1534 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1535
1536 if problems:
1537 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1538 else:
1539 return []
1540
1541
Saagar Sanghavifceeaae2020-08-12 16:40:361542def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541543 """Checks to make sure no .h files include <iostream>."""
1544 files = []
1545 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1546 input_api.re.MULTILINE)
1547 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1548 if not f.LocalPath().endswith('.h'):
1549 continue
1550 contents = input_api.ReadFile(f)
1551 if pattern.search(contents):
1552 files.append(f)
1553
1554 if len(files):
yolandyandaabc6d2016-04-18 18:29:391555 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061556 'Do not #include <iostream> in header files, since it inserts static '
1557 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541558 '#include <ostream>. See http://crbug.com/94794',
1559 files) ]
1560 return []
1561
Danil Chapovalov3518f362018-08-11 16:13:431562def _CheckNoStrCatRedefines(input_api, output_api):
1563 """Checks no windows headers with StrCat redefined are included directly."""
1564 files = []
1565 pattern_deny = input_api.re.compile(
1566 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1567 input_api.re.MULTILINE)
1568 pattern_allow = input_api.re.compile(
1569 r'^#include\s"base/win/windows_defines.inc"',
1570 input_api.re.MULTILINE)
1571 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1572 contents = input_api.ReadFile(f)
1573 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1574 files.append(f.LocalPath())
1575
1576 if len(files):
1577 return [output_api.PresubmitError(
1578 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1579 'directly since they pollute code with StrCat macro. Instead, '
1580 'include matching header from base/win. See http://crbug.com/856536',
1581 files) ]
1582 return []
1583
[email protected]10689ca2011-09-02 02:31:541584
Saagar Sanghavifceeaae2020-08-12 16:40:361585def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521586 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181587 problems = []
1588 for f in input_api.AffectedFiles():
1589 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1590 continue
1591
1592 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041593 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181594 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1595
1596 if not problems:
1597 return []
1598 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1599 '\n'.join(problems))]
1600
Saagar Sanghavifceeaae2020-08-12 16:40:361601def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341602 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1603
1604 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1605 instead of DISABLED_. To filter false positives, reports are only generated
1606 if a corresponding MAYBE_ line exists.
1607 """
1608 problems = []
1609
1610 # The following two patterns are looked for in tandem - is a test labeled
1611 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1612 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1613 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1614
1615 # This is for the case that a test is disabled on all platforms.
1616 full_disable_pattern = input_api.re.compile(
1617 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1618 input_api.re.MULTILINE)
1619
Katie Df13948e2018-09-25 07:33:441620 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341621 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1622 continue
1623
1624 # Search for MABYE_, DISABLE_ pairs.
1625 disable_lines = {} # Maps of test name to line number.
1626 maybe_lines = {}
1627 for line_num, line in f.ChangedContents():
1628 disable_match = disable_pattern.search(line)
1629 if disable_match:
1630 disable_lines[disable_match.group(1)] = line_num
1631 maybe_match = maybe_pattern.search(line)
1632 if maybe_match:
1633 maybe_lines[maybe_match.group(1)] = line_num
1634
1635 # Search for DISABLE_ occurrences within a TEST() macro.
1636 disable_tests = set(disable_lines.keys())
1637 maybe_tests = set(maybe_lines.keys())
1638 for test in disable_tests.intersection(maybe_tests):
1639 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1640
1641 contents = input_api.ReadFile(f)
1642 full_disable_match = full_disable_pattern.search(contents)
1643 if full_disable_match:
1644 problems.append(' %s' % f.LocalPath())
1645
1646 if not problems:
1647 return []
1648 return [
1649 output_api.PresubmitPromptWarning(
1650 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1651 '\n'.join(problems))
1652 ]
1653
[email protected]72df4e782012-06-21 16:28:181654
Saagar Sanghavifceeaae2020-08-12 16:40:361655def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571656 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521657 errors = []
Hans Wennborg944479f2020-06-25 21:39:251658 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521659 input_api.re.MULTILINE)
1660 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1661 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1662 continue
1663 for lnum, line in f.ChangedContents():
1664 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171665 errors.append(output_api.PresubmitError(
1666 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571667 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171668 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521669 return errors
1670
1671
Weilun Shia487fad2020-10-28 00:10:341672# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1673# more reliable way. See
1674# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191675
wnwenbdc444e2016-05-25 13:44:151676
Saagar Sanghavifceeaae2020-08-12 16:40:361677def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391678 """Check that FlakyTest annotation is our own instead of the android one"""
1679 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1680 files = []
1681 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1682 if f.LocalPath().endswith('Test.java'):
1683 if pattern.search(input_api.ReadFile(f)):
1684 files.append(f)
1685 if len(files):
1686 return [output_api.PresubmitError(
1687 'Use org.chromium.base.test.util.FlakyTest instead of '
1688 'android.test.FlakyTest',
1689 files)]
1690 return []
mcasasb7440c282015-02-04 14:52:191691
wnwenbdc444e2016-05-25 13:44:151692
Saagar Sanghavifceeaae2020-08-12 16:40:361693def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221694 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271695 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221696 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201697 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571698 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341699 '/win/' in f.LocalPath() or
1700 'chrome_elf' in f.LocalPath() or
1701 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201702 continue
[email protected]8ea5d4b2011-09-13 21:49:221703
[email protected]a11dbe9b2012-08-07 01:32:581704 allowWString = False
[email protected]b5c24292011-11-28 14:38:201705 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581706 if 'presubmit: allow wstring' in line:
1707 allowWString = True
1708 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271709 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581710 allowWString = False
1711 else:
1712 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221713
[email protected]55463aa62011-10-12 00:48:271714 if not problems:
1715 return []
1716 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581717 ' If you are calling a cross-platform API that accepts a wstring, '
1718 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271719 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221720
1721
Saagar Sanghavifceeaae2020-08-12 16:40:361722def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441723 """Make sure .DEPS.git is never modified manually."""
1724 if any(f.LocalPath().endswith('.DEPS.git') for f in
1725 input_api.AffectedFiles()):
1726 return [output_api.PresubmitError(
1727 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1728 'automated system based on what\'s in DEPS and your changes will be\n'
1729 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501730 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1731 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441732 'for more information')]
1733 return []
1734
1735
Saagar Sanghavifceeaae2020-08-12 16:40:361736def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471737 """Checks that DEPS file deps are from allowed_hosts."""
1738 # Run only if DEPS file has been modified to annoy fewer bystanders.
1739 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1740 return []
1741 # Outsource work to gclient verify
1742 try:
John Budorickf20c0042019-04-25 23:23:401743 gclient_path = input_api.os_path.join(
1744 input_api.PresubmitLocalPath(),
1745 'third_party', 'depot_tools', 'gclient.py')
1746 input_api.subprocess.check_output(
1747 [input_api.python_executable, gclient_path, 'verify'],
1748 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471749 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201750 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471751 return [output_api.PresubmitError(
1752 'DEPS file must have only git dependencies.',
1753 long_text=error.output)]
1754
1755
Mario Sanchez Prada2472cab2019-09-18 10:58:311756def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1757 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591758 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311759
1760 Returns an string composed of the name of the file, the line number where the
1761 match has been found and the additional text passed as |message| in case the
1762 target type name matches the text inside the line passed as parameter.
1763 """
Peng Huang9c5949a02020-06-11 19:20:541764 result = []
1765
danakjd18e8892020-12-17 17:42:011766 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1767 return result
1768 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541769 return result
1770
Mario Sanchez Prada2472cab2019-09-18 10:58:311771 matched = False
1772 if type_name[0:1] == '/':
1773 regex = type_name[1:]
1774 if input_api.re.search(regex, line):
1775 matched = True
1776 elif type_name in line:
1777 matched = True
1778
Mario Sanchez Prada2472cab2019-09-18 10:58:311779 if matched:
1780 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1781 for message_line in message:
1782 result.append(' %s' % message_line)
1783
1784 return result
1785
1786
Saagar Sanghavifceeaae2020-08-12 16:40:361787def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591788 """Make sure that banned functions are not used."""
1789 warnings = []
1790 errors = []
1791
James Cook24a504192020-07-23 00:08:441792 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151793 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441794 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151795 if input_api.re.match(item, local_path):
1796 return True
1797 return False
1798
Peter K. Lee6c03ccff2019-07-15 14:40:051799 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541800 local_path = affected_file.LocalPath()
1801 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1802 return False
1803 basename = input_api.os_path.basename(local_path)
1804 if 'ios' in basename.split('_'):
1805 return True
1806 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1807 if sep and 'ios' in local_path.split(sep):
1808 return True
1809 return False
1810
wnwenbdc444e2016-05-25 13:44:151811 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311812 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1813 func_name, message)
1814 if problems:
wnwenbdc444e2016-05-25 13:44:151815 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311816 errors.extend(problems)
1817 else:
1818 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151819
Eric Stevensona9a980972017-09-23 00:04:411820 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1821 for f in input_api.AffectedFiles(file_filter=file_filter):
1822 for line_num, line in f.ChangedContents():
1823 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1824 CheckForMatch(f, line_num, line, func_name, message, error)
1825
[email protected]127f18ec2012-06-16 05:05:591826 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1827 for f in input_api.AffectedFiles(file_filter=file_filter):
1828 for line_num, line in f.ChangedContents():
1829 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151830 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591831
Peter K. Lee6c03ccff2019-07-15 14:40:051832 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541833 for line_num, line in f.ChangedContents():
1834 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1835 CheckForMatch(f, line_num, line, func_name, message, error)
1836
Peter K. Lee6c03ccff2019-07-15 14:40:051837 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1838 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1839 for line_num, line in f.ChangedContents():
1840 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1841 CheckForMatch(f, line_num, line, func_name, message, error)
1842
[email protected]127f18ec2012-06-16 05:05:591843 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1844 for f in input_api.AffectedFiles(file_filter=file_filter):
1845 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491846 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441847 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491848 continue
wnwenbdc444e2016-05-25 13:44:151849 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591850
1851 result = []
1852 if (warnings):
1853 result.append(output_api.PresubmitPromptWarning(
1854 'Banned functions were used.\n' + '\n'.join(warnings)))
1855 if (errors):
1856 result.append(output_api.PresubmitError(
1857 'Banned functions were used.\n' + '\n'.join(errors)))
1858 return result
1859
1860
Michael Thiessen44457642020-02-06 00:24:151861def _CheckAndroidNoBannedImports(input_api, output_api):
1862 """Make sure that banned java imports are not used."""
1863 errors = []
1864
1865 def IsException(path, exceptions):
1866 for exception in exceptions:
1867 if (path.startswith(exception)):
1868 return True
1869 return False
1870
1871 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1872 for f in input_api.AffectedFiles(file_filter=file_filter):
1873 for line_num, line in f.ChangedContents():
1874 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1875 if IsException(f.LocalPath(), exceptions):
1876 continue;
1877 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1878 'import ' + import_name, message)
1879 if problems:
1880 errors.extend(problems)
1881 result = []
1882 if (errors):
1883 result.append(output_api.PresubmitError(
1884 'Banned imports were used.\n' + '\n'.join(errors)))
1885 return result
1886
1887
Saagar Sanghavifceeaae2020-08-12 16:40:361888def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311889 """Make sure that old Mojo types are not used."""
1890 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571891 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311892
Mario Sanchez Pradaaab91382019-12-19 08:57:091893 # For any path that is not an "ok" or an "error" path, a warning will be
1894 # raised if deprecated mojo types are found.
1895 ok_paths = ['components/arc']
1896 error_paths = ['third_party/blink', 'content']
1897
Mario Sanchez Prada2472cab2019-09-18 10:58:311898 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1899 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571900 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091901 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311902 continue
1903
1904 for line_num, line in f.ChangedContents():
1905 for func_name, message in _DEPRECATED_MOJO_TYPES:
1906 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1907 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571908
Mario Sanchez Prada2472cab2019-09-18 10:58:311909 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091910 # Raise errors inside |error_paths| and warnings everywhere else.
1911 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571912 errors.extend(problems)
1913 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311914 warnings.extend(problems)
1915
1916 result = []
1917 if (warnings):
1918 result.append(output_api.PresubmitPromptWarning(
1919 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571920 if (errors):
1921 result.append(output_api.PresubmitError(
1922 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311923 return result
1924
1925
Saagar Sanghavifceeaae2020-08-12 16:40:361926def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061927 """Make sure that banned functions are not used."""
1928 files = []
1929 pattern = input_api.re.compile(r'^#pragma\s+once',
1930 input_api.re.MULTILINE)
1931 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1932 if not f.LocalPath().endswith('.h'):
1933 continue
1934 contents = input_api.ReadFile(f)
1935 if pattern.search(contents):
1936 files.append(f)
1937
1938 if files:
1939 return [output_api.PresubmitError(
1940 'Do not use #pragma once in header files.\n'
1941 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1942 files)]
1943 return []
1944
[email protected]127f18ec2012-06-16 05:05:591945
Saagar Sanghavifceeaae2020-08-12 16:40:361946def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121947 """Checks to make sure we don't introduce use of foo ? true : false."""
1948 problems = []
1949 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1950 for f in input_api.AffectedFiles():
1951 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1952 continue
1953
1954 for line_num, line in f.ChangedContents():
1955 if pattern.match(line):
1956 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1957
1958 if not problems:
1959 return []
1960 return [output_api.PresubmitPromptWarning(
1961 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1962 '\n'.join(problems))]
1963
1964
Saagar Sanghavifceeaae2020-08-12 16:40:361965def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281966 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181967 change. Breaking - rules is an error, breaking ! rules is a
1968 warning.
1969 """
mohan.reddyf21db962014-10-16 12:26:471970 import sys
[email protected]55f9f382012-07-31 11:02:181971 # We need to wait until we have an input_api object and use this
1972 # roundabout construct to import checkdeps because this file is
1973 # eval-ed and thus doesn't have __file__.
1974 original_sys_path = sys.path
1975 try:
1976 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471977 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181978 import checkdeps
[email protected]55f9f382012-07-31 11:02:181979 from rules import Rule
1980 finally:
1981 # Restore sys.path to what it was before.
1982 sys.path = original_sys_path
1983
1984 added_includes = []
rhalavati08acd232017-04-03 07:23:281985 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241986 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181987 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061988 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501989 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081990 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061991 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501992 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081993 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061994 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501995 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081996 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181997
[email protected]26385172013-05-09 23:11:351998 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181999
2000 error_descriptions = []
2001 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282002 error_subjects = set()
2003 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362004
[email protected]55f9f382012-07-31 11:02:182005 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2006 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082007 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182008 description_with_path = '%s\n %s' % (path, rule_description)
2009 if rule_type == Rule.DISALLOW:
2010 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282011 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182012 else:
2013 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282014 warning_subjects.add("#includes")
2015
2016 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2017 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082018 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282019 description_with_path = '%s\n %s' % (path, rule_description)
2020 if rule_type == Rule.DISALLOW:
2021 error_descriptions.append(description_with_path)
2022 error_subjects.add("imports")
2023 else:
2024 warning_descriptions.append(description_with_path)
2025 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182026
Jinsuk Kim5a092672017-10-24 22:42:242027 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022028 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082029 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242030 description_with_path = '%s\n %s' % (path, rule_description)
2031 if rule_type == Rule.DISALLOW:
2032 error_descriptions.append(description_with_path)
2033 error_subjects.add("imports")
2034 else:
2035 warning_descriptions.append(description_with_path)
2036 warning_subjects.add("imports")
2037
[email protected]55f9f382012-07-31 11:02:182038 results = []
2039 if error_descriptions:
2040 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282041 'You added one or more %s that violate checkdeps rules.'
2042 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182043 error_descriptions))
2044 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422045 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282046 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182047 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282048 '%s? See relevant DEPS file(s) for details and contacts.' %
2049 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182050 warning_descriptions))
2051 return results
2052
2053
Saagar Sanghavifceeaae2020-08-12 16:40:362054def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222055 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152056 if input_api.platform == 'win32':
2057 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292058 checkperms_tool = input_api.os_path.join(
2059 input_api.PresubmitLocalPath(),
2060 'tools', 'checkperms', 'checkperms.py')
2061 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472062 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392063 with input_api.CreateTemporaryFile() as file_list:
2064 for f in input_api.AffectedFiles():
2065 # checkperms.py file/directory arguments must be relative to the
2066 # repository.
2067 file_list.write(f.LocalPath() + '\n')
2068 file_list.close()
2069 args += ['--file-list', file_list.name]
2070 try:
2071 input_api.subprocess.check_output(args)
2072 return []
2073 except input_api.subprocess.CalledProcessError as error:
2074 return [output_api.PresubmitError(
2075 'checkperms.py failed:',
2076 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222077
2078
Saagar Sanghavifceeaae2020-08-12 16:40:362079def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492080 """Makes sure we don't include ui/aura/window_property.h
2081 in header files.
2082 """
2083 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2084 errors = []
2085 for f in input_api.AffectedFiles():
2086 if not f.LocalPath().endswith('.h'):
2087 continue
2088 for line_num, line in f.ChangedContents():
2089 if pattern.match(line):
2090 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2091
2092 results = []
2093 if errors:
2094 results.append(output_api.PresubmitError(
2095 'Header files should not include ui/aura/window_property.h', errors))
2096 return results
2097
2098
[email protected]70ca77752012-11-20 03:45:032099def _CheckForVersionControlConflictsInFile(input_api, f):
2100 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2101 errors = []
2102 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162103 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232104 # First-level headers in markdown look a lot like version control
2105 # conflict markers. http://daringfireball.net/projects/markdown/basics
2106 continue
[email protected]70ca77752012-11-20 03:45:032107 if pattern.match(line):
2108 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2109 return errors
2110
2111
Saagar Sanghavifceeaae2020-08-12 16:40:362112def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032113 """Usually this is not intentional and will cause a compile failure."""
2114 errors = []
2115 for f in input_api.AffectedFiles():
2116 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2117
2118 results = []
2119 if errors:
2120 results.append(output_api.PresubmitError(
2121 'Version control conflict markers found, please resolve.', errors))
2122 return results
2123
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202124
Saagar Sanghavifceeaae2020-08-12 16:40:362125def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162126 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2127 errors = []
2128 for f in input_api.AffectedFiles():
2129 for line_num, line in f.ChangedContents():
2130 if pattern.search(line):
2131 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2132
2133 results = []
2134 if errors:
2135 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502136 'Found Google support URL addressed by answer number. Please replace '
2137 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162138 return results
2139
[email protected]70ca77752012-11-20 03:45:032140
Saagar Sanghavifceeaae2020-08-12 16:40:362141def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442142 def FilterFile(affected_file):
2143 """Filter function for use with input_api.AffectedSourceFiles,
2144 below. This filters out everything except non-test files from
2145 top-level directories that generally speaking should not hard-code
2146 service URLs (e.g. src/android_webview/, src/content/ and others).
2147 """
2148 return input_api.FilterSourceFile(
2149 affected_file,
James Cook24a504192020-07-23 00:08:442150 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2151 files_to_skip=(_EXCLUDED_PATHS +
2152 _TEST_CODE_EXCLUDED_PATHS +
2153 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442154
reillyi38965732015-11-16 18:27:332155 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2156 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462157 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2158 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442159 problems = [] # items are (filename, line_number, line)
2160 for f in input_api.AffectedSourceFiles(FilterFile):
2161 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462162 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442163 problems.append((f.LocalPath(), line_num, line))
2164
2165 if problems:
[email protected]f7051d52013-04-02 18:31:422166 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442167 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582168 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442169 [' %s:%d: %s' % (
2170 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032171 else:
2172 return []
[email protected]06e6d0ff2012-12-11 01:36:442173
2174
Saagar Sanghavifceeaae2020-08-12 16:40:362175def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292176 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2177 def FileFilter(affected_file):
2178 """Includes directories known to be Chrome OS only."""
2179 return input_api.FilterSourceFile(
2180 affected_file,
James Cook24a504192020-07-23 00:08:442181 files_to_check=('^ash/',
2182 '^chromeos/', # Top-level src/chromeos.
2183 '/chromeos/', # Any path component.
2184 '^components/arc',
2185 '^components/exo'),
2186 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292187
2188 prefs = []
2189 priority_prefs = []
2190 for f in input_api.AffectedFiles(file_filter=FileFilter):
2191 for line_num, line in f.ChangedContents():
2192 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2193 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2194 prefs.append(' %s' % line)
2195 if input_api.re.search(
2196 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2197 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2198 priority_prefs.append(' %s' % line)
2199
2200 results = []
2201 if (prefs):
2202 results.append(output_api.PresubmitPromptWarning(
2203 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2204 'by browser sync settings. If these prefs should be controlled by OS '
2205 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2206 if (priority_prefs):
2207 results.append(output_api.PresubmitPromptWarning(
2208 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2209 'controlled by browser sync settings. If these prefs should be '
2210 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2211 'instead.\n' + '\n'.join(prefs)))
2212 return results
2213
2214
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492215# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362216def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272217 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312218 The native_client_sdk directory is excluded because it has auto-generated PNG
2219 files for documentation.
[email protected]d2530012013-01-25 16:39:272220 """
[email protected]d2530012013-01-25 16:39:272221 errors = []
James Cook24a504192020-07-23 00:08:442222 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2223 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312224 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442225 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312226 for f in input_api.AffectedFiles(include_deletes=False,
2227 file_filter=file_filter):
2228 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272229
2230 results = []
2231 if errors:
2232 results.append(output_api.PresubmitError(
2233 'The name of PNG files should not have abbreviations. \n'
2234 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2235 'Contact [email protected] if you have questions.', errors))
2236 return results
2237
2238
Daniel Cheng4dcdb6b2017-04-13 08:30:172239def _ExtractAddRulesFromParsedDeps(parsed_deps):
2240 """Extract the rules that add dependencies from a parsed DEPS file.
2241
2242 Args:
2243 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2244 add_rules = set()
2245 add_rules.update([
2246 rule[1:] for rule in parsed_deps.get('include_rules', [])
2247 if rule.startswith('+') or rule.startswith('!')
2248 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502249 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172250 {}).iteritems():
2251 add_rules.update([
2252 rule[1:] for rule in rules
2253 if rule.startswith('+') or rule.startswith('!')
2254 ])
2255 return add_rules
2256
2257
2258def _ParseDeps(contents):
2259 """Simple helper for parsing DEPS files."""
2260 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172261 class _VarImpl:
2262
2263 def __init__(self, local_scope):
2264 self._local_scope = local_scope
2265
2266 def Lookup(self, var_name):
2267 """Implements the Var syntax."""
2268 try:
2269 return self._local_scope['vars'][var_name]
2270 except KeyError:
2271 raise Exception('Var is not defined: %s' % var_name)
2272
2273 local_scope = {}
2274 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172275 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592276 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172277 }
2278 exec contents in global_scope, local_scope
2279 return local_scope
2280
2281
2282def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592283 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412284 a set of DEPS entries that we should look up.
2285
2286 For a directory (rather than a specific filename) we fake a path to
2287 a specific filename by adding /DEPS. This is chosen as a file that
2288 will seldom or never be subject to per-file include_rules.
2289 """
[email protected]2b438d62013-11-14 17:54:142290 # We ignore deps entries on auto-generated directories.
2291 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082292
Daniel Cheng4dcdb6b2017-04-13 08:30:172293 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2294 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2295
2296 added_deps = new_deps.difference(old_deps)
2297
[email protected]2b438d62013-11-14 17:54:142298 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172299 for added_dep in added_deps:
2300 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2301 continue
2302 # Assume that a rule that ends in .h is a rule for a specific file.
2303 if added_dep.endswith('.h'):
2304 results.add(added_dep)
2305 else:
2306 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082307 return results
2308
2309
Saagar Sanghavifceeaae2020-08-12 16:40:362310def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552311 """When a dependency prefixed with + is added to a DEPS file, we
2312 want to make sure that the change is reviewed by an OWNER of the
2313 target file or directory, to avoid layering violations from being
2314 introduced. This check verifies that this happens.
2315 """
Joey Mou57048132021-02-26 22:17:552316 # We rely on Gerrit's code-owners to check approvals.
2317 # input_api.gerrit is always set for Chromium, but other projects
2318 # might not use Gerrit.
2319 if not input_api.gerrit:
2320 return []
Edward Lesmes6fba51082021-01-20 04:20:232321 if input_api.change.issue:
2322 # Skip OWNERS check when Bot-Commit label is approved. This label is
2323 # intended for commits made by trusted bots that don't require review nor
2324 # owners approval.
2325 if input_api.gerrit.IsBotCommitApproved(input_api.change.issue):
2326 return []
2327 # Skip OWNERS check when Owners-Override label is approved. This is intended
2328 # for global owners, trusted bots, and on-call sheriffs. Review is still
2329 # required for these changes.
2330 if input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue):
2331 return []
2332
Daniel Cheng4dcdb6b2017-04-13 08:30:172333 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242334
2335 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492336 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242337 for f in input_api.AffectedFiles(include_deletes=False,
2338 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552339 filename = input_api.os_path.basename(f.LocalPath())
2340 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172341 virtual_depended_on_files.update(_CalculateAddedDeps(
2342 input_api.os_path,
2343 '\n'.join(f.OldContents()),
2344 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552345
[email protected]e871964c2013-05-13 14:14:552346 if not virtual_depended_on_files:
2347 return []
2348
2349 if input_api.is_committing:
2350 if input_api.tbr:
2351 return [output_api.PresubmitNotifyResult(
2352 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272353 if input_api.dry_run:
2354 return [output_api.PresubmitNotifyResult(
2355 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552356 if not input_api.change.issue:
2357 return [output_api.PresubmitError(
2358 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402359 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552360 output = output_api.PresubmitError
2361 else:
2362 output = output_api.PresubmitNotifyResult
2363
tandriied3b7e12016-05-12 14:38:502364 owner_email, reviewers = (
2365 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2366 input_api,
Edward Lesmesa3846442021-02-08 20:20:032367 None,
tandriied3b7e12016-05-12 14:38:502368 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552369
2370 owner_email = owner_email or input_api.change.author_email
2371
Edward Lesmesa3846442021-02-08 20:20:032372 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2373 virtual_depended_on_files, reviewers.union([owner_email]), [])
2374 missing_files = [
2375 f for f in virtual_depended_on_files
2376 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412377
2378 # We strip the /DEPS part that was added by
2379 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2380 # directory.
2381 def StripDeps(path):
2382 start_deps = path.rfind('/DEPS')
2383 if start_deps != -1:
2384 return path[:start_deps]
2385 else:
2386 return path
2387 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552388 for path in missing_files]
2389
2390 if unapproved_dependencies:
2391 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152392 output('You need LGTM from owners of depends-on paths in DEPS that were '
2393 'modified in this CL:\n %s' %
2394 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032395 suggested_owners = input_api.owners_client.SuggestOwners(
2396 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152397 output_list.append(output(
2398 'Suggested missing target path OWNERS:\n %s' %
2399 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552400 return output_list
2401
2402 return []
2403
2404
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492405# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362406def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492407 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442408 files_to_skip = (_EXCLUDED_PATHS +
2409 _TEST_CODE_EXCLUDED_PATHS +
2410 input_api.DEFAULT_FILES_TO_SKIP +
2411 (r"^base[\\/]logging\.h$",
2412 r"^base[\\/]logging\.cc$",
2413 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2414 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2415 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2416 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2417 r"startup_browser_creator\.cc$",
2418 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2419 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2420 r"diagnostics_writer\.cc$",
2421 r"^chrome[\\/]chrome_cleaner[\\/].*",
2422 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2423 r"dll_hash_main\.cc$",
2424 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2425 r"^chromecast[\\/]",
2426 r"^cloud_print[\\/]",
2427 r"^components[\\/]browser_watcher[\\/]"
2428 r"dump_stability_report_main_win.cc$",
2429 r"^components[\\/]media_control[\\/]renderer[\\/]"
2430 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352431 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2432 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442433 r"^components[\\/]zucchini[\\/].*",
2434 # TODO(peter): Remove exception. https://crbug.com/534537
2435 r"^content[\\/]browser[\\/]notifications[\\/]"
2436 r"notification_event_dispatcher_impl\.cc$",
2437 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2438 r"gl_helper_benchmark\.cc$",
2439 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2440 r"^courgette[\\/]courgette_tool\.cc$",
2441 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2442 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2443 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi1d4c7ee2021-03-10 21:24:082444 # TODO(https://crbug.com/1181062): Temporary debugging.
Alexei Svitkine64505a92021-03-11 22:00:542445 r"^fuchsia[\\/]engine[\\/]renderer[\\/]"
2446 r"web_engine_render_frame_observer.cc$",
James Cook24a504192020-07-23 00:08:442447 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2448 r"^ipc[\\/]ipc_logging\.cc$",
2449 r"^native_client_sdk[\\/]",
2450 r"^remoting[\\/]base[\\/]logging\.h$",
2451 r"^remoting[\\/]host[\\/].*",
2452 r"^sandbox[\\/]linux[\\/].*",
2453 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2454 r"dump_file_system.cc$",
2455 r"^tools[\\/]",
2456 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2457 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2458 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2459 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2460 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402461 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442462 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402463
thomasanderson625d3932017-03-29 07:16:582464 log_info = set([])
2465 printf = set([])
[email protected]85218562013-11-22 07:41:402466
2467 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582468 for _, line in f.ChangedContents():
2469 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2470 log_info.add(f.LocalPath())
2471 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2472 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372473
thomasanderson625d3932017-03-29 07:16:582474 if input_api.re.search(r"\bprintf\(", line):
2475 printf.add(f.LocalPath())
2476 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2477 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402478
2479 if log_info:
2480 return [output_api.PresubmitError(
2481 'These files spam the console log with LOG(INFO):',
2482 items=log_info)]
2483 if printf:
2484 return [output_api.PresubmitError(
2485 'These files spam the console log with printf/fprintf:',
2486 items=printf)]
2487 return []
2488
2489
Saagar Sanghavifceeaae2020-08-12 16:40:362490def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162491 """These types are all expected to hold locks while in scope and
2492 so should never be anonymous (which causes them to be immediately
2493 destroyed)."""
2494 they_who_must_be_named = [
2495 'base::AutoLock',
2496 'base::AutoReset',
2497 'base::AutoUnlock',
2498 'SkAutoAlphaRestore',
2499 'SkAutoBitmapShaderInstall',
2500 'SkAutoBlitterChoose',
2501 'SkAutoBounderCommit',
2502 'SkAutoCallProc',
2503 'SkAutoCanvasRestore',
2504 'SkAutoCommentBlock',
2505 'SkAutoDescriptor',
2506 'SkAutoDisableDirectionCheck',
2507 'SkAutoDisableOvalCheck',
2508 'SkAutoFree',
2509 'SkAutoGlyphCache',
2510 'SkAutoHDC',
2511 'SkAutoLockColors',
2512 'SkAutoLockPixels',
2513 'SkAutoMalloc',
2514 'SkAutoMaskFreeImage',
2515 'SkAutoMutexAcquire',
2516 'SkAutoPathBoundsUpdate',
2517 'SkAutoPDFRelease',
2518 'SkAutoRasterClipValidate',
2519 'SkAutoRef',
2520 'SkAutoTime',
2521 'SkAutoTrace',
2522 'SkAutoUnref',
2523 ]
2524 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2525 # bad: base::AutoLock(lock.get());
2526 # not bad: base::AutoLock lock(lock.get());
2527 bad_pattern = input_api.re.compile(anonymous)
2528 # good: new base::AutoLock(lock.get())
2529 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2530 errors = []
2531
2532 for f in input_api.AffectedFiles():
2533 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2534 continue
2535 for linenum, line in f.ChangedContents():
2536 if bad_pattern.search(line) and not good_pattern.search(line):
2537 errors.append('%s:%d' % (f.LocalPath(), linenum))
2538
2539 if errors:
2540 return [output_api.PresubmitError(
2541 'These lines create anonymous variables that need to be named:',
2542 items=errors)]
2543 return []
2544
2545
Saagar Sanghavifceeaae2020-08-12 16:40:362546def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532547 # Returns whether |template_str| is of the form <T, U...> for some types T
2548 # and U. Assumes that |template_str| is already in the form <...>.
2549 def HasMoreThanOneArg(template_str):
2550 # Level of <...> nesting.
2551 nesting = 0
2552 for c in template_str:
2553 if c == '<':
2554 nesting += 1
2555 elif c == '>':
2556 nesting -= 1
2557 elif c == ',' and nesting == 1:
2558 return True
2559 return False
2560
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492561 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102562 sources = lambda affected_file: input_api.FilterSourceFile(
2563 affected_file,
James Cook24a504192020-07-23 00:08:442564 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2565 input_api.DEFAULT_FILES_TO_SKIP),
2566 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552567
2568 # Pattern to capture a single "<...>" block of template arguments. It can
2569 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2570 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2571 # latter would likely require counting that < and > match, which is not
2572 # expressible in regular languages. Should the need arise, one can introduce
2573 # limited counting (matching up to a total number of nesting depth), which
2574 # should cover all practical cases for already a low nesting limit.
2575 template_arg_pattern = (
2576 r'<[^>]*' # Opening block of <.
2577 r'>([^<]*>)?') # Closing block of >.
2578 # Prefix expressing that whatever follows is not already inside a <...>
2579 # block.
2580 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102581 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552582 not_inside_template_arg_pattern
2583 + r'\bstd::unique_ptr'
2584 + template_arg_pattern
2585 + r'\(\)')
2586
2587 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2588 template_arg_no_array_pattern = (
2589 r'<[^>]*[^]]' # Opening block of <.
2590 r'>([^(<]*[^]]>)?') # Closing block of >.
2591 # Prefix saying that what follows is the start of an expression.
2592 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2593 # Suffix saying that what follows are call parentheses with a non-empty list
2594 # of arguments.
2595 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532596 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552597 return_construct_pattern = input_api.re.compile(
2598 start_of_expr_pattern
2599 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532600 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552601 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532602 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552603 + nonempty_arg_list_pattern)
2604
Vaclav Brozek851d9602018-04-04 16:13:052605 problems_constructor = []
2606 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102607 for f in input_api.AffectedSourceFiles(sources):
2608 for line_number, line in f.ChangedContents():
2609 # Disallow:
2610 # return std::unique_ptr<T>(foo);
2611 # bar = std::unique_ptr<T>(foo);
2612 # But allow:
2613 # return std::unique_ptr<T[]>(foo);
2614 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532615 # And also allow cases when the second template argument is present. Those
2616 # cases cannot be handled by std::make_unique:
2617 # return std::unique_ptr<T, U>(foo);
2618 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052619 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532620 return_construct_result = return_construct_pattern.search(line)
2621 if return_construct_result and not HasMoreThanOneArg(
2622 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052623 problems_constructor.append(
2624 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102625 # Disallow:
2626 # std::unique_ptr<T>()
2627 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052628 problems_nullptr.append(
2629 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2630
2631 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162632 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052633 errors.append(output_api.PresubmitError(
2634 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162635 problems_nullptr))
2636 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052637 errors.append(output_api.PresubmitError(
2638 'The following files use explicit std::unique_ptr constructor.'
2639 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162640 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102641 return errors
2642
2643
Saagar Sanghavifceeaae2020-08-12 16:40:362644def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082645 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522646 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082647 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522648 # If actions.xml is already included in the changelist, the PRESUBMIT
2649 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082650 return []
2651
Alexei Svitkine64505a92021-03-11 22:00:542652 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2653 files_to_skip = (_EXCLUDED_PATHS +
2654 _TEST_CODE_EXCLUDED_PATHS +
2655 input_api.DEFAULT_FILES_TO_SKIP )
2656 file_filter = lambda f: input_api.FilterSourceFile(
2657 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2658
[email protected]999261d2014-03-03 20:08:082659 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522660 current_actions = None
[email protected]999261d2014-03-03 20:08:082661 for f in input_api.AffectedFiles(file_filter=file_filter):
2662 for line_num, line in f.ChangedContents():
2663 match = input_api.re.search(action_re, line)
2664 if match:
[email protected]2f92dec2014-03-07 19:21:522665 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2666 # loaded only once.
2667 if not current_actions:
2668 with open('tools/metrics/actions/actions.xml') as actions_f:
2669 current_actions = actions_f.read()
2670 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082671 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522672 action = 'name="{0}"'.format(action_name)
2673 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082674 return [output_api.PresubmitPromptWarning(
2675 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522676 'tools/metrics/actions/actions.xml. Please run '
2677 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082678 % (f.LocalPath(), line_num, action_name))]
2679 return []
2680
2681
Daniel Cheng13ca61a882017-08-25 15:11:252682def _ImportJSONCommentEater(input_api):
2683 import sys
2684 sys.path = sys.path + [input_api.os_path.join(
2685 input_api.PresubmitLocalPath(),
2686 'tools', 'json_comment_eater')]
2687 import json_comment_eater
2688 return json_comment_eater
2689
2690
[email protected]99171a92014-06-03 08:44:472691def _GetJSONParseError(input_api, filename, eat_comments=True):
2692 try:
2693 contents = input_api.ReadFile(filename)
2694 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252695 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132696 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472697
2698 input_api.json.loads(contents)
2699 except ValueError as e:
2700 return e
2701 return None
2702
2703
2704def _GetIDLParseError(input_api, filename):
2705 try:
2706 contents = input_api.ReadFile(filename)
2707 idl_schema = input_api.os_path.join(
2708 input_api.PresubmitLocalPath(),
2709 'tools', 'json_schema_compiler', 'idl_schema.py')
2710 process = input_api.subprocess.Popen(
2711 [input_api.python_executable, idl_schema],
2712 stdin=input_api.subprocess.PIPE,
2713 stdout=input_api.subprocess.PIPE,
2714 stderr=input_api.subprocess.PIPE,
2715 universal_newlines=True)
2716 (_, error) = process.communicate(input=contents)
2717 return error or None
2718 except ValueError as e:
2719 return e
2720
2721
Saagar Sanghavifceeaae2020-08-12 16:40:362722def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472723 """Check that IDL and JSON files do not contain syntax errors."""
2724 actions = {
2725 '.idl': _GetIDLParseError,
2726 '.json': _GetJSONParseError,
2727 }
[email protected]99171a92014-06-03 08:44:472728 # Most JSON files are preprocessed and support comments, but these do not.
2729 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042730 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472731 ]
2732 # Only run IDL checker on files in these directories.
2733 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042734 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2735 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472736 ]
2737
2738 def get_action(affected_file):
2739 filename = affected_file.LocalPath()
2740 return actions.get(input_api.os_path.splitext(filename)[1])
2741
[email protected]99171a92014-06-03 08:44:472742 def FilterFile(affected_file):
2743 action = get_action(affected_file)
2744 if not action:
2745 return False
2746 path = affected_file.LocalPath()
2747
Erik Staab2dd72b12020-04-16 15:03:402748 if _MatchesFile(input_api,
2749 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2750 path):
[email protected]99171a92014-06-03 08:44:472751 return False
2752
2753 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162754 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472755 return False
2756 return True
2757
2758 results = []
2759 for affected_file in input_api.AffectedFiles(
2760 file_filter=FilterFile, include_deletes=False):
2761 action = get_action(affected_file)
2762 kwargs = {}
2763 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162764 _MatchesFile(input_api, json_no_comments_patterns,
2765 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472766 kwargs['eat_comments'] = False
2767 parse_error = action(input_api,
2768 affected_file.AbsoluteLocalPath(),
2769 **kwargs)
2770 if parse_error:
2771 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2772 (affected_file.LocalPath(), parse_error)))
2773 return results
2774
2775
Saagar Sanghavifceeaae2020-08-12 16:40:362776def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492777 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472778 import sys
[email protected]760deea2013-12-10 19:33:492779 original_sys_path = sys.path
2780 try:
2781 sys.path = sys.path + [input_api.os_path.join(
2782 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2783 import checkstyle
2784 finally:
2785 # Restore sys.path to what it was before.
2786 sys.path = original_sys_path
2787
2788 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092789 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442790 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492791
2792
Saagar Sanghavifceeaae2020-08-12 16:40:362793def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002794 """Checks to make sure devil is initialized correctly in python scripts."""
2795 script_common_initialize_pattern = input_api.re.compile(
2796 r'script_common\.InitializeEnvironment\(')
2797 devil_env_config_initialize = input_api.re.compile(
2798 r'devil_env\.config\.Initialize\(')
2799
2800 errors = []
2801
2802 sources = lambda affected_file: input_api.FilterSourceFile(
2803 affected_file,
James Cook24a504192020-07-23 00:08:442804 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2805 (r'^build[\\/]android[\\/]devil_chromium\.py',
2806 r'^third_party[\\/].*',)),
2807 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002808
2809 for f in input_api.AffectedSourceFiles(sources):
2810 for line_num, line in f.ChangedContents():
2811 if (script_common_initialize_pattern.search(line) or
2812 devil_env_config_initialize.search(line)):
2813 errors.append("%s:%d" % (f.LocalPath(), line_num))
2814
2815 results = []
2816
2817 if errors:
2818 results.append(output_api.PresubmitError(
2819 'Devil initialization should always be done using '
2820 'devil_chromium.Initialize() in the chromium project, to use better '
2821 'defaults for dependencies (ex. up-to-date version of adb).',
2822 errors))
2823
2824 return results
2825
2826
Sean Kau46e29bc2017-08-28 16:31:162827def _MatchesFile(input_api, patterns, path):
2828 for pattern in patterns:
2829 if input_api.re.search(pattern, path):
2830 return True
2831 return False
2832
2833
Daniel Cheng7052cdf2017-11-21 19:23:292834def _GetOwnersFilesToCheckForIpcOwners(input_api):
2835 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172836
Daniel Cheng7052cdf2017-11-21 19:23:292837 Returns:
2838 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2839 contain to cover IPC-related files with noparent reviewer rules.
2840 """
2841 # Whether or not a file affects IPC is (mostly) determined by a simple list
2842 # of filename patterns.
dchenge07de812016-06-20 19:27:172843 file_patterns = [
palmerb19a0932017-01-24 04:00:312844 # Legacy IPC:
dchenge07de812016-06-20 19:27:172845 '*_messages.cc',
2846 '*_messages*.h',
2847 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312848 # Mojo IPC:
dchenge07de812016-06-20 19:27:172849 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472850 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172851 '*_struct_traits*.*',
2852 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312853 '*.typemap',
2854 # Android native IPC:
2855 '*.aidl',
2856 # Blink uses a different file naming convention:
2857 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472858 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172859 '*StructTraits*.*',
2860 '*TypeConverter*.*',
2861 ]
2862
scottmg7a6ed5ba2016-11-04 18:22:042863 # These third_party directories do not contain IPCs, but contain files
2864 # matching the above patterns, which trigger false positives.
2865 exclude_paths = [
2866 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162867 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232868 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292869 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542870 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162871 # These files are just used to communicate between class loaders running
2872 # in the same process.
2873 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572874 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2875
scottmg7a6ed5ba2016-11-04 18:22:042876 ]
2877
dchenge07de812016-06-20 19:27:172878 # Dictionary mapping an OWNERS file path to Patterns.
2879 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2880 # rules ) to a PatternEntry.
2881 # PatternEntry is a dictionary with two keys:
2882 # - 'files': the files that are matched by this pattern
2883 # - 'rules': the per-file rules needed for this pattern
2884 # For example, if we expect OWNERS file to contain rules for *.mojom and
2885 # *_struct_traits*.*, Patterns might look like this:
2886 # {
2887 # '*.mojom': {
2888 # 'files': ...,
2889 # 'rules': [
2890 # 'per-file *.mojom=set noparent',
2891 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2892 # ],
2893 # },
2894 # '*_struct_traits*.*': {
2895 # 'files': ...,
2896 # 'rules': [
2897 # 'per-file *_struct_traits*.*=set noparent',
2898 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2899 # ],
2900 # },
2901 # }
2902 to_check = {}
2903
Daniel Cheng13ca61a882017-08-25 15:11:252904 def AddPatternToCheck(input_file, pattern):
2905 owners_file = input_api.os_path.join(
2906 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2907 if owners_file not in to_check:
2908 to_check[owners_file] = {}
2909 if pattern not in to_check[owners_file]:
2910 to_check[owners_file][pattern] = {
2911 'files': [],
2912 'rules': [
2913 'per-file %s=set noparent' % pattern,
2914 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2915 ]
2916 }
Vaclav Brozekd5de76a2018-03-17 07:57:502917 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252918
dchenge07de812016-06-20 19:27:172919 # Iterate through the affected files to see what we actually need to check
2920 # for. We should only nag patch authors about per-file rules if a file in that
2921 # directory would match that pattern. If a directory only contains *.mojom
2922 # files and no *_messages*.h files, we should only nag about rules for
2923 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252924 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262925 # Manifest files don't have a strong naming convention. Instead, try to find
2926 # affected .cc and .h files which look like they contain a manifest
2927 # definition.
2928 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2929 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2930 if (manifest_pattern.search(f.LocalPath()) and not
2931 test_manifest_pattern.search(f.LocalPath())):
2932 # We expect all actual service manifest files to contain at least one
2933 # qualified reference to service_manager::Manifest.
2934 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252935 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172936 for pattern in file_patterns:
2937 if input_api.fnmatch.fnmatch(
2938 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042939 skip = False
2940 for exclude in exclude_paths:
2941 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2942 skip = True
2943 break
2944 if skip:
2945 continue
Daniel Cheng13ca61a882017-08-25 15:11:252946 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172947 break
2948
Daniel Cheng7052cdf2017-11-21 19:23:292949 return to_check
2950
2951
Wez17c66962020-04-29 15:26:032952def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2953 """Adds OWNERS files to check for correct Fuchsia security owners."""
2954
2955 file_patterns = [
2956 # Component specifications.
2957 '*.cml', # Component Framework v2.
2958 '*.cmx', # Component Framework v1.
2959
2960 # Fuchsia IDL protocol specifications.
2961 '*.fidl',
2962 ]
2963
Joshua Peraza1ca6d392020-12-08 00:14:092964 # Don't check for owners files for changes in these directories.
2965 exclude_paths = [
2966 'third_party/crashpad/*',
2967 ]
2968
Wez17c66962020-04-29 15:26:032969 def AddPatternToCheck(input_file, pattern):
2970 owners_file = input_api.os_path.join(
2971 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2972 if owners_file not in to_check:
2973 to_check[owners_file] = {}
2974 if pattern not in to_check[owners_file]:
2975 to_check[owners_file][pattern] = {
2976 'files': [],
2977 'rules': [
2978 'per-file %s=set noparent' % pattern,
2979 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2980 ]
2981 }
2982 to_check[owners_file][pattern]['files'].append(input_file)
2983
2984 # Iterate through the affected files to see what we actually need to check
2985 # for. We should only nag patch authors about per-file rules if a file in that
2986 # directory would match that pattern.
2987 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092988 skip = False
2989 for exclude in exclude_paths:
2990 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2991 skip = True
2992 if skip:
2993 continue
2994
Wez17c66962020-04-29 15:26:032995 for pattern in file_patterns:
2996 if input_api.fnmatch.fnmatch(
2997 input_api.os_path.basename(f.LocalPath()), pattern):
2998 AddPatternToCheck(f, pattern)
2999 break
3000
3001 return to_check
3002
3003
Saagar Sanghavifceeaae2020-08-12 16:40:363004def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293005 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3006 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033007 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293008
3009 if to_check:
3010 # If there are any OWNERS files to check, there are IPC-related changes in
3011 # this CL. Auto-CC the review list.
3012 output_api.AppendCC('[email protected]')
3013
3014 # Go through the OWNERS files to check, filtering out rules that are already
3015 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173016 for owners_file, patterns in to_check.iteritems():
3017 try:
3018 with file(owners_file) as f:
3019 lines = set(f.read().splitlines())
3020 for entry in patterns.itervalues():
3021 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3022 ]
3023 except IOError:
3024 # No OWNERS file, so all the rules are definitely missing.
3025 continue
3026
3027 # All the remaining lines weren't found in OWNERS files, so emit an error.
3028 errors = []
3029 for owners_file, patterns in to_check.iteritems():
3030 missing_lines = []
3031 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503032 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173033 missing_lines.extend(entry['rules'])
3034 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3035 if missing_lines:
3036 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053037 'Because of the presence of files:\n%s\n\n'
3038 '%s needs the following %d lines added:\n\n%s' %
3039 ('\n'.join(files), owners_file, len(missing_lines),
3040 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173041
3042 results = []
3043 if errors:
vabrf5ce3bf92016-07-11 14:52:413044 if input_api.is_committing:
3045 output = output_api.PresubmitError
3046 else:
3047 output = output_api.PresubmitPromptWarning
3048 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593049 'Found OWNERS files that need to be updated for IPC security ' +
3050 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173051 long_text='\n\n'.join(errors)))
3052
3053 return results
3054
3055
Robert Sesek2c905332020-05-06 23:17:133056def _GetFilesUsingSecurityCriticalFunctions(input_api):
3057 """Checks affected files for changes to security-critical calls. This
3058 function checks the full change diff, to catch both additions/changes
3059 and removals.
3060
3061 Returns a dict keyed by file name, and the value is a set of detected
3062 functions.
3063 """
3064 # Map of function pretty name (displayed in an error) to the pattern to
3065 # match it with.
3066 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373067 'content::GetServiceSandboxType<>()':
3068 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133069 }
3070 _PATTERNS_TO_CHECK = {
3071 k: input_api.re.compile(v)
3072 for k, v in _PATTERNS_TO_CHECK.items()
3073 }
3074
3075 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3076 files_to_functions = {}
3077 for f in input_api.AffectedFiles():
3078 diff = f.GenerateScmDiff()
3079 for line in diff.split('\n'):
3080 # Not using just RightHandSideLines() because removing a
3081 # call to a security-critical function can be just as important
3082 # as adding or changing the arguments.
3083 if line.startswith('-') or (line.startswith('+') and
3084 not line.startswith('++')):
3085 for name, pattern in _PATTERNS_TO_CHECK.items():
3086 if pattern.search(line):
3087 path = f.LocalPath()
3088 if not path in files_to_functions:
3089 files_to_functions[path] = set()
3090 files_to_functions[path].add(name)
3091 return files_to_functions
3092
3093
Saagar Sanghavifceeaae2020-08-12 16:40:363094def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133095 """Checks that changes involving security-critical functions are reviewed
3096 by the security team.
3097 """
3098 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:123099 if not len(files_to_functions):
3100 return []
Robert Sesek2c905332020-05-06 23:17:133101
Edward Lesmes1e9fade2021-02-08 20:31:123102 owner_email, reviewers = (
3103 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3104 input_api,
3105 None,
3106 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:133107
Edward Lesmes1e9fade2021-02-08 20:31:123108 # Load the OWNERS file for security changes.
3109 owners_file = 'ipc/SECURITY_OWNERS'
3110 security_owners = input_api.owners_client.ListOwners(owners_file)
3111 has_security_owner = any([owner in reviewers for owner in security_owners])
3112 if has_security_owner:
3113 return []
Robert Sesek2c905332020-05-06 23:17:133114
Edward Lesmes1e9fade2021-02-08 20:31:123115 msg = 'The following files change calls to security-sensive functions\n' \
3116 'that need to be reviewed by {}.\n'.format(owners_file)
3117 for path, names in files_to_functions.items():
3118 msg += ' {}\n'.format(path)
3119 for name in names:
3120 msg += ' {}\n'.format(name)
3121 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133122
Edward Lesmes1e9fade2021-02-08 20:31:123123 if input_api.is_committing:
3124 output = output_api.PresubmitError
3125 else:
3126 output = output_api.PresubmitNotifyResult
3127 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133128
3129
Saagar Sanghavifceeaae2020-08-12 16:40:363130def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263131 """Checks that set noparent is only used together with an OWNERS file in
3132 //build/OWNERS.setnoparent (see also
3133 //docs/code_reviews.md#owners-files-details)
3134 """
3135 errors = []
3136
3137 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3138 allowed_owners_files = set()
3139 with open(allowed_owners_files_file, 'r') as f:
3140 for line in f:
3141 line = line.strip()
3142 if not line or line.startswith('#'):
3143 continue
3144 allowed_owners_files.add(line)
3145
3146 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3147
3148 for f in input_api.AffectedFiles(include_deletes=False):
3149 if not f.LocalPath().endswith('OWNERS'):
3150 continue
3151
3152 found_owners_files = set()
3153 found_set_noparent_lines = dict()
3154
3155 # Parse the OWNERS file.
3156 for lineno, line in enumerate(f.NewContents(), 1):
3157 line = line.strip()
3158 if line.startswith('set noparent'):
3159 found_set_noparent_lines[''] = lineno
3160 if line.startswith('file://'):
3161 if line in allowed_owners_files:
3162 found_owners_files.add('')
3163 if line.startswith('per-file'):
3164 match = per_file_pattern.match(line)
3165 if match:
3166 glob = match.group(1).strip()
3167 directive = match.group(2).strip()
3168 if directive == 'set noparent':
3169 found_set_noparent_lines[glob] = lineno
3170 if directive.startswith('file://'):
3171 if directive in allowed_owners_files:
3172 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153173
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263174 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403175 # listed in build/OWNERS.setnoparent. An exception is made for top level
3176 # directories since src/OWNERS shouldn't review them.
3177 if f.LocalPath().count('/') != 1:
3178 for set_noparent_line in found_set_noparent_lines:
3179 if set_noparent_line in found_owners_files:
3180 continue
3181 errors.append(' %s:%d' % (f.LocalPath(),
3182 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263183
3184 results = []
3185 if errors:
3186 if input_api.is_committing:
3187 output = output_api.PresubmitError
3188 else:
3189 output = output_api.PresubmitPromptWarning
3190 results.append(output(
3191 'Found the following "set noparent" restrictions in OWNERS files that '
3192 'do not include owners from build/OWNERS.setnoparent:',
3193 long_text='\n\n'.join(errors)))
3194 return results
3195
3196
Saagar Sanghavifceeaae2020-08-12 16:40:363197def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313198 """Checks that added or removed lines in non third party affected
3199 header files do not lead to new useless class or struct forward
3200 declaration.
jbriance9e12f162016-11-25 07:57:503201 """
3202 results = []
3203 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3204 input_api.re.MULTILINE)
3205 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3206 input_api.re.MULTILINE)
3207 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313208 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193209 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493210 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313211 continue
3212
jbriance9e12f162016-11-25 07:57:503213 if not f.LocalPath().endswith('.h'):
3214 continue
3215
3216 contents = input_api.ReadFile(f)
3217 fwd_decls = input_api.re.findall(class_pattern, contents)
3218 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3219
3220 useless_fwd_decls = []
3221 for decl in fwd_decls:
3222 count = sum(1 for _ in input_api.re.finditer(
3223 r'\b%s\b' % input_api.re.escape(decl), contents))
3224 if count == 1:
3225 useless_fwd_decls.append(decl)
3226
3227 if not useless_fwd_decls:
3228 continue
3229
3230 for line in f.GenerateScmDiff().splitlines():
3231 if (line.startswith('-') and not line.startswith('--') or
3232 line.startswith('+') and not line.startswith('++')):
3233 for decl in useless_fwd_decls:
3234 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3235 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243236 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503237 (f.LocalPath(), decl)))
3238 useless_fwd_decls.remove(decl)
3239
3240 return results
3241
Jinsong Fan91ebbbd2019-04-16 14:57:173242def _CheckAndroidDebuggableBuild(input_api, output_api):
3243 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3244 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3245 this is a debuggable build of Android.
3246 """
3247 build_type_check_pattern = input_api.re.compile(
3248 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3249
3250 errors = []
3251
3252 sources = lambda affected_file: input_api.FilterSourceFile(
3253 affected_file,
James Cook24a504192020-07-23 00:08:443254 files_to_skip=(_EXCLUDED_PATHS +
3255 _TEST_CODE_EXCLUDED_PATHS +
3256 input_api.DEFAULT_FILES_TO_SKIP +
3257 (r"^android_webview[\\/]support_library[\\/]"
3258 "boundary_interfaces[\\/]",
3259 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3260 r'^third_party[\\/].*',
3261 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3262 r"webview[\\/]chromium[\\/]License.*",)),
3263 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173264
3265 for f in input_api.AffectedSourceFiles(sources):
3266 for line_num, line in f.ChangedContents():
3267 if build_type_check_pattern.search(line):
3268 errors.append("%s:%d" % (f.LocalPath(), line_num))
3269
3270 results = []
3271
3272 if errors:
3273 results.append(output_api.PresubmitPromptWarning(
3274 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3275 ' Please use BuildInfo.isDebugAndroid() instead.',
3276 errors))
3277
3278 return results
jbriance9e12f162016-11-25 07:57:503279
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493280# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293281def _CheckAndroidToastUsage(input_api, output_api):
3282 """Checks that code uses org.chromium.ui.widget.Toast instead of
3283 android.widget.Toast (Chromium Toast doesn't force hardware
3284 acceleration on low-end devices, saving memory).
3285 """
3286 toast_import_pattern = input_api.re.compile(
3287 r'^import android\.widget\.Toast;$')
3288
3289 errors = []
3290
3291 sources = lambda affected_file: input_api.FilterSourceFile(
3292 affected_file,
James Cook24a504192020-07-23 00:08:443293 files_to_skip=(_EXCLUDED_PATHS +
3294 _TEST_CODE_EXCLUDED_PATHS +
3295 input_api.DEFAULT_FILES_TO_SKIP +
3296 (r'^chromecast[\\/].*',
3297 r'^remoting[\\/].*')),
3298 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293299
3300 for f in input_api.AffectedSourceFiles(sources):
3301 for line_num, line in f.ChangedContents():
3302 if toast_import_pattern.search(line):
3303 errors.append("%s:%d" % (f.LocalPath(), line_num))
3304
3305 results = []
3306
3307 if errors:
3308 results.append(output_api.PresubmitError(
3309 'android.widget.Toast usage is detected. Android toasts use hardware'
3310 ' acceleration, and can be\ncostly on low-end devices. Please use'
3311 ' org.chromium.ui.widget.Toast instead.\n'
3312 'Contact [email protected] if you have any questions.',
3313 errors))
3314
3315 return results
3316
3317
dgnaa68d5e2015-06-10 10:08:223318def _CheckAndroidCrLogUsage(input_api, output_api):
3319 """Checks that new logs using org.chromium.base.Log:
3320 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513321 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223322 """
pkotwicza1dd0b002016-05-16 14:41:043323
torne89540622017-03-24 19:41:303324 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043325 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303326 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043327 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303328 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043329 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3330 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093331 # The customtabs_benchmark is a small app that does not depend on Chromium
3332 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043333 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043334 ]
3335
dgnaa68d5e2015-06-10 10:08:223336 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123337 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3338 class_in_base_pattern = input_api.re.compile(
3339 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3340 has_some_log_import_pattern = input_api.re.compile(
3341 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223342 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553343 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223344 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463345 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553346 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223347
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463348 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443349 sources = lambda x: input_api.FilterSourceFile(x,
3350 files_to_check=[r'.*\.java$'],
3351 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123352
dgnaa68d5e2015-06-10 10:08:223353 tag_decl_errors = []
3354 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123355 tag_errors = []
dgn38736db2015-09-18 19:20:513356 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123357 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223358
3359 for f in input_api.AffectedSourceFiles(sources):
3360 file_content = input_api.ReadFile(f)
3361 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223362 # Per line checks
dgn87d9fb62015-06-12 09:15:123363 if (cr_log_import_pattern.search(file_content) or
3364 (class_in_base_pattern.search(file_content) and
3365 not has_some_log_import_pattern.search(file_content))):
3366 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223367 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553368 if rough_log_decl_pattern.search(line):
3369 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223370
3371 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123372 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223373 if match:
3374 has_modified_logs = True
3375
3376 # Make sure it uses "TAG"
3377 if not match.group('tag') == 'TAG':
3378 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123379 else:
3380 # Report non cr Log function calls in changed lines
3381 for line_num, line in f.ChangedContents():
3382 if log_call_pattern.search(line):
3383 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223384
3385 # Per file checks
3386 if has_modified_logs:
3387 # Make sure the tag is using the "cr" prefix and is not too long
3388 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513389 tag_name = match.group('name') if match else None
3390 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223391 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513392 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223393 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513394 elif '.' in tag_name:
3395 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223396
3397 results = []
3398 if tag_decl_errors:
3399 results.append(output_api.PresubmitPromptWarning(
3400 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513401 '"private static final String TAG = "<package tag>".\n'
3402 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223403 tag_decl_errors))
3404
3405 if tag_length_errors:
3406 results.append(output_api.PresubmitError(
3407 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513408 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223409 tag_length_errors))
3410
3411 if tag_errors:
3412 results.append(output_api.PresubmitPromptWarning(
3413 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3414 tag_errors))
3415
dgn87d9fb62015-06-12 09:15:123416 if util_log_errors:
dgn4401aa52015-04-29 16:26:173417 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123418 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3419 util_log_errors))
3420
dgn38736db2015-09-18 19:20:513421 if tag_with_dot_errors:
3422 results.append(output_api.PresubmitPromptWarning(
3423 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3424 tag_with_dot_errors))
3425
dgn4401aa52015-04-29 16:26:173426 return results
3427
3428
Yoland Yanb92fa522017-08-28 17:37:063429def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3430 """Checks that junit.framework.* is no longer used."""
3431 deprecated_junit_framework_pattern = input_api.re.compile(
3432 r'^import junit\.framework\..*;',
3433 input_api.re.MULTILINE)
3434 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443435 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063436 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133437 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063438 for line_num, line in f.ChangedContents():
3439 if deprecated_junit_framework_pattern.search(line):
3440 errors.append("%s:%d" % (f.LocalPath(), line_num))
3441
3442 results = []
3443 if errors:
3444 results.append(output_api.PresubmitError(
3445 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3446 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3447 ' if you have any question.', errors))
3448 return results
3449
3450
3451def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3452 """Checks that if new Java test classes have inheritance.
3453 Either the new test class is JUnit3 test or it is a JUnit4 test class
3454 with a base class, either case is undesirable.
3455 """
3456 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3457
3458 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443459 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063460 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133461 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063462 if not f.OldContents():
3463 class_declaration_start_flag = False
3464 for line_num, line in f.ChangedContents():
3465 if class_declaration_pattern.search(line):
3466 class_declaration_start_flag = True
3467 if class_declaration_start_flag and ' extends ' in line:
3468 errors.append('%s:%d' % (f.LocalPath(), line_num))
3469 if '{' in line:
3470 class_declaration_start_flag = False
3471
3472 results = []
3473 if errors:
3474 results.append(output_api.PresubmitPromptWarning(
3475 'The newly created files include Test classes that inherits from base'
3476 ' class. Please do not use inheritance in JUnit4 tests or add new'
3477 ' JUnit3 tests. Contact [email protected] if you have any'
3478 ' questions.', errors))
3479 return results
3480
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203481
yolandyan45001472016-12-21 21:12:423482def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3483 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3484 deprecated_annotation_import_pattern = input_api.re.compile(
3485 r'^import android\.test\.suitebuilder\.annotation\..*;',
3486 input_api.re.MULTILINE)
3487 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443488 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423489 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133490 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423491 for line_num, line in f.ChangedContents():
3492 if deprecated_annotation_import_pattern.search(line):
3493 errors.append("%s:%d" % (f.LocalPath(), line_num))
3494
3495 results = []
3496 if errors:
3497 results.append(output_api.PresubmitError(
3498 'Annotations in android.test.suitebuilder.annotation have been'
3499 ' deprecated since API level 24. Please use android.support.test.filters'
3500 ' from //third_party/android_support_test_runner:runner_java instead.'
3501 ' Contact [email protected] if you have any questions.', errors))
3502 return results
3503
3504
agrieve7b6479d82015-10-07 14:24:223505def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3506 """Checks if MDPI assets are placed in a correct directory."""
3507 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3508 ('/res/drawable/' in f.LocalPath() or
3509 '/res/drawable-ldrtl/' in f.LocalPath()))
3510 errors = []
3511 for f in input_api.AffectedFiles(include_deletes=False,
3512 file_filter=file_filter):
3513 errors.append(' %s' % f.LocalPath())
3514
3515 results = []
3516 if errors:
3517 results.append(output_api.PresubmitError(
3518 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3519 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3520 '/res/drawable-ldrtl/.\n'
3521 'Contact [email protected] if you have questions.', errors))
3522 return results
3523
3524
Nate Fischer535972b2017-09-16 01:06:183525def _CheckAndroidWebkitImports(input_api, output_api):
3526 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353527 android.webview.ValueCallback except in the WebView glue layer
3528 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183529 """
3530 valuecallback_import_pattern = input_api.re.compile(
3531 r'^import android\.webkit\.ValueCallback;$')
3532
3533 errors = []
3534
3535 sources = lambda affected_file: input_api.FilterSourceFile(
3536 affected_file,
James Cook24a504192020-07-23 00:08:443537 files_to_skip=(_EXCLUDED_PATHS +
3538 _TEST_CODE_EXCLUDED_PATHS +
3539 input_api.DEFAULT_FILES_TO_SKIP +
3540 (r'^android_webview[\\/]glue[\\/].*',
3541 r'^weblayer[\\/].*',)),
3542 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183543
3544 for f in input_api.AffectedSourceFiles(sources):
3545 for line_num, line in f.ChangedContents():
3546 if valuecallback_import_pattern.search(line):
3547 errors.append("%s:%d" % (f.LocalPath(), line_num))
3548
3549 results = []
3550
3551 if errors:
3552 results.append(output_api.PresubmitError(
3553 'android.webkit.ValueCallback usage is detected outside of the glue'
3554 ' layer. To stay compatible with the support library, android.webkit.*'
3555 ' classes should only be used inside the glue layer and'
3556 ' org.chromium.base.Callback should be used instead.',
3557 errors))
3558
3559 return results
3560
3561
Becky Zhou7c69b50992018-12-10 19:37:573562def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3563 """Checks Android XML styles """
3564 import sys
3565 original_sys_path = sys.path
3566 try:
3567 sys.path = sys.path + [input_api.os_path.join(
3568 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3569 import checkxmlstyle
3570 finally:
3571 # Restore sys.path to what it was before.
3572 sys.path = original_sys_path
3573
3574 if is_check_on_upload:
3575 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3576 else:
3577 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3578
3579
agrievef32bcc72016-04-04 14:57:403580class PydepsChecker(object):
3581 def __init__(self, input_api, pydeps_files):
3582 self._file_cache = {}
3583 self._input_api = input_api
3584 self._pydeps_files = pydeps_files
3585
3586 def _LoadFile(self, path):
3587 """Returns the list of paths within a .pydeps file relative to //."""
3588 if path not in self._file_cache:
3589 with open(path) as f:
3590 self._file_cache[path] = f.read()
3591 return self._file_cache[path]
3592
3593 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3594 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393595 pydeps_data = self._LoadFile(pydeps_path)
3596 uses_gn_paths = '--gn-paths' in pydeps_data
3597 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3598 if uses_gn_paths:
3599 # Paths look like: //foo/bar/baz
3600 return (e[2:] for e in entries)
3601 else:
3602 # Paths look like: path/relative/to/file.pydeps
3603 os_path = self._input_api.os_path
3604 pydeps_dir = os_path.dirname(pydeps_path)
3605 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403606
3607 def _CreateFilesToPydepsMap(self):
3608 """Returns a map of local_path -> list_of_pydeps."""
3609 ret = {}
3610 for pydep_local_path in self._pydeps_files:
3611 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3612 ret.setdefault(path, []).append(pydep_local_path)
3613 return ret
3614
3615 def ComputeAffectedPydeps(self):
3616 """Returns an iterable of .pydeps files that might need regenerating."""
3617 affected_pydeps = set()
3618 file_to_pydeps_map = None
3619 for f in self._input_api.AffectedFiles(include_deletes=True):
3620 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463621 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3622 # subrepositories. We can't figure out which files change, so re-check
3623 # all files.
3624 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383625 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3626 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403627 return self._pydeps_files
3628 elif local_path.endswith('.pydeps'):
3629 if local_path in self._pydeps_files:
3630 affected_pydeps.add(local_path)
3631 elif local_path.endswith('.py'):
3632 if file_to_pydeps_map is None:
3633 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3634 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3635 return affected_pydeps
3636
3637 def DetermineIfStale(self, pydeps_path):
3638 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413639 import difflib
John Budorick47ca3fe2018-02-10 00:53:103640 import os
3641
agrievef32bcc72016-04-04 14:57:403642 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033643 if old_pydeps_data:
3644 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393645 if '--output' not in cmd:
3646 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033647 old_contents = old_pydeps_data[2:]
3648 else:
3649 # A default cmd that should work in most cases (as long as pydeps filename
3650 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3651 # file is empty/new.
3652 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3653 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3654 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103655 env = dict(os.environ)
3656 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403657 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103658 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413659 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033660 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413661 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403662
3663
Tibor Goldschwendt360793f72019-06-25 18:23:493664def _ParseGclientArgs():
3665 args = {}
3666 with open('build/config/gclient_args.gni', 'r') as f:
3667 for line in f:
3668 line = line.strip()
3669 if not line or line.startswith('#'):
3670 continue
3671 attribute, value = line.split('=')
3672 args[attribute.strip()] = value.strip()
3673 return args
3674
3675
Saagar Sanghavifceeaae2020-08-12 16:40:363676def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403677 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403678 # This check is for Python dependency lists (.pydeps files), and involves
3679 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3680 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283681 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003682 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493683 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403684 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403685 results = []
3686 # First, check for new / deleted .pydeps.
3687 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033688 # Check whether we are running the presubmit check for a file in src.
3689 # f.LocalPath is relative to repo (src, or internal repo).
3690 # os_path.exists is relative to src repo.
3691 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3692 # to src and we can conclude that the pydeps is in src.
3693 if input_api.os_path.exists(f.LocalPath()):
3694 if f.LocalPath().endswith('.pydeps'):
3695 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3696 results.append(output_api.PresubmitError(
3697 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3698 'remove %s' % f.LocalPath()))
3699 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3700 results.append(output_api.PresubmitError(
3701 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3702 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403703
3704 if results:
3705 return results
3706
Mohamed Heikal7cd4d8312020-06-16 16:49:403707 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3708 affected_pydeps = set(checker.ComputeAffectedPydeps())
3709 affected_android_pydeps = affected_pydeps.intersection(
3710 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3711 if affected_android_pydeps and not is_android:
3712 results.append(output_api.PresubmitPromptOrNotify(
3713 'You have changed python files that may affect pydeps for android\n'
3714 'specific scripts. However, the relevant presumbit check cannot be\n'
3715 'run because you are not using an Android checkout. To validate that\n'
3716 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3717 'use the android-internal-presubmit optional trybot.\n'
3718 'Possibly stale pydeps files:\n{}'.format(
3719 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403720
Mohamed Heikal7cd4d8312020-06-16 16:49:403721 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3722 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403723 try:
phajdan.jr0d9878552016-11-04 10:49:413724 result = checker.DetermineIfStale(pydep_path)
3725 if result:
3726 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403727 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413728 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3729 'To regenerate, run:\n\n %s' %
3730 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403731 except input_api.subprocess.CalledProcessError as error:
3732 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3733 long_text=error.output)]
3734
3735 return results
3736
3737
Saagar Sanghavifceeaae2020-08-12 16:40:363738def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433739 """Checks to make sure no header files have |Singleton<|."""
3740 def FileFilter(affected_file):
3741 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443742 files_to_skip = (_EXCLUDED_PATHS +
3743 input_api.DEFAULT_FILES_TO_SKIP +
3744 (r"^base[\\/]memory[\\/]singleton\.h$",
3745 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3746 r"quic_singleton_impl\.h$"))
3747 return input_api.FilterSourceFile(affected_file,
3748 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433749
sergeyu34d21222015-09-16 00:11:443750 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433751 files = []
3752 for f in input_api.AffectedSourceFiles(FileFilter):
3753 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3754 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3755 contents = input_api.ReadFile(f)
3756 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243757 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433758 pattern.search(line)):
3759 files.append(f)
3760 break
3761
3762 if files:
yolandyandaabc6d2016-04-18 18:29:393763 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443764 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433765 'Please move them to an appropriate source file so that the ' +
3766 'template gets instantiated in a single compilation unit.',
3767 files) ]
3768 return []
3769
3770
[email protected]fd20b902014-05-09 02:14:533771_DEPRECATED_CSS = [
3772 # Values
3773 ( "-webkit-box", "flex" ),
3774 ( "-webkit-inline-box", "inline-flex" ),
3775 ( "-webkit-flex", "flex" ),
3776 ( "-webkit-inline-flex", "inline-flex" ),
3777 ( "-webkit-min-content", "min-content" ),
3778 ( "-webkit-max-content", "max-content" ),
3779
3780 # Properties
3781 ( "-webkit-background-clip", "background-clip" ),
3782 ( "-webkit-background-origin", "background-origin" ),
3783 ( "-webkit-background-size", "background-size" ),
3784 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443785 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533786
3787 # Functions
3788 ( "-webkit-gradient", "gradient" ),
3789 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3790 ( "-webkit-linear-gradient", "linear-gradient" ),
3791 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3792 ( "-webkit-radial-gradient", "radial-gradient" ),
3793 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3794]
3795
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203796
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493797# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363798def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533799 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253800 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343801 documentation and iOS CSS for dom distiller
3802 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253803 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533804 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493805 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443806 files_to_skip = (_EXCLUDED_PATHS +
3807 _TEST_CODE_EXCLUDED_PATHS +
3808 input_api.DEFAULT_FILES_TO_SKIP +
3809 (r"^chrome/common/extensions/docs",
3810 r"^chrome/docs",
3811 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3812 r"^components/neterror/resources/neterror.css",
3813 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253814 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443815 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533816 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3817 for line_num, line in fpath.ChangedContents():
3818 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023819 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533820 results.append(output_api.PresubmitError(
3821 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3822 (fpath.LocalPath(), line_num, deprecated_value, value)))
3823 return results
3824
mohan.reddyf21db962014-10-16 12:26:473825
Saagar Sanghavifceeaae2020-08-12 16:40:363826def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363827 bad_files = {}
3828 for f in input_api.AffectedFiles(include_deletes=False):
3829 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493830 not f.LocalPath().startswith('third_party/blink') and
3831 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363832 continue
3833
Daniel Bratell65b033262019-04-23 08:17:063834 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363835 continue
3836
Vaclav Brozekd5de76a2018-03-17 07:57:503837 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363838 if "#include" in line and "../" in line]
3839 if not relative_includes:
3840 continue
3841 bad_files[f.LocalPath()] = relative_includes
3842
3843 if not bad_files:
3844 return []
3845
3846 error_descriptions = []
3847 for file_path, bad_lines in bad_files.iteritems():
3848 error_description = file_path
3849 for line in bad_lines:
3850 error_description += '\n ' + line
3851 error_descriptions.append(error_description)
3852
3853 results = []
3854 results.append(output_api.PresubmitError(
3855 'You added one or more relative #include paths (including "../").\n'
3856 'These shouldn\'t be used because they can be used to include headers\n'
3857 'from code that\'s not correctly specified as a dependency in the\n'
3858 'relevant BUILD.gn file(s).',
3859 error_descriptions))
3860
3861 return results
3862
Takeshi Yoshinoe387aa32017-08-02 13:16:133863
Saagar Sanghavifceeaae2020-08-12 16:40:363864def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063865 """Check that nobody tries to include a cc file. It's a relatively
3866 common error which results in duplicate symbols in object
3867 files. This may not always break the build until someone later gets
3868 very confusing linking errors."""
3869 results = []
3870 for f in input_api.AffectedFiles(include_deletes=False):
3871 # We let third_party code do whatever it wants
3872 if (f.LocalPath().startswith('third_party') and
3873 not f.LocalPath().startswith('third_party/blink') and
3874 not f.LocalPath().startswith('third_party\\blink')):
3875 continue
3876
3877 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3878 continue
3879
3880 for _, line in f.ChangedContents():
3881 if line.startswith('#include "'):
3882 included_file = line.split('"')[1]
3883 if _IsCPlusPlusFile(input_api, included_file):
3884 # The most common naming for external files with C++ code,
3885 # apart from standard headers, is to call them foo.inc, but
3886 # Chromium sometimes uses foo-inc.cc so allow that as well.
3887 if not included_file.endswith(('.h', '-inc.cc')):
3888 results.append(output_api.PresubmitError(
3889 'Only header files or .inc files should be included in other\n'
3890 'C++ files. Compiling the contents of a cc file more than once\n'
3891 'will cause duplicate information in the build which may later\n'
3892 'result in strange link_errors.\n' +
3893 f.LocalPath() + ':\n ' +
3894 line))
3895
3896 return results
3897
3898
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203899def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3900 if not isinstance(key, ast.Str):
3901 return 'Key at line %d must be a string literal' % key.lineno
3902 if not isinstance(value, ast.Dict):
3903 return 'Value at line %d must be a dict' % value.lineno
3904 if len(value.keys) != 1:
3905 return 'Dict at line %d must have single entry' % value.lineno
3906 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3907 return (
3908 'Entry at line %d must have a string literal \'filepath\' as key' %
3909 value.lineno)
3910 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133911
Takeshi Yoshinoe387aa32017-08-02 13:16:133912
Sergey Ulanov4af16052018-11-08 02:41:463913def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203914 if not isinstance(key, ast.Str):
3915 return 'Key at line %d must be a string literal' % key.lineno
3916 if not isinstance(value, ast.List):
3917 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463918 for element in value.elts:
3919 if not isinstance(element, ast.Str):
3920 return 'Watchlist elements on line %d is not a string' % key.lineno
3921 if not email_regex.match(element.s):
3922 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3923 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203924 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133925
Takeshi Yoshinoe387aa32017-08-02 13:16:133926
Sergey Ulanov4af16052018-11-08 02:41:463927def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203928 mismatch_template = (
3929 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3930 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133931
Sergey Ulanov4af16052018-11-08 02:41:463932 email_regex = input_api.re.compile(
3933 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3934
3935 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203936 i = 0
3937 last_key = ''
3938 while True:
3939 if i >= len(wd_dict.keys):
3940 if i >= len(w_dict.keys):
3941 return None
3942 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3943 elif i >= len(w_dict.keys):
3944 return (
3945 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133946
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203947 wd_key = wd_dict.keys[i]
3948 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133949
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203950 result = _CheckWatchlistDefinitionsEntrySyntax(
3951 wd_key, wd_dict.values[i], ast)
3952 if result is not None:
3953 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133954
Sergey Ulanov4af16052018-11-08 02:41:463955 result = _CheckWatchlistsEntrySyntax(
3956 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203957 if result is not None:
3958 return 'Bad entry in WATCHLISTS dict: %s' % result
3959
3960 if wd_key.s != w_key.s:
3961 return mismatch_template % (
3962 '%s at line %d' % (wd_key.s, wd_key.lineno),
3963 '%s at line %d' % (w_key.s, w_key.lineno))
3964
3965 if wd_key.s < last_key:
3966 return (
3967 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3968 (wd_key.lineno, w_key.lineno))
3969 last_key = wd_key.s
3970
3971 i = i + 1
3972
3973
Sergey Ulanov4af16052018-11-08 02:41:463974def _CheckWATCHLISTSSyntax(expression, input_api):
3975 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203976 if not isinstance(expression, ast.Expression):
3977 return 'WATCHLISTS file must contain a valid expression'
3978 dictionary = expression.body
3979 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3980 return 'WATCHLISTS file must have single dict with exactly two entries'
3981
3982 first_key = dictionary.keys[0]
3983 first_value = dictionary.values[0]
3984 second_key = dictionary.keys[1]
3985 second_value = dictionary.values[1]
3986
3987 if (not isinstance(first_key, ast.Str) or
3988 first_key.s != 'WATCHLIST_DEFINITIONS' or
3989 not isinstance(first_value, ast.Dict)):
3990 return (
3991 'The first entry of the dict in WATCHLISTS file must be '
3992 'WATCHLIST_DEFINITIONS dict')
3993
3994 if (not isinstance(second_key, ast.Str) or
3995 second_key.s != 'WATCHLISTS' or
3996 not isinstance(second_value, ast.Dict)):
3997 return (
3998 'The second entry of the dict in WATCHLISTS file must be '
3999 'WATCHLISTS dict')
4000
Sergey Ulanov4af16052018-11-08 02:41:464001 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134002
4003
Saagar Sanghavifceeaae2020-08-12 16:40:364004def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:134005 for f in input_api.AffectedFiles(include_deletes=False):
4006 if f.LocalPath() == 'WATCHLISTS':
4007 contents = input_api.ReadFile(f, 'r')
4008
4009 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204010 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134011 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204012 # Get an AST tree for it and scan the tree for detailed style checking.
4013 expression = input_api.ast.parse(
4014 contents, filename='WATCHLISTS', mode='eval')
4015 except ValueError as e:
4016 return [output_api.PresubmitError(
4017 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4018 except SyntaxError as e:
4019 return [output_api.PresubmitError(
4020 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4021 except TypeError as e:
4022 return [output_api.PresubmitError(
4023 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134024
Sergey Ulanov4af16052018-11-08 02:41:464025 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204026 if result is not None:
4027 return [output_api.PresubmitError(result)]
4028 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134029
4030 return []
4031
4032
Andrew Grieve1b290e4a22020-11-24 20:07:014033def CheckGnGlobForward(input_api, output_api):
4034 """Checks that forward_variables_from(invoker, "*") follows best practices.
4035
4036 As documented at //build/docs/writing_gn_templates.md
4037 """
4038 def gn_files(f):
4039 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
4040
4041 problems = []
4042 for f in input_api.AffectedSourceFiles(gn_files):
4043 for line_num, line in f.ChangedContents():
4044 if 'forward_variables_from(invoker, "*")' in line:
4045 problems.append(
4046 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
4047 f.LocalPath(), line_num))
4048
4049 if problems:
4050 return [output_api.PresubmitPromptWarning(
4051 'forward_variables_from("*") without exclusions',
4052 items=sorted(problems),
4053 long_text=('The variables "visibilty" and "test_only" should be '
4054 'explicitly listed in forward_variables_from(). For more '
4055 'details, see:\n'
4056 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4057 'build/docs/writing_gn_templates.md'
4058 '#Using-forward_variables_from'))]
4059 return []
4060
4061
Saagar Sanghavifceeaae2020-08-12 16:40:364062def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194063 """Checks that newly added header files have corresponding GN changes.
4064 Note that this is only a heuristic. To be precise, run script:
4065 build/check_gn_headers.py.
4066 """
4067
4068 def headers(f):
4069 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444070 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194071
4072 new_headers = []
4073 for f in input_api.AffectedSourceFiles(headers):
4074 if f.Action() != 'A':
4075 continue
4076 new_headers.append(f.LocalPath())
4077
4078 def gn_files(f):
James Cook24a504192020-07-23 00:08:444079 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194080
4081 all_gn_changed_contents = ''
4082 for f in input_api.AffectedSourceFiles(gn_files):
4083 for _, line in f.ChangedContents():
4084 all_gn_changed_contents += line
4085
4086 problems = []
4087 for header in new_headers:
4088 basename = input_api.os_path.basename(header)
4089 if basename not in all_gn_changed_contents:
4090 problems.append(header)
4091
4092 if problems:
4093 return [output_api.PresubmitPromptWarning(
4094 'Missing GN changes for new header files', items=sorted(problems),
4095 long_text='Please double check whether newly added header files need '
4096 'corresponding changes in gn or gni files.\nThis checking is only a '
4097 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4098 'Read https://crbug.com/661774 for more info.')]
4099 return []
4100
4101
Saagar Sanghavifceeaae2020-08-12 16:40:364102def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024103 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4104
4105 This assumes we won't intentionally reference one product from the other
4106 product.
4107 """
4108 all_problems = []
4109 test_cases = [{
4110 "filename_postfix": "google_chrome_strings.grd",
4111 "correct_name": "Chrome",
4112 "incorrect_name": "Chromium",
4113 }, {
4114 "filename_postfix": "chromium_strings.grd",
4115 "correct_name": "Chromium",
4116 "incorrect_name": "Chrome",
4117 }]
4118
4119 for test_case in test_cases:
4120 problems = []
4121 filename_filter = lambda x: x.LocalPath().endswith(
4122 test_case["filename_postfix"])
4123
4124 # Check each new line. Can yield false positives in multiline comments, but
4125 # easier than trying to parse the XML because messages can have nested
4126 # children, and associating message elements with affected lines is hard.
4127 for f in input_api.AffectedSourceFiles(filename_filter):
4128 for line_num, line in f.ChangedContents():
4129 if "<message" in line or "<!--" in line or "-->" in line:
4130 continue
4131 if test_case["incorrect_name"] in line:
4132 problems.append(
4133 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4134
4135 if problems:
4136 message = (
4137 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4138 % (test_case["correct_name"], test_case["correct_name"],
4139 test_case["incorrect_name"]))
4140 all_problems.append(
4141 output_api.PresubmitPromptWarning(message, items=problems))
4142
4143 return all_problems
4144
4145
Saagar Sanghavifceeaae2020-08-12 16:40:364146def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364147 """Avoid large files, especially binary files, in the repository since
4148 git doesn't scale well for those. They will be in everyone's repo
4149 clones forever, forever making Chromium slower to clone and work
4150 with."""
4151
4152 # Uploading files to cloud storage is not trivial so we don't want
4153 # to set the limit too low, but the upper limit for "normal" large
4154 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4155 # anything over 20 MB is exceptional.
4156 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4157
4158 too_large_files = []
4159 for f in input_api.AffectedFiles():
4160 # Check both added and modified files (but not deleted files).
4161 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384162 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364163 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4164 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4165
4166 if too_large_files:
4167 message = (
4168 'Do not commit large files to git since git scales badly for those.\n' +
4169 'Instead put the large files in cloud storage and use DEPS to\n' +
4170 'fetch them.\n' + '\n'.join(too_large_files)
4171 )
4172 return [output_api.PresubmitError(
4173 'Too large files found in commit', long_text=message + '\n')]
4174 else:
4175 return []
4176
Max Morozb47503b2019-08-08 21:03:274177
Saagar Sanghavifceeaae2020-08-12 16:40:364178def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274179 """Checks specific for fuzz target sources."""
4180 EXPORTED_SYMBOLS = [
4181 'LLVMFuzzerInitialize',
4182 'LLVMFuzzerCustomMutator',
4183 'LLVMFuzzerCustomCrossOver',
4184 'LLVMFuzzerMutate',
4185 ]
4186
4187 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4188
4189 def FilterFile(affected_file):
4190 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444191 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4192 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274193
4194 return input_api.FilterSourceFile(
4195 affected_file,
James Cook24a504192020-07-23 00:08:444196 files_to_check=[files_to_check],
4197 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274198
4199 files_with_missing_header = []
4200 for f in input_api.AffectedSourceFiles(FilterFile):
4201 contents = input_api.ReadFile(f, 'r')
4202 if REQUIRED_HEADER in contents:
4203 continue
4204
4205 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4206 files_with_missing_header.append(f.LocalPath())
4207
4208 if not files_with_missing_header:
4209 return []
4210
4211 long_text = (
4212 'If you define any of the libFuzzer optional functions (%s), it is '
4213 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4214 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4215 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4216 'to access command line arguments passed to the fuzzer. Instead, prefer '
4217 'static initialization and shared resources as documented in '
4218 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4219 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4220 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4221 )
4222
4223 return [output_api.PresubmitPromptWarning(
4224 message="Missing '%s' in:" % REQUIRED_HEADER,
4225 items=files_with_missing_header,
4226 long_text=long_text)]
4227
4228
Mohamed Heikald048240a2019-11-12 16:57:374229def _CheckNewImagesWarning(input_api, output_api):
4230 """
4231 Warns authors who add images into the repo to make sure their images are
4232 optimized before committing.
4233 """
4234 images_added = False
4235 image_paths = []
4236 errors = []
4237 filter_lambda = lambda x: input_api.FilterSourceFile(
4238 x,
James Cook24a504192020-07-23 00:08:444239 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4240 + input_api.DEFAULT_FILES_TO_SKIP),
4241 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374242 )
4243 for f in input_api.AffectedFiles(
4244 include_deletes=False, file_filter=filter_lambda):
4245 local_path = f.LocalPath().lower()
4246 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4247 images_added = True
4248 image_paths.append(f)
4249 if images_added:
4250 errors.append(output_api.PresubmitPromptWarning(
4251 'It looks like you are trying to commit some images. If these are '
4252 'non-test-only images, please make sure to read and apply the tips in '
4253 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4254 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4255 'FYI only and will not block your CL on the CQ.', image_paths))
4256 return errors
4257
4258
Saagar Sanghavifceeaae2020-08-12 16:40:364259def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574260 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224261 results = []
dgnaa68d5e2015-06-10 10:08:224262 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174263 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224264 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294265 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064266 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4267 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424268 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184269 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574270 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374271 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154272 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574273 return results
4274
Saagar Sanghavifceeaae2020-08-12 16:40:364275def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574276 """Groups commit checks that target android code."""
4277 results = []
4278 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224279 return results
4280
Chris Hall59f8d0c72020-05-01 07:31:194281# TODO(chrishall): could we additionally match on any path owned by
4282# ui/accessibility/OWNERS ?
4283_ACCESSIBILITY_PATHS = (
4284 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4285 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4286 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4287 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4288 r"^content[\\/]browser[\\/]accessibility[\\/]",
4289 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4290 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4291 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4292 r"^ui[\\/]accessibility[\\/]",
4293 r"^ui[\\/]views[\\/]accessibility[\\/]",
4294)
4295
Saagar Sanghavifceeaae2020-08-12 16:40:364296def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194297 """Checks that commits to accessibility code contain an AX-Relnotes field in
4298 their commit message."""
4299 def FileFilter(affected_file):
4300 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444301 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194302
4303 # Only consider changes affecting accessibility paths.
4304 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4305 return []
4306
Akihiro Ota08108e542020-05-20 15:30:534307 # AX-Relnotes can appear in either the description or the footer.
4308 # When searching the description, require 'AX-Relnotes:' to appear at the
4309 # beginning of a line.
4310 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4311 description_has_relnotes = any(ax_regex.match(line)
4312 for line in input_api.change.DescriptionText().lower().splitlines())
4313
4314 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4315 'AX-Relnotes', [])
4316 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194317 return []
4318
4319 # TODO(chrishall): link to Relnotes documentation in message.
4320 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4321 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4322 "user-facing changes"
4323 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4324 "user-facing effects"
4325 "\n if this is confusing or annoying then please contact members "
4326 "of ui/accessibility/OWNERS.")
4327
4328 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224329
Saagar Sanghavifceeaae2020-08-12 16:40:364330def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394331 """Checks common to both upload and commit."""
4332 results = []
4333 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384334 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544335 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084336
4337 author = input_api.change.author_email
4338 if author and author not in _KNOWN_ROBOTS:
4339 results.extend(
4340 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4341
[email protected]9f919cc2013-07-31 03:04:044342 results.extend(
4343 input_api.canned_checks.CheckChangeHasNoTabs(
4344 input_api,
4345 output_api,
4346 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434347 results.extend(input_api.RunTests(
4348 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244349
Edward Lesmesce51df52020-08-04 22:10:174350 dirmd_bin = input_api.os_path.join(
4351 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4352 results.extend(input_api.RunTests(
4353 input_api.canned_checks.CheckDirMetadataFormat(
4354 input_api, output_api, dirmd_bin)))
4355 results.extend(
4356 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4357 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554358 results.extend(
4359 input_api.canned_checks.CheckNoNewMetadataInOwners(
4360 input_api, output_api))
Edward Lesmesce51df52020-08-04 22:10:174361
Vaclav Brozekcdc7defb2018-03-20 09:54:354362 for f in input_api.AffectedFiles():
4363 path, name = input_api.os_path.split(f.LocalPath())
4364 if name == 'PRESUBMIT.py':
4365 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004366 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4367 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074368 # The PRESUBMIT.py file (and the directory containing it) might
4369 # have been affected by being moved or removed, so only try to
4370 # run the tests if they still exist.
4371 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4372 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444373 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394374 return results
[email protected]1f7b4172010-01-28 01:17:344375
[email protected]b337cb5b2011-01-23 21:24:054376
Saagar Sanghavifceeaae2020-08-12 16:40:364377def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494378 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4379 if f.LocalPath().endswith(('.orig', '.rej'))]
4380 if problems:
4381 return [output_api.PresubmitError(
4382 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034383 else:
4384 return []
[email protected]b8079ae4a2012-12-05 19:56:494385
4386
Saagar Sanghavifceeaae2020-08-12 16:40:364387def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214388 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4389 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4390 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074391 include_re = input_api.re.compile(
4392 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4393 extension_re = input_api.re.compile(r'\.[a-z]+$')
4394 errors = []
4395 for f in input_api.AffectedFiles():
4396 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4397 continue
4398 found_line_number = None
4399 found_macro = None
4400 for line_num, line in f.ChangedContents():
4401 match = macro_re.search(line)
4402 if match:
4403 found_line_number = line_num
4404 found_macro = match.group(2)
4405 break
4406 if not found_line_number:
4407 continue
4408
4409 found_include = False
4410 for line in f.NewContents():
4411 if include_re.search(line):
4412 found_include = True
4413 break
4414 if found_include:
4415 continue
4416
4417 if not f.LocalPath().endswith('.h'):
4418 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4419 try:
4420 content = input_api.ReadFile(primary_header_path, 'r')
4421 if include_re.search(content):
4422 continue
4423 except IOError:
4424 pass
4425 errors.append('%s:%d %s macro is used without including build/'
4426 'build_config.h.'
4427 % (f.LocalPath(), found_line_number, found_macro))
4428 if errors:
4429 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4430 return []
4431
4432
[email protected]b00342e7f2013-03-26 16:21:544433def _DidYouMeanOSMacro(bad_macro):
4434 try:
4435 return {'A': 'OS_ANDROID',
4436 'B': 'OS_BSD',
4437 'C': 'OS_CHROMEOS',
4438 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444439 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544440 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444441 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544442 'N': 'OS_NACL',
4443 'O': 'OS_OPENBSD',
4444 'P': 'OS_POSIX',
4445 'S': 'OS_SOLARIS',
4446 'W': 'OS_WIN'}[bad_macro[3].upper()]
4447 except KeyError:
4448 return ''
4449
4450
4451def _CheckForInvalidOSMacrosInFile(input_api, f):
4452 """Check for sensible looking, totally invalid OS macros."""
4453 preprocessor_statement = input_api.re.compile(r'^\s*#')
4454 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4455 results = []
4456 for lnum, line in f.ChangedContents():
4457 if preprocessor_statement.search(line):
4458 for match in os_macro.finditer(line):
4459 if not match.group(1) in _VALID_OS_MACROS:
4460 good = _DidYouMeanOSMacro(match.group(1))
4461 did_you_mean = ' (did you mean %s?)' % good if good else ''
4462 results.append(' %s:%d %s%s' % (f.LocalPath(),
4463 lnum,
4464 match.group(1),
4465 did_you_mean))
4466 return results
4467
4468
Saagar Sanghavifceeaae2020-08-12 16:40:364469def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544470 """Check all affected files for invalid OS macros."""
4471 bad_macros = []
tzik3f295992018-12-04 20:32:234472 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474473 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544474 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4475
4476 if not bad_macros:
4477 return []
4478
4479 return [output_api.PresubmitError(
4480 'Possibly invalid OS macro[s] found. Please fix your code\n'
4481 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4482
lliabraa35bab3932014-10-01 12:16:444483
4484def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4485 """Check all affected files for invalid "if defined" macros."""
4486 ALWAYS_DEFINED_MACROS = (
4487 "TARGET_CPU_PPC",
4488 "TARGET_CPU_PPC64",
4489 "TARGET_CPU_68K",
4490 "TARGET_CPU_X86",
4491 "TARGET_CPU_ARM",
4492 "TARGET_CPU_MIPS",
4493 "TARGET_CPU_SPARC",
4494 "TARGET_CPU_ALPHA",
4495 "TARGET_IPHONE_SIMULATOR",
4496 "TARGET_OS_EMBEDDED",
4497 "TARGET_OS_IPHONE",
4498 "TARGET_OS_MAC",
4499 "TARGET_OS_UNIX",
4500 "TARGET_OS_WIN32",
4501 )
4502 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4503 results = []
4504 for lnum, line in f.ChangedContents():
4505 for match in ifdef_macro.finditer(line):
4506 if match.group(1) in ALWAYS_DEFINED_MACROS:
4507 always_defined = ' %s is always defined. ' % match.group(1)
4508 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4509 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4510 lnum,
4511 always_defined,
4512 did_you_mean))
4513 return results
4514
4515
Saagar Sanghavifceeaae2020-08-12 16:40:364516def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444517 """Check all affected files for invalid "if defined" macros."""
4518 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054519 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444520 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054521 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214522 continue
lliabraa35bab3932014-10-01 12:16:444523 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4524 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4525
4526 if not bad_macros:
4527 return []
4528
4529 return [output_api.PresubmitError(
4530 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4531 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4532 bad_macros)]
4533
4534
Saagar Sanghavifceeaae2020-08-12 16:40:364535def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044536 """Check for same IPC rules described in
4537 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4538 """
4539 base_pattern = r'IPC_ENUM_TRAITS\('
4540 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4541 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4542
4543 problems = []
4544 for f in input_api.AffectedSourceFiles(None):
4545 local_path = f.LocalPath()
4546 if not local_path.endswith('.h'):
4547 continue
4548 for line_number, line in f.ChangedContents():
4549 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4550 problems.append(
4551 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4552
4553 if problems:
4554 return [output_api.PresubmitPromptWarning(
4555 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4556 else:
4557 return []
4558
[email protected]b00342e7f2013-03-26 16:21:544559
Saagar Sanghavifceeaae2020-08-12 16:40:364560def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054561 """Check to make sure no files being submitted have long paths.
4562 This causes issues on Windows.
4563 """
4564 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194565 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054566 local_path = f.LocalPath()
4567 # Windows has a path limit of 260 characters. Limit path length to 200 so
4568 # that we have some extra for the prefix on dev machines and the bots.
4569 if len(local_path) > 200:
4570 problems.append(local_path)
4571
4572 if problems:
4573 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4574 else:
4575 return []
4576
4577
Saagar Sanghavifceeaae2020-08-12 16:40:364578def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144579 """Check that header files have proper guards against multiple inclusion.
4580 If a file should not have such guards (and it probably should) then it
4581 should include the string "no-include-guard-because-multiply-included".
4582 """
Daniel Bratell6a75baef62018-06-04 10:04:454583 def is_chromium_header_file(f):
4584 # We only check header files under the control of the Chromium
4585 # project. That is, those outside third_party apart from
4586 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324587 # We also exclude *_message_generator.h headers as they use
4588 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454589 file_with_path = input_api.os_path.normpath(f.LocalPath())
4590 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324591 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454592 (not file_with_path.startswith('third_party') or
4593 file_with_path.startswith(
4594 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144595
4596 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344597 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144598
4599 errors = []
4600
Daniel Bratell6a75baef62018-06-04 10:04:454601 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144602 guard_name = None
4603 guard_line_number = None
4604 seen_guard_end = False
4605
4606 file_with_path = input_api.os_path.normpath(f.LocalPath())
4607 base_file_name = input_api.os_path.splitext(
4608 input_api.os_path.basename(file_with_path))[0]
4609 upper_base_file_name = base_file_name.upper()
4610
4611 expected_guard = replace_special_with_underscore(
4612 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144613
4614 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574615 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4616 # are too many (1000+) files with slight deviations from the
4617 # coding style. The most important part is that the include guard
4618 # is there, and that it's unique, not the name so this check is
4619 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144620 #
4621 # As code becomes more uniform, this could be made stricter.
4622
4623 guard_name_pattern_list = [
4624 # Anything with the right suffix (maybe with an extra _).
4625 r'\w+_H__?',
4626
Daniel Bratell39b5b062018-05-16 18:09:574627 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144628 r'\w+_h',
4629
4630 # Anything including the uppercase name of the file.
4631 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4632 upper_base_file_name)) + r'\w*',
4633 ]
4634 guard_name_pattern = '|'.join(guard_name_pattern_list)
4635 guard_pattern = input_api.re.compile(
4636 r'#ifndef\s+(' + guard_name_pattern + ')')
4637
4638 for line_number, line in enumerate(f.NewContents()):
4639 if 'no-include-guard-because-multiply-included' in line:
4640 guard_name = 'DUMMY' # To not trigger check outside the loop.
4641 break
4642
4643 if guard_name is None:
4644 match = guard_pattern.match(line)
4645 if match:
4646 guard_name = match.group(1)
4647 guard_line_number = line_number
4648
Daniel Bratell39b5b062018-05-16 18:09:574649 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454650 # don't match the chromium style guide, but new files should
4651 # get it right.
4652 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574653 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144654 errors.append(output_api.PresubmitPromptWarning(
4655 'Header using the wrong include guard name %s' % guard_name,
4656 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574657 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144658 else:
4659 # The line after #ifndef should have a #define of the same name.
4660 if line_number == guard_line_number + 1:
4661 expected_line = '#define %s' % guard_name
4662 if line != expected_line:
4663 errors.append(output_api.PresubmitPromptWarning(
4664 'Missing "%s" for include guard' % expected_line,
4665 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4666 'Expected: %r\nGot: %r' % (expected_line, line)))
4667
4668 if not seen_guard_end and line == '#endif // %s' % guard_name:
4669 seen_guard_end = True
4670 elif seen_guard_end:
4671 if line.strip() != '':
4672 errors.append(output_api.PresubmitPromptWarning(
4673 'Include guard %s not covering the whole file' % (
4674 guard_name), [f.LocalPath()]))
4675 break # Nothing else to check and enough to warn once.
4676
4677 if guard_name is None:
4678 errors.append(output_api.PresubmitPromptWarning(
4679 'Missing include guard %s' % expected_guard,
4680 [f.LocalPath()],
4681 'Missing include guard in %s\n'
4682 'Recommended name: %s\n'
4683 'This check can be disabled by having the string\n'
4684 'no-include-guard-because-multiply-included in the header.' %
4685 (f.LocalPath(), expected_guard)))
4686
4687 return errors
4688
4689
Saagar Sanghavifceeaae2020-08-12 16:40:364690def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234691 """Check source code and known ascii text files for Windows style line
4692 endings.
4693 """
earthdok1b5e0ee2015-03-10 15:19:104694 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234695
4696 file_inclusion_pattern = (
4697 known_text_files,
4698 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4699 )
4700
mostynbb639aca52015-01-07 20:31:234701 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534702 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444703 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534704 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504705 include_file = False
4706 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234707 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504708 include_file = True
4709 if include_file:
4710 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234711
4712 if problems:
4713 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4714 'these files to contain Windows style line endings?\n' +
4715 '\n'.join(problems))]
4716
4717 return []
4718
Jose Magana2b456f22021-03-09 23:26:404719def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4720 """Check source code for use of Chrome App technologies being
4721 deprecated.
4722 """
4723
4724 def _CheckForDeprecatedTech(input_api, output_api,
4725 detection_list, files_to_check = None, files_to_skip = None):
4726
4727 if (files_to_check or files_to_skip):
4728 source_file_filter = lambda f: input_api.FilterSourceFile(
4729 f, files_to_check=files_to_check,
4730 files_to_skip=files_to_skip)
4731 else:
4732 source_file_filter = None
4733
4734 problems = []
4735
4736 for f in input_api.AffectedSourceFiles(source_file_filter):
4737 if f.Action() == 'D':
4738 continue
4739 for _, line in f.ChangedContents():
4740 if any( detect in line for detect in detection_list ):
4741 problems.append(f.LocalPath())
4742
4743 return problems
4744
4745 # to avoid this presubmit script triggering warnings
4746 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4747
4748 problems =[]
4749
4750 # NMF: any files with extensions .nmf or NMF
4751 _NMF_FILES = r'\.(nmf|NMF)$'
4752 problems += _CheckForDeprecatedTech(input_api, output_api,
4753 detection_list = [''], # any change to the file will trigger warning
4754 files_to_check = [ r'.+%s' % _NMF_FILES ])
4755
4756 # MANIFEST: any manifest.json that in its diff includes "app":
4757 _MANIFEST_FILES = r'(manifest\.json)$'
4758 problems += _CheckForDeprecatedTech(input_api, output_api,
4759 detection_list = ['"app":'],
4760 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4761
4762 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4763 problems += _CheckForDeprecatedTech(input_api, output_api,
4764 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4765 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4766
4767 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4768 problems += _CheckForDeprecatedTech(input_api, output_api,
4769 detection_list = ['#include "ppapi','#include <ppapi'],
4770 files_to_check = (
4771 r'.+%s' % _HEADER_EXTENSIONS,
4772 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4773 files_to_skip = [r"^ppapi[\\/]"] )
4774
4775 # Chrome Apps: any JS/TS file that references an API in the list below.
4776 # This should include the list of Chrome Apps APIs that are not Chrome
4777 # Extensions APIs as documented in:
4778 # https://developer.chrome.com/docs/apps/migration/
4779 detection_list_chrome_apps = [
4780 'chrome.accessibilityFeatures',
4781 'chrome.alarms',
4782 'chrome.app.runtime',
4783 'chrome.app.window',
4784 'chrome.audio',
4785 'chrome.bluetooth',
4786 'chrome.bluetoothLowEnergy',
4787 'chrome.bluetoothSocket',
4788 'chrome.browser',
4789 'chrome.commands',
4790 'chrome.contextMenus',
4791 'chrome.documentScan',
4792 'chrome.events',
4793 'chrome.extensionTypes',
4794 'chrome.fileSystem',
4795 'chrome.fileSystemProvider',
4796 'chrome.gcm',
4797 'chrome.hid',
4798 'chrome.i18n',
4799 'chrome.identity',
4800 'chrome.idle',
4801 'chrome.instanceID',
4802 'chrome.mdns',
4803 'chrome.mediaGalleries',
4804 'chrome.networking.onc',
4805 'chrome.notifications',
4806 'chrome.permissions',
4807 'chrome.power',
4808 'chrome.printerProvider',
4809 'chrome.runtime',
4810 'chrome.serial',
4811 'chrome.sockets.tcp',
4812 'chrome.sockets.tcpServer',
4813 'chrome.sockets.udp',
4814 'chrome.storage',
4815 'chrome.syncFileSystem',
4816 'chrome.system.cpu',
4817 'chrome.system.display',
4818 'chrome.system.memory',
4819 'chrome.system.network',
4820 'chrome.system.storage',
4821 'chrome.tts',
4822 'chrome.types',
4823 'chrome.usb',
4824 'chrome.virtualKeyboard',
4825 'chrome.vpnProvider',
4826 'chrome.wallpaper'
4827 ]
4828 _JS_FILES = r'\.(js|ts)$'
4829 problems += _CheckForDeprecatedTech(input_api, output_api,
4830 detection_list = detection_list_chrome_apps,
4831 files_to_check = [ r'.+%s' % _JS_FILES ],
4832 files_to_skip = files_to_skip)
4833
4834 if problems:
4835 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4836 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4837 ' PNaCl, PPAPI). See this blog post for more details:\n'
4838 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4839 'and this documentation for options to replace these technologies:\n'
4840 'https://developer.chrome.com/docs/apps/migration/\n'+
4841 '\n'.join(problems))]
4842
4843 return []
4844
mostynbb639aca52015-01-07 20:31:234845
Saagar Sanghavifceeaae2020-08-12 16:40:364846def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134847 """Checks that all source files use SYSLOG properly."""
4848 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364849 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564850 for line_number, line in f.ChangedContents():
4851 if 'SYSLOG' in line:
4852 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4853
pastarmovj89f7ee12016-09-20 14:58:134854 if syslog_files:
4855 return [output_api.PresubmitPromptWarning(
4856 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4857 ' calls.\nFiles to check:\n', items=syslog_files)]
4858 return []
4859
4860
[email protected]1f7b4172010-01-28 01:17:344861def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364862 if input_api.version < [2, 0, 0]:
4863 return [output_api.PresubmitError("Your depot_tools is out of date. "
4864 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4865 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344866 results = []
scottmg39b29952014-12-08 18:31:284867 results.extend(
jam93a6ee792017-02-08 23:59:224868 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544869 return results
[email protected]ca8d1982009-02-19 16:33:124870
4871
[email protected]1bfb8322014-04-23 01:02:414872def GetTryServerMasterForBot(bot):
4873 """Returns the Try Server master for the given bot.
4874
[email protected]0bb112362014-07-26 04:38:324875 It tries to guess the master from the bot name, but may still fail
4876 and return None. There is no longer a default master.
4877 """
4878 # Potentially ambiguous bot names are listed explicitly.
4879 master_map = {
tandriie5587792016-07-14 00:34:504880 'chromium_presubmit': 'master.tryserver.chromium.linux',
4881 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414882 }
[email protected]0bb112362014-07-26 04:38:324883 master = master_map.get(bot)
4884 if not master:
wnwen4fbaab82016-05-25 12:54:364885 if 'android' in bot:
tandriie5587792016-07-14 00:34:504886 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364887 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504888 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324889 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504890 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324891 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504892 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324893 return master
[email protected]1bfb8322014-04-23 01:02:414894
4895
[email protected]ca8d1982009-02-19 16:33:124896def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364897 if input_api.version < [2, 0, 0]:
4898 return [output_api.PresubmitError("Your depot_tools is out of date. "
4899 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4900 "but your version is %d.%d.%d" % tuple(input_api.version))]
4901
[email protected]fe5f57c52009-06-05 14:25:544902 results = []
[email protected]fe5f57c52009-06-05 14:25:544903 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274904 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344905 input_api,
4906 output_api,
[email protected]2fdd1f362013-01-16 03:56:034907 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274908
jam93a6ee792017-02-08 23:59:224909 results.extend(
4910 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544911 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4912 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384913 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4914 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414915 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4916 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544917 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144918
4919
Saagar Sanghavifceeaae2020-08-12 16:40:364920def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264921 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024922 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4923 # footer is set to true.
4924 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264925 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024926 footer.lower()
4927 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264928 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024929
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144930 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264931 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144932 import sys
4933 from io import StringIO
4934
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144935 new_or_added_paths = set(f.LocalPath()
4936 for f in input_api.AffectedFiles()
4937 if (f.Action() == 'A' or f.Action() == 'M'))
4938 removed_paths = set(f.LocalPath()
4939 for f in input_api.AffectedFiles(include_deletes=True)
4940 if f.Action() == 'D')
4941
Andrew Grieve0e8790c2020-09-03 17:27:324942 affected_grds = [
4943 f for f in input_api.AffectedFiles()
4944 if f.LocalPath().endswith(('.grd', '.grdp'))
4945 ]
4946 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164947 if not affected_grds:
4948 return []
4949
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144950 affected_png_paths = [f.AbsoluteLocalPath()
4951 for f in input_api.AffectedFiles()
4952 if (f.LocalPath().endswith('.png'))]
4953
4954 # Check for screenshots. Developers can upload screenshots using
4955 # tools/translation/upload_screenshots.py which finds and uploads
4956 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4957 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4958 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4959 #
4960 # The logic here is as follows:
4961 #
4962 # - If the CL has a .png file under the screenshots directory for a grd
4963 # file, warn the developer. Actual images should never be checked into the
4964 # Chrome repo.
4965 #
4966 # - If the CL contains modified or new messages in grd files and doesn't
4967 # contain the corresponding .sha1 files, warn the developer to add images
4968 # and upload them via tools/translation/upload_screenshots.py.
4969 #
4970 # - If the CL contains modified or new messages in grd files and the
4971 # corresponding .sha1 files, everything looks good.
4972 #
4973 # - If the CL contains removed messages in grd files but the corresponding
4974 # .sha1 files aren't removed, warn the developer to remove them.
4975 unnecessary_screenshots = []
4976 missing_sha1 = []
4977 unnecessary_sha1_files = []
4978
Rainhard Findlingfc31844c52020-05-15 09:58:264979 # This checks verifies that the ICU syntax of messages this CL touched is
4980 # valid, and reports any found syntax errors.
4981 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4982 # without developers being aware of them. Later on, such ICU syntax errors
4983 # break message extraction for translation, hence would block Chromium
4984 # translations until they are fixed.
4985 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144986
4987 def _CheckScreenshotAdded(screenshots_dir, message_id):
4988 sha1_path = input_api.os_path.join(
4989 screenshots_dir, message_id + '.png.sha1')
4990 if sha1_path not in new_or_added_paths:
4991 missing_sha1.append(sha1_path)
4992
4993
4994 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4995 sha1_path = input_api.os_path.join(
4996 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034997 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144998 unnecessary_sha1_files.append(sha1_path)
4999
Rainhard Findlingfc31844c52020-05-15 09:58:265000
5001 def _ValidateIcuSyntax(text, level, signatures):
5002 """Validates ICU syntax of a text string.
5003
5004 Check if text looks similar to ICU and checks for ICU syntax correctness
5005 in this case. Reports various issues with ICU syntax and values of
5006 variants. Supports checking of nested messages. Accumulate information of
5007 each ICU messages found in the text for further checking.
5008
5009 Args:
5010 text: a string to check.
5011 level: a number of current nesting level.
5012 signatures: an accumulator, a list of tuple of (level, variable,
5013 kind, variants).
5014
5015 Returns:
5016 None if a string is not ICU or no issue detected.
5017 A tuple of (message, start index, end index) if an issue detected.
5018 """
5019 valid_types = {
5020 'plural': (frozenset(
5021 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5022 frozenset(['=1', 'other'])),
5023 'selectordinal': (frozenset(
5024 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5025 frozenset(['one', 'other'])),
5026 'select': (frozenset(), frozenset(['other'])),
5027 }
5028
5029 # Check if the message looks like an attempt to use ICU
5030 # plural. If yes - check if its syntax strictly matches ICU format.
5031 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
5032 if not like:
5033 signatures.append((level, None, None, None))
5034 return
5035
5036 # Check for valid prefix and suffix
5037 m = re.match(
5038 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5039 r'(plural|selectordinal|select),\s*'
5040 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5041 if not m:
5042 return (('This message looks like an ICU plural, '
5043 'but does not follow ICU syntax.'), like.start(), like.end())
5044 starting, variable, kind, variant_pairs = m.groups()
5045 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5046 if depth:
5047 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5048 len(text))
5049 first = text[0]
5050 ending = text[last_pos:]
5051 if not starting:
5052 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5053 last_pos)
5054 if not ending or '}' not in ending:
5055 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5056 last_pos)
5057 elif first != '{':
5058 return (
5059 ('Invalid ICU format. Extra characters at the start of a complex '
5060 'message (go/icu-message-migration): "%s"') %
5061 starting, 0, len(starting))
5062 elif ending != '}':
5063 return (('Invalid ICU format. Extra characters at the end of a complex '
5064 'message (go/icu-message-migration): "%s"')
5065 % ending, last_pos - 1, len(text) - 1)
5066 if kind not in valid_types:
5067 return (('Unknown ICU message type %s. '
5068 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5069 known, required = valid_types[kind]
5070 defined_variants = set()
5071 for variant, variant_range, value, value_range in variants:
5072 start, end = variant_range
5073 if variant in defined_variants:
5074 return ('Variant "%s" is defined more than once' % variant,
5075 start, end)
5076 elif known and variant not in known:
5077 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5078 start, end)
5079 defined_variants.add(variant)
5080 # Check for nested structure
5081 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5082 if res:
5083 return (res[0], res[1] + value_range[0] + 1,
5084 res[2] + value_range[0] + 1)
5085 missing = required - defined_variants
5086 if missing:
5087 return ('Required variants missing: %s' % ', '.join(missing), 0,
5088 len(text))
5089 signatures.append((level, variable, kind, defined_variants))
5090
5091
5092 def _ParseIcuVariants(text, offset=0):
5093 """Parse variants part of ICU complex message.
5094
5095 Builds a tuple of variant names and values, as well as
5096 their offsets in the input string.
5097
5098 Args:
5099 text: a string to parse
5100 offset: additional offset to add to positions in the text to get correct
5101 position in the complete ICU string.
5102
5103 Returns:
5104 List of tuples, each tuple consist of four fields: variant name,
5105 variant name span (tuple of two integers), variant value, value
5106 span (tuple of two integers).
5107 """
5108 depth, start, end = 0, -1, -1
5109 variants = []
5110 key = None
5111 for idx, char in enumerate(text):
5112 if char == '{':
5113 if not depth:
5114 start = idx
5115 chunk = text[end + 1:start]
5116 key = chunk.strip()
5117 pos = offset + end + 1 + chunk.find(key)
5118 span = (pos, pos + len(key))
5119 depth += 1
5120 elif char == '}':
5121 if not depth:
5122 return variants, depth, offset + idx
5123 depth -= 1
5124 if not depth:
5125 end = idx
5126 variants.append((key, span, text[start:end + 1], (offset + start,
5127 offset + end + 1)))
5128 return variants, depth, offset + end + 1
5129
meacer8c0d3832019-12-26 21:46:165130 try:
5131 old_sys_path = sys.path
5132 sys.path = sys.path + [input_api.os_path.join(
5133 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5134 from helper import grd_helper
5135 finally:
5136 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145137
5138 for f in affected_grds:
5139 file_path = f.LocalPath()
5140 old_id_to_msg_map = {}
5141 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385142 # Note that this code doesn't check if the file has been deleted. This is
5143 # OK because it only uses the old and new file contents and doesn't load
5144 # the file via its path.
5145 # It's also possible that a file's content refers to a renamed or deleted
5146 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5147 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5148 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145149 if file_path.endswith('.grdp'):
5150 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585151 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395152 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145153 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585154 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395155 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145156 else:
meacerff8a9b62019-12-10 19:43:585157 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145158 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585159 old_id_to_msg_map = grd_helper.GetGrdMessages(
5160 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145161 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585162 new_id_to_msg_map = grd_helper.GetGrdMessages(
5163 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145164
Rainhard Findlingd8d04372020-08-13 13:30:095165 grd_name, ext = input_api.os_path.splitext(
5166 input_api.os_path.basename(file_path))
5167 screenshots_dir = input_api.os_path.join(
5168 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5169
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145170 # Compute added, removed and modified message IDs.
5171 old_ids = set(old_id_to_msg_map)
5172 new_ids = set(new_id_to_msg_map)
5173 added_ids = new_ids - old_ids
5174 removed_ids = old_ids - new_ids
5175 modified_ids = set([])
5176 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355177 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095178 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5179 # The message content itself changed. Require an updated screenshot.
5180 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355181 elif old_id_to_msg_map[key].attrs['meaning'] != \
5182 new_id_to_msg_map[key].attrs['meaning']:
5183 # The message meaning changed. Ensure there is a screenshot for it.
5184 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5185 if sha1_path not in new_or_added_paths and not \
5186 input_api.os_path.exists(sha1_path):
5187 # There is neither a previous screenshot nor is a new one added now.
5188 # Require a screenshot.
5189 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145190
Rainhard Findlingfc31844c52020-05-15 09:58:265191 if run_screenshot_check:
5192 # Check the screenshot directory for .png files. Warn if there is any.
5193 for png_path in affected_png_paths:
5194 if png_path.startswith(screenshots_dir):
5195 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145196
Rainhard Findlingfc31844c52020-05-15 09:58:265197 for added_id in added_ids:
5198 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145199
Rainhard Findlingfc31844c52020-05-15 09:58:265200 for modified_id in modified_ids:
5201 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145202
Rainhard Findlingfc31844c52020-05-15 09:58:265203 for removed_id in removed_ids:
5204 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5205
5206 # Check new and changed strings for ICU syntax errors.
5207 for key in added_ids.union(modified_ids):
5208 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5209 err = _ValidateIcuSyntax(msg, 0, [])
5210 if err is not None:
5211 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145212
5213 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265214 if run_screenshot_check:
5215 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005216 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265217 'Do not include actual screenshots in the changelist. Run '
5218 'tools/translate/upload_screenshots.py to upload them instead:',
5219 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145220
Rainhard Findlingfc31844c52020-05-15 09:58:265221 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005222 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265223 'You are adding or modifying UI strings.\n'
5224 'To ensure the best translations, take screenshots of the relevant UI '
5225 '(https://g.co/chrome/translation) and add these files to your '
5226 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145227
Rainhard Findlingfc31844c52020-05-15 09:58:265228 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005229 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265230 'You removed strings associated with these files. Remove:',
5231 sorted(unnecessary_sha1_files)))
5232 else:
5233 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5234 'screenshots check.'))
5235
5236 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075237 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265238 'ICU syntax errors were found in the following strings (problems or '
5239 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145240
5241 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125242
5243
Saagar Sanghavifceeaae2020-08-12 16:40:365244def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125245 repo_root=None,
5246 translation_expectations_path=None,
5247 grd_files=None):
5248 import sys
5249 affected_grds = [f for f in input_api.AffectedFiles()
5250 if (f.LocalPath().endswith('.grd') or
5251 f.LocalPath().endswith('.grdp'))]
5252 if not affected_grds:
5253 return []
5254
5255 try:
5256 old_sys_path = sys.path
5257 sys.path = sys.path + [
5258 input_api.os_path.join(
5259 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5260 from helper import git_helper
5261 from helper import translation_helper
5262 finally:
5263 sys.path = old_sys_path
5264
5265 # Check that translation expectations can be parsed and we can get a list of
5266 # translatable grd files. |repo_root| and |translation_expectations_path| are
5267 # only passed by tests.
5268 if not repo_root:
5269 repo_root = input_api.PresubmitLocalPath()
5270 if not translation_expectations_path:
5271 translation_expectations_path = input_api.os_path.join(
5272 repo_root, 'tools', 'gritsettings',
5273 'translation_expectations.pyl')
5274 if not grd_files:
5275 grd_files = git_helper.list_grds_in_repository(repo_root)
5276
dpapad8e21b472020-10-23 17:15:035277 # Ignore bogus grd files used only for testing
5278 # ui/webui/resoucres/tools/generate_grd.py.
5279 ignore_path = input_api.os_path.join(
5280 'ui', 'webui', 'resources', 'tools', 'tests')
5281 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5282
Mustafa Emre Acer51f2f742020-03-09 19:41:125283 try:
5284 translation_helper.get_translatable_grds(repo_root, grd_files,
5285 translation_expectations_path)
5286 except Exception as e:
5287 return [output_api.PresubmitNotifyResult(
5288 'Failed to get a list of translatable grd files. This happens when:\n'
5289 ' - One of the modified grd or grdp files cannot be parsed or\n'
5290 ' - %s is not updated.\n'
5291 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5292 return []
Ken Rockotc31f4832020-05-29 18:58:515293
5294
Saagar Sanghavifceeaae2020-08-12 16:40:365295def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515296 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095297 changed_mojoms = input_api.AffectedFiles(
5298 include_deletes=True,
5299 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515300 delta = []
5301 for mojom in changed_mojoms:
5302 old_contents = ''.join(mojom.OldContents()) or None
5303 new_contents = ''.join(mojom.NewContents()) or None
5304 delta.append({
5305 'filename': mojom.LocalPath(),
5306 'old': '\n'.join(mojom.OldContents()) or None,
5307 'new': '\n'.join(mojom.NewContents()) or None,
5308 })
5309
5310 process = input_api.subprocess.Popen(
5311 [input_api.python_executable,
5312 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5313 'public', 'tools', 'mojom',
5314 'check_stable_mojom_compatibility.py'),
5315 '--src-root', input_api.PresubmitLocalPath()],
5316 stdin=input_api.subprocess.PIPE,
5317 stdout=input_api.subprocess.PIPE,
5318 stderr=input_api.subprocess.PIPE,
5319 universal_newlines=True)
5320 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5321 if process.returncode:
5322 return [output_api.PresubmitError(
5323 'One or more [Stable] mojom definitions appears to have been changed '
5324 'in a way that is not backward-compatible.',
5325 long_text=error)]
5326 return []
Dominic Battre645d42342020-12-04 16:14:105327
5328def CheckDeprecationOfPreferences(input_api, output_api):
5329 """Removing a preference should come with a deprecation."""
5330
5331 def FilterFile(affected_file):
5332 """Accept only .cc files and the like."""
5333 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5334 files_to_skip = (_EXCLUDED_PATHS +
5335 _TEST_CODE_EXCLUDED_PATHS +
5336 input_api.DEFAULT_FILES_TO_SKIP)
5337 return input_api.FilterSourceFile(
5338 affected_file,
5339 files_to_check=file_inclusion_pattern,
5340 files_to_skip=files_to_skip)
5341
5342 def ModifiedLines(affected_file):
5343 """Returns a list of tuples (line number, line text) of added and removed
5344 lines.
5345
5346 Deleted lines share the same line number as the previous line.
5347
5348 This relies on the scm diff output describing each changed code section
5349 with a line of the form
5350
5351 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5352 """
5353 line_num = 0
5354 modified_lines = []
5355 for line in affected_file.GenerateScmDiff().splitlines():
5356 # Extract <new line num> of the patch fragment (see format above).
5357 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5358 if m:
5359 line_num = int(m.groups(1)[0])
5360 continue
5361 if ((line.startswith('+') and not line.startswith('++')) or
5362 (line.startswith('-') and not line.startswith('--'))):
5363 modified_lines.append((line_num, line))
5364
5365 if not line.startswith('-'):
5366 line_num += 1
5367 return modified_lines
5368
5369 def FindLineWith(lines, needle):
5370 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5371
5372 If 0 or >1 lines contain `needle`, -1 is returned.
5373 """
5374 matching_line_numbers = [
5375 # + 1 for 1-based counting of line numbers.
5376 i + 1 for i, line
5377 in enumerate(lines)
5378 if needle in line]
5379 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5380
5381 def ModifiedPrefMigration(affected_file):
5382 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5383 # Determine first and last lines of MigrateObsolete.*Pref functions.
5384 new_contents = affected_file.NewContents();
5385 range_1 = (
5386 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5387 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5388 range_2 = (
5389 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5390 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5391 if (-1 in range_1 + range_2):
5392 raise Exception(
5393 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5394
5395 # Check whether any of the modified lines are part of the
5396 # MigrateObsolete.*Pref functions.
5397 for line_nr, line in ModifiedLines(affected_file):
5398 if (range_1[0] <= line_nr <= range_1[1] or
5399 range_2[0] <= line_nr <= range_2[1]):
5400 return True
5401 return False
5402
5403 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5404 browser_prefs_file_pattern = input_api.re.compile(
5405 r'chrome/browser/prefs/browser_prefs.cc')
5406
5407 changes = input_api.AffectedFiles(include_deletes=True,
5408 file_filter=FilterFile)
5409 potential_problems = []
5410 for f in changes:
5411 for line in f.GenerateScmDiff().splitlines():
5412 # Check deleted lines for pref registrations.
5413 if (line.startswith('-') and not line.startswith('--') and
5414 register_pref_pattern.search(line)):
5415 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5416
5417 if browser_prefs_file_pattern.search(f.LocalPath()):
5418 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5419 # assume that they knew that they have to deprecate preferences and don't
5420 # warn.
5421 try:
5422 if ModifiedPrefMigration(f):
5423 return []
5424 except Exception as e:
5425 return [output_api.PresubmitError(str(e))]
5426
5427 if potential_problems:
5428 return [output_api.PresubmitPromptWarning(
5429 'Discovered possible removal of preference registrations.\n\n'
5430 'Please make sure to properly deprecate preferences by clearing their\n'
5431 'value for a couple of milestones before finally removing the code.\n'
5432 'Otherwise data may stay in the preferences files forever. See\n'
5433 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5434 'This may be a false positive warning (e.g. if you move preference\n'
5435 'registrations to a different place).\n',
5436 potential_problems
5437 )]
5438 return []