Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 9857b183c0d9cece0013d6c58ad21e962c81cf6a [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-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]ca8d19842009-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]ca8d19842009-02-19 16:33:1237
wnwenbdc444e2016-05-25 13:44:1538
[email protected]06e6d0ff2012-12-11 01:36:4439# Fragment of a regular expression that matches C++ and Objective-C++
40# implementation files.
41_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
42
wnwenbdc444e2016-05-25 13:44:1543
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1944# Fragment of a regular expression that matches C++ and Objective-C++
45# header files.
46_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
47
48
[email protected]06e6d0ff2012-12-11 01:36:4449# Regular expression that matches code only used for test binaries
50# (best effort).
51_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0452 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4453 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4454 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1255 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1856 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4457 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0458 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4359 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0460 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4361 # Web test harness.
62 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4763 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0464 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0865 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0466 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4167 # EarlGrey app side code for tests.
68 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1769 # Views Examples code
70 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4171 # Chromium Codelab
72 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4473)
[email protected]ca8d19842009-02-19 16:33:1274
Daniel Bratell609102be2019-03-27 20:53:2175_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1576
[email protected]eea609a2011-11-18 13:10:1277_TEST_ONLY_WARNING = (
78 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5579 'production code. If you are doing this from inside another method\n'
80 'named as *ForTesting(), then consider exposing things to have tests\n'
81 'make that same call directly.\n'
82 'If that is not possible, you may put a comment on the same line with\n'
83 ' // IN-TEST \n'
84 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
85 'method and can be ignored. Do not do this inside production code.\n'
86 'The android-binary-size trybot will block if the method exists in the\n'
87 'release apk.')
[email protected]eea609a2011-11-18 13:10:1288
89
[email protected]cf9b78f2012-11-14 11:40:2890_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4091 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2192 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
93 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2894
Michael Thiessen44457642020-02-06 00:24:1595# Format: Sequence of tuples containing:
96# * Full import path.
97# * Sequence of strings to show when the pattern matches.
98# * Sequence of path or filename exceptions to this rule
99_BANNED_JAVA_IMPORTS = (
100 (
Colin Blundell170d78c82020-03-12 13:56:04101 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15102 (
103 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
104 ),
105 (
106 'net/android/javatests/src/org/chromium/net/'
107 'AndroidProxySelectorTest.java',
108 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04109 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15110 ),
111 ),
Michael Thiessened631912020-08-07 19:01:31112 (
113 'android.support.test.rule.UiThreadTestRule;',
114 (
115 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43116 '@org.chromium.base.test.UiThreadTest on test methods that should run '
117 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31118 ),
119 (),
120 ),
121 (
122 'android.support.test.annotation.UiThreadTest;',
123 (
124 'Do not use android.support.test.annotation.UiThreadTest, use '
125 'org.chromium.base.test.UiThreadTest instead. See '
126 'https://crbug.com/1111893.',
127 ),
128 ()
Michael Thiessenfd6919b2020-12-08 20:44:01129 ),
130 (
131 'android.support.test.rule.ActivityTestRule;',
132 (
133 'Do not use ActivityTestRule, use '
134 'org.chromium.base.test.BaseActivityTestRule instead.',
135 ),
136 (
137 'components/cronet/',
138 )
Michael Thiessened631912020-08-07 19:01:31139 )
Michael Thiessen44457642020-02-06 00:24:15140)
wnwenbdc444e2016-05-25 13:44:15141
Daniel Bratell609102be2019-03-27 20:53:21142# Format: Sequence of tuples containing:
143# * String pattern or, if starting with a slash, a regular expression.
144# * Sequence of strings to show when the pattern matches.
145# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41146_BANNED_JAVA_FUNCTIONS = (
147 (
148 'StrictMode.allowThreadDiskReads()',
149 (
150 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
151 'directly.',
152 ),
153 False,
154 ),
155 (
156 'StrictMode.allowThreadDiskWrites()',
157 (
158 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
159 'directly.',
160 ),
161 False,
162 ),
Michael Thiessen0f2547e32020-07-27 21:55:36163 (
164 '.waitForIdleSync()',
165 (
166 'Do not use waitForIdleSync as it masks underlying issues. There is '
167 'almost always something else you should wait on instead.',
168 ),
169 False,
170 ),
Eric Stevensona9a980972017-09-23 00:04:41171)
172
Daniel Bratell609102be2019-03-27 20:53:21173# Format: Sequence of tuples containing:
174# * String pattern or, if starting with a slash, a regular expression.
175# * Sequence of strings to show when the pattern matches.
176# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59177_BANNED_OBJC_FUNCTIONS = (
178 (
179 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20180 (
181 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59182 'prohibited. Please use CrTrackingArea instead.',
183 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
184 ),
185 False,
186 ),
187 (
[email protected]eaae1972014-04-16 04:17:26188 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20189 (
190 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59191 'instead.',
192 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
193 ),
194 False,
195 ),
196 (
197 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20198 (
199 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59200 'Please use |convertPoint:(point) fromView:nil| instead.',
201 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
202 ),
203 True,
204 ),
205 (
206 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20207 (
208 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59209 'Please use |convertPoint:(point) toView:nil| instead.',
210 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
211 ),
212 True,
213 ),
214 (
215 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20216 (
217 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59218 'Please use |convertRect:(point) fromView:nil| instead.',
219 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
220 ),
221 True,
222 ),
223 (
224 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20225 (
226 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59227 'Please use |convertRect:(point) toView:nil| instead.',
228 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
229 ),
230 True,
231 ),
232 (
233 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20234 (
235 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59236 'Please use |convertSize:(point) fromView:nil| instead.',
237 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
238 ),
239 True,
240 ),
241 (
242 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20243 (
244 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59245 'Please use |convertSize:(point) toView:nil| instead.',
246 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
247 ),
248 True,
249 ),
jif65398702016-10-27 10:19:48250 (
251 r"/\s+UTF8String\s*]",
252 (
253 'The use of -[NSString UTF8String] is dangerous as it can return null',
254 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
255 'Please use |SysNSStringToUTF8| instead.',
256 ),
257 True,
258 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34259 (
260 r'__unsafe_unretained',
261 (
262 'The use of __unsafe_unretained is almost certainly wrong, unless',
263 'when interacting with NSFastEnumeration or NSInvocation.',
264 'Please use __weak in files build with ARC, nothing otherwise.',
265 ),
266 False,
267 ),
Avi Drissman7382afa02019-04-29 23:27:13268 (
269 'freeWhenDone:NO',
270 (
271 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
272 'Foundation types is prohibited.',
273 ),
274 True,
275 ),
[email protected]127f18ec2012-06-16 05:05:59276)
277
Daniel Bratell609102be2019-03-27 20:53:21278# Format: Sequence of tuples containing:
279# * String pattern or, if starting with a slash, a regular expression.
280# * Sequence of strings to show when the pattern matches.
281# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54282_BANNED_IOS_OBJC_FUNCTIONS = (
283 (
284 r'/\bTEST[(]',
285 (
286 'TEST() macro should not be used in Objective-C++ code as it does not ',
287 'drain the autorelease pool at the end of the test. Use TEST_F() ',
288 'macro instead with a fixture inheriting from PlatformTest (or a ',
289 'typedef).'
290 ),
291 True,
292 ),
293 (
294 r'/\btesting::Test\b',
295 (
296 'testing::Test should not be used in Objective-C++ code as it does ',
297 'not drain the autorelease pool at the end of the test. Use ',
298 'PlatformTest instead.'
299 ),
300 True,
301 ),
302)
303
Peter K. Lee6c03ccff2019-07-15 14:40:05304# Format: Sequence of tuples containing:
305# * String pattern or, if starting with a slash, a regular expression.
306# * Sequence of strings to show when the pattern matches.
307# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
308_BANNED_IOS_EGTEST_FUNCTIONS = (
309 (
310 r'/\bEXPECT_OCMOCK_VERIFY\b',
311 (
312 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
313 'it is meant for GTests. Use [mock verify] instead.'
314 ),
315 True,
316 ),
317)
318
danakj7a2b7082019-05-21 21:13:51319# Directories that contain deprecated Bind() or Callback types.
320# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36321# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51322# echo "-- $i"
Alexander Cooperd1244c582021-01-26 02:25:27323# (cd $i; git grep -nP \
324# 'base::(Bind\(|(Cancelable)?(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51325# done
326#
327# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
328# when they have been converted to modern callback types (OnceCallback,
329# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
330# checks for them and prevent regressions.
331_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51332 '^base/callback.h', # Intentional.
Alex Turnerb3ea38c2020-11-25 18:03:07333 '^base/cancelable_callback.h', # Intentional.
Alexander Cooperd1244c582021-01-26 02:25:27334 '^chrome/browser/apps/guest_view/web_view_browsertest.cc',
Alexander Cooperb3f1af662021-02-01 19:47:26335 "^chrome/browser/ash/accessibility/",
Alexander Cooper6b447b22020-07-22 00:47:18336 '^chrome/browser/media_galleries/',
Alexander Cooperb3f1af662021-02-01 19:47:26337 "^chrome/browser/metrics/",
Alexander Cooperb3f1af662021-02-01 19:47:26338 "^chrome/browser/prefetch/no_state_prefetch/",
339 '^chrome/browser/previews/',
Alexander Cooper6b447b22020-07-22 00:47:18340 '^chrome/browser/resources/chromeos/accessibility/',
Shik Chene50b4462021-02-02 05:35:31341 '^chrome/browser/rlz/chrome_rlz_tracker_delegate.cc',
Alexander Cooper6b447b22020-07-22 00:47:18342 '^chrome/browser/signin/',
343 '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
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 Smolinskyb11abed72019-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 """
Edward Lesmes6fba51082021-01-20 04:20:232316 if input_api.change.issue:
2317 # Skip OWNERS check when Bot-Commit label is approved. This label is
2318 # intended for commits made by trusted bots that don't require review nor
2319 # owners approval.
2320 if input_api.gerrit.IsBotCommitApproved(input_api.change.issue):
2321 return []
2322 # Skip OWNERS check when Owners-Override label is approved. This is intended
2323 # for global owners, trusted bots, and on-call sheriffs. Review is still
2324 # required for these changes.
2325 if input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue):
2326 return []
2327
Daniel Cheng4dcdb6b2017-04-13 08:30:172328 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242329
2330 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492331 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242332 for f in input_api.AffectedFiles(include_deletes=False,
2333 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552334 filename = input_api.os_path.basename(f.LocalPath())
2335 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172336 virtual_depended_on_files.update(_CalculateAddedDeps(
2337 input_api.os_path,
2338 '\n'.join(f.OldContents()),
2339 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552340
[email protected]e871964c2013-05-13 14:14:552341 if not virtual_depended_on_files:
2342 return []
2343
2344 if input_api.is_committing:
2345 if input_api.tbr:
2346 return [output_api.PresubmitNotifyResult(
2347 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272348 if input_api.dry_run:
2349 return [output_api.PresubmitNotifyResult(
2350 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552351 if not input_api.change.issue:
2352 return [output_api.PresubmitError(
2353 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402354 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552355 output = output_api.PresubmitError
2356 else:
2357 output = output_api.PresubmitNotifyResult
2358
tandriied3b7e12016-05-12 14:38:502359 owner_email, reviewers = (
2360 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2361 input_api,
Edward Lesmesa3846442021-02-08 20:20:032362 None,
tandriied3b7e12016-05-12 14:38:502363 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552364
2365 owner_email = owner_email or input_api.change.author_email
2366
Edward Lesmesa3846442021-02-08 20:20:032367 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2368 virtual_depended_on_files, reviewers.union([owner_email]), [])
2369 missing_files = [
2370 f for f in virtual_depended_on_files
2371 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412372
2373 # We strip the /DEPS part that was added by
2374 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2375 # directory.
2376 def StripDeps(path):
2377 start_deps = path.rfind('/DEPS')
2378 if start_deps != -1:
2379 return path[:start_deps]
2380 else:
2381 return path
2382 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552383 for path in missing_files]
2384
2385 if unapproved_dependencies:
2386 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152387 output('You need LGTM from owners of depends-on paths in DEPS that were '
2388 'modified in this CL:\n %s' %
2389 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032390 suggested_owners = input_api.owners_client.SuggestOwners(
2391 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152392 output_list.append(output(
2393 'Suggested missing target path OWNERS:\n %s' %
2394 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552395 return output_list
2396
2397 return []
2398
2399
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492400# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362401def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492402 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442403 files_to_skip = (_EXCLUDED_PATHS +
2404 _TEST_CODE_EXCLUDED_PATHS +
2405 input_api.DEFAULT_FILES_TO_SKIP +
2406 (r"^base[\\/]logging\.h$",
2407 r"^base[\\/]logging\.cc$",
2408 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2409 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2410 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2411 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2412 r"startup_browser_creator\.cc$",
2413 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2414 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2415 r"diagnostics_writer\.cc$",
2416 r"^chrome[\\/]chrome_cleaner[\\/].*",
2417 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2418 r"dll_hash_main\.cc$",
2419 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2420 r"^chromecast[\\/]",
2421 r"^cloud_print[\\/]",
2422 r"^components[\\/]browser_watcher[\\/]"
2423 r"dump_stability_report_main_win.cc$",
2424 r"^components[\\/]media_control[\\/]renderer[\\/]"
2425 r"media_playback_options\.cc$",
2426 r"^components[\\/]zucchini[\\/].*",
2427 # TODO(peter): Remove exception. https://crbug.com/534537
2428 r"^content[\\/]browser[\\/]notifications[\\/]"
2429 r"notification_event_dispatcher_impl\.cc$",
2430 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2431 r"gl_helper_benchmark\.cc$",
2432 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2433 r"^courgette[\\/]courgette_tool\.cc$",
2434 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2435 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2436 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2437 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2438 r"^ipc[\\/]ipc_logging\.cc$",
2439 r"^native_client_sdk[\\/]",
2440 r"^remoting[\\/]base[\\/]logging\.h$",
2441 r"^remoting[\\/]host[\\/].*",
2442 r"^sandbox[\\/]linux[\\/].*",
2443 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2444 r"dump_file_system.cc$",
2445 r"^tools[\\/]",
2446 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2447 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2448 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2449 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2450 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402451 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442452 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402453
thomasanderson625d3932017-03-29 07:16:582454 log_info = set([])
2455 printf = set([])
[email protected]85218562013-11-22 07:41:402456
2457 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582458 for _, line in f.ChangedContents():
2459 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2460 log_info.add(f.LocalPath())
2461 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2462 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372463
thomasanderson625d3932017-03-29 07:16:582464 if input_api.re.search(r"\bprintf\(", line):
2465 printf.add(f.LocalPath())
2466 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2467 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402468
2469 if log_info:
2470 return [output_api.PresubmitError(
2471 'These files spam the console log with LOG(INFO):',
2472 items=log_info)]
2473 if printf:
2474 return [output_api.PresubmitError(
2475 'These files spam the console log with printf/fprintf:',
2476 items=printf)]
2477 return []
2478
2479
Saagar Sanghavifceeaae2020-08-12 16:40:362480def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162481 """These types are all expected to hold locks while in scope and
2482 so should never be anonymous (which causes them to be immediately
2483 destroyed)."""
2484 they_who_must_be_named = [
2485 'base::AutoLock',
2486 'base::AutoReset',
2487 'base::AutoUnlock',
2488 'SkAutoAlphaRestore',
2489 'SkAutoBitmapShaderInstall',
2490 'SkAutoBlitterChoose',
2491 'SkAutoBounderCommit',
2492 'SkAutoCallProc',
2493 'SkAutoCanvasRestore',
2494 'SkAutoCommentBlock',
2495 'SkAutoDescriptor',
2496 'SkAutoDisableDirectionCheck',
2497 'SkAutoDisableOvalCheck',
2498 'SkAutoFree',
2499 'SkAutoGlyphCache',
2500 'SkAutoHDC',
2501 'SkAutoLockColors',
2502 'SkAutoLockPixels',
2503 'SkAutoMalloc',
2504 'SkAutoMaskFreeImage',
2505 'SkAutoMutexAcquire',
2506 'SkAutoPathBoundsUpdate',
2507 'SkAutoPDFRelease',
2508 'SkAutoRasterClipValidate',
2509 'SkAutoRef',
2510 'SkAutoTime',
2511 'SkAutoTrace',
2512 'SkAutoUnref',
2513 ]
2514 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2515 # bad: base::AutoLock(lock.get());
2516 # not bad: base::AutoLock lock(lock.get());
2517 bad_pattern = input_api.re.compile(anonymous)
2518 # good: new base::AutoLock(lock.get())
2519 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2520 errors = []
2521
2522 for f in input_api.AffectedFiles():
2523 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2524 continue
2525 for linenum, line in f.ChangedContents():
2526 if bad_pattern.search(line) and not good_pattern.search(line):
2527 errors.append('%s:%d' % (f.LocalPath(), linenum))
2528
2529 if errors:
2530 return [output_api.PresubmitError(
2531 'These lines create anonymous variables that need to be named:',
2532 items=errors)]
2533 return []
2534
2535
Saagar Sanghavifceeaae2020-08-12 16:40:362536def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532537 # Returns whether |template_str| is of the form <T, U...> for some types T
2538 # and U. Assumes that |template_str| is already in the form <...>.
2539 def HasMoreThanOneArg(template_str):
2540 # Level of <...> nesting.
2541 nesting = 0
2542 for c in template_str:
2543 if c == '<':
2544 nesting += 1
2545 elif c == '>':
2546 nesting -= 1
2547 elif c == ',' and nesting == 1:
2548 return True
2549 return False
2550
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492551 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102552 sources = lambda affected_file: input_api.FilterSourceFile(
2553 affected_file,
James Cook24a504192020-07-23 00:08:442554 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2555 input_api.DEFAULT_FILES_TO_SKIP),
2556 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552557
2558 # Pattern to capture a single "<...>" block of template arguments. It can
2559 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2560 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2561 # latter would likely require counting that < and > match, which is not
2562 # expressible in regular languages. Should the need arise, one can introduce
2563 # limited counting (matching up to a total number of nesting depth), which
2564 # should cover all practical cases for already a low nesting limit.
2565 template_arg_pattern = (
2566 r'<[^>]*' # Opening block of <.
2567 r'>([^<]*>)?') # Closing block of >.
2568 # Prefix expressing that whatever follows is not already inside a <...>
2569 # block.
2570 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102571 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552572 not_inside_template_arg_pattern
2573 + r'\bstd::unique_ptr'
2574 + template_arg_pattern
2575 + r'\(\)')
2576
2577 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2578 template_arg_no_array_pattern = (
2579 r'<[^>]*[^]]' # Opening block of <.
2580 r'>([^(<]*[^]]>)?') # Closing block of >.
2581 # Prefix saying that what follows is the start of an expression.
2582 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2583 # Suffix saying that what follows are call parentheses with a non-empty list
2584 # of arguments.
2585 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532586 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552587 return_construct_pattern = input_api.re.compile(
2588 start_of_expr_pattern
2589 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532590 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552591 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532592 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552593 + nonempty_arg_list_pattern)
2594
Vaclav Brozek851d9602018-04-04 16:13:052595 problems_constructor = []
2596 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102597 for f in input_api.AffectedSourceFiles(sources):
2598 for line_number, line in f.ChangedContents():
2599 # Disallow:
2600 # return std::unique_ptr<T>(foo);
2601 # bar = std::unique_ptr<T>(foo);
2602 # But allow:
2603 # return std::unique_ptr<T[]>(foo);
2604 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532605 # And also allow cases when the second template argument is present. Those
2606 # cases cannot be handled by std::make_unique:
2607 # return std::unique_ptr<T, U>(foo);
2608 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052609 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532610 return_construct_result = return_construct_pattern.search(line)
2611 if return_construct_result and not HasMoreThanOneArg(
2612 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052613 problems_constructor.append(
2614 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102615 # Disallow:
2616 # std::unique_ptr<T>()
2617 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052618 problems_nullptr.append(
2619 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2620
2621 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162622 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052623 errors.append(output_api.PresubmitError(
2624 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162625 problems_nullptr))
2626 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052627 errors.append(output_api.PresubmitError(
2628 'The following files use explicit std::unique_ptr constructor.'
2629 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162630 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102631 return errors
2632
2633
Saagar Sanghavifceeaae2020-08-12 16:40:362634def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082635 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522636 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082637 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522638 # If actions.xml is already included in the changelist, the PRESUBMIT
2639 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082640 return []
2641
[email protected]999261d2014-03-03 20:08:082642 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2643 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522644 current_actions = None
[email protected]999261d2014-03-03 20:08:082645 for f in input_api.AffectedFiles(file_filter=file_filter):
2646 for line_num, line in f.ChangedContents():
2647 match = input_api.re.search(action_re, line)
2648 if match:
[email protected]2f92dec2014-03-07 19:21:522649 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2650 # loaded only once.
2651 if not current_actions:
2652 with open('tools/metrics/actions/actions.xml') as actions_f:
2653 current_actions = actions_f.read()
2654 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082655 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522656 action = 'name="{0}"'.format(action_name)
2657 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082658 return [output_api.PresubmitPromptWarning(
2659 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522660 'tools/metrics/actions/actions.xml. Please run '
2661 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082662 % (f.LocalPath(), line_num, action_name))]
2663 return []
2664
2665
Daniel Cheng13ca61a882017-08-25 15:11:252666def _ImportJSONCommentEater(input_api):
2667 import sys
2668 sys.path = sys.path + [input_api.os_path.join(
2669 input_api.PresubmitLocalPath(),
2670 'tools', 'json_comment_eater')]
2671 import json_comment_eater
2672 return json_comment_eater
2673
2674
[email protected]99171a92014-06-03 08:44:472675def _GetJSONParseError(input_api, filename, eat_comments=True):
2676 try:
2677 contents = input_api.ReadFile(filename)
2678 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252679 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132680 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472681
2682 input_api.json.loads(contents)
2683 except ValueError as e:
2684 return e
2685 return None
2686
2687
2688def _GetIDLParseError(input_api, filename):
2689 try:
2690 contents = input_api.ReadFile(filename)
2691 idl_schema = input_api.os_path.join(
2692 input_api.PresubmitLocalPath(),
2693 'tools', 'json_schema_compiler', 'idl_schema.py')
2694 process = input_api.subprocess.Popen(
2695 [input_api.python_executable, idl_schema],
2696 stdin=input_api.subprocess.PIPE,
2697 stdout=input_api.subprocess.PIPE,
2698 stderr=input_api.subprocess.PIPE,
2699 universal_newlines=True)
2700 (_, error) = process.communicate(input=contents)
2701 return error or None
2702 except ValueError as e:
2703 return e
2704
2705
Saagar Sanghavifceeaae2020-08-12 16:40:362706def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472707 """Check that IDL and JSON files do not contain syntax errors."""
2708 actions = {
2709 '.idl': _GetIDLParseError,
2710 '.json': _GetJSONParseError,
2711 }
[email protected]99171a92014-06-03 08:44:472712 # Most JSON files are preprocessed and support comments, but these do not.
2713 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042714 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472715 ]
2716 # Only run IDL checker on files in these directories.
2717 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042718 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2719 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472720 ]
2721
2722 def get_action(affected_file):
2723 filename = affected_file.LocalPath()
2724 return actions.get(input_api.os_path.splitext(filename)[1])
2725
[email protected]99171a92014-06-03 08:44:472726 def FilterFile(affected_file):
2727 action = get_action(affected_file)
2728 if not action:
2729 return False
2730 path = affected_file.LocalPath()
2731
Erik Staab2dd72b12020-04-16 15:03:402732 if _MatchesFile(input_api,
2733 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2734 path):
[email protected]99171a92014-06-03 08:44:472735 return False
2736
2737 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162738 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472739 return False
2740 return True
2741
2742 results = []
2743 for affected_file in input_api.AffectedFiles(
2744 file_filter=FilterFile, include_deletes=False):
2745 action = get_action(affected_file)
2746 kwargs = {}
2747 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162748 _MatchesFile(input_api, json_no_comments_patterns,
2749 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472750 kwargs['eat_comments'] = False
2751 parse_error = action(input_api,
2752 affected_file.AbsoluteLocalPath(),
2753 **kwargs)
2754 if parse_error:
2755 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2756 (affected_file.LocalPath(), parse_error)))
2757 return results
2758
2759
Saagar Sanghavifceeaae2020-08-12 16:40:362760def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492761 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472762 import sys
[email protected]760deea2013-12-10 19:33:492763 original_sys_path = sys.path
2764 try:
2765 sys.path = sys.path + [input_api.os_path.join(
2766 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2767 import checkstyle
2768 finally:
2769 # Restore sys.path to what it was before.
2770 sys.path = original_sys_path
2771
2772 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092773 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442774 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492775
2776
Saagar Sanghavifceeaae2020-08-12 16:40:362777def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002778 """Checks to make sure devil is initialized correctly in python scripts."""
2779 script_common_initialize_pattern = input_api.re.compile(
2780 r'script_common\.InitializeEnvironment\(')
2781 devil_env_config_initialize = input_api.re.compile(
2782 r'devil_env\.config\.Initialize\(')
2783
2784 errors = []
2785
2786 sources = lambda affected_file: input_api.FilterSourceFile(
2787 affected_file,
James Cook24a504192020-07-23 00:08:442788 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2789 (r'^build[\\/]android[\\/]devil_chromium\.py',
2790 r'^third_party[\\/].*',)),
2791 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002792
2793 for f in input_api.AffectedSourceFiles(sources):
2794 for line_num, line in f.ChangedContents():
2795 if (script_common_initialize_pattern.search(line) or
2796 devil_env_config_initialize.search(line)):
2797 errors.append("%s:%d" % (f.LocalPath(), line_num))
2798
2799 results = []
2800
2801 if errors:
2802 results.append(output_api.PresubmitError(
2803 'Devil initialization should always be done using '
2804 'devil_chromium.Initialize() in the chromium project, to use better '
2805 'defaults for dependencies (ex. up-to-date version of adb).',
2806 errors))
2807
2808 return results
2809
2810
Sean Kau46e29bc2017-08-28 16:31:162811def _MatchesFile(input_api, patterns, path):
2812 for pattern in patterns:
2813 if input_api.re.search(pattern, path):
2814 return True
2815 return False
2816
2817
Daniel Cheng7052cdf2017-11-21 19:23:292818def _GetOwnersFilesToCheckForIpcOwners(input_api):
2819 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172820
Daniel Cheng7052cdf2017-11-21 19:23:292821 Returns:
2822 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2823 contain to cover IPC-related files with noparent reviewer rules.
2824 """
2825 # Whether or not a file affects IPC is (mostly) determined by a simple list
2826 # of filename patterns.
dchenge07de812016-06-20 19:27:172827 file_patterns = [
palmerb19a0932017-01-24 04:00:312828 # Legacy IPC:
dchenge07de812016-06-20 19:27:172829 '*_messages.cc',
2830 '*_messages*.h',
2831 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312832 # Mojo IPC:
dchenge07de812016-06-20 19:27:172833 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472834 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172835 '*_struct_traits*.*',
2836 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312837 '*.typemap',
2838 # Android native IPC:
2839 '*.aidl',
2840 # Blink uses a different file naming convention:
2841 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472842 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172843 '*StructTraits*.*',
2844 '*TypeConverter*.*',
2845 ]
2846
scottmg7a6ed5ba2016-11-04 18:22:042847 # These third_party directories do not contain IPCs, but contain files
2848 # matching the above patterns, which trigger false positives.
2849 exclude_paths = [
2850 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162851 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232852 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292853 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542854 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162855 # These files are just used to communicate between class loaders running
2856 # in the same process.
2857 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572858 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2859
scottmg7a6ed5ba2016-11-04 18:22:042860 ]
2861
dchenge07de812016-06-20 19:27:172862 # Dictionary mapping an OWNERS file path to Patterns.
2863 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2864 # rules ) to a PatternEntry.
2865 # PatternEntry is a dictionary with two keys:
2866 # - 'files': the files that are matched by this pattern
2867 # - 'rules': the per-file rules needed for this pattern
2868 # For example, if we expect OWNERS file to contain rules for *.mojom and
2869 # *_struct_traits*.*, Patterns might look like this:
2870 # {
2871 # '*.mojom': {
2872 # 'files': ...,
2873 # 'rules': [
2874 # 'per-file *.mojom=set noparent',
2875 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2876 # ],
2877 # },
2878 # '*_struct_traits*.*': {
2879 # 'files': ...,
2880 # 'rules': [
2881 # 'per-file *_struct_traits*.*=set noparent',
2882 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2883 # ],
2884 # },
2885 # }
2886 to_check = {}
2887
Daniel Cheng13ca61a882017-08-25 15:11:252888 def AddPatternToCheck(input_file, pattern):
2889 owners_file = input_api.os_path.join(
2890 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2891 if owners_file not in to_check:
2892 to_check[owners_file] = {}
2893 if pattern not in to_check[owners_file]:
2894 to_check[owners_file][pattern] = {
2895 'files': [],
2896 'rules': [
2897 'per-file %s=set noparent' % pattern,
2898 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2899 ]
2900 }
Vaclav Brozekd5de76a2018-03-17 07:57:502901 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252902
dchenge07de812016-06-20 19:27:172903 # Iterate through the affected files to see what we actually need to check
2904 # for. We should only nag patch authors about per-file rules if a file in that
2905 # directory would match that pattern. If a directory only contains *.mojom
2906 # files and no *_messages*.h files, we should only nag about rules for
2907 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252908 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262909 # Manifest files don't have a strong naming convention. Instead, try to find
2910 # affected .cc and .h files which look like they contain a manifest
2911 # definition.
2912 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2913 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2914 if (manifest_pattern.search(f.LocalPath()) and not
2915 test_manifest_pattern.search(f.LocalPath())):
2916 # We expect all actual service manifest files to contain at least one
2917 # qualified reference to service_manager::Manifest.
2918 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252919 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172920 for pattern in file_patterns:
2921 if input_api.fnmatch.fnmatch(
2922 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042923 skip = False
2924 for exclude in exclude_paths:
2925 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2926 skip = True
2927 break
2928 if skip:
2929 continue
Daniel Cheng13ca61a882017-08-25 15:11:252930 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172931 break
2932
Daniel Cheng7052cdf2017-11-21 19:23:292933 return to_check
2934
2935
Wez17c66962020-04-29 15:26:032936def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2937 """Adds OWNERS files to check for correct Fuchsia security owners."""
2938
2939 file_patterns = [
2940 # Component specifications.
2941 '*.cml', # Component Framework v2.
2942 '*.cmx', # Component Framework v1.
2943
2944 # Fuchsia IDL protocol specifications.
2945 '*.fidl',
2946 ]
2947
Joshua Peraza1ca6d392020-12-08 00:14:092948 # Don't check for owners files for changes in these directories.
2949 exclude_paths = [
2950 'third_party/crashpad/*',
2951 ]
2952
Wez17c66962020-04-29 15:26:032953 def AddPatternToCheck(input_file, pattern):
2954 owners_file = input_api.os_path.join(
2955 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2956 if owners_file not in to_check:
2957 to_check[owners_file] = {}
2958 if pattern not in to_check[owners_file]:
2959 to_check[owners_file][pattern] = {
2960 'files': [],
2961 'rules': [
2962 'per-file %s=set noparent' % pattern,
2963 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2964 ]
2965 }
2966 to_check[owners_file][pattern]['files'].append(input_file)
2967
2968 # Iterate through the affected files to see what we actually need to check
2969 # for. We should only nag patch authors about per-file rules if a file in that
2970 # directory would match that pattern.
2971 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092972 skip = False
2973 for exclude in exclude_paths:
2974 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2975 skip = True
2976 if skip:
2977 continue
2978
Wez17c66962020-04-29 15:26:032979 for pattern in file_patterns:
2980 if input_api.fnmatch.fnmatch(
2981 input_api.os_path.basename(f.LocalPath()), pattern):
2982 AddPatternToCheck(f, pattern)
2983 break
2984
2985 return to_check
2986
2987
Saagar Sanghavifceeaae2020-08-12 16:40:362988def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292989 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2990 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032991 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292992
2993 if to_check:
2994 # If there are any OWNERS files to check, there are IPC-related changes in
2995 # this CL. Auto-CC the review list.
2996 output_api.AppendCC('[email protected]')
2997
2998 # Go through the OWNERS files to check, filtering out rules that are already
2999 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173000 for owners_file, patterns in to_check.iteritems():
3001 try:
3002 with file(owners_file) as f:
3003 lines = set(f.read().splitlines())
3004 for entry in patterns.itervalues():
3005 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3006 ]
3007 except IOError:
3008 # No OWNERS file, so all the rules are definitely missing.
3009 continue
3010
3011 # All the remaining lines weren't found in OWNERS files, so emit an error.
3012 errors = []
3013 for owners_file, patterns in to_check.iteritems():
3014 missing_lines = []
3015 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503016 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173017 missing_lines.extend(entry['rules'])
3018 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3019 if missing_lines:
3020 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053021 'Because of the presence of files:\n%s\n\n'
3022 '%s needs the following %d lines added:\n\n%s' %
3023 ('\n'.join(files), owners_file, len(missing_lines),
3024 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173025
3026 results = []
3027 if errors:
vabrf5ce3bf92016-07-11 14:52:413028 if input_api.is_committing:
3029 output = output_api.PresubmitError
3030 else:
3031 output = output_api.PresubmitPromptWarning
3032 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593033 'Found OWNERS files that need to be updated for IPC security ' +
3034 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173035 long_text='\n\n'.join(errors)))
3036
3037 return results
3038
3039
Robert Sesek2c905332020-05-06 23:17:133040def _GetFilesUsingSecurityCriticalFunctions(input_api):
3041 """Checks affected files for changes to security-critical calls. This
3042 function checks the full change diff, to catch both additions/changes
3043 and removals.
3044
3045 Returns a dict keyed by file name, and the value is a set of detected
3046 functions.
3047 """
3048 # Map of function pretty name (displayed in an error) to the pattern to
3049 # match it with.
3050 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373051 'content::GetServiceSandboxType<>()':
3052 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133053 }
3054 _PATTERNS_TO_CHECK = {
3055 k: input_api.re.compile(v)
3056 for k, v in _PATTERNS_TO_CHECK.items()
3057 }
3058
3059 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3060 files_to_functions = {}
3061 for f in input_api.AffectedFiles():
3062 diff = f.GenerateScmDiff()
3063 for line in diff.split('\n'):
3064 # Not using just RightHandSideLines() because removing a
3065 # call to a security-critical function can be just as important
3066 # as adding or changing the arguments.
3067 if line.startswith('-') or (line.startswith('+') and
3068 not line.startswith('++')):
3069 for name, pattern in _PATTERNS_TO_CHECK.items():
3070 if pattern.search(line):
3071 path = f.LocalPath()
3072 if not path in files_to_functions:
3073 files_to_functions[path] = set()
3074 files_to_functions[path].add(name)
3075 return files_to_functions
3076
3077
Saagar Sanghavifceeaae2020-08-12 16:40:363078def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133079 """Checks that changes involving security-critical functions are reviewed
3080 by the security team.
3081 """
3082 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:123083 if not len(files_to_functions):
3084 return []
Robert Sesek2c905332020-05-06 23:17:133085
Edward Lesmes1e9fade2021-02-08 20:31:123086 owner_email, reviewers = (
3087 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3088 input_api,
3089 None,
3090 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:133091
Edward Lesmes1e9fade2021-02-08 20:31:123092 # Load the OWNERS file for security changes.
3093 owners_file = 'ipc/SECURITY_OWNERS'
3094 security_owners = input_api.owners_client.ListOwners(owners_file)
3095 has_security_owner = any([owner in reviewers for owner in security_owners])
3096 if has_security_owner:
3097 return []
Robert Sesek2c905332020-05-06 23:17:133098
Edward Lesmes1e9fade2021-02-08 20:31:123099 msg = 'The following files change calls to security-sensive functions\n' \
3100 'that need to be reviewed by {}.\n'.format(owners_file)
3101 for path, names in files_to_functions.items():
3102 msg += ' {}\n'.format(path)
3103 for name in names:
3104 msg += ' {}\n'.format(name)
3105 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133106
Edward Lesmes1e9fade2021-02-08 20:31:123107 if input_api.is_committing:
3108 output = output_api.PresubmitError
3109 else:
3110 output = output_api.PresubmitNotifyResult
3111 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133112
3113
Saagar Sanghavifceeaae2020-08-12 16:40:363114def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263115 """Checks that set noparent is only used together with an OWNERS file in
3116 //build/OWNERS.setnoparent (see also
3117 //docs/code_reviews.md#owners-files-details)
3118 """
3119 errors = []
3120
3121 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3122 allowed_owners_files = set()
3123 with open(allowed_owners_files_file, 'r') as f:
3124 for line in f:
3125 line = line.strip()
3126 if not line or line.startswith('#'):
3127 continue
3128 allowed_owners_files.add(line)
3129
3130 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3131
3132 for f in input_api.AffectedFiles(include_deletes=False):
3133 if not f.LocalPath().endswith('OWNERS'):
3134 continue
3135
3136 found_owners_files = set()
3137 found_set_noparent_lines = dict()
3138
3139 # Parse the OWNERS file.
3140 for lineno, line in enumerate(f.NewContents(), 1):
3141 line = line.strip()
3142 if line.startswith('set noparent'):
3143 found_set_noparent_lines[''] = lineno
3144 if line.startswith('file://'):
3145 if line in allowed_owners_files:
3146 found_owners_files.add('')
3147 if line.startswith('per-file'):
3148 match = per_file_pattern.match(line)
3149 if match:
3150 glob = match.group(1).strip()
3151 directive = match.group(2).strip()
3152 if directive == 'set noparent':
3153 found_set_noparent_lines[glob] = lineno
3154 if directive.startswith('file://'):
3155 if directive in allowed_owners_files:
3156 found_owners_files.add(glob)
3157
3158 # Check that every set noparent line has a corresponding file:// line
3159 # listed in build/OWNERS.setnoparent.
3160 for set_noparent_line in found_set_noparent_lines:
3161 if set_noparent_line in found_owners_files:
3162 continue
3163 errors.append(' %s:%d' % (f.LocalPath(),
3164 found_set_noparent_lines[set_noparent_line]))
3165
3166 results = []
3167 if errors:
3168 if input_api.is_committing:
3169 output = output_api.PresubmitError
3170 else:
3171 output = output_api.PresubmitPromptWarning
3172 results.append(output(
3173 'Found the following "set noparent" restrictions in OWNERS files that '
3174 'do not include owners from build/OWNERS.setnoparent:',
3175 long_text='\n\n'.join(errors)))
3176 return results
3177
3178
Saagar Sanghavifceeaae2020-08-12 16:40:363179def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313180 """Checks that added or removed lines in non third party affected
3181 header files do not lead to new useless class or struct forward
3182 declaration.
jbriance9e12f162016-11-25 07:57:503183 """
3184 results = []
3185 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3186 input_api.re.MULTILINE)
3187 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3188 input_api.re.MULTILINE)
3189 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313190 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193191 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493192 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313193 continue
3194
jbriance9e12f162016-11-25 07:57:503195 if not f.LocalPath().endswith('.h'):
3196 continue
3197
3198 contents = input_api.ReadFile(f)
3199 fwd_decls = input_api.re.findall(class_pattern, contents)
3200 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3201
3202 useless_fwd_decls = []
3203 for decl in fwd_decls:
3204 count = sum(1 for _ in input_api.re.finditer(
3205 r'\b%s\b' % input_api.re.escape(decl), contents))
3206 if count == 1:
3207 useless_fwd_decls.append(decl)
3208
3209 if not useless_fwd_decls:
3210 continue
3211
3212 for line in f.GenerateScmDiff().splitlines():
3213 if (line.startswith('-') and not line.startswith('--') or
3214 line.startswith('+') and not line.startswith('++')):
3215 for decl in useless_fwd_decls:
3216 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3217 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243218 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503219 (f.LocalPath(), decl)))
3220 useless_fwd_decls.remove(decl)
3221
3222 return results
3223
Jinsong Fan91ebbbd2019-04-16 14:57:173224def _CheckAndroidDebuggableBuild(input_api, output_api):
3225 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3226 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3227 this is a debuggable build of Android.
3228 """
3229 build_type_check_pattern = input_api.re.compile(
3230 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3231
3232 errors = []
3233
3234 sources = lambda affected_file: input_api.FilterSourceFile(
3235 affected_file,
James Cook24a504192020-07-23 00:08:443236 files_to_skip=(_EXCLUDED_PATHS +
3237 _TEST_CODE_EXCLUDED_PATHS +
3238 input_api.DEFAULT_FILES_TO_SKIP +
3239 (r"^android_webview[\\/]support_library[\\/]"
3240 "boundary_interfaces[\\/]",
3241 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3242 r'^third_party[\\/].*',
3243 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3244 r"webview[\\/]chromium[\\/]License.*",)),
3245 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173246
3247 for f in input_api.AffectedSourceFiles(sources):
3248 for line_num, line in f.ChangedContents():
3249 if build_type_check_pattern.search(line):
3250 errors.append("%s:%d" % (f.LocalPath(), line_num))
3251
3252 results = []
3253
3254 if errors:
3255 results.append(output_api.PresubmitPromptWarning(
3256 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3257 ' Please use BuildInfo.isDebugAndroid() instead.',
3258 errors))
3259
3260 return results
jbriance9e12f162016-11-25 07:57:503261
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493262# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293263def _CheckAndroidToastUsage(input_api, output_api):
3264 """Checks that code uses org.chromium.ui.widget.Toast instead of
3265 android.widget.Toast (Chromium Toast doesn't force hardware
3266 acceleration on low-end devices, saving memory).
3267 """
3268 toast_import_pattern = input_api.re.compile(
3269 r'^import android\.widget\.Toast;$')
3270
3271 errors = []
3272
3273 sources = lambda affected_file: input_api.FilterSourceFile(
3274 affected_file,
James Cook24a504192020-07-23 00:08:443275 files_to_skip=(_EXCLUDED_PATHS +
3276 _TEST_CODE_EXCLUDED_PATHS +
3277 input_api.DEFAULT_FILES_TO_SKIP +
3278 (r'^chromecast[\\/].*',
3279 r'^remoting[\\/].*')),
3280 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293281
3282 for f in input_api.AffectedSourceFiles(sources):
3283 for line_num, line in f.ChangedContents():
3284 if toast_import_pattern.search(line):
3285 errors.append("%s:%d" % (f.LocalPath(), line_num))
3286
3287 results = []
3288
3289 if errors:
3290 results.append(output_api.PresubmitError(
3291 'android.widget.Toast usage is detected. Android toasts use hardware'
3292 ' acceleration, and can be\ncostly on low-end devices. Please use'
3293 ' org.chromium.ui.widget.Toast instead.\n'
3294 'Contact [email protected] if you have any questions.',
3295 errors))
3296
3297 return results
3298
3299
dgnaa68d5e2015-06-10 10:08:223300def _CheckAndroidCrLogUsage(input_api, output_api):
3301 """Checks that new logs using org.chromium.base.Log:
3302 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513303 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223304 """
pkotwicza1dd0b002016-05-16 14:41:043305
torne89540622017-03-24 19:41:303306 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043307 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303308 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043309 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303310 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043311 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3312 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093313 # The customtabs_benchmark is a small app that does not depend on Chromium
3314 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043315 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043316 ]
3317
dgnaa68d5e2015-06-10 10:08:223318 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123319 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3320 class_in_base_pattern = input_api.re.compile(
3321 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3322 has_some_log_import_pattern = input_api.re.compile(
3323 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223324 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553325 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223326 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463327 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553328 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223329
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463330 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443331 sources = lambda x: input_api.FilterSourceFile(x,
3332 files_to_check=[r'.*\.java$'],
3333 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123334
dgnaa68d5e2015-06-10 10:08:223335 tag_decl_errors = []
3336 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123337 tag_errors = []
dgn38736db2015-09-18 19:20:513338 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123339 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223340
3341 for f in input_api.AffectedSourceFiles(sources):
3342 file_content = input_api.ReadFile(f)
3343 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223344 # Per line checks
dgn87d9fb62015-06-12 09:15:123345 if (cr_log_import_pattern.search(file_content) or
3346 (class_in_base_pattern.search(file_content) and
3347 not has_some_log_import_pattern.search(file_content))):
3348 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223349 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553350 if rough_log_decl_pattern.search(line):
3351 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223352
3353 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123354 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223355 if match:
3356 has_modified_logs = True
3357
3358 # Make sure it uses "TAG"
3359 if not match.group('tag') == 'TAG':
3360 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123361 else:
3362 # Report non cr Log function calls in changed lines
3363 for line_num, line in f.ChangedContents():
3364 if log_call_pattern.search(line):
3365 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223366
3367 # Per file checks
3368 if has_modified_logs:
3369 # Make sure the tag is using the "cr" prefix and is not too long
3370 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513371 tag_name = match.group('name') if match else None
3372 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223373 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513374 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223375 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513376 elif '.' in tag_name:
3377 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223378
3379 results = []
3380 if tag_decl_errors:
3381 results.append(output_api.PresubmitPromptWarning(
3382 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513383 '"private static final String TAG = "<package tag>".\n'
3384 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223385 tag_decl_errors))
3386
3387 if tag_length_errors:
3388 results.append(output_api.PresubmitError(
3389 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513390 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223391 tag_length_errors))
3392
3393 if tag_errors:
3394 results.append(output_api.PresubmitPromptWarning(
3395 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3396 tag_errors))
3397
dgn87d9fb62015-06-12 09:15:123398 if util_log_errors:
dgn4401aa52015-04-29 16:26:173399 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123400 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3401 util_log_errors))
3402
dgn38736db2015-09-18 19:20:513403 if tag_with_dot_errors:
3404 results.append(output_api.PresubmitPromptWarning(
3405 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3406 tag_with_dot_errors))
3407
dgn4401aa52015-04-29 16:26:173408 return results
3409
3410
Yoland Yanb92fa522017-08-28 17:37:063411def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3412 """Checks that junit.framework.* is no longer used."""
3413 deprecated_junit_framework_pattern = input_api.re.compile(
3414 r'^import junit\.framework\..*;',
3415 input_api.re.MULTILINE)
3416 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443417 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063418 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133419 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063420 for line_num, line in f.ChangedContents():
3421 if deprecated_junit_framework_pattern.search(line):
3422 errors.append("%s:%d" % (f.LocalPath(), line_num))
3423
3424 results = []
3425 if errors:
3426 results.append(output_api.PresubmitError(
3427 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3428 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3429 ' if you have any question.', errors))
3430 return results
3431
3432
3433def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3434 """Checks that if new Java test classes have inheritance.
3435 Either the new test class is JUnit3 test or it is a JUnit4 test class
3436 with a base class, either case is undesirable.
3437 """
3438 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3439
3440 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443441 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063442 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133443 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063444 if not f.OldContents():
3445 class_declaration_start_flag = False
3446 for line_num, line in f.ChangedContents():
3447 if class_declaration_pattern.search(line):
3448 class_declaration_start_flag = True
3449 if class_declaration_start_flag and ' extends ' in line:
3450 errors.append('%s:%d' % (f.LocalPath(), line_num))
3451 if '{' in line:
3452 class_declaration_start_flag = False
3453
3454 results = []
3455 if errors:
3456 results.append(output_api.PresubmitPromptWarning(
3457 'The newly created files include Test classes that inherits from base'
3458 ' class. Please do not use inheritance in JUnit4 tests or add new'
3459 ' JUnit3 tests. Contact [email protected] if you have any'
3460 ' questions.', errors))
3461 return results
3462
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203463
yolandyan45001472016-12-21 21:12:423464def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3465 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3466 deprecated_annotation_import_pattern = input_api.re.compile(
3467 r'^import android\.test\.suitebuilder\.annotation\..*;',
3468 input_api.re.MULTILINE)
3469 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443470 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423471 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133472 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423473 for line_num, line in f.ChangedContents():
3474 if deprecated_annotation_import_pattern.search(line):
3475 errors.append("%s:%d" % (f.LocalPath(), line_num))
3476
3477 results = []
3478 if errors:
3479 results.append(output_api.PresubmitError(
3480 'Annotations in android.test.suitebuilder.annotation have been'
3481 ' deprecated since API level 24. Please use android.support.test.filters'
3482 ' from //third_party/android_support_test_runner:runner_java instead.'
3483 ' Contact [email protected] if you have any questions.', errors))
3484 return results
3485
3486
agrieve7b6479d82015-10-07 14:24:223487def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3488 """Checks if MDPI assets are placed in a correct directory."""
3489 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3490 ('/res/drawable/' in f.LocalPath() or
3491 '/res/drawable-ldrtl/' in f.LocalPath()))
3492 errors = []
3493 for f in input_api.AffectedFiles(include_deletes=False,
3494 file_filter=file_filter):
3495 errors.append(' %s' % f.LocalPath())
3496
3497 results = []
3498 if errors:
3499 results.append(output_api.PresubmitError(
3500 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3501 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3502 '/res/drawable-ldrtl/.\n'
3503 'Contact [email protected] if you have questions.', errors))
3504 return results
3505
3506
Nate Fischer535972b2017-09-16 01:06:183507def _CheckAndroidWebkitImports(input_api, output_api):
3508 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353509 android.webview.ValueCallback except in the WebView glue layer
3510 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183511 """
3512 valuecallback_import_pattern = input_api.re.compile(
3513 r'^import android\.webkit\.ValueCallback;$')
3514
3515 errors = []
3516
3517 sources = lambda affected_file: input_api.FilterSourceFile(
3518 affected_file,
James Cook24a504192020-07-23 00:08:443519 files_to_skip=(_EXCLUDED_PATHS +
3520 _TEST_CODE_EXCLUDED_PATHS +
3521 input_api.DEFAULT_FILES_TO_SKIP +
3522 (r'^android_webview[\\/]glue[\\/].*',
3523 r'^weblayer[\\/].*',)),
3524 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183525
3526 for f in input_api.AffectedSourceFiles(sources):
3527 for line_num, line in f.ChangedContents():
3528 if valuecallback_import_pattern.search(line):
3529 errors.append("%s:%d" % (f.LocalPath(), line_num))
3530
3531 results = []
3532
3533 if errors:
3534 results.append(output_api.PresubmitError(
3535 'android.webkit.ValueCallback usage is detected outside of the glue'
3536 ' layer. To stay compatible with the support library, android.webkit.*'
3537 ' classes should only be used inside the glue layer and'
3538 ' org.chromium.base.Callback should be used instead.',
3539 errors))
3540
3541 return results
3542
3543
Becky Zhou7c69b50992018-12-10 19:37:573544def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3545 """Checks Android XML styles """
3546 import sys
3547 original_sys_path = sys.path
3548 try:
3549 sys.path = sys.path + [input_api.os_path.join(
3550 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3551 import checkxmlstyle
3552 finally:
3553 # Restore sys.path to what it was before.
3554 sys.path = original_sys_path
3555
3556 if is_check_on_upload:
3557 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3558 else:
3559 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3560
3561
agrievef32bcc72016-04-04 14:57:403562class PydepsChecker(object):
3563 def __init__(self, input_api, pydeps_files):
3564 self._file_cache = {}
3565 self._input_api = input_api
3566 self._pydeps_files = pydeps_files
3567
3568 def _LoadFile(self, path):
3569 """Returns the list of paths within a .pydeps file relative to //."""
3570 if path not in self._file_cache:
3571 with open(path) as f:
3572 self._file_cache[path] = f.read()
3573 return self._file_cache[path]
3574
3575 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3576 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393577 pydeps_data = self._LoadFile(pydeps_path)
3578 uses_gn_paths = '--gn-paths' in pydeps_data
3579 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3580 if uses_gn_paths:
3581 # Paths look like: //foo/bar/baz
3582 return (e[2:] for e in entries)
3583 else:
3584 # Paths look like: path/relative/to/file.pydeps
3585 os_path = self._input_api.os_path
3586 pydeps_dir = os_path.dirname(pydeps_path)
3587 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403588
3589 def _CreateFilesToPydepsMap(self):
3590 """Returns a map of local_path -> list_of_pydeps."""
3591 ret = {}
3592 for pydep_local_path in self._pydeps_files:
3593 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3594 ret.setdefault(path, []).append(pydep_local_path)
3595 return ret
3596
3597 def ComputeAffectedPydeps(self):
3598 """Returns an iterable of .pydeps files that might need regenerating."""
3599 affected_pydeps = set()
3600 file_to_pydeps_map = None
3601 for f in self._input_api.AffectedFiles(include_deletes=True):
3602 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463603 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3604 # subrepositories. We can't figure out which files change, so re-check
3605 # all files.
3606 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383607 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3608 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403609 return self._pydeps_files
3610 elif local_path.endswith('.pydeps'):
3611 if local_path in self._pydeps_files:
3612 affected_pydeps.add(local_path)
3613 elif local_path.endswith('.py'):
3614 if file_to_pydeps_map is None:
3615 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3616 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3617 return affected_pydeps
3618
3619 def DetermineIfStale(self, pydeps_path):
3620 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413621 import difflib
John Budorick47ca3fe2018-02-10 00:53:103622 import os
3623
agrievef32bcc72016-04-04 14:57:403624 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033625 if old_pydeps_data:
3626 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393627 if '--output' not in cmd:
3628 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033629 old_contents = old_pydeps_data[2:]
3630 else:
3631 # A default cmd that should work in most cases (as long as pydeps filename
3632 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3633 # file is empty/new.
3634 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3635 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3636 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103637 env = dict(os.environ)
3638 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403639 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103640 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413641 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033642 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413643 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403644
3645
Tibor Goldschwendt360793f72019-06-25 18:23:493646def _ParseGclientArgs():
3647 args = {}
3648 with open('build/config/gclient_args.gni', 'r') as f:
3649 for line in f:
3650 line = line.strip()
3651 if not line or line.startswith('#'):
3652 continue
3653 attribute, value = line.split('=')
3654 args[attribute.strip()] = value.strip()
3655 return args
3656
3657
Saagar Sanghavifceeaae2020-08-12 16:40:363658def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403659 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403660 # This check is for Python dependency lists (.pydeps files), and involves
3661 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3662 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283663 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003664 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493665 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403666 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403667 results = []
3668 # First, check for new / deleted .pydeps.
3669 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033670 # Check whether we are running the presubmit check for a file in src.
3671 # f.LocalPath is relative to repo (src, or internal repo).
3672 # os_path.exists is relative to src repo.
3673 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3674 # to src and we can conclude that the pydeps is in src.
3675 if input_api.os_path.exists(f.LocalPath()):
3676 if f.LocalPath().endswith('.pydeps'):
3677 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3678 results.append(output_api.PresubmitError(
3679 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3680 'remove %s' % f.LocalPath()))
3681 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3682 results.append(output_api.PresubmitError(
3683 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3684 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403685
3686 if results:
3687 return results
3688
Mohamed Heikal7cd4d8312020-06-16 16:49:403689 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3690 affected_pydeps = set(checker.ComputeAffectedPydeps())
3691 affected_android_pydeps = affected_pydeps.intersection(
3692 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3693 if affected_android_pydeps and not is_android:
3694 results.append(output_api.PresubmitPromptOrNotify(
3695 'You have changed python files that may affect pydeps for android\n'
3696 'specific scripts. However, the relevant presumbit check cannot be\n'
3697 'run because you are not using an Android checkout. To validate that\n'
3698 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3699 'use the android-internal-presubmit optional trybot.\n'
3700 'Possibly stale pydeps files:\n{}'.format(
3701 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403702
Mohamed Heikal7cd4d8312020-06-16 16:49:403703 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3704 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403705 try:
phajdan.jr0d9878552016-11-04 10:49:413706 result = checker.DetermineIfStale(pydep_path)
3707 if result:
3708 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403709 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413710 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3711 'To regenerate, run:\n\n %s' %
3712 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403713 except input_api.subprocess.CalledProcessError as error:
3714 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3715 long_text=error.output)]
3716
3717 return results
3718
3719
Saagar Sanghavifceeaae2020-08-12 16:40:363720def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433721 """Checks to make sure no header files have |Singleton<|."""
3722 def FileFilter(affected_file):
3723 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443724 files_to_skip = (_EXCLUDED_PATHS +
3725 input_api.DEFAULT_FILES_TO_SKIP +
3726 (r"^base[\\/]memory[\\/]singleton\.h$",
3727 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3728 r"quic_singleton_impl\.h$"))
3729 return input_api.FilterSourceFile(affected_file,
3730 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433731
sergeyu34d21222015-09-16 00:11:443732 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433733 files = []
3734 for f in input_api.AffectedSourceFiles(FileFilter):
3735 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3736 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3737 contents = input_api.ReadFile(f)
3738 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243739 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433740 pattern.search(line)):
3741 files.append(f)
3742 break
3743
3744 if files:
yolandyandaabc6d2016-04-18 18:29:393745 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443746 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433747 'Please move them to an appropriate source file so that the ' +
3748 'template gets instantiated in a single compilation unit.',
3749 files) ]
3750 return []
3751
3752
[email protected]fd20b902014-05-09 02:14:533753_DEPRECATED_CSS = [
3754 # Values
3755 ( "-webkit-box", "flex" ),
3756 ( "-webkit-inline-box", "inline-flex" ),
3757 ( "-webkit-flex", "flex" ),
3758 ( "-webkit-inline-flex", "inline-flex" ),
3759 ( "-webkit-min-content", "min-content" ),
3760 ( "-webkit-max-content", "max-content" ),
3761
3762 # Properties
3763 ( "-webkit-background-clip", "background-clip" ),
3764 ( "-webkit-background-origin", "background-origin" ),
3765 ( "-webkit-background-size", "background-size" ),
3766 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443767 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533768
3769 # Functions
3770 ( "-webkit-gradient", "gradient" ),
3771 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3772 ( "-webkit-linear-gradient", "linear-gradient" ),
3773 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3774 ( "-webkit-radial-gradient", "radial-gradient" ),
3775 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3776]
3777
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203778
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493779# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363780def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533781 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253782 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343783 documentation and iOS CSS for dom distiller
3784 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253785 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533786 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493787 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443788 files_to_skip = (_EXCLUDED_PATHS +
3789 _TEST_CODE_EXCLUDED_PATHS +
3790 input_api.DEFAULT_FILES_TO_SKIP +
3791 (r"^chrome/common/extensions/docs",
3792 r"^chrome/docs",
3793 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3794 r"^components/neterror/resources/neterror.css",
3795 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253796 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443797 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533798 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3799 for line_num, line in fpath.ChangedContents():
3800 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023801 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533802 results.append(output_api.PresubmitError(
3803 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3804 (fpath.LocalPath(), line_num, deprecated_value, value)))
3805 return results
3806
mohan.reddyf21db962014-10-16 12:26:473807
Saagar Sanghavifceeaae2020-08-12 16:40:363808def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363809 bad_files = {}
3810 for f in input_api.AffectedFiles(include_deletes=False):
3811 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493812 not f.LocalPath().startswith('third_party/blink') and
3813 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363814 continue
3815
Daniel Bratell65b033262019-04-23 08:17:063816 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363817 continue
3818
Vaclav Brozekd5de76a2018-03-17 07:57:503819 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363820 if "#include" in line and "../" in line]
3821 if not relative_includes:
3822 continue
3823 bad_files[f.LocalPath()] = relative_includes
3824
3825 if not bad_files:
3826 return []
3827
3828 error_descriptions = []
3829 for file_path, bad_lines in bad_files.iteritems():
3830 error_description = file_path
3831 for line in bad_lines:
3832 error_description += '\n ' + line
3833 error_descriptions.append(error_description)
3834
3835 results = []
3836 results.append(output_api.PresubmitError(
3837 'You added one or more relative #include paths (including "../").\n'
3838 'These shouldn\'t be used because they can be used to include headers\n'
3839 'from code that\'s not correctly specified as a dependency in the\n'
3840 'relevant BUILD.gn file(s).',
3841 error_descriptions))
3842
3843 return results
3844
Takeshi Yoshinoe387aa32017-08-02 13:16:133845
Saagar Sanghavifceeaae2020-08-12 16:40:363846def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063847 """Check that nobody tries to include a cc file. It's a relatively
3848 common error which results in duplicate symbols in object
3849 files. This may not always break the build until someone later gets
3850 very confusing linking errors."""
3851 results = []
3852 for f in input_api.AffectedFiles(include_deletes=False):
3853 # We let third_party code do whatever it wants
3854 if (f.LocalPath().startswith('third_party') and
3855 not f.LocalPath().startswith('third_party/blink') and
3856 not f.LocalPath().startswith('third_party\\blink')):
3857 continue
3858
3859 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3860 continue
3861
3862 for _, line in f.ChangedContents():
3863 if line.startswith('#include "'):
3864 included_file = line.split('"')[1]
3865 if _IsCPlusPlusFile(input_api, included_file):
3866 # The most common naming for external files with C++ code,
3867 # apart from standard headers, is to call them foo.inc, but
3868 # Chromium sometimes uses foo-inc.cc so allow that as well.
3869 if not included_file.endswith(('.h', '-inc.cc')):
3870 results.append(output_api.PresubmitError(
3871 'Only header files or .inc files should be included in other\n'
3872 'C++ files. Compiling the contents of a cc file more than once\n'
3873 'will cause duplicate information in the build which may later\n'
3874 'result in strange link_errors.\n' +
3875 f.LocalPath() + ':\n ' +
3876 line))
3877
3878 return results
3879
3880
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203881def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3882 if not isinstance(key, ast.Str):
3883 return 'Key at line %d must be a string literal' % key.lineno
3884 if not isinstance(value, ast.Dict):
3885 return 'Value at line %d must be a dict' % value.lineno
3886 if len(value.keys) != 1:
3887 return 'Dict at line %d must have single entry' % value.lineno
3888 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3889 return (
3890 'Entry at line %d must have a string literal \'filepath\' as key' %
3891 value.lineno)
3892 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133893
Takeshi Yoshinoe387aa32017-08-02 13:16:133894
Sergey Ulanov4af16052018-11-08 02:41:463895def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203896 if not isinstance(key, ast.Str):
3897 return 'Key at line %d must be a string literal' % key.lineno
3898 if not isinstance(value, ast.List):
3899 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463900 for element in value.elts:
3901 if not isinstance(element, ast.Str):
3902 return 'Watchlist elements on line %d is not a string' % key.lineno
3903 if not email_regex.match(element.s):
3904 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3905 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203906 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133907
Takeshi Yoshinoe387aa32017-08-02 13:16:133908
Sergey Ulanov4af16052018-11-08 02:41:463909def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203910 mismatch_template = (
3911 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3912 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133913
Sergey Ulanov4af16052018-11-08 02:41:463914 email_regex = input_api.re.compile(
3915 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3916
3917 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203918 i = 0
3919 last_key = ''
3920 while True:
3921 if i >= len(wd_dict.keys):
3922 if i >= len(w_dict.keys):
3923 return None
3924 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3925 elif i >= len(w_dict.keys):
3926 return (
3927 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133928
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203929 wd_key = wd_dict.keys[i]
3930 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133931
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203932 result = _CheckWatchlistDefinitionsEntrySyntax(
3933 wd_key, wd_dict.values[i], ast)
3934 if result is not None:
3935 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133936
Sergey Ulanov4af16052018-11-08 02:41:463937 result = _CheckWatchlistsEntrySyntax(
3938 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203939 if result is not None:
3940 return 'Bad entry in WATCHLISTS dict: %s' % result
3941
3942 if wd_key.s != w_key.s:
3943 return mismatch_template % (
3944 '%s at line %d' % (wd_key.s, wd_key.lineno),
3945 '%s at line %d' % (w_key.s, w_key.lineno))
3946
3947 if wd_key.s < last_key:
3948 return (
3949 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3950 (wd_key.lineno, w_key.lineno))
3951 last_key = wd_key.s
3952
3953 i = i + 1
3954
3955
Sergey Ulanov4af16052018-11-08 02:41:463956def _CheckWATCHLISTSSyntax(expression, input_api):
3957 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203958 if not isinstance(expression, ast.Expression):
3959 return 'WATCHLISTS file must contain a valid expression'
3960 dictionary = expression.body
3961 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3962 return 'WATCHLISTS file must have single dict with exactly two entries'
3963
3964 first_key = dictionary.keys[0]
3965 first_value = dictionary.values[0]
3966 second_key = dictionary.keys[1]
3967 second_value = dictionary.values[1]
3968
3969 if (not isinstance(first_key, ast.Str) or
3970 first_key.s != 'WATCHLIST_DEFINITIONS' or
3971 not isinstance(first_value, ast.Dict)):
3972 return (
3973 'The first entry of the dict in WATCHLISTS file must be '
3974 'WATCHLIST_DEFINITIONS dict')
3975
3976 if (not isinstance(second_key, ast.Str) or
3977 second_key.s != 'WATCHLISTS' or
3978 not isinstance(second_value, ast.Dict)):
3979 return (
3980 'The second entry of the dict in WATCHLISTS file must be '
3981 'WATCHLISTS dict')
3982
Sergey Ulanov4af16052018-11-08 02:41:463983 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133984
3985
Saagar Sanghavifceeaae2020-08-12 16:40:363986def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133987 for f in input_api.AffectedFiles(include_deletes=False):
3988 if f.LocalPath() == 'WATCHLISTS':
3989 contents = input_api.ReadFile(f, 'r')
3990
3991 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203992 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133993 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203994 # Get an AST tree for it and scan the tree for detailed style checking.
3995 expression = input_api.ast.parse(
3996 contents, filename='WATCHLISTS', mode='eval')
3997 except ValueError as e:
3998 return [output_api.PresubmitError(
3999 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4000 except SyntaxError as e:
4001 return [output_api.PresubmitError(
4002 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4003 except TypeError as e:
4004 return [output_api.PresubmitError(
4005 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134006
Sergey Ulanov4af16052018-11-08 02:41:464007 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204008 if result is not None:
4009 return [output_api.PresubmitError(result)]
4010 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134011
4012 return []
4013
4014
Andrew Grieve1b290e4a22020-11-24 20:07:014015def CheckGnGlobForward(input_api, output_api):
4016 """Checks that forward_variables_from(invoker, "*") follows best practices.
4017
4018 As documented at //build/docs/writing_gn_templates.md
4019 """
4020 def gn_files(f):
4021 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
4022
4023 problems = []
4024 for f in input_api.AffectedSourceFiles(gn_files):
4025 for line_num, line in f.ChangedContents():
4026 if 'forward_variables_from(invoker, "*")' in line:
4027 problems.append(
4028 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
4029 f.LocalPath(), line_num))
4030
4031 if problems:
4032 return [output_api.PresubmitPromptWarning(
4033 'forward_variables_from("*") without exclusions',
4034 items=sorted(problems),
4035 long_text=('The variables "visibilty" and "test_only" should be '
4036 'explicitly listed in forward_variables_from(). For more '
4037 'details, see:\n'
4038 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4039 'build/docs/writing_gn_templates.md'
4040 '#Using-forward_variables_from'))]
4041 return []
4042
4043
Saagar Sanghavifceeaae2020-08-12 16:40:364044def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194045 """Checks that newly added header files have corresponding GN changes.
4046 Note that this is only a heuristic. To be precise, run script:
4047 build/check_gn_headers.py.
4048 """
4049
4050 def headers(f):
4051 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444052 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194053
4054 new_headers = []
4055 for f in input_api.AffectedSourceFiles(headers):
4056 if f.Action() != 'A':
4057 continue
4058 new_headers.append(f.LocalPath())
4059
4060 def gn_files(f):
James Cook24a504192020-07-23 00:08:444061 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194062
4063 all_gn_changed_contents = ''
4064 for f in input_api.AffectedSourceFiles(gn_files):
4065 for _, line in f.ChangedContents():
4066 all_gn_changed_contents += line
4067
4068 problems = []
4069 for header in new_headers:
4070 basename = input_api.os_path.basename(header)
4071 if basename not in all_gn_changed_contents:
4072 problems.append(header)
4073
4074 if problems:
4075 return [output_api.PresubmitPromptWarning(
4076 'Missing GN changes for new header files', items=sorted(problems),
4077 long_text='Please double check whether newly added header files need '
4078 'corresponding changes in gn or gni files.\nThis checking is only a '
4079 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4080 'Read https://crbug.com/661774 for more info.')]
4081 return []
4082
4083
Saagar Sanghavifceeaae2020-08-12 16:40:364084def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024085 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4086
4087 This assumes we won't intentionally reference one product from the other
4088 product.
4089 """
4090 all_problems = []
4091 test_cases = [{
4092 "filename_postfix": "google_chrome_strings.grd",
4093 "correct_name": "Chrome",
4094 "incorrect_name": "Chromium",
4095 }, {
4096 "filename_postfix": "chromium_strings.grd",
4097 "correct_name": "Chromium",
4098 "incorrect_name": "Chrome",
4099 }]
4100
4101 for test_case in test_cases:
4102 problems = []
4103 filename_filter = lambda x: x.LocalPath().endswith(
4104 test_case["filename_postfix"])
4105
4106 # Check each new line. Can yield false positives in multiline comments, but
4107 # easier than trying to parse the XML because messages can have nested
4108 # children, and associating message elements with affected lines is hard.
4109 for f in input_api.AffectedSourceFiles(filename_filter):
4110 for line_num, line in f.ChangedContents():
4111 if "<message" in line or "<!--" in line or "-->" in line:
4112 continue
4113 if test_case["incorrect_name"] in line:
4114 problems.append(
4115 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4116
4117 if problems:
4118 message = (
4119 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4120 % (test_case["correct_name"], test_case["correct_name"],
4121 test_case["incorrect_name"]))
4122 all_problems.append(
4123 output_api.PresubmitPromptWarning(message, items=problems))
4124
4125 return all_problems
4126
4127
Saagar Sanghavifceeaae2020-08-12 16:40:364128def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514129 # TODO(crbug.com/941824): We need to make sure the entries in
4130 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4131 # so that users of //buildtools in other projects get the same tooling
4132 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4133 # support to gclient, we can eliminate the duplication and delete
4134 # this presubmit check.
4135
4136 # Update this regexp if new revisions are added to the files.
4137 rev_regexp = input_api.re.compile(
Michael Savigny8b078012020-12-09 16:19:054138 ("'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version|"
4139 "reclient_version)':"))
Dirk Pranke3c18a382019-03-15 01:07:514140
4141 # If a user is changing one revision, they need to change the same
4142 # line in both files. This means that any given change should contain
4143 # exactly the same list of changed lines that match the regexps. The
4144 # replace(' ', '') call allows us to ignore whitespace changes to the
4145 # lines. The 'long_text' parameter to the error will contain the
4146 # list of changed lines in both files, which should make it easy enough
4147 # to spot the error without going overboard in this implementation.
Ola Rozenfeld355a1b4e2021-01-26 03:41:574148 buildtools_deps = input_api.os_path.join('buildtools', 'DEPS')
Dirk Pranke3c18a382019-03-15 01:07:514149 revs_changes = {
4150 'DEPS': {},
Ola Rozenfeld355a1b4e2021-01-26 03:41:574151 buildtools_deps: {},
Dirk Pranke3c18a382019-03-15 01:07:514152 }
4153 long_text = ''
4154
4155 for f in input_api.AffectedFiles(
Ola Rozenfeld355a1b4e2021-01-26 03:41:574156 file_filter=lambda f: f.LocalPath() in ('DEPS', buildtools_deps)):
Dirk Pranke3c18a382019-03-15 01:07:514157 for line_num, line in f.ChangedContents():
4158 if rev_regexp.search(line):
4159 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4160 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4161
Ola Rozenfeld355a1b4e2021-01-26 03:41:574162 if set(revs_changes['DEPS']) != set(revs_changes[buildtools_deps]):
Dirk Pranke3c18a382019-03-15 01:07:514163 return [output_api.PresubmitError(
Ola Rozenfeld355a1b4e2021-01-26 03:41:574164 'Change buildtools revisions in sync in both DEPS and ' +
4165 buildtools_deps + '.', long_text=long_text + '\n')]
Dirk Pranke3c18a382019-03-15 01:07:514166 else:
4167 return []
4168
4169
Saagar Sanghavifceeaae2020-08-12 16:40:364170def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364171 """Avoid large files, especially binary files, in the repository since
4172 git doesn't scale well for those. They will be in everyone's repo
4173 clones forever, forever making Chromium slower to clone and work
4174 with."""
4175
4176 # Uploading files to cloud storage is not trivial so we don't want
4177 # to set the limit too low, but the upper limit for "normal" large
4178 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4179 # anything over 20 MB is exceptional.
4180 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4181
4182 too_large_files = []
4183 for f in input_api.AffectedFiles():
4184 # Check both added and modified files (but not deleted files).
4185 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384186 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364187 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4188 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4189
4190 if too_large_files:
4191 message = (
4192 'Do not commit large files to git since git scales badly for those.\n' +
4193 'Instead put the large files in cloud storage and use DEPS to\n' +
4194 'fetch them.\n' + '\n'.join(too_large_files)
4195 )
4196 return [output_api.PresubmitError(
4197 'Too large files found in commit', long_text=message + '\n')]
4198 else:
4199 return []
4200
Max Morozb47503b2019-08-08 21:03:274201
Saagar Sanghavifceeaae2020-08-12 16:40:364202def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274203 """Checks specific for fuzz target sources."""
4204 EXPORTED_SYMBOLS = [
4205 'LLVMFuzzerInitialize',
4206 'LLVMFuzzerCustomMutator',
4207 'LLVMFuzzerCustomCrossOver',
4208 'LLVMFuzzerMutate',
4209 ]
4210
4211 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4212
4213 def FilterFile(affected_file):
4214 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444215 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4216 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274217
4218 return input_api.FilterSourceFile(
4219 affected_file,
James Cook24a504192020-07-23 00:08:444220 files_to_check=[files_to_check],
4221 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274222
4223 files_with_missing_header = []
4224 for f in input_api.AffectedSourceFiles(FilterFile):
4225 contents = input_api.ReadFile(f, 'r')
4226 if REQUIRED_HEADER in contents:
4227 continue
4228
4229 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4230 files_with_missing_header.append(f.LocalPath())
4231
4232 if not files_with_missing_header:
4233 return []
4234
4235 long_text = (
4236 'If you define any of the libFuzzer optional functions (%s), it is '
4237 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4238 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4239 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4240 'to access command line arguments passed to the fuzzer. Instead, prefer '
4241 'static initialization and shared resources as documented in '
4242 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4243 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4244 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4245 )
4246
4247 return [output_api.PresubmitPromptWarning(
4248 message="Missing '%s' in:" % REQUIRED_HEADER,
4249 items=files_with_missing_header,
4250 long_text=long_text)]
4251
4252
Mohamed Heikald048240a2019-11-12 16:57:374253def _CheckNewImagesWarning(input_api, output_api):
4254 """
4255 Warns authors who add images into the repo to make sure their images are
4256 optimized before committing.
4257 """
4258 images_added = False
4259 image_paths = []
4260 errors = []
4261 filter_lambda = lambda x: input_api.FilterSourceFile(
4262 x,
James Cook24a504192020-07-23 00:08:444263 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4264 + input_api.DEFAULT_FILES_TO_SKIP),
4265 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374266 )
4267 for f in input_api.AffectedFiles(
4268 include_deletes=False, file_filter=filter_lambda):
4269 local_path = f.LocalPath().lower()
4270 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4271 images_added = True
4272 image_paths.append(f)
4273 if images_added:
4274 errors.append(output_api.PresubmitPromptWarning(
4275 'It looks like you are trying to commit some images. If these are '
4276 'non-test-only images, please make sure to read and apply the tips in '
4277 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4278 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4279 'FYI only and will not block your CL on the CQ.', image_paths))
4280 return errors
4281
4282
Saagar Sanghavifceeaae2020-08-12 16:40:364283def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574284 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224285 results = []
dgnaa68d5e2015-06-10 10:08:224286 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174287 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224288 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294289 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064290 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4291 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424292 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184293 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574294 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374295 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154296 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574297 return results
4298
Saagar Sanghavifceeaae2020-08-12 16:40:364299def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574300 """Groups commit checks that target android code."""
4301 results = []
4302 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224303 return results
4304
Chris Hall59f8d0c72020-05-01 07:31:194305# TODO(chrishall): could we additionally match on any path owned by
4306# ui/accessibility/OWNERS ?
4307_ACCESSIBILITY_PATHS = (
4308 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4309 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4310 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4311 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4312 r"^content[\\/]browser[\\/]accessibility[\\/]",
4313 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4314 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4315 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4316 r"^ui[\\/]accessibility[\\/]",
4317 r"^ui[\\/]views[\\/]accessibility[\\/]",
4318)
4319
Saagar Sanghavifceeaae2020-08-12 16:40:364320def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194321 """Checks that commits to accessibility code contain an AX-Relnotes field in
4322 their commit message."""
4323 def FileFilter(affected_file):
4324 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444325 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194326
4327 # Only consider changes affecting accessibility paths.
4328 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4329 return []
4330
Akihiro Ota08108e542020-05-20 15:30:534331 # AX-Relnotes can appear in either the description or the footer.
4332 # When searching the description, require 'AX-Relnotes:' to appear at the
4333 # beginning of a line.
4334 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4335 description_has_relnotes = any(ax_regex.match(line)
4336 for line in input_api.change.DescriptionText().lower().splitlines())
4337
4338 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4339 'AX-Relnotes', [])
4340 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194341 return []
4342
4343 # TODO(chrishall): link to Relnotes documentation in message.
4344 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4345 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4346 "user-facing changes"
4347 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4348 "user-facing effects"
4349 "\n if this is confusing or annoying then please contact members "
4350 "of ui/accessibility/OWNERS.")
4351
4352 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224353
Saagar Sanghavifceeaae2020-08-12 16:40:364354def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394355 """Checks common to both upload and commit."""
4356 results = []
4357 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384358 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544359 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084360
4361 author = input_api.change.author_email
4362 if author and author not in _KNOWN_ROBOTS:
4363 results.extend(
4364 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4365
[email protected]9f919cc2013-07-31 03:04:044366 results.extend(
4367 input_api.canned_checks.CheckChangeHasNoTabs(
4368 input_api,
4369 output_api,
4370 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434371 results.extend(input_api.RunTests(
4372 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244373
Edward Lesmesce51df52020-08-04 22:10:174374 dirmd_bin = input_api.os_path.join(
4375 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4376 results.extend(input_api.RunTests(
4377 input_api.canned_checks.CheckDirMetadataFormat(
4378 input_api, output_api, dirmd_bin)))
4379 results.extend(
4380 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4381 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554382 results.extend(
4383 input_api.canned_checks.CheckNoNewMetadataInOwners(
4384 input_api, output_api))
Edward Lesmesce51df52020-08-04 22:10:174385
Vaclav Brozekcdc7defb2018-03-20 09:54:354386 for f in input_api.AffectedFiles():
4387 path, name = input_api.os_path.split(f.LocalPath())
4388 if name == 'PRESUBMIT.py':
4389 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004390 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4391 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074392 # The PRESUBMIT.py file (and the directory containing it) might
4393 # have been affected by being moved or removed, so only try to
4394 # run the tests if they still exist.
4395 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4396 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444397 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394398 return results
[email protected]1f7b4172010-01-28 01:17:344399
[email protected]b337cb5b2011-01-23 21:24:054400
Saagar Sanghavifceeaae2020-08-12 16:40:364401def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494402 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4403 if f.LocalPath().endswith(('.orig', '.rej'))]
4404 if problems:
4405 return [output_api.PresubmitError(
4406 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034407 else:
4408 return []
[email protected]b8079ae4a2012-12-05 19:56:494409
4410
Saagar Sanghavifceeaae2020-08-12 16:40:364411def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214412 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4413 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4414 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074415 include_re = input_api.re.compile(
4416 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4417 extension_re = input_api.re.compile(r'\.[a-z]+$')
4418 errors = []
4419 for f in input_api.AffectedFiles():
4420 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4421 continue
4422 found_line_number = None
4423 found_macro = None
4424 for line_num, line in f.ChangedContents():
4425 match = macro_re.search(line)
4426 if match:
4427 found_line_number = line_num
4428 found_macro = match.group(2)
4429 break
4430 if not found_line_number:
4431 continue
4432
4433 found_include = False
4434 for line in f.NewContents():
4435 if include_re.search(line):
4436 found_include = True
4437 break
4438 if found_include:
4439 continue
4440
4441 if not f.LocalPath().endswith('.h'):
4442 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4443 try:
4444 content = input_api.ReadFile(primary_header_path, 'r')
4445 if include_re.search(content):
4446 continue
4447 except IOError:
4448 pass
4449 errors.append('%s:%d %s macro is used without including build/'
4450 'build_config.h.'
4451 % (f.LocalPath(), found_line_number, found_macro))
4452 if errors:
4453 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4454 return []
4455
4456
[email protected]b00342e7f2013-03-26 16:21:544457def _DidYouMeanOSMacro(bad_macro):
4458 try:
4459 return {'A': 'OS_ANDROID',
4460 'B': 'OS_BSD',
4461 'C': 'OS_CHROMEOS',
4462 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444463 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544464 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444465 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544466 'N': 'OS_NACL',
4467 'O': 'OS_OPENBSD',
4468 'P': 'OS_POSIX',
4469 'S': 'OS_SOLARIS',
4470 'W': 'OS_WIN'}[bad_macro[3].upper()]
4471 except KeyError:
4472 return ''
4473
4474
4475def _CheckForInvalidOSMacrosInFile(input_api, f):
4476 """Check for sensible looking, totally invalid OS macros."""
4477 preprocessor_statement = input_api.re.compile(r'^\s*#')
4478 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4479 results = []
4480 for lnum, line in f.ChangedContents():
4481 if preprocessor_statement.search(line):
4482 for match in os_macro.finditer(line):
4483 if not match.group(1) in _VALID_OS_MACROS:
4484 good = _DidYouMeanOSMacro(match.group(1))
4485 did_you_mean = ' (did you mean %s?)' % good if good else ''
4486 results.append(' %s:%d %s%s' % (f.LocalPath(),
4487 lnum,
4488 match.group(1),
4489 did_you_mean))
4490 return results
4491
4492
Saagar Sanghavifceeaae2020-08-12 16:40:364493def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544494 """Check all affected files for invalid OS macros."""
4495 bad_macros = []
tzik3f295992018-12-04 20:32:234496 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474497 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544498 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4499
4500 if not bad_macros:
4501 return []
4502
4503 return [output_api.PresubmitError(
4504 'Possibly invalid OS macro[s] found. Please fix your code\n'
4505 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4506
lliabraa35bab3932014-10-01 12:16:444507
4508def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4509 """Check all affected files for invalid "if defined" macros."""
4510 ALWAYS_DEFINED_MACROS = (
4511 "TARGET_CPU_PPC",
4512 "TARGET_CPU_PPC64",
4513 "TARGET_CPU_68K",
4514 "TARGET_CPU_X86",
4515 "TARGET_CPU_ARM",
4516 "TARGET_CPU_MIPS",
4517 "TARGET_CPU_SPARC",
4518 "TARGET_CPU_ALPHA",
4519 "TARGET_IPHONE_SIMULATOR",
4520 "TARGET_OS_EMBEDDED",
4521 "TARGET_OS_IPHONE",
4522 "TARGET_OS_MAC",
4523 "TARGET_OS_UNIX",
4524 "TARGET_OS_WIN32",
4525 )
4526 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4527 results = []
4528 for lnum, line in f.ChangedContents():
4529 for match in ifdef_macro.finditer(line):
4530 if match.group(1) in ALWAYS_DEFINED_MACROS:
4531 always_defined = ' %s is always defined. ' % match.group(1)
4532 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4533 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4534 lnum,
4535 always_defined,
4536 did_you_mean))
4537 return results
4538
4539
Saagar Sanghavifceeaae2020-08-12 16:40:364540def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444541 """Check all affected files for invalid "if defined" macros."""
4542 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054543 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444544 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054545 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214546 continue
lliabraa35bab3932014-10-01 12:16:444547 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4548 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4549
4550 if not bad_macros:
4551 return []
4552
4553 return [output_api.PresubmitError(
4554 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4555 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4556 bad_macros)]
4557
4558
Saagar Sanghavifceeaae2020-08-12 16:40:364559def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044560 """Check for same IPC rules described in
4561 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4562 """
4563 base_pattern = r'IPC_ENUM_TRAITS\('
4564 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4565 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4566
4567 problems = []
4568 for f in input_api.AffectedSourceFiles(None):
4569 local_path = f.LocalPath()
4570 if not local_path.endswith('.h'):
4571 continue
4572 for line_number, line in f.ChangedContents():
4573 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4574 problems.append(
4575 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4576
4577 if problems:
4578 return [output_api.PresubmitPromptWarning(
4579 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4580 else:
4581 return []
4582
[email protected]b00342e7f2013-03-26 16:21:544583
Saagar Sanghavifceeaae2020-08-12 16:40:364584def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054585 """Check to make sure no files being submitted have long paths.
4586 This causes issues on Windows.
4587 """
4588 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194589 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054590 local_path = f.LocalPath()
4591 # Windows has a path limit of 260 characters. Limit path length to 200 so
4592 # that we have some extra for the prefix on dev machines and the bots.
4593 if len(local_path) > 200:
4594 problems.append(local_path)
4595
4596 if problems:
4597 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4598 else:
4599 return []
4600
4601
Saagar Sanghavifceeaae2020-08-12 16:40:364602def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144603 """Check that header files have proper guards against multiple inclusion.
4604 If a file should not have such guards (and it probably should) then it
4605 should include the string "no-include-guard-because-multiply-included".
4606 """
Daniel Bratell6a75baef62018-06-04 10:04:454607 def is_chromium_header_file(f):
4608 # We only check header files under the control of the Chromium
4609 # project. That is, those outside third_party apart from
4610 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324611 # We also exclude *_message_generator.h headers as they use
4612 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454613 file_with_path = input_api.os_path.normpath(f.LocalPath())
4614 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324615 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454616 (not file_with_path.startswith('third_party') or
4617 file_with_path.startswith(
4618 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144619
4620 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344621 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144622
4623 errors = []
4624
Daniel Bratell6a75baef62018-06-04 10:04:454625 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144626 guard_name = None
4627 guard_line_number = None
4628 seen_guard_end = False
4629
4630 file_with_path = input_api.os_path.normpath(f.LocalPath())
4631 base_file_name = input_api.os_path.splitext(
4632 input_api.os_path.basename(file_with_path))[0]
4633 upper_base_file_name = base_file_name.upper()
4634
4635 expected_guard = replace_special_with_underscore(
4636 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144637
4638 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574639 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4640 # are too many (1000+) files with slight deviations from the
4641 # coding style. The most important part is that the include guard
4642 # is there, and that it's unique, not the name so this check is
4643 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144644 #
4645 # As code becomes more uniform, this could be made stricter.
4646
4647 guard_name_pattern_list = [
4648 # Anything with the right suffix (maybe with an extra _).
4649 r'\w+_H__?',
4650
Daniel Bratell39b5b062018-05-16 18:09:574651 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144652 r'\w+_h',
4653
4654 # Anything including the uppercase name of the file.
4655 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4656 upper_base_file_name)) + r'\w*',
4657 ]
4658 guard_name_pattern = '|'.join(guard_name_pattern_list)
4659 guard_pattern = input_api.re.compile(
4660 r'#ifndef\s+(' + guard_name_pattern + ')')
4661
4662 for line_number, line in enumerate(f.NewContents()):
4663 if 'no-include-guard-because-multiply-included' in line:
4664 guard_name = 'DUMMY' # To not trigger check outside the loop.
4665 break
4666
4667 if guard_name is None:
4668 match = guard_pattern.match(line)
4669 if match:
4670 guard_name = match.group(1)
4671 guard_line_number = line_number
4672
Daniel Bratell39b5b062018-05-16 18:09:574673 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454674 # don't match the chromium style guide, but new files should
4675 # get it right.
4676 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574677 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144678 errors.append(output_api.PresubmitPromptWarning(
4679 'Header using the wrong include guard name %s' % guard_name,
4680 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574681 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144682 else:
4683 # The line after #ifndef should have a #define of the same name.
4684 if line_number == guard_line_number + 1:
4685 expected_line = '#define %s' % guard_name
4686 if line != expected_line:
4687 errors.append(output_api.PresubmitPromptWarning(
4688 'Missing "%s" for include guard' % expected_line,
4689 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4690 'Expected: %r\nGot: %r' % (expected_line, line)))
4691
4692 if not seen_guard_end and line == '#endif // %s' % guard_name:
4693 seen_guard_end = True
4694 elif seen_guard_end:
4695 if line.strip() != '':
4696 errors.append(output_api.PresubmitPromptWarning(
4697 'Include guard %s not covering the whole file' % (
4698 guard_name), [f.LocalPath()]))
4699 break # Nothing else to check and enough to warn once.
4700
4701 if guard_name is None:
4702 errors.append(output_api.PresubmitPromptWarning(
4703 'Missing include guard %s' % expected_guard,
4704 [f.LocalPath()],
4705 'Missing include guard in %s\n'
4706 'Recommended name: %s\n'
4707 'This check can be disabled by having the string\n'
4708 'no-include-guard-because-multiply-included in the header.' %
4709 (f.LocalPath(), expected_guard)))
4710
4711 return errors
4712
4713
Saagar Sanghavifceeaae2020-08-12 16:40:364714def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234715 """Check source code and known ascii text files for Windows style line
4716 endings.
4717 """
earthdok1b5e0ee2015-03-10 15:19:104718 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234719
4720 file_inclusion_pattern = (
4721 known_text_files,
4722 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4723 )
4724
mostynbb639aca52015-01-07 20:31:234725 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534726 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444727 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534728 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504729 include_file = False
4730 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234731 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504732 include_file = True
4733 if include_file:
4734 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234735
4736 if problems:
4737 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4738 'these files to contain Windows style line endings?\n' +
4739 '\n'.join(problems))]
4740
4741 return []
4742
4743
Saagar Sanghavifceeaae2020-08-12 16:40:364744def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134745 """Checks that all source files use SYSLOG properly."""
4746 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364747 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564748 for line_number, line in f.ChangedContents():
4749 if 'SYSLOG' in line:
4750 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4751
pastarmovj89f7ee12016-09-20 14:58:134752 if syslog_files:
4753 return [output_api.PresubmitPromptWarning(
4754 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4755 ' calls.\nFiles to check:\n', items=syslog_files)]
4756 return []
4757
4758
[email protected]1f7b4172010-01-28 01:17:344759def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364760 if input_api.version < [2, 0, 0]:
4761 return [output_api.PresubmitError("Your depot_tools is out of date. "
4762 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4763 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344764 results = []
scottmg39b29952014-12-08 18:31:284765 results.extend(
jam93a6ee792017-02-08 23:59:224766 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544767 return results
[email protected]ca8d19842009-02-19 16:33:124768
4769
[email protected]1bfb8322014-04-23 01:02:414770def GetTryServerMasterForBot(bot):
4771 """Returns the Try Server master for the given bot.
4772
[email protected]0bb112362014-07-26 04:38:324773 It tries to guess the master from the bot name, but may still fail
4774 and return None. There is no longer a default master.
4775 """
4776 # Potentially ambiguous bot names are listed explicitly.
4777 master_map = {
tandriie5587792016-07-14 00:34:504778 'chromium_presubmit': 'master.tryserver.chromium.linux',
4779 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414780 }
[email protected]0bb112362014-07-26 04:38:324781 master = master_map.get(bot)
4782 if not master:
wnwen4fbaab82016-05-25 12:54:364783 if 'android' in bot:
tandriie5587792016-07-14 00:34:504784 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364785 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504786 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324787 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504788 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324789 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504790 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324791 return master
[email protected]1bfb8322014-04-23 01:02:414792
4793
[email protected]ca8d19842009-02-19 16:33:124794def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364795 if input_api.version < [2, 0, 0]:
4796 return [output_api.PresubmitError("Your depot_tools is out of date. "
4797 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4798 "but your version is %d.%d.%d" % tuple(input_api.version))]
4799
[email protected]fe5f57c52009-06-05 14:25:544800 results = []
[email protected]fe5f57c52009-06-05 14:25:544801 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274802 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344803 input_api,
4804 output_api,
[email protected]2fdd1f362013-01-16 03:56:034805 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274806
jam93a6ee792017-02-08 23:59:224807 results.extend(
4808 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544809 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4810 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384811 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4812 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414813 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4814 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544815 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144816
4817
Saagar Sanghavifceeaae2020-08-12 16:40:364818def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264819 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024820 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4821 # footer is set to true.
4822 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264823 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024824 footer.lower()
4825 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264826 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024827
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144828 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264829 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144830 import sys
4831 from io import StringIO
4832
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144833 new_or_added_paths = set(f.LocalPath()
4834 for f in input_api.AffectedFiles()
4835 if (f.Action() == 'A' or f.Action() == 'M'))
4836 removed_paths = set(f.LocalPath()
4837 for f in input_api.AffectedFiles(include_deletes=True)
4838 if f.Action() == 'D')
4839
Andrew Grieve0e8790c2020-09-03 17:27:324840 affected_grds = [
4841 f for f in input_api.AffectedFiles()
4842 if f.LocalPath().endswith(('.grd', '.grdp'))
4843 ]
4844 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164845 if not affected_grds:
4846 return []
4847
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144848 affected_png_paths = [f.AbsoluteLocalPath()
4849 for f in input_api.AffectedFiles()
4850 if (f.LocalPath().endswith('.png'))]
4851
4852 # Check for screenshots. Developers can upload screenshots using
4853 # tools/translation/upload_screenshots.py which finds and uploads
4854 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4855 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4856 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4857 #
4858 # The logic here is as follows:
4859 #
4860 # - If the CL has a .png file under the screenshots directory for a grd
4861 # file, warn the developer. Actual images should never be checked into the
4862 # Chrome repo.
4863 #
4864 # - If the CL contains modified or new messages in grd files and doesn't
4865 # contain the corresponding .sha1 files, warn the developer to add images
4866 # and upload them via tools/translation/upload_screenshots.py.
4867 #
4868 # - If the CL contains modified or new messages in grd files and the
4869 # corresponding .sha1 files, everything looks good.
4870 #
4871 # - If the CL contains removed messages in grd files but the corresponding
4872 # .sha1 files aren't removed, warn the developer to remove them.
4873 unnecessary_screenshots = []
4874 missing_sha1 = []
4875 unnecessary_sha1_files = []
4876
Rainhard Findlingfc31844c52020-05-15 09:58:264877 # This checks verifies that the ICU syntax of messages this CL touched is
4878 # valid, and reports any found syntax errors.
4879 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4880 # without developers being aware of them. Later on, such ICU syntax errors
4881 # break message extraction for translation, hence would block Chromium
4882 # translations until they are fixed.
4883 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144884
4885 def _CheckScreenshotAdded(screenshots_dir, message_id):
4886 sha1_path = input_api.os_path.join(
4887 screenshots_dir, message_id + '.png.sha1')
4888 if sha1_path not in new_or_added_paths:
4889 missing_sha1.append(sha1_path)
4890
4891
4892 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4893 sha1_path = input_api.os_path.join(
4894 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034895 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144896 unnecessary_sha1_files.append(sha1_path)
4897
Rainhard Findlingfc31844c52020-05-15 09:58:264898
4899 def _ValidateIcuSyntax(text, level, signatures):
4900 """Validates ICU syntax of a text string.
4901
4902 Check if text looks similar to ICU and checks for ICU syntax correctness
4903 in this case. Reports various issues with ICU syntax and values of
4904 variants. Supports checking of nested messages. Accumulate information of
4905 each ICU messages found in the text for further checking.
4906
4907 Args:
4908 text: a string to check.
4909 level: a number of current nesting level.
4910 signatures: an accumulator, a list of tuple of (level, variable,
4911 kind, variants).
4912
4913 Returns:
4914 None if a string is not ICU or no issue detected.
4915 A tuple of (message, start index, end index) if an issue detected.
4916 """
4917 valid_types = {
4918 'plural': (frozenset(
4919 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4920 frozenset(['=1', 'other'])),
4921 'selectordinal': (frozenset(
4922 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4923 frozenset(['one', 'other'])),
4924 'select': (frozenset(), frozenset(['other'])),
4925 }
4926
4927 # Check if the message looks like an attempt to use ICU
4928 # plural. If yes - check if its syntax strictly matches ICU format.
4929 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4930 if not like:
4931 signatures.append((level, None, None, None))
4932 return
4933
4934 # Check for valid prefix and suffix
4935 m = re.match(
4936 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4937 r'(plural|selectordinal|select),\s*'
4938 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4939 if not m:
4940 return (('This message looks like an ICU plural, '
4941 'but does not follow ICU syntax.'), like.start(), like.end())
4942 starting, variable, kind, variant_pairs = m.groups()
4943 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4944 if depth:
4945 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4946 len(text))
4947 first = text[0]
4948 ending = text[last_pos:]
4949 if not starting:
4950 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4951 last_pos)
4952 if not ending or '}' not in ending:
4953 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4954 last_pos)
4955 elif first != '{':
4956 return (
4957 ('Invalid ICU format. Extra characters at the start of a complex '
4958 'message (go/icu-message-migration): "%s"') %
4959 starting, 0, len(starting))
4960 elif ending != '}':
4961 return (('Invalid ICU format. Extra characters at the end of a complex '
4962 'message (go/icu-message-migration): "%s"')
4963 % ending, last_pos - 1, len(text) - 1)
4964 if kind not in valid_types:
4965 return (('Unknown ICU message type %s. '
4966 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4967 known, required = valid_types[kind]
4968 defined_variants = set()
4969 for variant, variant_range, value, value_range in variants:
4970 start, end = variant_range
4971 if variant in defined_variants:
4972 return ('Variant "%s" is defined more than once' % variant,
4973 start, end)
4974 elif known and variant not in known:
4975 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4976 start, end)
4977 defined_variants.add(variant)
4978 # Check for nested structure
4979 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4980 if res:
4981 return (res[0], res[1] + value_range[0] + 1,
4982 res[2] + value_range[0] + 1)
4983 missing = required - defined_variants
4984 if missing:
4985 return ('Required variants missing: %s' % ', '.join(missing), 0,
4986 len(text))
4987 signatures.append((level, variable, kind, defined_variants))
4988
4989
4990 def _ParseIcuVariants(text, offset=0):
4991 """Parse variants part of ICU complex message.
4992
4993 Builds a tuple of variant names and values, as well as
4994 their offsets in the input string.
4995
4996 Args:
4997 text: a string to parse
4998 offset: additional offset to add to positions in the text to get correct
4999 position in the complete ICU string.
5000
5001 Returns:
5002 List of tuples, each tuple consist of four fields: variant name,
5003 variant name span (tuple of two integers), variant value, value
5004 span (tuple of two integers).
5005 """
5006 depth, start, end = 0, -1, -1
5007 variants = []
5008 key = None
5009 for idx, char in enumerate(text):
5010 if char == '{':
5011 if not depth:
5012 start = idx
5013 chunk = text[end + 1:start]
5014 key = chunk.strip()
5015 pos = offset + end + 1 + chunk.find(key)
5016 span = (pos, pos + len(key))
5017 depth += 1
5018 elif char == '}':
5019 if not depth:
5020 return variants, depth, offset + idx
5021 depth -= 1
5022 if not depth:
5023 end = idx
5024 variants.append((key, span, text[start:end + 1], (offset + start,
5025 offset + end + 1)))
5026 return variants, depth, offset + end + 1
5027
meacer8c0d3832019-12-26 21:46:165028 try:
5029 old_sys_path = sys.path
5030 sys.path = sys.path + [input_api.os_path.join(
5031 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5032 from helper import grd_helper
5033 finally:
5034 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145035
5036 for f in affected_grds:
5037 file_path = f.LocalPath()
5038 old_id_to_msg_map = {}
5039 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385040 # Note that this code doesn't check if the file has been deleted. This is
5041 # OK because it only uses the old and new file contents and doesn't load
5042 # the file via its path.
5043 # It's also possible that a file's content refers to a renamed or deleted
5044 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5045 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5046 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145047 if file_path.endswith('.grdp'):
5048 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585049 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395050 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145051 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585052 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395053 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145054 else:
meacerff8a9b62019-12-10 19:43:585055 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145056 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585057 old_id_to_msg_map = grd_helper.GetGrdMessages(
5058 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145059 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585060 new_id_to_msg_map = grd_helper.GetGrdMessages(
5061 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145062
Rainhard Findlingd8d04372020-08-13 13:30:095063 grd_name, ext = input_api.os_path.splitext(
5064 input_api.os_path.basename(file_path))
5065 screenshots_dir = input_api.os_path.join(
5066 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5067
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145068 # Compute added, removed and modified message IDs.
5069 old_ids = set(old_id_to_msg_map)
5070 new_ids = set(new_id_to_msg_map)
5071 added_ids = new_ids - old_ids
5072 removed_ids = old_ids - new_ids
5073 modified_ids = set([])
5074 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355075 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095076 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5077 # The message content itself changed. Require an updated screenshot.
5078 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355079 elif old_id_to_msg_map[key].attrs['meaning'] != \
5080 new_id_to_msg_map[key].attrs['meaning']:
5081 # The message meaning changed. Ensure there is a screenshot for it.
5082 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5083 if sha1_path not in new_or_added_paths and not \
5084 input_api.os_path.exists(sha1_path):
5085 # There is neither a previous screenshot nor is a new one added now.
5086 # Require a screenshot.
5087 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145088
Rainhard Findlingfc31844c52020-05-15 09:58:265089 if run_screenshot_check:
5090 # Check the screenshot directory for .png files. Warn if there is any.
5091 for png_path in affected_png_paths:
5092 if png_path.startswith(screenshots_dir):
5093 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145094
Rainhard Findlingfc31844c52020-05-15 09:58:265095 for added_id in added_ids:
5096 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145097
Rainhard Findlingfc31844c52020-05-15 09:58:265098 for modified_id in modified_ids:
5099 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145100
Rainhard Findlingfc31844c52020-05-15 09:58:265101 for removed_id in removed_ids:
5102 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5103
5104 # Check new and changed strings for ICU syntax errors.
5105 for key in added_ids.union(modified_ids):
5106 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5107 err = _ValidateIcuSyntax(msg, 0, [])
5108 if err is not None:
5109 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145110
5111 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265112 if run_screenshot_check:
5113 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005114 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265115 'Do not include actual screenshots in the changelist. Run '
5116 'tools/translate/upload_screenshots.py to upload them instead:',
5117 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145118
Rainhard Findlingfc31844c52020-05-15 09:58:265119 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005120 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265121 'You are adding or modifying UI strings.\n'
5122 'To ensure the best translations, take screenshots of the relevant UI '
5123 '(https://g.co/chrome/translation) and add these files to your '
5124 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145125
Rainhard Findlingfc31844c52020-05-15 09:58:265126 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005127 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265128 'You removed strings associated with these files. Remove:',
5129 sorted(unnecessary_sha1_files)))
5130 else:
5131 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5132 'screenshots check.'))
5133
5134 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075135 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265136 'ICU syntax errors were found in the following strings (problems or '
5137 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145138
5139 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125140
5141
Saagar Sanghavifceeaae2020-08-12 16:40:365142def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125143 repo_root=None,
5144 translation_expectations_path=None,
5145 grd_files=None):
5146 import sys
5147 affected_grds = [f for f in input_api.AffectedFiles()
5148 if (f.LocalPath().endswith('.grd') or
5149 f.LocalPath().endswith('.grdp'))]
5150 if not affected_grds:
5151 return []
5152
5153 try:
5154 old_sys_path = sys.path
5155 sys.path = sys.path + [
5156 input_api.os_path.join(
5157 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5158 from helper import git_helper
5159 from helper import translation_helper
5160 finally:
5161 sys.path = old_sys_path
5162
5163 # Check that translation expectations can be parsed and we can get a list of
5164 # translatable grd files. |repo_root| and |translation_expectations_path| are
5165 # only passed by tests.
5166 if not repo_root:
5167 repo_root = input_api.PresubmitLocalPath()
5168 if not translation_expectations_path:
5169 translation_expectations_path = input_api.os_path.join(
5170 repo_root, 'tools', 'gritsettings',
5171 'translation_expectations.pyl')
5172 if not grd_files:
5173 grd_files = git_helper.list_grds_in_repository(repo_root)
5174
dpapad8e21b472020-10-23 17:15:035175 # Ignore bogus grd files used only for testing
5176 # ui/webui/resoucres/tools/generate_grd.py.
5177 ignore_path = input_api.os_path.join(
5178 'ui', 'webui', 'resources', 'tools', 'tests')
5179 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5180
Mustafa Emre Acer51f2f742020-03-09 19:41:125181 try:
5182 translation_helper.get_translatable_grds(repo_root, grd_files,
5183 translation_expectations_path)
5184 except Exception as e:
5185 return [output_api.PresubmitNotifyResult(
5186 'Failed to get a list of translatable grd files. This happens when:\n'
5187 ' - One of the modified grd or grdp files cannot be parsed or\n'
5188 ' - %s is not updated.\n'
5189 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5190 return []
Ken Rockotc31f4832020-05-29 18:58:515191
5192
Saagar Sanghavifceeaae2020-08-12 16:40:365193def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515194 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095195 changed_mojoms = input_api.AffectedFiles(
5196 include_deletes=True,
5197 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515198 delta = []
5199 for mojom in changed_mojoms:
5200 old_contents = ''.join(mojom.OldContents()) or None
5201 new_contents = ''.join(mojom.NewContents()) or None
5202 delta.append({
5203 'filename': mojom.LocalPath(),
5204 'old': '\n'.join(mojom.OldContents()) or None,
5205 'new': '\n'.join(mojom.NewContents()) or None,
5206 })
5207
5208 process = input_api.subprocess.Popen(
5209 [input_api.python_executable,
5210 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5211 'public', 'tools', 'mojom',
5212 'check_stable_mojom_compatibility.py'),
5213 '--src-root', input_api.PresubmitLocalPath()],
5214 stdin=input_api.subprocess.PIPE,
5215 stdout=input_api.subprocess.PIPE,
5216 stderr=input_api.subprocess.PIPE,
5217 universal_newlines=True)
5218 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5219 if process.returncode:
5220 return [output_api.PresubmitError(
5221 'One or more [Stable] mojom definitions appears to have been changed '
5222 'in a way that is not backward-compatible.',
5223 long_text=error)]
5224 return []
Dominic Battre645d42342020-12-04 16:14:105225
5226def CheckDeprecationOfPreferences(input_api, output_api):
5227 """Removing a preference should come with a deprecation."""
5228
5229 def FilterFile(affected_file):
5230 """Accept only .cc files and the like."""
5231 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5232 files_to_skip = (_EXCLUDED_PATHS +
5233 _TEST_CODE_EXCLUDED_PATHS +
5234 input_api.DEFAULT_FILES_TO_SKIP)
5235 return input_api.FilterSourceFile(
5236 affected_file,
5237 files_to_check=file_inclusion_pattern,
5238 files_to_skip=files_to_skip)
5239
5240 def ModifiedLines(affected_file):
5241 """Returns a list of tuples (line number, line text) of added and removed
5242 lines.
5243
5244 Deleted lines share the same line number as the previous line.
5245
5246 This relies on the scm diff output describing each changed code section
5247 with a line of the form
5248
5249 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5250 """
5251 line_num = 0
5252 modified_lines = []
5253 for line in affected_file.GenerateScmDiff().splitlines():
5254 # Extract <new line num> of the patch fragment (see format above).
5255 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5256 if m:
5257 line_num = int(m.groups(1)[0])
5258 continue
5259 if ((line.startswith('+') and not line.startswith('++')) or
5260 (line.startswith('-') and not line.startswith('--'))):
5261 modified_lines.append((line_num, line))
5262
5263 if not line.startswith('-'):
5264 line_num += 1
5265 return modified_lines
5266
5267 def FindLineWith(lines, needle):
5268 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5269
5270 If 0 or >1 lines contain `needle`, -1 is returned.
5271 """
5272 matching_line_numbers = [
5273 # + 1 for 1-based counting of line numbers.
5274 i + 1 for i, line
5275 in enumerate(lines)
5276 if needle in line]
5277 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5278
5279 def ModifiedPrefMigration(affected_file):
5280 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5281 # Determine first and last lines of MigrateObsolete.*Pref functions.
5282 new_contents = affected_file.NewContents();
5283 range_1 = (
5284 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5285 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5286 range_2 = (
5287 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5288 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5289 if (-1 in range_1 + range_2):
5290 raise Exception(
5291 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5292
5293 # Check whether any of the modified lines are part of the
5294 # MigrateObsolete.*Pref functions.
5295 for line_nr, line in ModifiedLines(affected_file):
5296 if (range_1[0] <= line_nr <= range_1[1] or
5297 range_2[0] <= line_nr <= range_2[1]):
5298 return True
5299 return False
5300
5301 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5302 browser_prefs_file_pattern = input_api.re.compile(
5303 r'chrome/browser/prefs/browser_prefs.cc')
5304
5305 changes = input_api.AffectedFiles(include_deletes=True,
5306 file_filter=FilterFile)
5307 potential_problems = []
5308 for f in changes:
5309 for line in f.GenerateScmDiff().splitlines():
5310 # Check deleted lines for pref registrations.
5311 if (line.startswith('-') and not line.startswith('--') and
5312 register_pref_pattern.search(line)):
5313 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5314
5315 if browser_prefs_file_pattern.search(f.LocalPath()):
5316 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5317 # assume that they knew that they have to deprecate preferences and don't
5318 # warn.
5319 try:
5320 if ModifiedPrefMigration(f):
5321 return []
5322 except Exception as e:
5323 return [output_api.PresubmitError(str(e))]
5324
5325 if potential_problems:
5326 return [output_api.PresubmitPromptWarning(
5327 'Discovered possible removal of preference registrations.\n\n'
5328 'Please make sure to properly deprecate preferences by clearing their\n'
5329 'value for a couple of milestones before finally removing the code.\n'
5330 'Otherwise data may stay in the preferences files forever. See\n'
5331 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5332 'This may be a false positive warning (e.g. if you move preference\n'
5333 'registrations to a different place).\n',
5334 potential_problems
5335 )]
5336 return []